Merge branches 'clk-marvell', 'clk-xilinx', 'clk-mediatek' and 'clk-loongson' into clk-next

- Add Mediatek MT8196 clk drivers

* clk-marvell:
  clk: mmp: pxa1908: Instantiate power driver through auxiliary bus

* clk-xilinx:
  clk: clocking-wizard: Fix output clock register offset for Versal platforms
  clk: xilinx: Optimize divisor search in clk_wzrd_get_divisors_ver()

* clk-mediatek: (31 commits)
  clk: mediatek: Add MT8196 vencsys clock support
  clk: mediatek: Add MT8196 vdecsys clock support
  clk: mediatek: Add MT8196 ovl1 clock support
  clk: mediatek: Add MT8196 ovl0 clock support
  clk: mediatek: Add MT8196 disp-ao clock support
  clk: mediatek: Add MT8196 disp1 clock support
  clk: mediatek: Add MT8196 disp0 clock support
  clk: mediatek: Add MT8196 mfg clock support
  clk: mediatek: Add MT8196 mdpsys clock support
  clk: mediatek: Add MT8196 mcu clock support
  clk: mediatek: Add MT8196 I2C clock support
  clk: mediatek: Add MT8196 pextpsys clock support
  clk: mediatek: Add MT8196 ufssys clock support
  clk: mediatek: Add MT8196 peripheral clock support
  clk: mediatek: Add MT8196 vlpckgen clock support
  clk: mediatek: Add MT8196 topckgen2 clock support
  clk: mediatek: Add MT8196 topckgen clock support
  clk: mediatek: Add MT8196 apmixedsys clock support
  dt-bindings: clock: mediatek: Describe MT8196 clock controllers
  clk: mediatek: clk-mtk: Add MUX_DIV_GATE macro
  ...

* clk-loongson:
  clk: loongson2: Add clock definitions for Loongson-2K0300 SoC
  clk: loongson2: Avoid hardcoding firmware name of the reference clock
  clk: loongson2: Allow zero divisors for dividers
  clk: loongson2: Support scale clocks with an alternative mode
  clk: loongson2: Allow specifying clock flags for gate clock
  dt-bindings: clock: loongson2: Add Loongson-2K0300 compatible
This commit is contained in:
Stephen Boyd committed 2025-10-06 13:00:22 -05:00
44 files changed
+6414 -77

No files matched your search

@@ -16,6 +16,7 @@ description: |
properties:
compatible:
enum:
- loongson,ls2k0300-clk
- loongson,ls2k0500-clk
- loongson,ls2k-clk # This is for Loongson-2K1000
- loongson,ls2k2000-clk
@@ -24,8 +25,7 @@ properties:
maxItems: 1
clocks:
items:
- description: 100m ref
maxItems: 1
clock-names:
items:
@@ -38,11 +38,23 @@ properties:
ID in its "clocks" phandle cell. See include/dt-bindings/clock/loongson,ls2k-clk.h
for the full list of Loongson-2 SoC clock IDs.
allOf:
- if:
properties:
compatible:
contains:
const: loongson,ls2k0300-clk
then:
properties:
clock-names: false
else:
required:
- clock-names
required:
- compatible
- reg
- clocks
- clock-names
- '#clock-cells'
additionalProperties: false
@@ -0,0 +1,112 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/mediatek,mt8196-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek Functional Clock Controller for MT8196
maintainers:
- Guangjie Song <guangjie.song@mediatek.com>
- Laura Nao <laura.nao@collabora.com>
description: |
The clock architecture in MediaTek SoCs is structured like below:
PLLs -->
dividers -->
muxes
-->
clock gate
The device nodes provide clock gate control in different IP blocks.
properties:
compatible:
items:
- enum:
- mediatek,mt8196-imp-iic-wrap-c
- mediatek,mt8196-imp-iic-wrap-e
- mediatek,mt8196-imp-iic-wrap-n
- mediatek,mt8196-imp-iic-wrap-w
- mediatek,mt8196-mdpsys0
- mediatek,mt8196-mdpsys1
- mediatek,mt8196-pericfg-ao
- mediatek,mt8196-pextp0cfg-ao
- mediatek,mt8196-pextp1cfg-ao
- mediatek,mt8196-ufscfg-ao
- mediatek,mt8196-vencsys
- mediatek,mt8196-vencsys-c1
- mediatek,mt8196-vencsys-c2
- mediatek,mt8196-vdecsys
- mediatek,mt8196-vdecsys-soc
- mediatek,mt8196-vdisp-ao
- const: syscon
reg:
maxItems: 1
'#clock-cells':
const: 1
'#reset-cells':
const: 1
description:
Reset lines for PEXTP0/1 and UFS blocks.
mediatek,hardware-voter:
$ref: /schemas/types.yaml#/definitions/phandle
description: |
Phandle to the "Hardware Voter" (HWV), as named in the vendor
documentation for MT8196/MT6991.
The HWV is a SoC-internal fixed-function MCU used to collect votes from
both the Application Processor and other remote processors within the SoC.
It is intended to transparently enable or disable hardware resources (such
as power domains or clocks) based on internal vote aggregation handled by
the MCU's internal state machine.
However, in practice, this design is incomplete. While the HWV performs
some internal vote aggregation,software is still required to
- Manually enable power supplies externally, if present and if required
- Manually enable parent clocks via direct MMIO writes to clock controllers
- Enable the FENC after the clock has been ungated via direct MMIO
writes to clock controllers
As such, the HWV behaves more like a hardware-managed clock reference
counter than a true voter. Furthermore, it is not a separate
controller. It merely serves as an alternative interface to the same
underlying clock or power controller. Actual control still requires
direct access to the controller's own MMIO register space, in
addition to writing to the HWV's MMIO region.
For this reason, a custom phandle is used here - drivers need to directly
access the HWV MMIO region in a syscon-like fashion, due to how the
hardware is wired. This differs from true hardware voting systems, which
typically do not require custom phandles and rely instead on generic APIs
(clocks, power domains, interconnects).
The name "hardware-voter" is retained to match vendor documentation, but
this should not be reused or misunderstood as a proper voting mechanism.
required:
- compatible
- reg
- '#clock-cells'
additionalProperties: false
examples:
- |
pericfg_ao: clock-controller@16640000 {
compatible = "mediatek,mt8196-pericfg-ao", "syscon";
reg = <0x16640000 0x1000>;
mediatek,hardware-voter = <&scp_hwv>;
#clock-cells = <1>;
};
- |
pextp0cfg_ao: clock-controller@169b0000 {
compatible = "mediatek,mt8196-pextp0cfg-ao", "syscon";
reg = <0x169b0000 0x1000>;
#clock-cells = <1>;
#reset-cells = <1>;
};
@@ -0,0 +1,107 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/mediatek,mt8196-sys-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek System Clock Controller for MT8196
maintainers:
- Guangjie Song <guangjie.song@mediatek.com>
- Laura Nao <laura.nao@collabora.com>
description: |
The clock architecture in MediaTek SoCs is structured like below:
PLLs -->
dividers -->
muxes
-->
clock gate
The apmixedsys, apmixedsys_gp2, vlpckgen, armpll, ccipll, mfgpll and ptppll
provide most of the PLLs which are generated from the SoC's 26MHZ crystal oscillator.
The topckgen, topckgen_gp2 and vlpckgen provide dividers and muxes which
provide the clock source to other IP blocks.
properties:
compatible:
items:
- enum:
- mediatek,mt8196-apmixedsys
- mediatek,mt8196-armpll-b-pll-ctrl
- mediatek,mt8196-armpll-bl-pll-ctrl
- mediatek,mt8196-armpll-ll-pll-ctrl
- mediatek,mt8196-apmixedsys-gp2
- mediatek,mt8196-ccipll-pll-ctrl
- mediatek,mt8196-mfgpll-pll-ctrl
- mediatek,mt8196-mfgpll-sc0-pll-ctrl
- mediatek,mt8196-mfgpll-sc1-pll-ctrl
- mediatek,mt8196-ptppll-pll-ctrl
- mediatek,mt8196-topckgen
- mediatek,mt8196-topckgen-gp2
- mediatek,mt8196-vlpckgen
- const: syscon
reg:
maxItems: 1
'#clock-cells':
const: 1
mediatek,hardware-voter:
$ref: /schemas/types.yaml#/definitions/phandle
description: |
Phandle to the "Hardware Voter" (HWV), as named in the vendor
documentation for MT8196/MT6991.
The HWV is a SoC-internal fixed-function MCU used to collect votes from
both the Application Processor and other remote processors within the SoC.
It is intended to transparently enable or disable hardware resources (such
as power domains or clocks) based on internal vote aggregation handled by
the MCU's internal state machine.
However, in practice, this design is incomplete. While the HWV performs
some internal vote aggregation,software is still required to
- Manually enable power supplies externally, if present and if required
- Manually enable parent clocks via direct MMIO writes to clock controllers
- Enable the FENC after the clock has been ungated via direct MMIO
writes to clock controllers
As such, the HWV behaves more like a hardware-managed clock reference
counter than a true voter. Furthermore, it is not a separate
controller. It merely serves as an alternative interface to the same
underlying clock or power controller. Actual control still requires
direct access to the controller's own MMIO register space, in
addition to writing to the HWV's MMIO region.
For this reason, a custom phandle is used here - drivers need to directly
access the HWV MMIO region in a syscon-like fashion, due to how the
hardware is wired. This differs from true hardware voting systems, which
typically do not require custom phandles and rely instead on generic APIs
(clocks, power domains, interconnects).
The name "hardware-voter" is retained to match vendor documentation, but
this should not be reused or misunderstood as a proper voting mechanism.
required:
- compatible
- reg
- '#clock-cells'
additionalProperties: false
examples:
- |
apmixedsys_clk: syscon@10000800 {
compatible = "mediatek,mt8196-apmixedsys", "syscon";
reg = <0x10000800 0x1000>;
#clock-cells = <1>;
};
- |
topckgen: syscon@10000000 {
compatible = "mediatek,mt8196-topckgen", "syscon";
reg = <0x10000000 0x800>;
mediatek,hardware-voter = <&scp_hwv>;
#clock-cells = <1>;
};
+2
View File
@@ -2869,7 +2869,9 @@ ARM/Marvell PXA1908 SOC support
M: Duje Mihanović <duje@dujemihanovic.xyz>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/clock/marvell,pxa1908.yaml
F: arch/arm64/boot/dts/marvell/mmp/
F: drivers/clk/mmp/Kconfig
F: drivers/clk/mmp/clk-pxa1908*.c
F: include/dt-bindings/clock/marvell,pxa1908.h
+1
View File
@@ -512,6 +512,7 @@ source "drivers/clk/imx/Kconfig"
source "drivers/clk/ingenic/Kconfig"
source "drivers/clk/keystone/Kconfig"
source "drivers/clk/mediatek/Kconfig"
source "drivers/clk/mmp/Kconfig"
source "drivers/clk/meson/Kconfig"
source "drivers/clk/mstar/Kconfig"
source "drivers/clk/microchip/Kconfig"
+102 -20
View File
@@ -13,10 +13,6 @@
#include <linux/io-64-nonatomic-lo-hi.h>
#include <dt-bindings/clock/loongson,ls2k-clk.h>
static const struct clk_parent_data pdata[] = {
{ .fw_name = "ref_100m", },
};
enum loongson2_clk_type {
CLK_TYPE_PLL,
CLK_TYPE_SCALE,
@@ -42,6 +38,7 @@ struct loongson2_clk_data {
u8 div_width;
u8 mult_shift;
u8 mult_width;
u8 bit_idx;
};
struct loongson2_clk_board_info {
@@ -50,6 +47,7 @@ struct loongson2_clk_board_info {
const char *name;
const char *parent_name;
unsigned long fixed_rate;
unsigned long flags;
u8 reg_offset;
u8 div_shift;
u8 div_width;
@@ -95,6 +93,19 @@ struct loongson2_clk_board_info {
.div_width = _dwidth, \
}
#define CLK_SCALE_MODE(_id, _name, _pname, _offset, \
_dshift, _dwidth, _midx) \
{ \
.id = _id, \
.type = CLK_TYPE_SCALE, \
.name = _name, \
.parent_name = _pname, \
.reg_offset = _offset, \
.div_shift = _dshift, \
.div_width = _dwidth, \
.bit_idx = _midx + 1, \
}
#define CLK_GATE(_id, _name, _pname, _offset, _bidx) \
{ \
.id = _id, \
@@ -105,6 +116,18 @@ struct loongson2_clk_board_info {
.bit_idx = _bidx, \
}
#define CLK_GATE_FLAGS(_id, _name, _pname, _offset, _bidx, \
_flags) \
{ \
.id = _id, \
.type = CLK_TYPE_GATE, \
.name = _name, \
.parent_name = _pname, \
.reg_offset = _offset, \
.bit_idx = _bidx, \
.flags = _flags \
}
#define CLK_FIXED(_id, _name, _pname, _rate) \
{ \
.id = _id, \
@@ -114,6 +137,51 @@ struct loongson2_clk_board_info {
.fixed_rate = _rate, \
}
static const struct loongson2_clk_board_info ls2k0300_clks[] = {
/* Reference Clock */
CLK_PLL(LS2K0300_NODE_PLL, "pll_node", 0x00, 15, 9, 8, 7),
CLK_PLL(LS2K0300_DDR_PLL, "pll_ddr", 0x08, 15, 9, 8, 7),
CLK_PLL(LS2K0300_PIX_PLL, "pll_pix", 0x10, 15, 9, 8, 7),
CLK_FIXED(LS2K0300_CLK_STABLE, "clk_stable", NULL, 100000000),
CLK_FIXED(LS2K0300_CLK_THSENS, "clk_thsens", NULL, 10000000),
/* Node PLL */
CLK_DIV(LS2K0300_CLK_NODE_DIV, "clk_node_div", "pll_node", 0x00, 24, 7),
CLK_DIV(LS2K0300_CLK_GMAC_DIV, "clk_gmac_div", "pll_node", 0x04, 0, 7),
CLK_DIV(LS2K0300_CLK_I2S_DIV, "clk_i2s_div", "pll_node", 0x04, 8, 7),
CLK_GATE(LS2K0300_CLK_NODE_PLL_GATE, "clk_node_pll_gate", "clk_node_div", 0x00, 0),
CLK_GATE(LS2K0300_CLK_GMAC_GATE, "clk_gmac_gate", "clk_gmac_div", 0x00, 1),
CLK_GATE(LS2K0300_CLK_I2S_GATE, "clk_i2s_gate", "clk_i2s_div", 0x00, 2),
CLK_GATE_FLAGS(LS2K0300_CLK_NODE_GATE, "clk_node_gate", "clk_node_scale", 0x24, 0,
CLK_IS_CRITICAL),
CLK_SCALE_MODE(LS2K0300_CLK_NODE_SCALE, "clk_node_scale", "clk_node_pll_gate", 0x20, 0, 3,
3),
/* DDR PLL */
CLK_DIV(LS2K0300_CLK_DDR_DIV, "clk_ddr_div", "pll_ddr", 0x08, 24, 7),
CLK_DIV(LS2K0300_CLK_NET_DIV, "clk_net_div", "pll_ddr", 0x0c, 0, 7),
CLK_DIV(LS2K0300_CLK_DEV_DIV, "clk_dev_div", "pll_ddr", 0x0c, 8, 7),
CLK_GATE(LS2K0300_CLK_NET_GATE, "clk_net_gate", "clk_net_div", 0x08, 1),
CLK_GATE(LS2K0300_CLK_DEV_GATE, "clk_dev_gate", "clk_dev_div", 0x08, 2),
CLK_GATE_FLAGS(LS2K0300_CLK_DDR_GATE, "clk_ddr_gate", "clk_ddr_div", 0x08, 0,
CLK_IS_CRITICAL),
/* PIX PLL */
CLK_DIV(LS2K0300_CLK_PIX_DIV, "clk_pix_div", "pll_pix", 0x10, 24, 7),
CLK_DIV(LS2K0300_CLK_GMACBP_DIV, "clk_gmacbp_div", "pll_pix", 0x14, 0, 7),
CLK_GATE(LS2K0300_CLK_PIX_PLL_GATE, "clk_pix_pll_gate", "clk_pix_div", 0x10, 0),
CLK_GATE(LS2K0300_CLK_PIX_GATE, "clk_pix_gate", "clk_pix_scale", 0x24, 6),
CLK_GATE(LS2K0300_CLK_GMACBP_GATE, "clk_gmacbp_gate", "clk_gmacbp_div", 0x10, 1),
CLK_SCALE_MODE(LS2K0300_CLK_PIX_SCALE, "clk_pix_scale", "clk_pix_pll_gate", 0x20, 4, 3, 7),
/* clk_dev_gate */
CLK_DIV(LS2K0300_CLK_SDIO_SCALE, "clk_sdio_scale", "clk_dev_gate", 0x20, 24, 4),
CLK_GATE(LS2K0300_CLK_USB_GATE, "clk_usb_gate", "clk_usb_scale", 0x24, 2),
CLK_GATE(LS2K0300_CLK_SDIO_GATE, "clk_sdio_gate", "clk_sdio_scale", 0x24, 4),
CLK_GATE(LS2K0300_CLK_APB_GATE, "clk_apb_gate", "clk_apb_scale", 0x24, 3),
CLK_GATE_FLAGS(LS2K0300_CLK_BOOT_GATE, "clk_boot_gate", "clk_boot_scale", 0x24, 1,
CLK_IS_CRITICAL),
CLK_SCALE_MODE(LS2K0300_CLK_USB_SCALE, "clk_usb_scale", "clk_dev_gate", 0x20, 12, 3, 15),
CLK_SCALE_MODE(LS2K0300_CLK_APB_SCALE, "clk_apb_scale", "clk_dev_gate", 0x20, 16, 3, 19),
CLK_SCALE_MODE(LS2K0300_CLK_BOOT_SCALE, "clk_boot_scale", "clk_dev_gate", 0x20, 8, 3, 11),
};
static const struct loongson2_clk_board_info ls2k0500_clks[] = {
CLK_PLL(LOONGSON2_NODE_PLL, "pll_node", 0, 16, 8, 8, 6),
CLK_PLL(LOONGSON2_DDR_PLL, "pll_ddr", 0x8, 16, 8, 8, 6),
@@ -230,20 +298,26 @@ static const struct clk_ops loongson2_pll_recalc_ops = {
static unsigned long loongson2_freqscale_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
u64 val, mult;
u64 val, scale;
u32 mode = 0;
struct loongson2_clk_data *clk = to_loongson2_clk(hw);
val = readq(clk->reg);
mult = loongson2_rate_part(val, clk->div_shift, clk->div_width) + 1;
scale = loongson2_rate_part(val, clk->div_shift, clk->div_width) + 1;
return div_u64((u64)parent_rate * mult, 8);
if (clk->bit_idx)
mode = val & BIT(clk->bit_idx - 1);
return mode == 0 ? div_u64((u64)parent_rate * scale, 8) :
div_u64((u64)parent_rate, scale);
}
static const struct clk_ops loongson2_freqscale_recalc_ops = {
.recalc_rate = loongson2_freqscale_recalc_rate,
};
static struct clk_hw *loongson2_clk_register(struct loongson2_clk_provider *clp,
static struct clk_hw *loongson2_clk_register(const char *parent,
struct loongson2_clk_provider *clp,
const struct loongson2_clk_board_info *cld,
const struct clk_ops *ops)
{
@@ -260,17 +334,14 @@ static struct clk_hw *loongson2_clk_register(struct loongson2_clk_provider *clp,
init.ops = ops;
init.flags = 0;
init.num_parents = 1;
if (!cld->parent_name)
init.parent_data = pdata;
else
init.parent_names = &cld->parent_name;
init.parent_names = &parent;
clk->reg = clp->base + cld->reg_offset;
clk->div_shift = cld->div_shift;
clk->div_width = cld->div_width;
clk->mult_shift = cld->mult_shift;
clk->mult_width = cld->mult_width;
clk->bit_idx = cld->bit_idx;
clk->hw.init = &init;
hw = &clk->hw;
@@ -288,11 +359,17 @@ static int loongson2_clk_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct loongson2_clk_provider *clp;
const struct loongson2_clk_board_info *p, *data;
const char *refclk_name, *parent_name;
data = device_get_match_data(dev);
if (!data)
return -EINVAL;
refclk_name = of_clk_get_parent_name(dev->of_node, 0);
if (IS_ERR(refclk_name))
return dev_err_probe(dev, PTR_ERR(refclk_name),
"failed to get refclk name\n");
for (p = data; p->name; p++)
clks_num = max(clks_num, p->id + 1);
@@ -314,32 +391,36 @@ static int loongson2_clk_probe(struct platform_device *pdev)
for (i = 0; i < clks_num; i++) {
p = &data[i];
parent_name = p->parent_name ? p->parent_name : refclk_name;
switch (p->type) {
case CLK_TYPE_PLL:
hw = loongson2_clk_register(clp, p,
hw = loongson2_clk_register(parent_name, clp, p,
&loongson2_pll_recalc_ops);
break;
case CLK_TYPE_SCALE:
hw = loongson2_clk_register(clp, p,
hw = loongson2_clk_register(parent_name, clp, p,
&loongson2_freqscale_recalc_ops);
break;
case CLK_TYPE_DIVIDER:
hw = devm_clk_hw_register_divider(dev, p->name,
p->parent_name, 0,
parent_name, 0,
clp->base + p->reg_offset,
p->div_shift, p->div_width,
CLK_DIVIDER_ONE_BASED,
CLK_DIVIDER_ONE_BASED |
CLK_DIVIDER_ALLOW_ZERO,
&clp->clk_lock);
break;
case CLK_TYPE_GATE:
hw = devm_clk_hw_register_gate(dev, p->name, p->parent_name, 0,
hw = devm_clk_hw_register_gate(dev, p->name, parent_name,
p->flags,
clp->base + p->reg_offset,
p->bit_idx, 0,
&clp->clk_lock);
break;
case CLK_TYPE_FIXED:
hw = devm_clk_hw_register_fixed_rate_parent_data(dev, p->name, pdata,
0, p->fixed_rate);
hw = devm_clk_hw_register_fixed_rate(dev, p->name, parent_name,
0, p->fixed_rate);
break;
default:
return dev_err_probe(dev, -EINVAL, "Invalid clk type\n");
@@ -357,6 +438,7 @@ static int loongson2_clk_probe(struct platform_device *pdev)
}
static const struct of_device_id loongson2_clk_match_table[] = {
{ .compatible = "loongson,ls2k0300-clk", .data = &ls2k0300_clks },
{ .compatible = "loongson,ls2k0500-clk", .data = &ls2k0500_clks },
{ .compatible = "loongson,ls2k-clk", .data = &ls2k1000_clks },
{ .compatible = "loongson,ls2k2000-clk", .data = &ls2k2000_clks },
+71
View File
@@ -1002,6 +1002,77 @@ config COMMON_CLK_MT8195_VENCSYS
help
This driver supports MediaTek MT8195 vencsys clocks.
config COMMON_CLK_MT8196
tristate "Clock driver for MediaTek MT8196"
depends on ARM64 || COMPILE_TEST
select COMMON_CLK_MEDIATEK
default ARCH_MEDIATEK
help
This driver supports MediaTek MT8196 basic clocks.
config COMMON_CLK_MT8196_IMP_IIC_WRAP
tristate "Clock driver for MediaTek MT8196 imp_iic_wrap"
depends on COMMON_CLK_MT8196
default COMMON_CLK_MT8196
help
This driver supports MediaTek MT8196 i2c clocks.
config COMMON_CLK_MT8196_MCUSYS
tristate "Clock driver for MediaTek MT8196 mcusys"
depends on COMMON_CLK_MT8196
default COMMON_CLK_MT8196
help
This driver supports MediaTek MT8196 mcusys clocks.
config COMMON_CLK_MT8196_MDPSYS
tristate "Clock driver for MediaTek MT8196 mdpsys"
depends on COMMON_CLK_MT8196
default COMMON_CLK_MT8196
help
This driver supports MediaTek MT8196 mdpsys clocks.
config COMMON_CLK_MT8196_MFGCFG
tristate "Clock driver for MediaTek MT8196 mfgcfg"
depends on COMMON_CLK_MT8196
default m
help
This driver supports MediaTek MT8196 mfgcfg clocks.
config COMMON_CLK_MT8196_MMSYS
tristate "Clock driver for MediaTek MT8196 mmsys"
depends on COMMON_CLK_MT8196
default m
help
This driver supports MediaTek MT8196 mmsys clocks.
config COMMON_CLK_MT8196_PEXTPSYS
tristate "Clock driver for MediaTek MT8196 pextpsys"
depends on COMMON_CLK_MT8196
default COMMON_CLK_MT8196
help
This driver supports MediaTek MT8196 pextpsys clocks.
config COMMON_CLK_MT8196_UFSSYS
tristate "Clock driver for MediaTek MT8196 ufssys"
depends on COMMON_CLK_MT8196
default COMMON_CLK_MT8196
help
This driver supports MediaTek MT8196 ufssys clocks.
config COMMON_CLK_MT8196_VDECSYS
tristate "Clock driver for MediaTek MT8196 vdecsys"
depends on COMMON_CLK_MT8196
default m
help
This driver supports MediaTek MT8196 vdecsys clocks.
config COMMON_CLK_MT8196_VENCSYS
tristate "Clock driver for MediaTek MT8196 vencsys"
depends on COMMON_CLK_MT8196
default m
help
This driver supports MediaTek MT8196 vencsys clocks.
config COMMON_CLK_MT8365
tristate "Clock driver for MediaTek MT8365"
depends on ARCH_MEDIATEK || COMPILE_TEST
+13
View File
@@ -150,6 +150,19 @@ obj-$(CONFIG_COMMON_CLK_MT8195_VDOSYS) += clk-mt8195-vdo0.o clk-mt8195-vdo1.o
obj-$(CONFIG_COMMON_CLK_MT8195_VENCSYS) += clk-mt8195-venc.o
obj-$(CONFIG_COMMON_CLK_MT8195_VPPSYS) += clk-mt8195-vpp0.o clk-mt8195-vpp1.o
obj-$(CONFIG_COMMON_CLK_MT8195_WPESYS) += clk-mt8195-wpe.o
obj-$(CONFIG_COMMON_CLK_MT8196) += clk-mt8196-apmixedsys.o clk-mt8196-topckgen.o \
clk-mt8196-topckgen2.o clk-mt8196-vlpckgen.o \
clk-mt8196-peri_ao.o
obj-$(CONFIG_COMMON_CLK_MT8196_IMP_IIC_WRAP) += clk-mt8196-imp_iic_wrap.o
obj-$(CONFIG_COMMON_CLK_MT8196_MCUSYS) += clk-mt8196-mcu.o
obj-$(CONFIG_COMMON_CLK_MT8196_MDPSYS) += clk-mt8196-mdpsys.o
obj-$(CONFIG_COMMON_CLK_MT8196_MFGCFG) += clk-mt8196-mfg.o
obj-$(CONFIG_COMMON_CLK_MT8196_MMSYS) += clk-mt8196-disp0.o clk-mt8196-disp1.o clk-mt8196-vdisp_ao.o \
clk-mt8196-ovl0.o clk-mt8196-ovl1.o
obj-$(CONFIG_COMMON_CLK_MT8196_PEXTPSYS) += clk-mt8196-pextp.o
obj-$(CONFIG_COMMON_CLK_MT8196_UFSSYS) += clk-mt8196-ufs_ao.o
obj-$(CONFIG_COMMON_CLK_MT8196_VDECSYS) += clk-mt8196-vdec.o
obj-$(CONFIG_COMMON_CLK_MT8196_VENCSYS) += clk-mt8196-venc.o
obj-$(CONFIG_COMMON_CLK_MT8365) += clk-mt8365-apmixedsys.o clk-mt8365.o
obj-$(CONFIG_COMMON_CLK_MT8365_APU) += clk-mt8365-apu.o
obj-$(CONFIG_COMMON_CLK_MT8365_CAM) += clk-mt8365-cam.o
+84 -33
View File
@@ -5,6 +5,7 @@
*/
#include <linux/clk-provider.h>
#include <linux/dev_printk.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/printk.h>
@@ -12,15 +13,14 @@
#include <linux/slab.h>
#include <linux/types.h>
#include "clk-mtk.h"
#include "clk-gate.h"
struct mtk_clk_gate {
struct clk_hw hw;
struct regmap *regmap;
int set_ofs;
int clr_ofs;
int sta_ofs;
u8 bit;
struct regmap *regmap_hwv;
const struct mtk_gate *gate;
};
static inline struct mtk_clk_gate *to_mtk_clk_gate(struct clk_hw *hw)
@@ -33,9 +33,9 @@ static u32 mtk_get_clockgating(struct clk_hw *hw)
struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
u32 val;
regmap_read(cg->regmap, cg->sta_ofs, &val);
regmap_read(cg->regmap, cg->gate->regs->sta_ofs, &val);
return val & BIT(cg->bit);
return val & BIT(cg->gate->shift);
}
static int mtk_cg_bit_is_cleared(struct clk_hw *hw)
@@ -52,28 +52,30 @@ static void mtk_cg_set_bit(struct clk_hw *hw)
{
struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
regmap_write(cg->regmap, cg->set_ofs, BIT(cg->bit));
regmap_write(cg->regmap, cg->gate->regs->set_ofs, BIT(cg->gate->shift));
}
static void mtk_cg_clr_bit(struct clk_hw *hw)
{
struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
regmap_write(cg->regmap, cg->clr_ofs, BIT(cg->bit));
regmap_write(cg->regmap, cg->gate->regs->clr_ofs, BIT(cg->gate->shift));
}
static void mtk_cg_set_bit_no_setclr(struct clk_hw *hw)
{
struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
regmap_set_bits(cg->regmap, cg->sta_ofs, BIT(cg->bit));
regmap_set_bits(cg->regmap, cg->gate->regs->sta_ofs,
BIT(cg->gate->shift));
}
static void mtk_cg_clr_bit_no_setclr(struct clk_hw *hw)
{
struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
regmap_clear_bits(cg->regmap, cg->sta_ofs, BIT(cg->bit));
regmap_clear_bits(cg->regmap, cg->gate->regs->sta_ofs,
BIT(cg->gate->shift));
}
static int mtk_cg_enable(struct clk_hw *hw)
@@ -100,6 +102,32 @@ static void mtk_cg_disable_inv(struct clk_hw *hw)
mtk_cg_clr_bit(hw);
}
static int mtk_cg_hwv_set_en(struct clk_hw *hw, bool enable)
{
struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
u32 val;
regmap_write(cg->regmap_hwv,
enable ? cg->gate->hwv_regs->set_ofs :
cg->gate->hwv_regs->clr_ofs,
BIT(cg->gate->shift));
return regmap_read_poll_timeout_atomic(cg->regmap_hwv,
cg->gate->hwv_regs->sta_ofs, val,
val & BIT(cg->gate->shift), 0,
MTK_WAIT_HWV_DONE_US);
}
static int mtk_cg_hwv_enable(struct clk_hw *hw)
{
return mtk_cg_hwv_set_en(hw, true);
}
static void mtk_cg_hwv_disable(struct clk_hw *hw)
{
mtk_cg_hwv_set_en(hw, false);
}
static int mtk_cg_enable_no_setclr(struct clk_hw *hw)
{
mtk_cg_clr_bit_no_setclr(hw);
@@ -124,6 +152,15 @@ static void mtk_cg_disable_inv_no_setclr(struct clk_hw *hw)
mtk_cg_clr_bit_no_setclr(hw);
}
static bool mtk_cg_uses_hwv(const struct clk_ops *ops)
{
if (ops == &mtk_clk_gate_hwv_ops_setclr ||
ops == &mtk_clk_gate_hwv_ops_setclr_inv)
return true;
return false;
}
const struct clk_ops mtk_clk_gate_ops_setclr = {
.is_enabled = mtk_cg_bit_is_cleared,
.enable = mtk_cg_enable,
@@ -138,6 +175,20 @@ const struct clk_ops mtk_clk_gate_ops_setclr_inv = {
};
EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_setclr_inv);
const struct clk_ops mtk_clk_gate_hwv_ops_setclr = {
.is_enabled = mtk_cg_bit_is_cleared,
.enable = mtk_cg_hwv_enable,
.disable = mtk_cg_hwv_disable,
};
EXPORT_SYMBOL_GPL(mtk_clk_gate_hwv_ops_setclr);
const struct clk_ops mtk_clk_gate_hwv_ops_setclr_inv = {
.is_enabled = mtk_cg_bit_is_set,
.enable = mtk_cg_hwv_enable,
.disable = mtk_cg_hwv_disable,
};
EXPORT_SYMBOL_GPL(mtk_clk_gate_hwv_ops_setclr_inv);
const struct clk_ops mtk_clk_gate_ops_no_setclr = {
.is_enabled = mtk_cg_bit_is_cleared,
.enable = mtk_cg_enable_no_setclr,
@@ -152,12 +203,10 @@ const struct clk_ops mtk_clk_gate_ops_no_setclr_inv = {
};
EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_no_setclr_inv);
static struct clk_hw *mtk_clk_register_gate(struct device *dev, const char *name,
const char *parent_name,
struct regmap *regmap, int set_ofs,
int clr_ofs, int sta_ofs, u8 bit,
const struct clk_ops *ops,
unsigned long flags)
static struct clk_hw *mtk_clk_register_gate(struct device *dev,
const struct mtk_gate *gate,
struct regmap *regmap,
struct regmap *regmap_hwv)
{
struct mtk_clk_gate *cg;
int ret;
@@ -167,18 +216,19 @@ static struct clk_hw *mtk_clk_register_gate(struct device *dev, const char *name
if (!cg)
return ERR_PTR(-ENOMEM);
init.name = name;
init.flags = flags | CLK_SET_RATE_PARENT;
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
init.ops = ops;
init.name = gate->name;
init.flags = gate->flags | CLK_SET_RATE_PARENT;
init.parent_names = gate->parent_name ? &gate->parent_name : NULL;
init.num_parents = gate->parent_name ? 1 : 0;
init.ops = gate->ops;
if (mtk_cg_uses_hwv(init.ops) && !regmap_hwv)
return dev_err_ptr_probe(
dev, -ENXIO,
"regmap not found for hardware voter clocks\n");
cg->regmap = regmap;
cg->set_ofs = set_ofs;
cg->clr_ofs = clr_ofs;
cg->sta_ofs = sta_ofs;
cg->bit = bit;
cg->regmap_hwv = regmap_hwv;
cg->gate = gate;
cg->hw.init = &init;
ret = clk_hw_register(dev, &cg->hw);
@@ -209,6 +259,7 @@ int mtk_clk_register_gates(struct device *dev, struct device_node *node,
int i;
struct clk_hw *hw;
struct regmap *regmap;
struct regmap *regmap_hwv;
if (!clk_data)
return -ENOMEM;
@@ -219,6 +270,12 @@ int mtk_clk_register_gates(struct device *dev, struct device_node *node,
return PTR_ERR(regmap);
}
regmap_hwv = mtk_clk_get_hwv_regmap(node);
if (IS_ERR(regmap_hwv))
return dev_err_probe(
dev, PTR_ERR(regmap_hwv),
"Cannot find hardware voter regmap for %pOF\n", node);
for (i = 0; i < num; i++) {
const struct mtk_gate *gate = &clks[i];
@@ -228,13 +285,7 @@ int mtk_clk_register_gates(struct device *dev, struct device_node *node,
continue;
}
hw = mtk_clk_register_gate(dev, gate->name, gate->parent_name,
regmap,
gate->regs->set_ofs,
gate->regs->clr_ofs,
gate->regs->sta_ofs,
gate->shift, gate->ops,
gate->flags);
hw = mtk_clk_register_gate(dev, gate, regmap, regmap_hwv);
if (IS_ERR(hw)) {
pr_err("Failed to register clk %s: %pe\n", gate->name,
+3
View File
@@ -19,6 +19,8 @@ extern const struct clk_ops mtk_clk_gate_ops_setclr;
extern const struct clk_ops mtk_clk_gate_ops_setclr_inv;
extern const struct clk_ops mtk_clk_gate_ops_no_setclr;
extern const struct clk_ops mtk_clk_gate_ops_no_setclr_inv;
extern const struct clk_ops mtk_clk_gate_hwv_ops_setclr;
extern const struct clk_ops mtk_clk_gate_hwv_ops_setclr_inv;
struct mtk_gate_regs {
u32 sta_ofs;
@@ -31,6 +33,7 @@ struct mtk_gate {
const char *name;
const char *parent_name;
const struct mtk_gate_regs *regs;
const struct mtk_gate_regs *hwv_regs;
int shift;
const struct clk_ops *ops;
unsigned long flags;
+1
View File
@@ -75,6 +75,7 @@ static const struct mtk_gate audio_clks[] = {
GATE_AUDIO1(CLK_AUDIO_A1SYS, "audio_a1sys", "a1sys_hp_sel", 21),
GATE_AUDIO1(CLK_AUDIO_A2SYS, "audio_a2sys", "a2sys_hp_sel", 22),
GATE_AUDIO1(CLK_AUDIO_AFE_CONN, "audio_afe_conn", "a1sys_hp_sel", 23),
GATE_AUDIO1(CLK_AUDIO_AFE_MRGIF, "audio_afe_mrgif", "aud_mux1_sel", 25),
/* AUDIO2 */
GATE_AUDIO2(CLK_AUDIO_UL1, "audio_ul1", "a1sys_hp_sel", 0),
GATE_AUDIO2(CLK_AUDIO_UL2, "audio_ul2", "a1sys_hp_sel", 1),
+1 -1
View File
@@ -103,7 +103,7 @@ static const struct mtk_gate infra_ao_clks[] = {
GATE_INFRA_AO0(CLK_INFRA_AO_CQ_DMA_FPC, "infra_ao_cq_dma_fpc", "fpc", 28),
GATE_INFRA_AO0(CLK_INFRA_AO_UART5, "infra_ao_uart5", "top_uart", 29),
/* INFRA_AO1 */
GATE_INFRA_AO1(CLK_INFRA_AO_HDMI_26M, "infra_ao_hdmi_26m", "clk26m", 0),
GATE_INFRA_AO1(CLK_INFRA_AO_HDMI_26M, "infra_ao_hdmi_26m", "top_hdmi_xtal", 0),
GATE_INFRA_AO1(CLK_INFRA_AO_SPI0, "infra_ao_spi0", "top_spi", 1),
GATE_INFRA_AO1(CLK_INFRA_AO_MSDC0, "infra_ao_msdc0", "top_msdc50_0_hclk", 2),
GATE_INFRA_AO1(CLK_INFRA_AO_MSDC1, "infra_ao_msdc1", "top_axi", 4),
@@ -0,0 +1,204 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2025 MediaTek Inc.
* Guangjie Song <guangjie.song@mediatek.com>
* Copyright (c) 2025 Collabora Ltd.
* Laura Nao <laura.nao@collabora.com>
*/
#include <dt-bindings/clock/mediatek,mt8196-clock.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include "clk-mtk.h"
#include "clk-pll.h"
/* APMIXEDSYS PLL control register offsets */
#define MAINPLL_CON0 0x250
#define MAINPLL_CON1 0x254
#define UNIVPLL_CON0 0x264
#define UNIVPLL_CON1 0x268
#define MSDCPLL_CON0 0x278
#define MSDCPLL_CON1 0x27c
#define ADSPPLL_CON0 0x28c
#define ADSPPLL_CON1 0x290
#define EMIPLL_CON0 0x2a0
#define EMIPLL_CON1 0x2a4
#define EMIPLL2_CON0 0x2b4
#define EMIPLL2_CON1 0x2b8
#define NET1PLL_CON0 0x2c8
#define NET1PLL_CON1 0x2cc
#define SGMIIPLL_CON0 0x2dc
#define SGMIIPLL_CON1 0x2e0
/* APMIXEDSYS_GP2 PLL control register offsets*/
#define MAINPLL2_CON0 0x250
#define MAINPLL2_CON1 0x254
#define UNIVPLL2_CON0 0x264
#define UNIVPLL2_CON1 0x268
#define MMPLL2_CON0 0x278
#define MMPLL2_CON1 0x27c
#define IMGPLL_CON0 0x28c
#define IMGPLL_CON1 0x290
#define TVDPLL1_CON0 0x2a0
#define TVDPLL1_CON1 0x2a4
#define TVDPLL2_CON0 0x2b4
#define TVDPLL2_CON1 0x2b8
#define TVDPLL3_CON0 0x2c8
#define TVDPLL3_CON1 0x2cc
#define PLLEN_ALL 0x080
#define PLLEN_ALL_SET 0x084
#define PLLEN_ALL_CLR 0x088
#define FENC_STATUS_CON0 0x03c
#define MT8196_PLL_FMAX (3800UL * MHZ)
#define MT8196_PLL_FMIN (1500UL * MHZ)
#define MT8196_INTEGER_BITS 8
#define PLL_FENC(_id, _name, _reg, _fenc_sta_ofs, _fenc_sta_bit,\
_flags, _pd_reg, _pd_shift, \
_pcw_reg, _pcw_shift, _pcwbits, \
_pll_en_bit) { \
.id = _id, \
.name = _name, \
.reg = _reg, \
.fenc_sta_ofs = _fenc_sta_ofs, \
.fenc_sta_bit = _fenc_sta_bit, \
.flags = _flags, \
.fmax = MT8196_PLL_FMAX, \
.fmin = MT8196_PLL_FMIN, \
.pd_reg = _pd_reg, \
.pd_shift = _pd_shift, \
.pcw_reg = _pcw_reg, \
.pcw_shift = _pcw_shift, \
.pcwbits = _pcwbits, \
.pcwibits = MT8196_INTEGER_BITS, \
.en_reg = PLLEN_ALL, \
.en_set_reg = PLLEN_ALL_SET, \
.en_clr_reg = PLLEN_ALL_CLR, \
.pll_en_bit = _pll_en_bit, \
.ops = &mtk_pll_fenc_clr_set_ops, \
}
struct mtk_pll_desc {
const struct mtk_pll_data *clks;
size_t num_clks;
};
static const struct mtk_pll_data apmixed_plls[] = {
PLL_FENC(CLK_APMIXED_MAINPLL, "mainpll", MAINPLL_CON0, FENC_STATUS_CON0,
7, PLL_AO, MAINPLL_CON1, 24, MAINPLL_CON1, 0, 22, 0),
PLL_FENC(CLK_APMIXED_UNIVPLL, "univpll", UNIVPLL_CON0, FENC_STATUS_CON0,
6, 0, UNIVPLL_CON1, 24, UNIVPLL_CON1, 0, 22, 1),
PLL_FENC(CLK_APMIXED_MSDCPLL, "msdcpll", MSDCPLL_CON0, FENC_STATUS_CON0,
5, 0, MSDCPLL_CON1, 24, MSDCPLL_CON1, 0, 22, 2),
PLL_FENC(CLK_APMIXED_ADSPPLL, "adsppll", ADSPPLL_CON0, FENC_STATUS_CON0,
4, 0, ADSPPLL_CON1, 24, ADSPPLL_CON1, 0, 22, 3),
PLL_FENC(CLK_APMIXED_EMIPLL, "emipll", EMIPLL_CON0, FENC_STATUS_CON0, 3,
PLL_AO, EMIPLL_CON1, 24, EMIPLL_CON1, 0, 22, 4),
PLL_FENC(CLK_APMIXED_EMIPLL2, "emipll2", EMIPLL2_CON0, FENC_STATUS_CON0,
2, PLL_AO, EMIPLL2_CON1, 24, EMIPLL2_CON1, 0, 22, 5),
PLL_FENC(CLK_APMIXED_NET1PLL, "net1pll", NET1PLL_CON0, FENC_STATUS_CON0,
1, 0, NET1PLL_CON1, 24, NET1PLL_CON1, 0, 22, 6),
PLL_FENC(CLK_APMIXED_SGMIIPLL, "sgmiipll", SGMIIPLL_CON0, FENC_STATUS_CON0,
0, 0, SGMIIPLL_CON1, 24, SGMIIPLL_CON1, 0, 22, 7),
};
static const struct mtk_pll_desc apmixed_desc = {
.clks = apmixed_plls,
.num_clks = ARRAY_SIZE(apmixed_plls),
};
static const struct mtk_pll_data apmixed2_plls[] = {
PLL_FENC(CLK_APMIXED2_MAINPLL2, "mainpll2", MAINPLL2_CON0, FENC_STATUS_CON0,
6, 0, MAINPLL2_CON1, 24, MAINPLL2_CON1, 0, 22, 0),
PLL_FENC(CLK_APMIXED2_UNIVPLL2, "univpll2", UNIVPLL2_CON0, FENC_STATUS_CON0,
5, 0, UNIVPLL2_CON1, 24, UNIVPLL2_CON1, 0, 22, 1),
PLL_FENC(CLK_APMIXED2_MMPLL2, "mmpll2", MMPLL2_CON0, FENC_STATUS_CON0,
4, 0, MMPLL2_CON1, 24, MMPLL2_CON1, 0, 22, 2),
PLL_FENC(CLK_APMIXED2_IMGPLL, "imgpll", IMGPLL_CON0, FENC_STATUS_CON0,
3, 0, IMGPLL_CON1, 24, IMGPLL_CON1, 0, 22, 3),
PLL_FENC(CLK_APMIXED2_TVDPLL1, "tvdpll1", TVDPLL1_CON0, FENC_STATUS_CON0,
2, 0, TVDPLL1_CON1, 24, TVDPLL1_CON1, 0, 22, 4),
PLL_FENC(CLK_APMIXED2_TVDPLL2, "tvdpll2", TVDPLL2_CON0, FENC_STATUS_CON0,
1, 0, TVDPLL2_CON1, 24, TVDPLL2_CON1, 0, 22, 5),
PLL_FENC(CLK_APMIXED2_TVDPLL3, "tvdpll3", TVDPLL3_CON0, FENC_STATUS_CON0,
0, 0, TVDPLL3_CON1, 24, TVDPLL3_CON1, 0, 22, 6),
};
static const struct mtk_pll_desc apmixed2_desc = {
.clks = apmixed2_plls,
.num_clks = ARRAY_SIZE(apmixed2_plls),
};
static int clk_mt8196_apmixed_probe(struct platform_device *pdev)
{
struct clk_hw_onecell_data *clk_data;
struct device_node *node = pdev->dev.of_node;
const struct mtk_pll_desc *mcd;
int r;
mcd = device_get_match_data(&pdev->dev);
if (!mcd)
return -EINVAL;
clk_data = mtk_alloc_clk_data(mcd->num_clks);
if (!clk_data)
return -ENOMEM;
r = mtk_clk_register_plls(node, mcd->clks, mcd->num_clks, clk_data);
if (r)
goto free_apmixed_data;
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
if (r)
goto unregister_plls;
platform_set_drvdata(pdev, clk_data);
return r;
unregister_plls:
mtk_clk_unregister_plls(mcd->clks, mcd->num_clks, clk_data);
free_apmixed_data:
mtk_free_clk_data(clk_data);
return r;
}
static void clk_mt8196_apmixed_remove(struct platform_device *pdev)
{
const struct mtk_pll_desc *mcd = device_get_match_data(&pdev->dev);
struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev);
struct device_node *node = pdev->dev.of_node;
of_clk_del_provider(node);
mtk_clk_unregister_plls(mcd->clks, mcd->num_clks, clk_data);
mtk_free_clk_data(clk_data);
}
static const struct of_device_id of_match_clk_mt8196_apmixed[] = {
{ .compatible = "mediatek,mt8196-apmixedsys", .data = &apmixed_desc },
{ .compatible = "mediatek,mt8196-apmixedsys-gp2",
.data = &apmixed2_desc },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_match_clk_mt8196_apmixed);
static struct platform_driver clk_mt8196_apmixed_drv = {
.probe = clk_mt8196_apmixed_probe,
.remove = clk_mt8196_apmixed_remove,
.driver = {
.name = "clk-mt8196-apmixed",
.of_match_table = of_match_clk_mt8196_apmixed,
},
};
module_platform_driver(clk_mt8196_apmixed_drv);
MODULE_DESCRIPTION("MediaTek MT8196 apmixedsys clocks driver");
MODULE_LICENSE("GPL");
+170
View File
@@ -0,0 +1,170 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2025 MediaTek Inc.
* Guangjie Song <guangjie.song@mediatek.com>
* Copyright (c) 2025 Collabora Ltd.
* Laura Nao <laura.nao@collabora.com>
*/
#include <dt-bindings/clock/mediatek,mt8196-clock.h>
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include "clk-gate.h"
#include "clk-mtk.h"
static const struct mtk_gate_regs mm0_cg_regs = {
.set_ofs = 0x104,
.clr_ofs = 0x108,
.sta_ofs = 0x100,
};
static const struct mtk_gate_regs mm0_hwv_regs = {
.set_ofs = 0x0020,
.clr_ofs = 0x0024,
.sta_ofs = 0x2c10,
};
static const struct mtk_gate_regs mm1_cg_regs = {
.set_ofs = 0x114,
.clr_ofs = 0x118,
.sta_ofs = 0x110,
};
static const struct mtk_gate_regs mm1_hwv_regs = {
.set_ofs = 0x0028,
.clr_ofs = 0x002c,
.sta_ofs = 0x2c14,
};
#define GATE_MM0(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &mm0_cg_regs, \
.shift = _shift, \
.flags = CLK_OPS_PARENT_ENABLE, \
.ops = &mtk_clk_gate_ops_setclr,\
}
#define GATE_HWV_MM0(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &mm0_cg_regs, \
.hwv_regs = &mm0_hwv_regs, \
.shift = _shift, \
.ops = &mtk_clk_gate_hwv_ops_setclr, \
.flags = CLK_OPS_PARENT_ENABLE \
}
#define GATE_MM1(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &mm1_cg_regs, \
.shift = _shift, \
.flags = CLK_OPS_PARENT_ENABLE, \
.ops = &mtk_clk_gate_ops_setclr,\
}
#define GATE_HWV_MM1(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &mm1_cg_regs, \
.hwv_regs = &mm1_hwv_regs, \
.shift = _shift, \
.ops = &mtk_clk_gate_hwv_ops_setclr, \
.flags = CLK_OPS_PARENT_ENABLE, \
}
static const struct mtk_gate mm_clks[] = {
/* MM0 */
GATE_HWV_MM0(CLK_MM_CONFIG, "mm_config", "disp", 0),
GATE_HWV_MM0(CLK_MM_DISP_MUTEX0, "mm_disp_mutex0", "disp", 1),
GATE_HWV_MM0(CLK_MM_DISP_AAL0, "mm_disp_aal0", "disp", 2),
GATE_HWV_MM0(CLK_MM_DISP_AAL1, "mm_disp_aal1", "disp", 3),
GATE_MM0(CLK_MM_DISP_C3D0, "mm_disp_c3d0", "disp", 4),
GATE_MM0(CLK_MM_DISP_C3D1, "mm_disp_c3d1", "disp", 5),
GATE_MM0(CLK_MM_DISP_C3D2, "mm_disp_c3d2", "disp", 6),
GATE_MM0(CLK_MM_DISP_C3D3, "mm_disp_c3d3", "disp", 7),
GATE_MM0(CLK_MM_DISP_CCORR0, "mm_disp_ccorr0", "disp", 8),
GATE_MM0(CLK_MM_DISP_CCORR1, "mm_disp_ccorr1", "disp", 9),
GATE_MM0(CLK_MM_DISP_CCORR2, "mm_disp_ccorr2", "disp", 10),
GATE_MM0(CLK_MM_DISP_CCORR3, "mm_disp_ccorr3", "disp", 11),
GATE_MM0(CLK_MM_DISP_CHIST0, "mm_disp_chist0", "disp", 12),
GATE_MM0(CLK_MM_DISP_CHIST1, "mm_disp_chist1", "disp", 13),
GATE_MM0(CLK_MM_DISP_COLOR0, "mm_disp_color0", "disp", 14),
GATE_MM0(CLK_MM_DISP_COLOR1, "mm_disp_color1", "disp", 15),
GATE_MM0(CLK_MM_DISP_DITHER0, "mm_disp_dither0", "disp", 16),
GATE_MM0(CLK_MM_DISP_DITHER1, "mm_disp_dither1", "disp", 17),
GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC0, "mm_disp_dli_async0", "disp", 18),
GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC1, "mm_disp_dli_async1", "disp", 19),
GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC2, "mm_disp_dli_async2", "disp", 20),
GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC3, "mm_disp_dli_async3", "disp", 21),
GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC4, "mm_disp_dli_async4", "disp", 22),
GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC5, "mm_disp_dli_async5", "disp", 23),
GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC6, "mm_disp_dli_async6", "disp", 24),
GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC7, "mm_disp_dli_async7", "disp", 25),
GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC8, "mm_disp_dli_async8", "disp", 26),
GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC9, "mm_disp_dli_async9", "disp", 27),
GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC10, "mm_disp_dli_async10", "disp", 28),
GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC11, "mm_disp_dli_async11", "disp", 29),
GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC12, "mm_disp_dli_async12", "disp", 30),
GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC13, "mm_disp_dli_async13", "disp", 31),
/* MM1 */
GATE_HWV_MM1(CLK_MM_DISP_DLI_ASYNC14, "mm_disp_dli_async14", "disp", 0),
GATE_HWV_MM1(CLK_MM_DISP_DLI_ASYNC15, "mm_disp_dli_async15", "disp", 1),
GATE_HWV_MM1(CLK_MM_DISP_DLO_ASYNC0, "mm_disp_dlo_async0", "disp", 2),
GATE_HWV_MM1(CLK_MM_DISP_DLO_ASYNC1, "mm_disp_dlo_async1", "disp", 3),
GATE_HWV_MM1(CLK_MM_DISP_DLO_ASYNC2, "mm_disp_dlo_async2", "disp", 4),
GATE_HWV_MM1(CLK_MM_DISP_DLO_ASYNC3, "mm_disp_dlo_async3", "disp", 5),
GATE_HWV_MM1(CLK_MM_DISP_DLO_ASYNC4, "mm_disp_dlo_async4", "disp", 6),
GATE_HWV_MM1(CLK_MM_DISP_DLO_ASYNC5, "mm_disp_dlo_async5", "disp", 7),
GATE_HWV_MM1(CLK_MM_DISP_DLO_ASYNC6, "mm_disp_dlo_async6", "disp", 8),
GATE_HWV_MM1(CLK_MM_DISP_DLO_ASYNC7, "mm_disp_dlo_async7", "disp", 9),
GATE_HWV_MM1(CLK_MM_DISP_DLO_ASYNC8, "mm_disp_dlo_async8", "disp", 10),
GATE_MM1(CLK_MM_DISP_GAMMA0, "mm_disp_gamma0", "disp", 11),
GATE_MM1(CLK_MM_DISP_GAMMA1, "mm_disp_gamma1", "disp", 12),
GATE_MM1(CLK_MM_MDP_AAL0, "mm_mdp_aal0", "disp", 13),
GATE_MM1(CLK_MM_MDP_AAL1, "mm_mdp_aal1", "disp", 14),
GATE_HWV_MM1(CLK_MM_MDP_RDMA0, "mm_mdp_rdma0", "disp", 15),
GATE_HWV_MM1(CLK_MM_DISP_POSTMASK0, "mm_disp_postmask0", "disp", 16),
GATE_HWV_MM1(CLK_MM_DISP_POSTMASK1, "mm_disp_postmask1", "disp", 17),
GATE_HWV_MM1(CLK_MM_MDP_RSZ0, "mm_mdp_rsz0", "disp", 18),
GATE_HWV_MM1(CLK_MM_MDP_RSZ1, "mm_mdp_rsz1", "disp", 19),
GATE_HWV_MM1(CLK_MM_DISP_SPR0, "mm_disp_spr0", "disp", 20),
GATE_MM1(CLK_MM_DISP_TDSHP0, "mm_disp_tdshp0", "disp", 21),
GATE_MM1(CLK_MM_DISP_TDSHP1, "mm_disp_tdshp1", "disp", 22),
GATE_HWV_MM1(CLK_MM_DISP_WDMA0, "mm_disp_wdma0", "disp", 23),
GATE_HWV_MM1(CLK_MM_DISP_Y2R0, "mm_disp_y2r0", "disp", 24),
GATE_HWV_MM1(CLK_MM_SMI_SUB_COMM0, "mm_ssc", "disp", 25),
GATE_HWV_MM1(CLK_MM_DISP_FAKE_ENG0, "mm_disp_fake_eng0", "disp", 26),
};
static const struct mtk_clk_desc mm_mcd = {
.clks = mm_clks,
.num_clks = ARRAY_SIZE(mm_clks),
};
static const struct platform_device_id clk_mt8196_disp0_id_table[] = {
{ .name = "clk-mt8196-disp0", .driver_data = (kernel_ulong_t)&mm_mcd },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, clk_mt8196_disp0_id_table);
static struct platform_driver clk_mt8196_disp0_drv = {
.probe = mtk_clk_pdev_probe,
.remove = mtk_clk_pdev_remove,
.driver = {
.name = "clk-mt8196-disp0",
},
.id_table = clk_mt8196_disp0_id_table,
};
module_platform_driver(clk_mt8196_disp0_drv);
MODULE_DESCRIPTION("MediaTek MT8196 disp0 clocks driver");
MODULE_LICENSE("GPL");
+170
View File
@@ -0,0 +1,170 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2025 MediaTek Inc.
* Guangjie Song <guangjie.song@mediatek.com>
* Copyright (c) 2025 Collabora Ltd.
* Laura Nao <laura.nao@collabora.com>
*/
#include <dt-bindings/clock/mediatek,mt8196-clock.h>
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include "clk-gate.h"
#include "clk-mtk.h"
static const struct mtk_gate_regs mm10_cg_regs = {
.set_ofs = 0x104,
.clr_ofs = 0x108,
.sta_ofs = 0x100,
};
static const struct mtk_gate_regs mm10_hwv_regs = {
.set_ofs = 0x0010,
.clr_ofs = 0x0014,
.sta_ofs = 0x2c08,
};
static const struct mtk_gate_regs mm11_cg_regs = {
.set_ofs = 0x114,
.clr_ofs = 0x118,
.sta_ofs = 0x110,
};
static const struct mtk_gate_regs mm11_hwv_regs = {
.set_ofs = 0x0018,
.clr_ofs = 0x001c,
.sta_ofs = 0x2c0c,
};
#define GATE_MM10(_id, _name, _parent, _shift) {\
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &mm10_cg_regs, \
.shift = _shift, \
.flags = CLK_OPS_PARENT_ENABLE, \
.ops = &mtk_clk_gate_ops_setclr,\
}
#define GATE_HWV_MM10(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &mm10_cg_regs, \
.hwv_regs = &mm10_hwv_regs, \
.shift = _shift, \
.ops = &mtk_clk_gate_hwv_ops_setclr, \
.flags = CLK_OPS_PARENT_ENABLE, \
}
#define GATE_MM11(_id, _name, _parent, _shift) {\
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &mm11_cg_regs, \
.shift = _shift, \
.flags = CLK_OPS_PARENT_ENABLE, \
.ops = &mtk_clk_gate_ops_setclr,\
}
#define GATE_HWV_MM11(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &mm11_cg_regs, \
.hwv_regs = &mm11_hwv_regs, \
.shift = _shift, \
.ops = &mtk_clk_gate_hwv_ops_setclr, \
}
static const struct mtk_gate mm1_clks[] = {
/* MM10 */
GATE_HWV_MM10(CLK_MM1_DISPSYS1_CONFIG, "mm1_dispsys1_config", "disp", 0),
GATE_HWV_MM10(CLK_MM1_DISPSYS1_S_CONFIG, "mm1_dispsys1_s_config", "disp", 1),
GATE_HWV_MM10(CLK_MM1_DISP_MUTEX0, "mm1_disp_mutex0", "disp", 2),
GATE_HWV_MM10(CLK_MM1_DISP_DLI_ASYNC20, "mm1_disp_dli_async20", "disp", 3),
GATE_HWV_MM10(CLK_MM1_DISP_DLI_ASYNC21, "mm1_disp_dli_async21", "disp", 4),
GATE_HWV_MM10(CLK_MM1_DISP_DLI_ASYNC22, "mm1_disp_dli_async22", "disp", 5),
GATE_HWV_MM10(CLK_MM1_DISP_DLI_ASYNC23, "mm1_disp_dli_async23", "disp", 6),
GATE_HWV_MM10(CLK_MM1_DISP_DLI_ASYNC24, "mm1_disp_dli_async24", "disp", 7),
GATE_HWV_MM10(CLK_MM1_DISP_DLI_ASYNC25, "mm1_disp_dli_async25", "disp", 8),
GATE_HWV_MM10(CLK_MM1_DISP_DLI_ASYNC26, "mm1_disp_dli_async26", "disp", 9),
GATE_HWV_MM10(CLK_MM1_DISP_DLI_ASYNC27, "mm1_disp_dli_async27", "disp", 10),
GATE_HWV_MM10(CLK_MM1_DISP_DLI_ASYNC28, "mm1_disp_dli_async28", "disp", 11),
GATE_HWV_MM10(CLK_MM1_DISP_RELAY0, "mm1_disp_relay0", "disp", 12),
GATE_HWV_MM10(CLK_MM1_DISP_RELAY1, "mm1_disp_relay1", "disp", 13),
GATE_HWV_MM10(CLK_MM1_DISP_RELAY2, "mm1_disp_relay2", "disp", 14),
GATE_HWV_MM10(CLK_MM1_DISP_RELAY3, "mm1_disp_relay3", "disp", 15),
GATE_HWV_MM10(CLK_MM1_DISP_DP_INTF0, "mm1_DP_CLK", "disp", 16),
GATE_HWV_MM10(CLK_MM1_DISP_DP_INTF1, "mm1_disp_dp_intf1", "disp", 17),
GATE_HWV_MM10(CLK_MM1_DISP_DSC_WRAP0, "mm1_disp_dsc_wrap0", "disp", 18),
GATE_HWV_MM10(CLK_MM1_DISP_DSC_WRAP1, "mm1_disp_dsc_wrap1", "disp", 19),
GATE_HWV_MM10(CLK_MM1_DISP_DSC_WRAP2, "mm1_disp_dsc_wrap2", "disp", 20),
GATE_HWV_MM10(CLK_MM1_DISP_DSC_WRAP3, "mm1_disp_dsc_wrap3", "disp", 21),
GATE_HWV_MM10(CLK_MM1_DISP_DSI0, "mm1_CLK0", "disp", 22),
GATE_HWV_MM10(CLK_MM1_DISP_DSI1, "mm1_CLK1", "disp", 23),
GATE_HWV_MM10(CLK_MM1_DISP_DSI2, "mm1_CLK2", "disp", 24),
GATE_HWV_MM10(CLK_MM1_DISP_DVO0, "mm1_disp_dvo0", "disp", 25),
GATE_HWV_MM10(CLK_MM1_DISP_GDMA0, "mm1_disp_gdma0", "disp", 26),
GATE_HWV_MM10(CLK_MM1_DISP_MERGE0, "mm1_disp_merge0", "disp", 27),
GATE_HWV_MM10(CLK_MM1_DISP_MERGE1, "mm1_disp_merge1", "disp", 28),
GATE_HWV_MM10(CLK_MM1_DISP_MERGE2, "mm1_disp_merge2", "disp", 29),
GATE_HWV_MM10(CLK_MM1_DISP_ODDMR0, "mm1_disp_oddmr0", "disp", 30),
GATE_HWV_MM10(CLK_MM1_DISP_POSTALIGN0, "mm1_disp_postalign0", "disp", 31),
/* MM11 */
GATE_HWV_MM11(CLK_MM1_DISP_DITHER2, "mm1_disp_dither2", "disp", 0),
GATE_HWV_MM11(CLK_MM1_DISP_R2Y0, "mm1_disp_r2y0", "disp", 1),
GATE_HWV_MM11(CLK_MM1_DISP_SPLITTER0, "mm1_disp_splitter0", "disp", 2),
GATE_HWV_MM11(CLK_MM1_DISP_SPLITTER1, "mm1_disp_splitter1", "disp", 3),
GATE_HWV_MM11(CLK_MM1_DISP_SPLITTER2, "mm1_disp_splitter2", "disp", 4),
GATE_HWV_MM11(CLK_MM1_DISP_SPLITTER3, "mm1_disp_splitter3", "disp", 5),
GATE_HWV_MM11(CLK_MM1_DISP_VDCM0, "mm1_disp_vdcm0", "disp", 6),
GATE_HWV_MM11(CLK_MM1_DISP_WDMA1, "mm1_disp_wdma1", "disp", 7),
GATE_HWV_MM11(CLK_MM1_DISP_WDMA2, "mm1_disp_wdma2", "disp", 8),
GATE_HWV_MM11(CLK_MM1_DISP_WDMA3, "mm1_disp_wdma3", "disp", 9),
GATE_HWV_MM11(CLK_MM1_DISP_WDMA4, "mm1_disp_wdma4", "disp", 10),
GATE_HWV_MM11(CLK_MM1_MDP_RDMA1, "mm1_mdp_rdma1", "disp", 11),
GATE_HWV_MM11(CLK_MM1_SMI_LARB0, "mm1_smi_larb0", "disp", 12),
GATE_HWV_MM11(CLK_MM1_MOD1, "mm1_mod1", "clk26m", 13),
GATE_HWV_MM11(CLK_MM1_MOD2, "mm1_mod2", "clk26m", 14),
GATE_HWV_MM11(CLK_MM1_MOD3, "mm1_mod3", "clk26m", 15),
GATE_HWV_MM11(CLK_MM1_MOD4, "mm1_mod4", "dp0", 16),
GATE_HWV_MM11(CLK_MM1_MOD5, "mm1_mod5", "dp1", 17),
GATE_HWV_MM11(CLK_MM1_MOD6, "mm1_mod6", "dp1", 18),
GATE_HWV_MM11(CLK_MM1_CG0, "mm1_cg0", "disp", 20),
GATE_HWV_MM11(CLK_MM1_CG1, "mm1_cg1", "disp", 21),
GATE_HWV_MM11(CLK_MM1_CG2, "mm1_cg2", "disp", 22),
GATE_HWV_MM11(CLK_MM1_CG3, "mm1_cg3", "disp", 23),
GATE_HWV_MM11(CLK_MM1_CG4, "mm1_cg4", "disp", 24),
GATE_HWV_MM11(CLK_MM1_CG5, "mm1_cg5", "disp", 25),
GATE_HWV_MM11(CLK_MM1_CG6, "mm1_cg6", "disp", 26),
GATE_HWV_MM11(CLK_MM1_CG7, "mm1_cg7", "disp", 27),
GATE_HWV_MM11(CLK_MM1_F26M, "mm1_f26m_ck", "clk26m", 28),
};
static const struct mtk_clk_desc mm1_mcd = {
.clks = mm1_clks,
.num_clks = ARRAY_SIZE(mm1_clks),
};
static const struct platform_device_id clk_mt8196_disp1_id_table[] = {
{ .name = "clk-mt8196-disp1", .driver_data = (kernel_ulong_t)&mm1_mcd },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, clk_mt8196_disp1_id_table);
static struct platform_driver clk_mt8196_disp1_drv = {
.probe = mtk_clk_pdev_probe,
.remove = mtk_clk_pdev_remove,
.driver = {
.name = "clk-mt8196-disp1",
},
.id_table = clk_mt8196_disp1_id_table,
};
module_platform_driver(clk_mt8196_disp1_drv);
MODULE_DESCRIPTION("MediaTek MT8196 disp1 clocks driver");
MODULE_LICENSE("GPL");
@@ -0,0 +1,118 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2025 MediaTek Inc.
* Guangjie Song <guangjie.song@mediatek.com>
* Copyright (c) 2025 Collabora Ltd.
* Laura Nao <laura.nao@collabora.com>
*/
#include <dt-bindings/clock/mediatek,mt8196-clock.h>
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include "clk-gate.h"
#include "clk-mtk.h"
static const struct mtk_gate_regs imp_cg_regs = {
.set_ofs = 0xe08,
.clr_ofs = 0xe04,
.sta_ofs = 0xe00,
};
#define GATE_IMP(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &imp_cg_regs, \
.shift = _shift, \
.flags = CLK_OPS_PARENT_ENABLE, \
.ops = &mtk_clk_gate_ops_setclr, \
}
static const struct mtk_gate impc_clks[] = {
GATE_IMP(CLK_IMPC_I2C11, "impc_i2c11", "i2c_p", 0),
GATE_IMP(CLK_IMPC_I2C12, "impc_i2c12", "i2c_p", 1),
GATE_IMP(CLK_IMPC_I2C13, "impc_i2c13", "i2c_p", 2),
GATE_IMP(CLK_IMPC_I2C14, "impc_i2c14", "i2c_p", 3),
};
static const struct mtk_clk_desc impc_mcd = {
.clks = impc_clks,
.num_clks = ARRAY_SIZE(impc_clks),
};
static const struct mtk_gate impe_clks[] = {
GATE_IMP(CLK_IMPE_I2C5, "impe_i2c5", "i2c_east", 0),
};
static const struct mtk_clk_desc impe_mcd = {
.clks = impe_clks,
.num_clks = ARRAY_SIZE(impe_clks),
};
static const struct mtk_gate_regs impn_hwv_regs = {
.set_ofs = 0x0000,
.clr_ofs = 0x0004,
.sta_ofs = 0x2c00,
};
#define GATE_HWV_IMPN(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &imp_cg_regs, \
.hwv_regs = &impn_hwv_regs, \
.shift = _shift, \
.ops = &mtk_clk_gate_hwv_ops_setclr, \
.flags = CLK_OPS_PARENT_ENABLE, \
}
static const struct mtk_gate impn_clks[] = {
GATE_IMP(CLK_IMPN_I2C1, "impn_i2c1", "i2c_north", 0),
GATE_IMP(CLK_IMPN_I2C2, "impn_i2c2", "i2c_north", 1),
GATE_IMP(CLK_IMPN_I2C4, "impn_i2c4", "i2c_north", 2),
GATE_HWV_IMPN(CLK_IMPN_I2C7, "impn_i2c7", "i2c_north", 3),
GATE_IMP(CLK_IMPN_I2C8, "impn_i2c8", "i2c_north", 4),
GATE_IMP(CLK_IMPN_I2C9, "impn_i2c9", "i2c_north", 5),
};
static const struct mtk_clk_desc impn_mcd = {
.clks = impn_clks,
.num_clks = ARRAY_SIZE(impn_clks),
};
static const struct mtk_gate impw_clks[] = {
GATE_IMP(CLK_IMPW_I2C0, "impw_i2c0", "i2c_west", 0),
GATE_IMP(CLK_IMPW_I2C3, "impw_i2c3", "i2c_west", 1),
GATE_IMP(CLK_IMPW_I2C6, "impw_i2c6", "i2c_west", 2),
GATE_IMP(CLK_IMPW_I2C10, "impw_i2c10", "i2c_west", 3),
};
static const struct mtk_clk_desc impw_mcd = {
.clks = impw_clks,
.num_clks = ARRAY_SIZE(impw_clks),
};
static const struct of_device_id of_match_clk_mt8196_imp_iic_wrap[] = {
{ .compatible = "mediatek,mt8196-imp-iic-wrap-c", .data = &impc_mcd },
{ .compatible = "mediatek,mt8196-imp-iic-wrap-e", .data = &impe_mcd },
{ .compatible = "mediatek,mt8196-imp-iic-wrap-n", .data = &impn_mcd },
{ .compatible = "mediatek,mt8196-imp-iic-wrap-w", .data = &impw_mcd },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_match_clk_mt8196_imp_iic_wrap);
static struct platform_driver clk_mt8196_imp_iic_wrap_drv = {
.probe = mtk_clk_simple_probe,
.remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8196-imp_iic_wrap",
.of_match_table = of_match_clk_mt8196_imp_iic_wrap,
},
};
module_platform_driver(clk_mt8196_imp_iic_wrap_drv);
MODULE_DESCRIPTION("MediaTek MT8196 I2C Wrapper clocks driver");
MODULE_LICENSE("GPL");
+167
View File
@@ -0,0 +1,167 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2025 MediaTek Inc.
* Guangjie Song <guangjie.song@mediatek.com>
* Copyright (c) 2025 Collabora Ltd.
* Laura Nao <laura.nao@collabora.com>
*/
#include <dt-bindings/clock/mediatek,mt8196-clock.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include "clk-mtk.h"
#include "clk-pll.h"
#define ARMPLL_LL_CON0 0x008
#define ARMPLL_LL_CON1 0x00c
#define ARMPLL_LL_CON2 0x010
#define ARMPLL_LL_CON3 0x014
#define ARMPLL_BL_CON0 0x008
#define ARMPLL_BL_CON1 0x00c
#define ARMPLL_BL_CON2 0x010
#define ARMPLL_BL_CON3 0x014
#define ARMPLL_B_CON0 0x008
#define ARMPLL_B_CON1 0x00c
#define ARMPLL_B_CON2 0x010
#define ARMPLL_B_CON3 0x014
#define CCIPLL_CON0 0x008
#define CCIPLL_CON1 0x00c
#define CCIPLL_CON2 0x010
#define CCIPLL_CON3 0x014
#define PTPPLL_CON0 0x008
#define PTPPLL_CON1 0x00c
#define PTPPLL_CON2 0x010
#define PTPPLL_CON3 0x014
#define MT8196_PLL_FMAX (3800UL * MHZ)
#define MT8196_PLL_FMIN (1500UL * MHZ)
#define MT8196_INTEGER_BITS 8
#define PLL(_id, _name, _reg, _en_reg, _en_mask, _pll_en_bit, \
_flags, _rst_bar_mask, \
_pd_reg, _pd_shift, _tuner_reg, \
_tuner_en_reg, _tuner_en_bit, \
_pcw_reg, _pcw_shift, _pcwbits) { \
.id = _id, \
.name = _name, \
.reg = _reg, \
.en_reg = _en_reg, \
.en_mask = _en_mask, \
.pll_en_bit = _pll_en_bit, \
.flags = _flags, \
.rst_bar_mask = _rst_bar_mask, \
.fmax = MT8196_PLL_FMAX, \
.fmin = MT8196_PLL_FMIN, \
.pd_reg = _pd_reg, \
.pd_shift = _pd_shift, \
.tuner_reg = _tuner_reg, \
.tuner_en_reg = _tuner_en_reg, \
.tuner_en_bit = _tuner_en_bit, \
.pcw_reg = _pcw_reg, \
.pcw_shift = _pcw_shift, \
.pcwbits = _pcwbits, \
.pcwibits = MT8196_INTEGER_BITS, \
}
static const struct mtk_pll_data cpu_bl_plls[] = {
PLL(CLK_CPBL_ARMPLL_BL, "armpll-bl", ARMPLL_BL_CON0, ARMPLL_BL_CON0, 0,
0, PLL_AO, BIT(0), ARMPLL_BL_CON1, 24, 0, 0, 0, ARMPLL_BL_CON1, 0, 22),
};
static const struct mtk_pll_data cpu_b_plls[] = {
PLL(CLK_CPB_ARMPLL_B, "armpll-b", ARMPLL_B_CON0, ARMPLL_B_CON0, 0, 0,
PLL_AO, BIT(0), ARMPLL_B_CON1, 24, 0, 0, 0, ARMPLL_B_CON1, 0, 22),
};
static const struct mtk_pll_data cpu_ll_plls[] = {
PLL(CLK_CPLL_ARMPLL_LL, "armpll-ll", ARMPLL_LL_CON0, ARMPLL_LL_CON0, 0,
0, PLL_AO, BIT(0), ARMPLL_LL_CON1, 24, 0, 0, 0, ARMPLL_LL_CON1, 0, 22),
};
static const struct mtk_pll_data cci_plls[] = {
PLL(CLK_CCIPLL, "ccipll", CCIPLL_CON0, CCIPLL_CON0, 0, 0, PLL_AO,
BIT(0), CCIPLL_CON1, 24, 0, 0, 0, CCIPLL_CON1, 0, 22),
};
static const struct mtk_pll_data ptp_plls[] = {
PLL(CLK_PTPPLL, "ptppll", PTPPLL_CON0, PTPPLL_CON0, 0, 0, PLL_AO,
BIT(0), PTPPLL_CON1, 24, 0, 0, 0, PTPPLL_CON1, 0, 22),
};
static const struct of_device_id of_match_clk_mt8196_mcu[] = {
{ .compatible = "mediatek,mt8196-armpll-bl-pll-ctrl",
.data = &cpu_bl_plls },
{ .compatible = "mediatek,mt8196-armpll-b-pll-ctrl",
.data = &cpu_b_plls },
{ .compatible = "mediatek,mt8196-armpll-ll-pll-ctrl",
.data = &cpu_ll_plls },
{ .compatible = "mediatek,mt8196-ccipll-pll-ctrl", .data = &cci_plls },
{ .compatible = "mediatek,mt8196-ptppll-pll-ctrl", .data = &ptp_plls },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_match_clk_mt8196_mcu);
static int clk_mt8196_mcu_probe(struct platform_device *pdev)
{
const struct mtk_pll_data *plls;
struct clk_hw_onecell_data *clk_data;
struct device_node *node = pdev->dev.of_node;
const int num_plls = 1;
int r;
plls = of_device_get_match_data(&pdev->dev);
if (!plls)
return -EINVAL;
clk_data = mtk_alloc_clk_data(num_plls);
if (!clk_data)
return -ENOMEM;
r = mtk_clk_register_plls(node, plls, num_plls, clk_data);
if (r)
goto free_clk_data;
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
if (r)
goto unregister_plls;
platform_set_drvdata(pdev, clk_data);
return r;
unregister_plls:
mtk_clk_unregister_plls(plls, num_plls, clk_data);
free_clk_data:
mtk_free_clk_data(clk_data);
return r;
}
static void clk_mt8196_mcu_remove(struct platform_device *pdev)
{
const struct mtk_pll_data *plls = of_device_get_match_data(&pdev->dev);
struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev);
struct device_node *node = pdev->dev.of_node;
of_clk_del_provider(node);
mtk_clk_unregister_plls(plls, 1, clk_data);
mtk_free_clk_data(clk_data);
}
static struct platform_driver clk_mt8196_mcu_drv = {
.probe = clk_mt8196_mcu_probe,
.remove = clk_mt8196_mcu_remove,
.driver = {
.name = "clk-mt8196-mcu",
.of_match_table = of_match_clk_mt8196_mcu,
},
};
module_platform_driver(clk_mt8196_mcu_drv);
MODULE_DESCRIPTION("MediaTek MT8196 mcusys clocks driver");
MODULE_LICENSE("GPL");
+186
View File
@@ -0,0 +1,186 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2025 MediaTek Inc.
* Guangjie Song <guangjie.song@mediatek.com>
* Copyright (c) 2025 Collabora Ltd.
* Laura Nao <laura.nao@collabora.com>
*/
#include <dt-bindings/clock/mediatek,mt8196-clock.h>
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include "clk-gate.h"
#include "clk-mtk.h"
static const struct mtk_gate_regs mdp0_cg_regs = {
.set_ofs = 0x104,
.clr_ofs = 0x108,
.sta_ofs = 0x100,
};
static const struct mtk_gate_regs mdp1_cg_regs = {
.set_ofs = 0x114,
.clr_ofs = 0x118,
.sta_ofs = 0x110,
};
static const struct mtk_gate_regs mdp2_cg_regs = {
.set_ofs = 0x124,
.clr_ofs = 0x128,
.sta_ofs = 0x120,
};
#define GATE_MDP0(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &mdp0_cg_regs, \
.shift = _shift, \
.flags = CLK_OPS_PARENT_ENABLE, \
.ops = &mtk_clk_gate_ops_setclr, \
}
#define GATE_MDP1(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &mdp1_cg_regs, \
.shift = _shift, \
.ops = &mtk_clk_gate_ops_setclr, \
}
#define GATE_MDP2(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &mdp2_cg_regs, \
.shift = _shift, \
.flags = CLK_OPS_PARENT_ENABLE, \
.ops = &mtk_clk_gate_ops_setclr, \
}
static const struct mtk_gate mdp1_clks[] = {
/* MDP1-0 */
GATE_MDP0(CLK_MDP1_MDP_MUTEX0, "mdp1_mdp_mutex0", "mdp", 0),
GATE_MDP0(CLK_MDP1_SMI0, "mdp1_smi0", "mdp", 1),
GATE_MDP0(CLK_MDP1_APB_BUS, "mdp1_apb_bus", "mdp", 2),
GATE_MDP0(CLK_MDP1_MDP_RDMA0, "mdp1_mdp_rdma0", "mdp", 3),
GATE_MDP0(CLK_MDP1_MDP_RDMA1, "mdp1_mdp_rdma1", "mdp", 4),
GATE_MDP0(CLK_MDP1_MDP_RDMA2, "mdp1_mdp_rdma2", "mdp", 5),
GATE_MDP0(CLK_MDP1_MDP_BIRSZ0, "mdp1_mdp_birsz0", "mdp", 6),
GATE_MDP0(CLK_MDP1_MDP_HDR0, "mdp1_mdp_hdr0", "mdp", 7),
GATE_MDP0(CLK_MDP1_MDP_AAL0, "mdp1_mdp_aal0", "mdp", 8),
GATE_MDP0(CLK_MDP1_MDP_RSZ0, "mdp1_mdp_rsz0", "mdp", 9),
GATE_MDP0(CLK_MDP1_MDP_RSZ2, "mdp1_mdp_rsz2", "mdp", 10),
GATE_MDP0(CLK_MDP1_MDP_TDSHP0, "mdp1_mdp_tdshp0", "mdp", 11),
GATE_MDP0(CLK_MDP1_MDP_COLOR0, "mdp1_mdp_color0", "mdp", 12),
GATE_MDP0(CLK_MDP1_MDP_WROT0, "mdp1_mdp_wrot0", "mdp", 13),
GATE_MDP0(CLK_MDP1_MDP_WROT1, "mdp1_mdp_wrot1", "mdp", 14),
GATE_MDP0(CLK_MDP1_MDP_WROT2, "mdp1_mdp_wrot2", "mdp", 15),
GATE_MDP0(CLK_MDP1_MDP_FAKE_ENG0, "mdp1_mdp_fake_eng0", "mdp", 16),
GATE_MDP0(CLK_MDP1_APB_DB, "mdp1_apb_db", "mdp", 17),
GATE_MDP0(CLK_MDP1_MDP_DLI_ASYNC0, "mdp1_mdp_dli_async0", "mdp", 18),
GATE_MDP0(CLK_MDP1_MDP_DLI_ASYNC1, "mdp1_mdp_dli_async1", "mdp", 19),
GATE_MDP0(CLK_MDP1_MDP_DLO_ASYNC0, "mdp1_mdp_dlo_async0", "mdp", 20),
GATE_MDP0(CLK_MDP1_MDP_DLO_ASYNC1, "mdp1_mdp_dlo_async1", "mdp", 21),
GATE_MDP0(CLK_MDP1_MDP_DLI_ASYNC2, "mdp1_mdp_dli_async2", "mdp", 22),
GATE_MDP0(CLK_MDP1_MDP_DLO_ASYNC2, "mdp1_mdp_dlo_async2", "mdp", 23),
GATE_MDP0(CLK_MDP1_MDP_DLO_ASYNC3, "mdp1_mdp_dlo_async3", "mdp", 24),
GATE_MDP0(CLK_MDP1_IMG_DL_ASYNC0, "mdp1_img_dl_async0", "mdp", 25),
GATE_MDP0(CLK_MDP1_MDP_RROT0, "mdp1_mdp_rrot0", "mdp", 26),
GATE_MDP0(CLK_MDP1_MDP_MERGE0, "mdp1_mdp_merge0", "mdp", 27),
GATE_MDP0(CLK_MDP1_MDP_C3D0, "mdp1_mdp_c3d0", "mdp", 28),
GATE_MDP0(CLK_MDP1_MDP_FG0, "mdp1_mdp_fg0", "mdp", 29),
GATE_MDP0(CLK_MDP1_MDP_CLA2, "mdp1_mdp_cla2", "mdp", 30),
GATE_MDP0(CLK_MDP1_MDP_DLO_ASYNC4, "mdp1_mdp_dlo_async4", "mdp", 31),
/* MDP1-1 */
GATE_MDP1(CLK_MDP1_VPP_RSZ0, "mdp1_vpp_rsz0", "mdp", 0),
GATE_MDP1(CLK_MDP1_VPP_RSZ1, "mdp1_vpp_rsz1", "mdp", 1),
GATE_MDP1(CLK_MDP1_MDP_DLO_ASYNC5, "mdp1_mdp_dlo_async5", "mdp", 2),
GATE_MDP1(CLK_MDP1_IMG0, "mdp1_img0", "mdp", 3),
GATE_MDP1(CLK_MDP1_F26M, "mdp1_f26m", "clk26m", 27),
/* MDP1-2 */
GATE_MDP2(CLK_MDP1_IMG_DL_RELAY0, "mdp1_img_dl_relay0", "mdp", 0),
GATE_MDP2(CLK_MDP1_IMG_DL_RELAY1, "mdp1_img_dl_relay1", "mdp", 8),
};
static const struct mtk_clk_desc mdp1_mcd = {
.clks = mdp1_clks,
.num_clks = ARRAY_SIZE(mdp1_clks),
.need_runtime_pm = true,
};
static const struct mtk_gate mdp_clks[] = {
/* MDP0 */
GATE_MDP0(CLK_MDP_MDP_MUTEX0, "mdp_mdp_mutex0", "mdp", 0),
GATE_MDP0(CLK_MDP_SMI0, "mdp_smi0", "mdp", 1),
GATE_MDP0(CLK_MDP_APB_BUS, "mdp_apb_bus", "mdp", 2),
GATE_MDP0(CLK_MDP_MDP_RDMA0, "mdp_mdp_rdma0", "mdp", 3),
GATE_MDP0(CLK_MDP_MDP_RDMA1, "mdp_mdp_rdma1", "mdp", 4),
GATE_MDP0(CLK_MDP_MDP_RDMA2, "mdp_mdp_rdma2", "mdp", 5),
GATE_MDP0(CLK_MDP_MDP_BIRSZ0, "mdp_mdp_birsz0", "mdp", 6),
GATE_MDP0(CLK_MDP_MDP_HDR0, "mdp_mdp_hdr0", "mdp", 7),
GATE_MDP0(CLK_MDP_MDP_AAL0, "mdp_mdp_aal0", "mdp", 8),
GATE_MDP0(CLK_MDP_MDP_RSZ0, "mdp_mdp_rsz0", "mdp", 9),
GATE_MDP0(CLK_MDP_MDP_RSZ2, "mdp_mdp_rsz2", "mdp", 10),
GATE_MDP0(CLK_MDP_MDP_TDSHP0, "mdp_mdp_tdshp0", "mdp", 11),
GATE_MDP0(CLK_MDP_MDP_COLOR0, "mdp_mdp_color0", "mdp", 12),
GATE_MDP0(CLK_MDP_MDP_WROT0, "mdp_mdp_wrot0", "mdp", 13),
GATE_MDP0(CLK_MDP_MDP_WROT1, "mdp_mdp_wrot1", "mdp", 14),
GATE_MDP0(CLK_MDP_MDP_WROT2, "mdp_mdp_wrot2", "mdp", 15),
GATE_MDP0(CLK_MDP_MDP_FAKE_ENG0, "mdp_mdp_fake_eng0", "mdp", 16),
GATE_MDP0(CLK_MDP_APB_DB, "mdp_apb_db", "mdp", 17),
GATE_MDP0(CLK_MDP_MDP_DLI_ASYNC0, "mdp_mdp_dli_async0", "mdp", 18),
GATE_MDP0(CLK_MDP_MDP_DLI_ASYNC1, "mdp_mdp_dli_async1", "mdp", 19),
GATE_MDP0(CLK_MDP_MDP_DLO_ASYNC0, "mdp_mdp_dlo_async0", "mdp", 20),
GATE_MDP0(CLK_MDP_MDP_DLO_ASYNC1, "mdp_mdp_dlo_async1", "mdp", 21),
GATE_MDP0(CLK_MDP_MDP_DLI_ASYNC2, "mdp_mdp_dli_async2", "mdp", 22),
GATE_MDP0(CLK_MDP_MDP_DLO_ASYNC2, "mdp_mdp_dlo_async2", "mdp", 23),
GATE_MDP0(CLK_MDP_MDP_DLO_ASYNC3, "mdp_mdp_dlo_async3", "mdp", 24),
GATE_MDP0(CLK_MDP_IMG_DL_ASYNC0, "mdp_img_dl_async0", "mdp", 25),
GATE_MDP0(CLK_MDP_MDP_RROT0, "mdp_mdp_rrot0", "mdp", 26),
GATE_MDP0(CLK_MDP_MDP_MERGE0, "mdp_mdp_merge0", "mdp", 27),
GATE_MDP0(CLK_MDP_MDP_C3D0, "mdp_mdp_c3d0", "mdp", 28),
GATE_MDP0(CLK_MDP_MDP_FG0, "mdp_mdp_fg0", "mdp", 29),
GATE_MDP0(CLK_MDP_MDP_CLA2, "mdp_mdp_cla2", "mdp", 30),
GATE_MDP0(CLK_MDP_MDP_DLO_ASYNC4, "mdp_mdp_dlo_async4", "mdp", 31),
/* MDP1 */
GATE_MDP1(CLK_MDP_VPP_RSZ0, "mdp_vpp_rsz0", "mdp", 0),
GATE_MDP1(CLK_MDP_VPP_RSZ1, "mdp_vpp_rsz1", "mdp", 1),
GATE_MDP1(CLK_MDP_MDP_DLO_ASYNC5, "mdp_mdp_dlo_async5", "mdp", 2),
GATE_MDP1(CLK_MDP_IMG0, "mdp_img0", "mdp", 3),
GATE_MDP1(CLK_MDP_F26M, "mdp_f26m", "clk26m", 27),
/* MDP2 */
GATE_MDP2(CLK_MDP_IMG_DL_RELAY0, "mdp_img_dl_relay0", "mdp", 0),
GATE_MDP2(CLK_MDP_IMG_DL_RELAY1, "mdp_img_dl_relay1", "mdp", 8),
};
static const struct mtk_clk_desc mdp_mcd = {
.clks = mdp_clks,
.num_clks = ARRAY_SIZE(mdp_clks),
.need_runtime_pm = true,
};
static const struct of_device_id of_match_clk_mt8196_mdpsys[] = {
{ .compatible = "mediatek,mt8196-mdpsys0", .data = &mdp_mcd },
{ .compatible = "mediatek,mt8196-mdpsys1", .data = &mdp1_mcd },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_match_clk_mt8196_mdpsys);
static struct platform_driver clk_mt8196_mdpsys_drv = {
.probe = mtk_clk_simple_probe,
.remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8196-mdpsys",
.of_match_table = of_match_clk_mt8196_mdpsys,
},
};
module_platform_driver(clk_mt8196_mdpsys_drv);
MODULE_DESCRIPTION("MediaTek MT8196 Multimedia Data Path clocks driver");
MODULE_LICENSE("GPL");
+150
View File
@@ -0,0 +1,150 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2025 MediaTek Inc.
* Guangjie Song <guangjie.song@mediatek.com>
* Copyright (c) 2025 Collabora Ltd.
* Laura Nao <laura.nao@collabora.com>
*/
#include <dt-bindings/clock/mediatek,mt8196-clock.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include "clk-mtk.h"
#include "clk-pll.h"
#define MFGPLL_CON0 0x008
#define MFGPLL_CON1 0x00c
#define MFGPLL_CON2 0x010
#define MFGPLL_CON3 0x014
#define MFGPLL_SC0_CON0 0x008
#define MFGPLL_SC0_CON1 0x00c
#define MFGPLL_SC0_CON2 0x010
#define MFGPLL_SC0_CON3 0x014
#define MFGPLL_SC1_CON0 0x008
#define MFGPLL_SC1_CON1 0x00c
#define MFGPLL_SC1_CON2 0x010
#define MFGPLL_SC1_CON3 0x014
#define MT8196_PLL_FMAX (3800UL * MHZ)
#define MT8196_PLL_FMIN (1500UL * MHZ)
#define MT8196_INTEGER_BITS 8
#define PLL(_id, _name, _reg, _en_reg, _en_mask, _pll_en_bit, \
_flags, _rst_bar_mask, \
_pd_reg, _pd_shift, _tuner_reg, \
_tuner_en_reg, _tuner_en_bit, \
_pcw_reg, _pcw_shift, _pcwbits) { \
.id = _id, \
.name = _name, \
.reg = _reg, \
.en_reg = _en_reg, \
.en_mask = _en_mask, \
.pll_en_bit = _pll_en_bit, \
.flags = _flags, \
.rst_bar_mask = _rst_bar_mask, \
.fmax = MT8196_PLL_FMAX, \
.fmin = MT8196_PLL_FMIN, \
.pd_reg = _pd_reg, \
.pd_shift = _pd_shift, \
.tuner_reg = _tuner_reg, \
.tuner_en_reg = _tuner_en_reg, \
.tuner_en_bit = _tuner_en_bit, \
.pcw_reg = _pcw_reg, \
.pcw_shift = _pcw_shift, \
.pcwbits = _pcwbits, \
.pcwibits = MT8196_INTEGER_BITS, \
}
static const struct mtk_pll_data mfg_ao_plls[] = {
PLL(CLK_MFG_AO_MFGPLL, "mfgpll", MFGPLL_CON0, MFGPLL_CON0, 0, 0, 0,
BIT(0), MFGPLL_CON1, 24, 0, 0, 0,
MFGPLL_CON1, 0, 22),
};
static const struct mtk_pll_data mfgsc0_ao_plls[] = {
PLL(CLK_MFGSC0_AO_MFGPLL_SC0, "mfgpll-sc0", MFGPLL_SC0_CON0,
MFGPLL_SC0_CON0, 0, 0, 0, BIT(0), MFGPLL_SC0_CON1, 24, 0, 0, 0,
MFGPLL_SC0_CON1, 0, 22),
};
static const struct mtk_pll_data mfgsc1_ao_plls[] = {
PLL(CLK_MFGSC1_AO_MFGPLL_SC1, "mfgpll-sc1", MFGPLL_SC1_CON0,
MFGPLL_SC1_CON0, 0, 0, 0, BIT(0), MFGPLL_SC1_CON1, 24, 0, 0, 0,
MFGPLL_SC1_CON1, 0, 22),
};
static const struct of_device_id of_match_clk_mt8196_mfg[] = {
{ .compatible = "mediatek,mt8196-mfgpll-pll-ctrl",
.data = &mfg_ao_plls },
{ .compatible = "mediatek,mt8196-mfgpll-sc0-pll-ctrl",
.data = &mfgsc0_ao_plls },
{ .compatible = "mediatek,mt8196-mfgpll-sc1-pll-ctrl",
.data = &mfgsc1_ao_plls },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_match_clk_mt8196_mfg);
static int clk_mt8196_mfg_probe(struct platform_device *pdev)
{
const struct mtk_pll_data *plls;
struct clk_hw_onecell_data *clk_data;
struct device_node *node = pdev->dev.of_node;
const int num_plls = 1;
int r;
plls = of_device_get_match_data(&pdev->dev);
if (!plls)
return -EINVAL;
clk_data = mtk_alloc_clk_data(num_plls);
if (!clk_data)
return -ENOMEM;
r = mtk_clk_register_plls(node, plls, num_plls, clk_data);
if (r)
goto free_clk_data;
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
if (r)
goto unregister_plls;
platform_set_drvdata(pdev, clk_data);
return r;
unregister_plls:
mtk_clk_unregister_plls(plls, num_plls, clk_data);
free_clk_data:
mtk_free_clk_data(clk_data);
return r;
}
static void clk_mt8196_mfg_remove(struct platform_device *pdev)
{
const struct mtk_pll_data *plls = of_device_get_match_data(&pdev->dev);
struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev);
struct device_node *node = pdev->dev.of_node;
of_clk_del_provider(node);
mtk_clk_unregister_plls(plls, 1, clk_data);
mtk_free_clk_data(clk_data);
}
static struct platform_driver clk_mt8196_mfg_drv = {
.probe = clk_mt8196_mfg_probe,
.remove = clk_mt8196_mfg_remove,
.driver = {
.name = "clk-mt8196-mfg",
.of_match_table = of_match_clk_mt8196_mfg,
},
};
module_platform_driver(clk_mt8196_mfg_drv);
MODULE_DESCRIPTION("MediaTek MT8196 GPU mfg clocks driver");
MODULE_LICENSE("GPL");
+154
View File
@@ -0,0 +1,154 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2025 MediaTek Inc.
* Guangjie Song <guangjie.song@mediatek.com>
* Copyright (c) 2025 Collabora Ltd.
* Laura Nao <laura.nao@collabora.com>
*/
#include <dt-bindings/clock/mediatek,mt8196-clock.h>
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include "clk-gate.h"
#include "clk-mtk.h"
static const struct mtk_gate_regs ovl0_cg_regs = {
.set_ofs = 0x104,
.clr_ofs = 0x108,
.sta_ofs = 0x100,
};
static const struct mtk_gate_regs ovl0_hwv_regs = {
.set_ofs = 0x0060,
.clr_ofs = 0x0064,
.sta_ofs = 0x2c30,
};
static const struct mtk_gate_regs ovl1_cg_regs = {
.set_ofs = 0x114,
.clr_ofs = 0x118,
.sta_ofs = 0x110,
};
static const struct mtk_gate_regs ovl1_hwv_regs = {
.set_ofs = 0x0068,
.clr_ofs = 0x006c,
.sta_ofs = 0x2c34,
};
#define GATE_HWV_OVL0(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &ovl0_cg_regs, \
.hwv_regs = &ovl0_hwv_regs, \
.shift = _shift, \
.ops = &mtk_clk_gate_hwv_ops_setclr, \
.flags = CLK_OPS_PARENT_ENABLE, \
}
#define GATE_HWV_OVL1(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &ovl1_cg_regs, \
.hwv_regs = &ovl1_hwv_regs, \
.shift = _shift, \
.ops = &mtk_clk_gate_hwv_ops_setclr, \
.flags = CLK_OPS_PARENT_ENABLE, \
}
static const struct mtk_gate ovl_clks[] = {
/* OVL0 */
GATE_HWV_OVL0(CLK_OVLSYS_CONFIG, "ovlsys_config", "disp", 0),
GATE_HWV_OVL0(CLK_OVL_FAKE_ENG0, "ovl_fake_eng0", "disp", 1),
GATE_HWV_OVL0(CLK_OVL_FAKE_ENG1, "ovl_fake_eng1", "disp", 2),
GATE_HWV_OVL0(CLK_OVL_MUTEX0, "ovl_mutex0", "disp", 3),
GATE_HWV_OVL0(CLK_OVL_EXDMA0, "ovl_exdma0", "disp", 4),
GATE_HWV_OVL0(CLK_OVL_EXDMA1, "ovl_exdma1", "disp", 5),
GATE_HWV_OVL0(CLK_OVL_EXDMA2, "ovl_exdma2", "disp", 6),
GATE_HWV_OVL0(CLK_OVL_EXDMA3, "ovl_exdma3", "disp", 7),
GATE_HWV_OVL0(CLK_OVL_EXDMA4, "ovl_exdma4", "disp", 8),
GATE_HWV_OVL0(CLK_OVL_EXDMA5, "ovl_exdma5", "disp", 9),
GATE_HWV_OVL0(CLK_OVL_EXDMA6, "ovl_exdma6", "disp", 10),
GATE_HWV_OVL0(CLK_OVL_EXDMA7, "ovl_exdma7", "disp", 11),
GATE_HWV_OVL0(CLK_OVL_EXDMA8, "ovl_exdma8", "disp", 12),
GATE_HWV_OVL0(CLK_OVL_EXDMA9, "ovl_exdma9", "disp", 13),
GATE_HWV_OVL0(CLK_OVL_BLENDER0, "ovl_blender0", "disp", 14),
GATE_HWV_OVL0(CLK_OVL_BLENDER1, "ovl_blender1", "disp", 15),
GATE_HWV_OVL0(CLK_OVL_BLENDER2, "ovl_blender2", "disp", 16),
GATE_HWV_OVL0(CLK_OVL_BLENDER3, "ovl_blender3", "disp", 17),
GATE_HWV_OVL0(CLK_OVL_BLENDER4, "ovl_blender4", "disp", 18),
GATE_HWV_OVL0(CLK_OVL_BLENDER5, "ovl_blender5", "disp", 19),
GATE_HWV_OVL0(CLK_OVL_BLENDER6, "ovl_blender6", "disp", 20),
GATE_HWV_OVL0(CLK_OVL_BLENDER7, "ovl_blender7", "disp", 21),
GATE_HWV_OVL0(CLK_OVL_BLENDER8, "ovl_blender8", "disp", 22),
GATE_HWV_OVL0(CLK_OVL_BLENDER9, "ovl_blender9", "disp", 23),
GATE_HWV_OVL0(CLK_OVL_OUTPROC0, "ovl_outproc0", "disp", 24),
GATE_HWV_OVL0(CLK_OVL_OUTPROC1, "ovl_outproc1", "disp", 25),
GATE_HWV_OVL0(CLK_OVL_OUTPROC2, "ovl_outproc2", "disp", 26),
GATE_HWV_OVL0(CLK_OVL_OUTPROC3, "ovl_outproc3", "disp", 27),
GATE_HWV_OVL0(CLK_OVL_OUTPROC4, "ovl_outproc4", "disp", 28),
GATE_HWV_OVL0(CLK_OVL_OUTPROC5, "ovl_outproc5", "disp", 29),
GATE_HWV_OVL0(CLK_OVL_MDP_RSZ0, "ovl_mdp_rsz0", "disp", 30),
GATE_HWV_OVL0(CLK_OVL_MDP_RSZ1, "ovl_mdp_rsz1", "disp", 31),
/* OVL1 */
GATE_HWV_OVL1(CLK_OVL_DISP_WDMA0, "ovl_disp_wdma0", "disp", 0),
GATE_HWV_OVL1(CLK_OVL_DISP_WDMA1, "ovl_disp_wdma1", "disp", 1),
GATE_HWV_OVL1(CLK_OVL_UFBC_WDMA0, "ovl_ufbc_wdma0", "disp", 2),
GATE_HWV_OVL1(CLK_OVL_MDP_RDMA0, "ovl_mdp_rdma0", "disp", 3),
GATE_HWV_OVL1(CLK_OVL_MDP_RDMA1, "ovl_mdp_rdma1", "disp", 4),
GATE_HWV_OVL1(CLK_OVL_BWM0, "ovl_bwm0", "disp", 5),
GATE_HWV_OVL1(CLK_OVL_DLI0, "ovl_dli0", "disp", 6),
GATE_HWV_OVL1(CLK_OVL_DLI1, "ovl_dli1", "disp", 7),
GATE_HWV_OVL1(CLK_OVL_DLI2, "ovl_dli2", "disp", 8),
GATE_HWV_OVL1(CLK_OVL_DLI3, "ovl_dli3", "disp", 9),
GATE_HWV_OVL1(CLK_OVL_DLI4, "ovl_dli4", "disp", 10),
GATE_HWV_OVL1(CLK_OVL_DLI5, "ovl_dli5", "disp", 11),
GATE_HWV_OVL1(CLK_OVL_DLI6, "ovl_dli6", "disp", 12),
GATE_HWV_OVL1(CLK_OVL_DLI7, "ovl_dli7", "disp", 13),
GATE_HWV_OVL1(CLK_OVL_DLI8, "ovl_dli8", "disp", 14),
GATE_HWV_OVL1(CLK_OVL_DLO0, "ovl_dlo0", "disp", 15),
GATE_HWV_OVL1(CLK_OVL_DLO1, "ovl_dlo1", "disp", 16),
GATE_HWV_OVL1(CLK_OVL_DLO2, "ovl_dlo2", "disp", 17),
GATE_HWV_OVL1(CLK_OVL_DLO3, "ovl_dlo3", "disp", 18),
GATE_HWV_OVL1(CLK_OVL_DLO4, "ovl_dlo4", "disp", 19),
GATE_HWV_OVL1(CLK_OVL_DLO5, "ovl_dlo5", "disp", 20),
GATE_HWV_OVL1(CLK_OVL_DLO6, "ovl_dlo6", "disp", 21),
GATE_HWV_OVL1(CLK_OVL_DLO7, "ovl_dlo7", "disp", 22),
GATE_HWV_OVL1(CLK_OVL_DLO8, "ovl_dlo8", "disp", 23),
GATE_HWV_OVL1(CLK_OVL_DLO9, "ovl_dlo9", "disp", 24),
GATE_HWV_OVL1(CLK_OVL_DLO10, "ovl_dlo10", "disp", 25),
GATE_HWV_OVL1(CLK_OVL_DLO11, "ovl_dlo11", "disp", 26),
GATE_HWV_OVL1(CLK_OVL_DLO12, "ovl_dlo12", "disp", 27),
GATE_HWV_OVL1(CLK_OVLSYS_RELAY0, "ovlsys_relay0", "disp", 28),
GATE_HWV_OVL1(CLK_OVL_INLINEROT0, "ovl_inlinerot0", "disp", 29),
GATE_HWV_OVL1(CLK_OVL_SMI, "ovl_smi", "disp", 30),
};
static const struct mtk_clk_desc ovl_mcd = {
.clks = ovl_clks,
.num_clks = ARRAY_SIZE(ovl_clks),
};
static const struct platform_device_id clk_mt8196_ovl0_id_table[] = {
{ .name = "clk-mt8196-ovl0", .driver_data = (kernel_ulong_t)&ovl_mcd },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, clk_mt8196_ovl0_id_table);
static struct platform_driver clk_mt8196_ovl0_drv = {
.probe = mtk_clk_pdev_probe,
.remove = mtk_clk_pdev_remove,
.driver = {
.name = "clk-mt8196-ovl0",
},
.id_table = clk_mt8196_ovl0_id_table,
};
module_platform_driver(clk_mt8196_ovl0_drv);
MODULE_DESCRIPTION("MediaTek MT8196 ovl0 clocks driver");
MODULE_LICENSE("GPL");
Loaded 20 of 44 files, more files were not shown because too many files have changed in this diff. Show more