From: Tomasz Figa <t.figa@xxxxxxxxxxx> Add clock controller for CMU ISP clock domain on Exynos3250, providing clocks for FIMC-IS subsystem. [b.michalska: initial setup of ISP block source clocks (setting root oscillator clock as the input); use samsung_cmu_register_one to register the provider; updated DT binding documentation] Signed-off-by: Tomasz Figa <t.figa@xxxxxxxxxxx> Signed-off-by: Sylwester Nawrocki <s.nawrocki@xxxxxxxxxxx> Signed-off-by: Chanwoo Choi <cw00.choi@xxxxxxxxxxx> Signed-off-by: Beata Michalska <b.michalska@xxxxxxxxxxx> Acked-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx> --- .../devicetree/bindings/clock/exynos3250-clock.txt | 8 + drivers/clk/samsung/clk-exynos3250.c | 189 ++++++++++++++++++++ include/dt-bindings/clock/exynos3250.h | 61 +++++++ 3 files changed, 258 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/exynos3250-clock.txt b/Documentation/devicetree/bindings/clock/exynos3250-clock.txt index f57d9dd..f1738b8 100644 --- a/Documentation/devicetree/bindings/clock/exynos3250-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos3250-clock.txt @@ -9,6 +9,8 @@ Required Properties: - "samsung,exynos3250-cmu" - controller compatible with Exynos3250 SoC. - "samsung,exynos3250-cmu-dmc" - controller compatible with Exynos3250 SoC for Dynamic Memory Controller domain. + - "samsung,exynos3250-cmu-isp" - ISP block clock controller compatible + with Exynos3250 SOC - reg: physical base address of the controller and length of memory mapped region. @@ -36,6 +38,12 @@ Example 1: Examples of clock controller nodes are listed below. #clock-cells = <1>; }; + cmu_isp: clock-controller@10048000 { + compatible = "samsung,exynos3250-cmu-isp"; + reg = <0x10048000 0x1000>; + #clock-cells = <1>; + }; + Example 2: UART controller node that consumes the clock generated by the clock controller. Refer to the standard clock bindings for information about 'clocks' and 'clock-names' property. diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c index 6e6cca3..36dceb6 100644 --- a/drivers/clk/samsung/clk-exynos3250.c +++ b/drivers/clk/samsung/clk-exynos3250.c @@ -814,9 +814,16 @@ static void __init exynos3_core_down_clock(void) __raw_writel(0x0, reg_base + PWR_CTRL2); } +static inline struct clk *__samsung_clk_get(struct samsung_clk_provider *ctx, + unsigned int idx) +{ + return ctx->clk_data.clks[idx]; +} + static void __init exynos3250_cmu_init(struct device_node *np) { struct samsung_clk_provider *ctx; + struct clk* clk_mux, *clk_parent; reg_base = of_iomap(np, 0); if (!reg_base) @@ -841,6 +848,27 @@ static void __init exynos3250_cmu_init(struct device_node *np) samsung_clk_register_div(ctx, div_clks, ARRAY_SIZE(div_clks)); samsung_clk_register_gate(ctx, gate_clks, ARRAY_SIZE(gate_clks)); + /** + * Both mux clocks: mout_aclk_400_mcuisp_sub and mout_aclk_266_sub + * drive the source clocks for ISP block (MCUISP and ISP respectively). + * Switch both muxes to root oscillator clock to secure + * proper power down of ISP power domain case it's state + * transitions remain unhandled (by a relevant device driver). + * This will also reduce the risk of accessing the ISP CMU registers + * while the ISP power domain remains turned off. + * Note: This still requires some real solutions (involving + * the ISP CMU) + */ + clk_parent = __samsung_clk_get(ctx, CLK_FIN_PLL); + if (!IS_ERR(clk_parent)) { + clk_mux = __samsung_clk_get(ctx, CLK_MOUT_ACLK_400_MCUISP_SUB); + if (!IS_ERR(clk_mux)) + clk_set_parent(clk_mux, clk_parent); + clk_mux = __samsung_clk_get(ctx, CLK_MOUT_ACLK_266_SUB); + if (!IS_ERR(clk_mux)) + clk_set_parent(clk_mux, clk_parent); + } + exynos3_core_down_clock(); exynos3250_clk_sleep_init(); @@ -1017,3 +1045,164 @@ static void __init exynos3250_cmu_dmc_init(struct device_node *np) } CLK_OF_DECLARE(exynos3250_cmu_dmc, "samsung,exynos3250-cmu-dmc", exynos3250_cmu_dmc_init); + +/* + * CMU ISP + */ + +#define DIV_ISP0 0x300 +#define DIV_ISP1 0x304 +#define GATE_IP_ISP0 0x800 +#define GATE_IP_ISP1 0x804 +#define GATE_SCLK_ISP 0x900 + +static struct samsung_div_clock isp_div_clks[] __initdata = { + /* + * NOTE: Following table is sorted by register address in ascending + * order and then bitfield shift in descending order, as it is done + * in the User's Manual. When adding new entries, please make sure + * that the order is preserved, to avoid merge conflicts and make + * further work with defined data easier. + */ + /* DIV_ISP0 */ + DIV(CLK_DIV_ISP1, "div_isp1", "mout_aclk_266_sub", DIV_ISP0, 4, 3), + DIV(CLK_DIV_ISP0, "div_isp0", "mout_aclk_266_sub", DIV_ISP0, 0, 3), + + /* DIV_ISP1 */ + DIV(CLK_DIV_MCUISP1, "div_mcuisp1", "mout_aclk_400_mcuisp_sub", + DIV_ISP1, 8, 3), + DIV(CLK_DIV_MCUISP0, "div_mcuisp0", "mout_aclk_400_mcuisp_sub", + DIV_ISP1, 4, 3), + DIV(CLK_DIV_MPWM, "div_mpwm", "div_isp1", DIV_ISP1, 0, 3), +}; + +static struct samsung_gate_clock isp_gate_clks[] __initdata = { + /* + * NOTE: Following table is sorted by register address in ascending + * order and then bitfield shift in descending order, as it is done + * in the User's Manual. When adding new entries, please make sure + * that the order is preserved, to avoid merge conflicts and make + * further work with defined data easier. + */ + + /* GATE_IP_ISP0 */ + GATE(CLK_UART_ISP, "uart_isp", "uart_isp_top", + GATE_IP_ISP0, 31, CLK_IGNORE_UNUSED, 0), + GATE(CLK_WDT_ISP, "wdt_isp", "mout_aclk_266_sub", + GATE_IP_ISP0, 30, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PWM_ISP, "pwm_isp", "mout_aclk_266_sub", + GATE_IP_ISP0, 28, CLK_IGNORE_UNUSED, 0), + GATE(CLK_I2C1_ISP, "i2c1_isp", "mout_aclk_266_sub", + GATE_IP_ISP0, 26, CLK_IGNORE_UNUSED, 0), + GATE(CLK_I2C0_ISP, "i2c0_isp", "mout_aclk_266_sub", + GATE_IP_ISP0, 25, CLK_IGNORE_UNUSED, 0), + GATE(CLK_MPWM_ISP, "mpwm_isp", "mout_aclk_266_sub", + GATE_IP_ISP0, 24, CLK_IGNORE_UNUSED, 0), + GATE(CLK_MCUCTL_ISP, "mcuctl_isp", "mout_aclk_266_sub", + GATE_IP_ISP0, 23, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PPMUISPX, "ppmuispx", "mout_aclk_266_sub", + GATE_IP_ISP0, 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PPMUISPMX, "ppmuispmx", "mout_aclk_266_sub", + GATE_IP_ISP0, 20, CLK_IGNORE_UNUSED, 0), + GATE(CLK_QE_LITE1, "qe_lite1", "mout_aclk_266_sub", + GATE_IP_ISP0, 18, CLK_IGNORE_UNUSED, 0), + GATE(CLK_QE_LITE0, "qe_lite0", "mout_aclk_266_sub", + GATE_IP_ISP0, 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_QE_FD, "qe_fd", "mout_aclk_266_sub", + GATE_IP_ISP0, 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_QE_DRC, "qe_drc", "mout_aclk_266_sub", + GATE_IP_ISP0, 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_QE_ISP, "qe_isp", "mout_aclk_266_sub", + GATE_IP_ISP0, 14, CLK_IGNORE_UNUSED, 0), + GATE(CLK_CSIS1, "csis1", "mout_aclk_266_sub", + GATE_IP_ISP0, 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SMMU_LITE1, "smmu_lite1", "mout_aclk_266_sub", + GATE_IP_ISP0, 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SMMU_LITE0, "smmu_lite0", "mout_aclk_266_sub", + GATE_IP_ISP0, 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SMMU_FD, "smmu_fd", "mout_aclk_266_sub", + GATE_IP_ISP0, 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SMMU_DRC, "smmu_drc", "mout_aclk_266_sub", + GATE_IP_ISP0, 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SMMU_ISP, "smmu_isp", "mout_aclk_266_sub", + GATE_IP_ISP0, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GICISP, "gicisp", "mout_aclk_266_sub", + GATE_IP_ISP0, 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_CSIS0, "csis0", "mout_aclk_266_sub", + GATE_IP_ISP0, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_MCUISP, "mcuisp", "mout_aclk_266_sub", + GATE_IP_ISP0, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_LITE1, "lite1", "mout_aclk_266_sub", + GATE_IP_ISP0, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_LITE0, "lite0", "mout_aclk_266_sub", + GATE_IP_ISP0, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_FD, "fd", "mout_aclk_266_sub", + GATE_IP_ISP0, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_DRC, "drc", "mout_aclk_266_sub", + GATE_IP_ISP0, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ISP, "isp", "mout_aclk_266_sub", + GATE_IP_ISP0, 0, CLK_IGNORE_UNUSED, 0), + + /* GATE_IP_ISP1 */ + GATE(CLK_QE_ISPCX, "qe_ispcx", "uart_isp_top", + GATE_IP_ISP0, 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_QE_SCALERP, "qe_scalerp", "uart_isp_top", + GATE_IP_ISP0, 20, CLK_IGNORE_UNUSED, 0), + GATE(CLK_QE_SCALERC, "qe_scalerc", "uart_isp_top", + GATE_IP_ISP0, 19, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SMMU_SCALERP, "smmu_scalerp", "uart_isp_top", + GATE_IP_ISP0, 18, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SMMU_SCALERC, "smmu_scalerc", "uart_isp_top", + GATE_IP_ISP0, 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCALERP, "scalerp", "uart_isp_top", + GATE_IP_ISP0, 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCALERC, "scalerc", "uart_isp_top", + GATE_IP_ISP0, 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SPI1_ISP, "spi1_isp", "uart_isp_top", + GATE_IP_ISP0, 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SPI0_ISP, "spi0_isp", "uart_isp_top", + GATE_IP_ISP0, 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SMMU_ISPCX, "smmu_ispcx", "uart_isp_top", + GATE_IP_ISP0, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ASYNCAXIM, "asyncaxim", "uart_isp_top", + GATE_IP_ISP0, 0, CLK_IGNORE_UNUSED, 0), + + /* GATE_SCLK_ISP */ + GATE(CLK_SCLK_MPWM_ISP, "sclk_mpwm_isp", "div_mpwm", + GATE_SCLK_ISP, 0, CLK_IGNORE_UNUSED, 0), +}; + +static struct samsung_cmu_info isp_cmu_info __initdata = { + .div_clks = isp_div_clks, + .nr_div_clks = ARRAY_SIZE(isp_div_clks), + .gate_clks = isp_gate_clks, + .nr_gate_clks = ARRAY_SIZE(isp_gate_clks), + .nr_clk_ids = NR_CLKS_ISP, +}; + +static int __init exynos3250_cmu_isp_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + + samsung_cmu_register_one(np, &isp_cmu_info); + return 0; +} + +static const struct of_device_id exynos3250_cmu_isp_of_match[] = { + { .compatible = "samsung,exynos3250-cmu-isp", }, + { /* sentinel */ } +}; + +static struct platform_driver exynos3250_cmu_isp_driver = { + .driver = { + .name = "exynos3250-cmu-isp", + .of_match_table = exynos3250_cmu_isp_of_match, + }, +}; + +static int exynos3250_cmu_platform_init(void) +{ + return platform_driver_probe(&exynos3250_cmu_isp_driver, + exynos3250_cmu_isp_probe); +} +subsys_initcall(exynos3250_cmu_platform_init); diff --git a/include/dt-bindings/clock/exynos3250.h b/include/dt-bindings/clock/exynos3250.h index 961b9c1..aab088d 100644 --- a/include/dt-bindings/clock/exynos3250.h +++ b/include/dt-bindings/clock/exynos3250.h @@ -282,4 +282,65 @@ */ #define NR_CLKS_DMC 21 +/* + * CMU ISP + */ + +/* Dividers */ + +#define CLK_DIV_ISP1 1 +#define CLK_DIV_ISP0 2 +#define CLK_DIV_MCUISP1 3 +#define CLK_DIV_MCUISP0 4 +#define CLK_DIV_MPWM 5 + +/* Gates */ + +#define CLK_UART_ISP 8 +#define CLK_WDT_ISP 9 +#define CLK_PWM_ISP 10 +#define CLK_I2C1_ISP 11 +#define CLK_I2C0_ISP 12 +#define CLK_MPWM_ISP 13 +#define CLK_MCUCTL_ISP 14 +#define CLK_PPMUISPX 15 +#define CLK_PPMUISPMX 16 +#define CLK_QE_LITE1 17 +#define CLK_QE_LITE0 18 +#define CLK_QE_FD 19 +#define CLK_QE_DRC 20 +#define CLK_QE_ISP 21 +#define CLK_CSIS1 22 +#define CLK_SMMU_LITE1 23 +#define CLK_SMMU_LITE0 24 +#define CLK_SMMU_FD 25 +#define CLK_SMMU_DRC 26 +#define CLK_SMMU_ISP 27 +#define CLK_GICISP 28 +#define CLK_CSIS0 29 +#define CLK_MCUISP 30 +#define CLK_LITE1 31 +#define CLK_LITE0 32 +#define CLK_FD 33 +#define CLK_DRC 34 +#define CLK_ISP 35 +#define CLK_QE_ISPCX 36 +#define CLK_QE_SCALERP 37 +#define CLK_QE_SCALERC 38 +#define CLK_SMMU_SCALERP 39 +#define CLK_SMMU_SCALERC 40 +#define CLK_SCALERP 41 +#define CLK_SCALERC 42 +#define CLK_SPI1_ISP 43 +#define CLK_SPI0_ISP 44 +#define CLK_SMMU_ISPCX 45 +#define CLK_ASYNCAXIM 46 +#define CLK_SCLK_MPWM_ISP 47 + +/* + * Total number of clocks of CMU_ISP. + * NOTE: Must be equal to last clock ID increased by one. + */ +#define NR_CLKS_ISP 48 + #endif /* _DT_BINDINGS_CLOCK_SAMSUNG_EXYNOS3250_CLOCK_H */ -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html