mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
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:
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>;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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 },
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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
Reference in new issue
Block a user