From 77d8f3068c63ee0983f0b5ba3207d3f7cce11be4 Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Wed, 29 Jul 2020 16:00:10 +0800 Subject: [PATCH 001/134] clk: imx: scu: add two cells binding support This patch implements the new two cells binding for SCU clocks. The usage is as follows: clocks = <&uart0_clk IMX_SC_R_UART_0 IMX_SC_PM_CLK_PER> Due to each SCU clock is associated with a power domain, without power on the domain, the SCU clock can't work. So we create platform devices for each domain clock respectively and manually attach the required domain before register the clock devices, then we can register clocks in the clock platform driver accordingly. Note because we do not have power domain info in device tree and the SCU resource ID is the same for power domain and clock, so we use resource ID to find power domains. Later, we will also use this clock platform driver to support suspend/resume and runtime pm. Cc: Stephen Boyd Cc: Shawn Guo Cc: Sascha Hauer Cc: Michael Turquette Signed-off-by: Dong Aisheng Reviewed-by: Stephen Boyd Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8qxp.c | 136 ++++++++++++++++------------- drivers/clk/imx/clk-scu.c | 156 +++++++++++++++++++++++++++++++++- drivers/clk/imx/clk-scu.h | 27 ++++-- 3 files changed, 252 insertions(+), 67 deletions(-) diff --git a/drivers/clk/imx/clk-imx8qxp.c b/drivers/clk/imx/clk-imx8qxp.c index d650ca33cdc8..5b3d4ede7c7c 100644 --- a/drivers/clk/imx/clk-imx8qxp.c +++ b/drivers/clk/imx/clk-imx8qxp.c @@ -22,9 +22,10 @@ static int imx8qxp_clk_probe(struct platform_device *pdev) struct device_node *ccm_node = pdev->dev.of_node; struct clk_hw_onecell_data *clk_data; struct clk_hw **clks; + u32 clk_cells; int ret, i; - ret = imx_clk_scu_init(); + ret = imx_clk_scu_init(ccm_node); if (ret) return ret; @@ -33,6 +34,9 @@ static int imx8qxp_clk_probe(struct platform_device *pdev) if (!clk_data) return -ENOMEM; + if (of_property_read_u32(ccm_node, "#clock-cells", &clk_cells)) + return -EINVAL; + clk_data->num = IMX_SCU_CLK_END; clks = clk_data->hws; @@ -55,78 +59,78 @@ static int imx8qxp_clk_probe(struct platform_device *pdev) clks[IMX_LSIO_BUS_CLK] = clk_hw_register_fixed_rate(NULL, "lsio_bus_clk_root", NULL, 0, 100000000); /* ARM core */ - clks[IMX_A35_CLK] = imx_clk_scu("a35_clk", IMX_SC_R_A35, IMX_SC_PM_CLK_CPU); + clks[IMX_A35_CLK] = imx_clk_scu("a35_clk", IMX_SC_R_A35, IMX_SC_PM_CLK_CPU, clk_cells); /* LSIO SS */ - clks[IMX_LSIO_PWM0_CLK] = imx_clk_scu("pwm0_clk", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_PWM1_CLK] = imx_clk_scu("pwm1_clk", IMX_SC_R_PWM_1, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_PWM2_CLK] = imx_clk_scu("pwm2_clk", IMX_SC_R_PWM_2, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_PWM3_CLK] = imx_clk_scu("pwm3_clk", IMX_SC_R_PWM_3, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_PWM4_CLK] = imx_clk_scu("pwm4_clk", IMX_SC_R_PWM_4, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_PWM5_CLK] = imx_clk_scu("pwm5_clk", IMX_SC_R_PWM_5, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_PWM6_CLK] = imx_clk_scu("pwm6_clk", IMX_SC_R_PWM_6, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_PWM7_CLK] = imx_clk_scu("pwm7_clk", IMX_SC_R_PWM_7, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_GPT0_CLK] = imx_clk_scu("gpt0_clk", IMX_SC_R_GPT_0, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_GPT1_CLK] = imx_clk_scu("gpt1_clk", IMX_SC_R_GPT_1, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_GPT2_CLK] = imx_clk_scu("gpt2_clk", IMX_SC_R_GPT_2, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_GPT3_CLK] = imx_clk_scu("gpt3_clk", IMX_SC_R_GPT_3, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_GPT4_CLK] = imx_clk_scu("gpt4_clk", IMX_SC_R_GPT_4, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_FSPI0_CLK] = imx_clk_scu("fspi0_clk", IMX_SC_R_FSPI_0, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_FSPI1_CLK] = imx_clk_scu("fspi1_clk", IMX_SC_R_FSPI_1, IMX_SC_PM_CLK_PER); + clks[IMX_LSIO_PWM0_CLK] = imx_clk_scu("pwm0_clk", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_LSIO_PWM1_CLK] = imx_clk_scu("pwm1_clk", IMX_SC_R_PWM_1, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_LSIO_PWM2_CLK] = imx_clk_scu("pwm2_clk", IMX_SC_R_PWM_2, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_LSIO_PWM3_CLK] = imx_clk_scu("pwm3_clk", IMX_SC_R_PWM_3, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_LSIO_PWM4_CLK] = imx_clk_scu("pwm4_clk", IMX_SC_R_PWM_4, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_LSIO_PWM5_CLK] = imx_clk_scu("pwm5_clk", IMX_SC_R_PWM_5, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_LSIO_PWM6_CLK] = imx_clk_scu("pwm6_clk", IMX_SC_R_PWM_6, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_LSIO_PWM7_CLK] = imx_clk_scu("pwm7_clk", IMX_SC_R_PWM_7, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_LSIO_GPT0_CLK] = imx_clk_scu("gpt0_clk", IMX_SC_R_GPT_0, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_LSIO_GPT1_CLK] = imx_clk_scu("gpt1_clk", IMX_SC_R_GPT_1, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_LSIO_GPT2_CLK] = imx_clk_scu("gpt2_clk", IMX_SC_R_GPT_2, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_LSIO_GPT3_CLK] = imx_clk_scu("gpt3_clk", IMX_SC_R_GPT_3, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_LSIO_GPT4_CLK] = imx_clk_scu("gpt4_clk", IMX_SC_R_GPT_4, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_LSIO_FSPI0_CLK] = imx_clk_scu("fspi0_clk", IMX_SC_R_FSPI_0, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_LSIO_FSPI1_CLK] = imx_clk_scu("fspi1_clk", IMX_SC_R_FSPI_1, IMX_SC_PM_CLK_PER, clk_cells); /* ADMA SS */ - clks[IMX_ADMA_UART0_CLK] = imx_clk_scu("uart0_clk", IMX_SC_R_UART_0, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_UART1_CLK] = imx_clk_scu("uart1_clk", IMX_SC_R_UART_1, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_UART2_CLK] = imx_clk_scu("uart2_clk", IMX_SC_R_UART_2, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_UART3_CLK] = imx_clk_scu("uart3_clk", IMX_SC_R_UART_3, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_SPI0_CLK] = imx_clk_scu("spi0_clk", IMX_SC_R_SPI_0, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_SPI1_CLK] = imx_clk_scu("spi1_clk", IMX_SC_R_SPI_1, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_SPI2_CLK] = imx_clk_scu("spi2_clk", IMX_SC_R_SPI_2, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_SPI3_CLK] = imx_clk_scu("spi3_clk", IMX_SC_R_SPI_3, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_CAN0_CLK] = imx_clk_scu("can0_clk", IMX_SC_R_CAN_0, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_I2C0_CLK] = imx_clk_scu("i2c0_clk", IMX_SC_R_I2C_0, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_I2C1_CLK] = imx_clk_scu("i2c1_clk", IMX_SC_R_I2C_1, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_I2C2_CLK] = imx_clk_scu("i2c2_clk", IMX_SC_R_I2C_2, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_I2C3_CLK] = imx_clk_scu("i2c3_clk", IMX_SC_R_I2C_3, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_FTM0_CLK] = imx_clk_scu("ftm0_clk", IMX_SC_R_FTM_0, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_FTM1_CLK] = imx_clk_scu("ftm1_clk", IMX_SC_R_FTM_1, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_ADC0_CLK] = imx_clk_scu("adc0_clk", IMX_SC_R_ADC_0, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_PWM_CLK] = imx_clk_scu("pwm_clk", IMX_SC_R_LCD_0_PWM_0, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_LCD_CLK] = imx_clk_scu("lcd_clk", IMX_SC_R_LCD_0, IMX_SC_PM_CLK_PER); + clks[IMX_ADMA_UART0_CLK] = imx_clk_scu("uart0_clk", IMX_SC_R_UART_0, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_ADMA_UART1_CLK] = imx_clk_scu("uart1_clk", IMX_SC_R_UART_1, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_ADMA_UART2_CLK] = imx_clk_scu("uart2_clk", IMX_SC_R_UART_2, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_ADMA_UART3_CLK] = imx_clk_scu("uart3_clk", IMX_SC_R_UART_3, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_ADMA_SPI0_CLK] = imx_clk_scu("spi0_clk", IMX_SC_R_SPI_0, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_ADMA_SPI1_CLK] = imx_clk_scu("spi1_clk", IMX_SC_R_SPI_1, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_ADMA_SPI2_CLK] = imx_clk_scu("spi2_clk", IMX_SC_R_SPI_2, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_ADMA_SPI3_CLK] = imx_clk_scu("spi3_clk", IMX_SC_R_SPI_3, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_ADMA_CAN0_CLK] = imx_clk_scu("can0_clk", IMX_SC_R_CAN_0, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_ADMA_I2C0_CLK] = imx_clk_scu("i2c0_clk", IMX_SC_R_I2C_0, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_ADMA_I2C1_CLK] = imx_clk_scu("i2c1_clk", IMX_SC_R_I2C_1, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_ADMA_I2C2_CLK] = imx_clk_scu("i2c2_clk", IMX_SC_R_I2C_2, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_ADMA_I2C3_CLK] = imx_clk_scu("i2c3_clk", IMX_SC_R_I2C_3, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_ADMA_FTM0_CLK] = imx_clk_scu("ftm0_clk", IMX_SC_R_FTM_0, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_ADMA_FTM1_CLK] = imx_clk_scu("ftm1_clk", IMX_SC_R_FTM_1, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_ADMA_ADC0_CLK] = imx_clk_scu("adc0_clk", IMX_SC_R_ADC_0, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_ADMA_PWM_CLK] = imx_clk_scu("pwm_clk", IMX_SC_R_LCD_0_PWM_0, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_ADMA_LCD_CLK] = imx_clk_scu("lcd_clk", IMX_SC_R_LCD_0, IMX_SC_PM_CLK_PER, clk_cells); /* Connectivity */ - clks[IMX_CONN_SDHC0_CLK] = imx_clk_scu("sdhc0_clk", IMX_SC_R_SDHC_0, IMX_SC_PM_CLK_PER); - clks[IMX_CONN_SDHC1_CLK] = imx_clk_scu("sdhc1_clk", IMX_SC_R_SDHC_1, IMX_SC_PM_CLK_PER); - clks[IMX_CONN_SDHC2_CLK] = imx_clk_scu("sdhc2_clk", IMX_SC_R_SDHC_2, IMX_SC_PM_CLK_PER); - clks[IMX_CONN_ENET0_ROOT_CLK] = imx_clk_scu("enet0_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_PER); - clks[IMX_CONN_ENET0_BYPASS_CLK] = imx_clk_scu("enet0_bypass_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_BYPASS); - clks[IMX_CONN_ENET0_RGMII_CLK] = imx_clk_scu("enet0_rgmii_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_MISC0); - clks[IMX_CONN_ENET1_ROOT_CLK] = imx_clk_scu("enet1_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_PER); - clks[IMX_CONN_ENET1_BYPASS_CLK] = imx_clk_scu("enet1_bypass_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_BYPASS); - clks[IMX_CONN_ENET1_RGMII_CLK] = imx_clk_scu("enet1_rgmii_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_MISC0); - clks[IMX_CONN_GPMI_BCH_IO_CLK] = imx_clk_scu("gpmi_io_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_MST_BUS); - clks[IMX_CONN_GPMI_BCH_CLK] = imx_clk_scu("gpmi_bch_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_PER); - clks[IMX_CONN_USB2_ACLK] = imx_clk_scu("usb3_aclk_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_PER); - clks[IMX_CONN_USB2_BUS_CLK] = imx_clk_scu("usb3_bus_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MST_BUS); - clks[IMX_CONN_USB2_LPM_CLK] = imx_clk_scu("usb3_lpm_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MISC); + clks[IMX_CONN_SDHC0_CLK] = imx_clk_scu("sdhc0_clk", IMX_SC_R_SDHC_0, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_CONN_SDHC1_CLK] = imx_clk_scu("sdhc1_clk", IMX_SC_R_SDHC_1, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_CONN_SDHC2_CLK] = imx_clk_scu("sdhc2_clk", IMX_SC_R_SDHC_2, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_CONN_ENET0_ROOT_CLK] = imx_clk_scu("enet0_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_CONN_ENET0_BYPASS_CLK] = imx_clk_scu("enet0_bypass_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_BYPASS, clk_cells); + clks[IMX_CONN_ENET0_RGMII_CLK] = imx_clk_scu("enet0_rgmii_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_MISC0, clk_cells); + clks[IMX_CONN_ENET1_ROOT_CLK] = imx_clk_scu("enet1_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_CONN_ENET1_BYPASS_CLK] = imx_clk_scu("enet1_bypass_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_BYPASS, clk_cells); + clks[IMX_CONN_ENET1_RGMII_CLK] = imx_clk_scu("enet1_rgmii_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_MISC0, clk_cells); + clks[IMX_CONN_GPMI_BCH_IO_CLK] = imx_clk_scu("gpmi_io_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_MST_BUS, clk_cells); + clks[IMX_CONN_GPMI_BCH_CLK] = imx_clk_scu("gpmi_bch_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_CONN_USB2_ACLK] = imx_clk_scu("usb3_aclk_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_CONN_USB2_BUS_CLK] = imx_clk_scu("usb3_bus_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MST_BUS, clk_cells); + clks[IMX_CONN_USB2_LPM_CLK] = imx_clk_scu("usb3_lpm_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MISC, clk_cells); /* Display controller SS */ - clks[IMX_DC0_DISP0_CLK] = imx_clk_scu("dc0_disp0_clk", IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC0); - clks[IMX_DC0_DISP1_CLK] = imx_clk_scu("dc0_disp1_clk", IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC1); + clks[IMX_DC0_DISP0_CLK] = imx_clk_scu("dc0_disp0_clk", IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC0, clk_cells); + clks[IMX_DC0_DISP1_CLK] = imx_clk_scu("dc0_disp1_clk", IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC1, clk_cells); /* MIPI-LVDS SS */ - clks[IMX_MIPI0_I2C0_CLK] = imx_clk_scu("mipi0_i2c0_clk", IMX_SC_R_MIPI_0_I2C_0, IMX_SC_PM_CLK_MISC2); - clks[IMX_MIPI0_I2C1_CLK] = imx_clk_scu("mipi0_i2c1_clk", IMX_SC_R_MIPI_0_I2C_1, IMX_SC_PM_CLK_MISC2); + clks[IMX_MIPI0_I2C0_CLK] = imx_clk_scu("mipi0_i2c0_clk", IMX_SC_R_MIPI_0_I2C_0, IMX_SC_PM_CLK_MISC2, clk_cells); + clks[IMX_MIPI0_I2C1_CLK] = imx_clk_scu("mipi0_i2c1_clk", IMX_SC_R_MIPI_0_I2C_1, IMX_SC_PM_CLK_MISC2, clk_cells); /* MIPI CSI SS */ - clks[IMX_CSI0_CORE_CLK] = imx_clk_scu("mipi_csi0_core_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_PER); - clks[IMX_CSI0_ESC_CLK] = imx_clk_scu("mipi_csi0_esc_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_MISC); - clks[IMX_CSI0_I2C0_CLK] = imx_clk_scu("mipi_csi0_i2c0_clk", IMX_SC_R_CSI_0_I2C_0, IMX_SC_PM_CLK_PER); - clks[IMX_CSI0_PWM0_CLK] = imx_clk_scu("mipi_csi0_pwm0_clk", IMX_SC_R_CSI_0_PWM_0, IMX_SC_PM_CLK_PER); + clks[IMX_CSI0_CORE_CLK] = imx_clk_scu("mipi_csi0_core_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_CSI0_ESC_CLK] = imx_clk_scu("mipi_csi0_esc_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_MISC, clk_cells); + clks[IMX_CSI0_I2C0_CLK] = imx_clk_scu("mipi_csi0_i2c0_clk", IMX_SC_R_CSI_0_I2C_0, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_CSI0_PWM0_CLK] = imx_clk_scu("mipi_csi0_pwm0_clk", IMX_SC_R_CSI_0_PWM_0, IMX_SC_PM_CLK_PER, clk_cells); /* GPU SS */ - clks[IMX_GPU0_CORE_CLK] = imx_clk_scu("gpu_core0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_PER); - clks[IMX_GPU0_SHADER_CLK] = imx_clk_scu("gpu_shader0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_MISC); + clks[IMX_GPU0_CORE_CLK] = imx_clk_scu("gpu_core0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_PER, clk_cells); + clks[IMX_GPU0_SHADER_CLK] = imx_clk_scu("gpu_shader0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_MISC, clk_cells); for (i = 0; i < clk_data->num; i++) { if (IS_ERR(clks[i])) @@ -134,7 +138,19 @@ static int imx8qxp_clk_probe(struct platform_device *pdev) i, PTR_ERR(clks[i])); } - return of_clk_add_hw_provider(ccm_node, of_clk_hw_onecell_get, clk_data); + if (clk_cells == 2) { + ret = of_clk_add_hw_provider(ccm_node, imx_scu_of_clk_src_get, imx_scu_clks); + if (ret) + imx_clk_scu_unregister(); + } else { + /* + * legacy binding code path doesn't unregister here because + * it will be removed later. + */ + ret = of_clk_add_hw_provider(ccm_node, of_clk_hw_onecell_get, clk_data); + } + + return ret; } static const struct of_device_id imx8qxp_match[] = { diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c index b8b2072742a5..e5837e7caa50 100644 --- a/drivers/clk/imx/clk-scu.c +++ b/drivers/clk/imx/clk-scu.c @@ -8,6 +8,9 @@ #include #include #include +#include +#include +#include #include #include "clk-scu.h" @@ -16,6 +19,20 @@ #define IMX_SIP_SET_CPUFREQ 0x00 static struct imx_sc_ipc *ccm_ipc_handle; +struct device_node *pd_np; + +struct imx_scu_clk_node { + const char *name; + u32 rsrc; + u8 clk_type; + const char * const *parents; + int num_parents; + + struct clk_hw *hw; + struct list_head node; +}; + +struct list_head imx_scu_clks[IMX_SC_R_LAST]; /* * struct clk_scu - Description of one SCU clock @@ -128,9 +145,35 @@ static inline struct clk_scu *to_clk_scu(struct clk_hw *hw) return container_of(hw, struct clk_scu, hw); } -int imx_clk_scu_init(void) +int imx_clk_scu_init(struct device_node *np) { - return imx_scu_get_handle(&ccm_ipc_handle); + struct platform_device *pd_dev; + u32 clk_cells; + int ret, i; + + ret = imx_scu_get_handle(&ccm_ipc_handle); + if (ret) + return ret; + + of_property_read_u32(np, "#clock-cells", &clk_cells); + + if (clk_cells == 2) { + for (i = 0; i < IMX_SC_R_LAST; i++) + INIT_LIST_HEAD(&imx_scu_clks[i]); + /* + * Note: SCU clock driver depends on SCU power domain to be ready + * first. As there're no power domains under scu clock node in dts, + * we can't use PROBE_DEFER automatically. + */ + pd_np = of_find_compatible_node(NULL, NULL, "fsl,scu-pd"); + pd_dev = of_find_device_by_node(pd_np); + if (!pd_dev || !device_is_bound(&pd_dev->dev)) { + of_node_put(pd_np); + return -EPROBE_DEFER; + } + } + + return 0; } /* @@ -387,3 +430,112 @@ struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents, return hw; } + +struct clk_hw *imx_scu_of_clk_src_get(struct of_phandle_args *clkspec, + void *data) +{ + unsigned int rsrc = clkspec->args[0]; + unsigned int idx = clkspec->args[1]; + struct list_head *scu_clks = data; + struct imx_scu_clk_node *clk; + + list_for_each_entry(clk, &scu_clks[rsrc], node) { + if (clk->clk_type == idx) + return clk->hw; + } + + return ERR_PTR(-ENODEV); +} + +static int imx_clk_scu_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct imx_scu_clk_node *clk = dev_get_platdata(dev); + struct clk_hw *hw; + + hw = __imx_clk_scu(clk->name, clk->parents, clk->num_parents, + clk->rsrc, clk->clk_type); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + clk->hw = hw; + list_add_tail(&clk->node, &imx_scu_clks[clk->rsrc]); + + dev_dbg(dev, "register SCU clock rsrc:%d type:%d\n", clk->rsrc, + clk->clk_type); + + return 0; +} + +static struct platform_driver imx_clk_scu_driver = { + .driver = { + .name = "imx-scu-clk", + .suppress_bind_attrs = true, + }, + .probe = imx_clk_scu_probe, +}; +builtin_platform_driver(imx_clk_scu_driver); + +static int imx_clk_scu_attach_pd(struct device *dev, u32 rsrc_id) +{ + struct of_phandle_args genpdspec = { + .np = pd_np, + .args_count = 1, + .args[0] = rsrc_id, + }; + + return of_genpd_add_device(&genpdspec, dev); +} + +struct clk_hw *imx_clk_scu_alloc_dev(const char *name, + const char * const *parents, + int num_parents, u32 rsrc_id, u8 clk_type) +{ + struct imx_scu_clk_node clk = { + .name = name, + .rsrc = rsrc_id, + .clk_type = clk_type, + .parents = parents, + .num_parents = num_parents, + }; + struct platform_device *pdev; + int ret; + + pdev = platform_device_alloc(name, PLATFORM_DEVID_NONE); + if (!pdev) { + pr_err("%s: failed to allocate scu clk dev rsrc %d type %d\n", + name, rsrc_id, clk_type); + return ERR_PTR(-ENOMEM); + } + + ret = platform_device_add_data(pdev, &clk, sizeof(clk)); + if (ret) { + platform_device_put(pdev); + return ERR_PTR(ret); + } + + pdev->driver_override = "imx-scu-clk"; + + ret = imx_clk_scu_attach_pd(&pdev->dev, rsrc_id); + if (ret) + pr_warn("%s: failed to attached the power domain %d\n", + name, ret); + + platform_device_add(pdev); + + /* For API backwards compatiblilty, simply return NULL for success */ + return NULL; +} + +void imx_clk_scu_unregister(void) +{ + struct imx_scu_clk_node *clk; + int i; + + for (i = 0; i < IMX_SC_R_LAST; i++) { + list_for_each_entry(clk, &imx_scu_clks[i], node) { + clk_hw_unregister(clk->hw); + kfree(clk); + } + } +} diff --git a/drivers/clk/imx/clk-scu.h b/drivers/clk/imx/clk-scu.h index 2bcfaf06a458..f7480898ea74 100644 --- a/drivers/clk/imx/clk-scu.h +++ b/drivers/clk/imx/clk-scu.h @@ -8,22 +8,39 @@ #define __IMX_CLK_SCU_H #include +#include -int imx_clk_scu_init(void); +extern struct list_head imx_scu_clks[]; + +int imx_clk_scu_init(struct device_node *np); +struct clk_hw *imx_scu_of_clk_src_get(struct of_phandle_args *clkspec, + void *data); +struct clk_hw *imx_clk_scu_alloc_dev(const char *name, + const char * const *parents, + int num_parents, u32 rsrc_id, u8 clk_type); struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents, int num_parents, u32 rsrc_id, u8 clk_type); +void imx_clk_scu_unregister(void); + static inline struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id, - u8 clk_type) + u8 clk_type, u8 clk_cells) { - return __imx_clk_scu(name, NULL, 0, rsrc_id, clk_type); + if (clk_cells == 2) + return imx_clk_scu_alloc_dev(name, NULL, 0, rsrc_id, clk_type); + else + return __imx_clk_scu(name, NULL, 0, rsrc_id, clk_type); } static inline struct clk_hw *imx_clk_scu2(const char *name, const char * const *parents, - int num_parents, u32 rsrc_id, u8 clk_type) + int num_parents, u32 rsrc_id, u8 clk_type, + u8 clk_cells) { - return __imx_clk_scu(name, parents, num_parents, rsrc_id, clk_type); + if (clk_cells == 2) + return imx_clk_scu_alloc_dev(name, parents, num_parents, rsrc_id, clk_type); + else + return __imx_clk_scu(name, parents, num_parents, rsrc_id, clk_type); } struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name, From 0d5f1f4731b52e294f25de193978d8b181b55faa Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Wed, 29 Jul 2020 16:00:11 +0800 Subject: [PATCH 002/134] clk: imx: scu: bypass cpu power domains Bypass cpu power domains which are owned by ATF. Reviewed-by: Stephen Boyd Signed-off-by: Dong Aisheng Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-scu.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c index e5837e7caa50..dae2529bf64e 100644 --- a/drivers/clk/imx/clk-scu.c +++ b/drivers/clk/imx/clk-scu.c @@ -484,6 +484,10 @@ static int imx_clk_scu_attach_pd(struct device *dev, u32 rsrc_id) .args[0] = rsrc_id, }; + if (rsrc_id == IMX_SC_R_A35 || rsrc_id == IMX_SC_R_A53 || + rsrc_id == IMX_SC_R_A72) + return 0; + return of_genpd_add_device(&genpdspec, dev); } From 2f1a2c1d00bc9417f5faa54777a23a52f054e9cf Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Wed, 29 Jul 2020 16:00:12 +0800 Subject: [PATCH 003/134] clk: imx: scu: allow scu clk to take device pointer Used to support runtime pm. Cc: Shawn Guo Cc: Sascha Hauer Cc: Michael Turquette Reviewed-by: Stephen Boyd Signed-off-by: Dong Aisheng Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-scu.c | 9 +++++---- drivers/clk/imx/clk-scu.h | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c index dae2529bf64e..a67cca0a32ad 100644 --- a/drivers/clk/imx/clk-scu.c +++ b/drivers/clk/imx/clk-scu.c @@ -387,8 +387,9 @@ static const struct clk_ops clk_scu_cpu_ops = { .unprepare = clk_scu_unprepare, }; -struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents, - int num_parents, u32 rsrc_id, u8 clk_type) +struct clk_hw *__imx_clk_scu(struct device *dev, const char *name, + const char * const *parents, int num_parents, + u32 rsrc_id, u8 clk_type) { struct clk_init_data init; struct clk_scu *clk; @@ -422,7 +423,7 @@ struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents, clk->hw.init = &init; hw = &clk->hw; - ret = clk_hw_register(NULL, hw); + ret = clk_hw_register(dev, hw); if (ret) { kfree(clk); hw = ERR_PTR(ret); @@ -453,7 +454,7 @@ static int imx_clk_scu_probe(struct platform_device *pdev) struct imx_scu_clk_node *clk = dev_get_platdata(dev); struct clk_hw *hw; - hw = __imx_clk_scu(clk->name, clk->parents, clk->num_parents, + hw = __imx_clk_scu(NULL, clk->name, clk->parents, clk->num_parents, clk->rsrc, clk->clk_type); if (IS_ERR(hw)) return PTR_ERR(hw); diff --git a/drivers/clk/imx/clk-scu.h b/drivers/clk/imx/clk-scu.h index f7480898ea74..22976d64a96a 100644 --- a/drivers/clk/imx/clk-scu.h +++ b/drivers/clk/imx/clk-scu.h @@ -19,8 +19,9 @@ struct clk_hw *imx_clk_scu_alloc_dev(const char *name, const char * const *parents, int num_parents, u32 rsrc_id, u8 clk_type); -struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents, - int num_parents, u32 rsrc_id, u8 clk_type); +struct clk_hw *__imx_clk_scu(struct device *dev, const char *name, + const char * const *parents, int num_parents, + u32 rsrc_id, u8 clk_type); void imx_clk_scu_unregister(void); @@ -30,7 +31,7 @@ static inline struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id, if (clk_cells == 2) return imx_clk_scu_alloc_dev(name, NULL, 0, rsrc_id, clk_type); else - return __imx_clk_scu(name, NULL, 0, rsrc_id, clk_type); + return __imx_clk_scu(NULL, name, NULL, 0, rsrc_id, clk_type); } static inline struct clk_hw *imx_clk_scu2(const char *name, const char * const *parents, @@ -40,7 +41,7 @@ static inline struct clk_hw *imx_clk_scu2(const char *name, const char * const * if (clk_cells == 2) return imx_clk_scu_alloc_dev(name, parents, num_parents, rsrc_id, clk_type); else - return __imx_clk_scu(name, parents, num_parents, rsrc_id, clk_type); + return __imx_clk_scu(NULL, name, parents, num_parents, rsrc_id, clk_type); } struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name, From 78edeb080330ca2bc6c9b20d388c8ceb7a2ef8c0 Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Wed, 29 Jul 2020 16:00:13 +0800 Subject: [PATCH 004/134] clk: imx: scu: add runtime pm support Add runtime pm support Cc: Shawn Guo Cc: Sascha Hauer Cc: Michael Turquette Reviewed-by: Stephen Boyd Signed-off-by: Dong Aisheng Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-scu.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c index a67cca0a32ad..f5dc6731a217 100644 --- a/drivers/clk/imx/clk-scu.c +++ b/drivers/clk/imx/clk-scu.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "clk-scu.h" @@ -453,15 +454,32 @@ static int imx_clk_scu_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct imx_scu_clk_node *clk = dev_get_platdata(dev); struct clk_hw *hw; + int ret; - hw = __imx_clk_scu(NULL, clk->name, clk->parents, clk->num_parents, + pm_runtime_set_suspended(dev); + pm_runtime_set_autosuspend_delay(dev, 50); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(dev); + + ret = pm_runtime_get_sync(dev); + if (ret) { + pm_runtime_disable(dev); + return ret; + } + + hw = __imx_clk_scu(dev, clk->name, clk->parents, clk->num_parents, clk->rsrc, clk->clk_type); - if (IS_ERR(hw)) + if (IS_ERR(hw)) { + pm_runtime_disable(dev); return PTR_ERR(hw); + } clk->hw = hw; list_add_tail(&clk->node, &imx_scu_clks[clk->rsrc]); + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); + dev_dbg(dev, "register SCU clock rsrc:%d type:%d\n", clk->rsrc, clk->clk_type); From d0409631f466ae2e572a6a0ca684cced97fa1ade Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Wed, 29 Jul 2020 16:00:14 +0800 Subject: [PATCH 005/134] clk: imx: scu: add suspend/resume support Clock state will be lost when its power domain is completely off during system suspend/resume. So we save and restore the state accordingly in suspend/resume callback. Cc: Shawn Guo Cc: Sascha Hauer Cc: Michael Turquette Reviewed-by: Stephen Boyd Signed-off-by: Dong Aisheng Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-scu.c | 49 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c index f5dc6731a217..229a290ca5b6 100644 --- a/drivers/clk/imx/clk-scu.c +++ b/drivers/clk/imx/clk-scu.c @@ -45,6 +45,10 @@ struct clk_scu { struct clk_hw hw; u16 rsrc_id; u8 clk_type; + + /* for state save&restore */ + bool is_enabled; + u32 rate; }; /* @@ -430,6 +434,9 @@ struct clk_hw *__imx_clk_scu(struct device *dev, const char *name, hw = ERR_PTR(ret); } + if (dev) + dev_set_drvdata(dev, clk); + return hw; } @@ -486,10 +493,52 @@ static int imx_clk_scu_probe(struct platform_device *pdev) return 0; } +static int __maybe_unused imx_clk_scu_suspend(struct device *dev) +{ + struct clk_scu *clk = dev_get_drvdata(dev); + + clk->rate = clk_hw_get_rate(&clk->hw); + clk->is_enabled = clk_hw_is_enabled(&clk->hw); + + if (clk->rate) + dev_dbg(dev, "save rate %d\n", clk->rate); + + if (clk->is_enabled) + dev_dbg(dev, "save enabled state\n"); + + return 0; +} + +static int __maybe_unused imx_clk_scu_resume(struct device *dev) +{ + struct clk_scu *clk = dev_get_drvdata(dev); + int ret = 0; + + if (clk->rate) { + ret = clk_scu_set_rate(&clk->hw, clk->rate, 0); + dev_dbg(dev, "restore rate %d %s\n", clk->rate, + !ret ? "success" : "failed"); + } + + if (clk->is_enabled) { + ret = clk_scu_prepare(&clk->hw); + dev_dbg(dev, "restore enabled state %s\n", + !ret ? "success" : "failed"); + } + + return ret; +} + +static const struct dev_pm_ops imx_clk_scu_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_clk_scu_suspend, + imx_clk_scu_resume) +}; + static struct platform_driver imx_clk_scu_driver = { .driver = { .name = "imx-scu-clk", .suppress_bind_attrs = true, + .pm = &imx_clk_scu_pm_ops, }, .probe = imx_clk_scu_probe, }; From d5f1e6a2bb61db8d4bd269edac8b52a853b48ce8 Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Wed, 29 Jul 2020 16:00:15 +0800 Subject: [PATCH 006/134] clk: imx: imx8qxp-lpcg: add parsing clocks from device tree One LPCG controller supports up to 8 clock outputs while each of them is fixed to 4 bits. It supports only gating function with fixed bits. So we can use the clk-indices to fetch the corresponding clock idx from device tree. With this way, we can write a generic LPCG clock drivers. This patch add that support to parse clocks from device tree. Cc: Shawn Guo Cc: Sascha Hauer Cc: Michael Turquette Reviewed-by: Stephen Boyd Signed-off-by: Dong Aisheng Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8qxp-lpcg.c | 124 +++++++++++++++++++++++++++++ drivers/clk/imx/clk-lpcg-scu.c | 8 ++ drivers/clk/imx/clk-scu.h | 1 + 3 files changed, 133 insertions(+) diff --git a/drivers/clk/imx/clk-imx8qxp-lpcg.c b/drivers/clk/imx/clk-imx8qxp-lpcg.c index e947a70054ac..84ac374ae8ff 100644 --- a/drivers/clk/imx/clk-imx8qxp-lpcg.c +++ b/drivers/clk/imx/clk-imx8qxp-lpcg.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -157,6 +158,122 @@ static const struct imx8qxp_ss_lpcg imx8qxp_ss_lsio = { .num_max = IMX_LSIO_LPCG_CLK_END, }; +#define IMX_LPCG_MAX_CLKS 8 + +static struct clk_hw *imx_lpcg_of_clk_src_get(struct of_phandle_args *clkspec, + void *data) +{ + struct clk_hw_onecell_data *hw_data = data; + unsigned int idx = clkspec->args[0] / 4; + + if (idx >= hw_data->num) { + pr_err("%s: invalid index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + return hw_data->hws[idx]; +} + +static int imx_lpcg_parse_clks_from_dt(struct platform_device *pdev, + struct device_node *np) +{ + const char *output_names[IMX_LPCG_MAX_CLKS]; + const char *parent_names[IMX_LPCG_MAX_CLKS]; + unsigned int bit_offset[IMX_LPCG_MAX_CLKS]; + struct clk_hw_onecell_data *clk_data; + struct clk_hw **clk_hws; + struct resource *res; + void __iomem *base; + int count; + int idx; + int ret; + int i; + + if (!of_device_is_compatible(np, "fsl,imx8qxp-lpcg")) + return -EINVAL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + count = of_property_count_u32_elems(np, "clock-indices"); + if (count < 0) { + dev_err(&pdev->dev, "failed to count clocks\n"); + return -EINVAL; + } + + /* + * A trick here is that we set the num of clks to the MAX instead + * of the count from clock-indices because one LPCG supports up to + * 8 clock outputs which each of them is fixed to 4 bits. Then we can + * easily get the clock by clk-indices (bit-offset) / 4. + * And the cost is very limited few pointers. + */ + + clk_data = devm_kzalloc(&pdev->dev, struct_size(clk_data, hws, + IMX_LPCG_MAX_CLKS), GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->num = IMX_LPCG_MAX_CLKS; + clk_hws = clk_data->hws; + + ret = of_property_read_u32_array(np, "clock-indices", bit_offset, + count); + if (ret < 0) { + dev_err(&pdev->dev, "failed to read clock-indices\n"); + return -EINVAL; + } + + ret = of_clk_parent_fill(np, parent_names, count); + if (ret != count) { + dev_err(&pdev->dev, "failed to get clock parent names\n"); + return count; + } + + ret = of_property_read_string_array(np, "clock-output-names", + output_names, count); + if (ret != count) { + dev_err(&pdev->dev, "failed to read clock-output-names\n"); + return -EINVAL; + } + + for (i = 0; i < count; i++) { + idx = bit_offset[i] / 4; + if (idx > IMX_LPCG_MAX_CLKS) { + dev_warn(&pdev->dev, "invalid bit offset of clock %d\n", + i); + ret = -EINVAL; + goto unreg; + } + + clk_hws[idx] = imx_clk_lpcg_scu(output_names[i], + parent_names[i], 0, base, + bit_offset[i], false); + if (IS_ERR(clk_hws[idx])) { + dev_warn(&pdev->dev, "failed to register clock %d\n", + idx); + ret = PTR_ERR(clk_hws[idx]); + goto unreg; + } + } + + ret = devm_of_clk_add_hw_provider(&pdev->dev, imx_lpcg_of_clk_src_get, + clk_data); + if (!ret) + return 0; + +unreg: + while (--i >= 0) { + idx = bit_offset[i] / 4; + if (clk_hws[idx]) + imx_clk_lpcg_scu_unregister(clk_hws[idx]); + } + + return ret; +} + static int imx8qxp_lpcg_clk_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -167,8 +284,14 @@ static int imx8qxp_lpcg_clk_probe(struct platform_device *pdev) struct resource *res; struct clk_hw **clks; void __iomem *base; + int ret; int i; + /* try new binding to parse clocks from device tree first */ + ret = imx_lpcg_parse_clks_from_dt(pdev, np); + if (!ret) + return 0; + ss_lpcg = of_device_get_match_data(dev); if (!ss_lpcg) return -ENODEV; @@ -219,6 +342,7 @@ static const struct of_device_id imx8qxp_lpcg_match[] = { { .compatible = "fsl,imx8qxp-lpcg-adma", &imx8qxp_ss_adma, }, { .compatible = "fsl,imx8qxp-lpcg-conn", &imx8qxp_ss_conn, }, { .compatible = "fsl,imx8qxp-lpcg-lsio", &imx8qxp_ss_lsio, }, + { .compatible = "fsl,imx8qxp-lpcg", NULL }, { /* sentinel */ } }; diff --git a/drivers/clk/imx/clk-lpcg-scu.c b/drivers/clk/imx/clk-lpcg-scu.c index 1f0e44f921ae..fab9c94a5e69 100644 --- a/drivers/clk/imx/clk-lpcg-scu.c +++ b/drivers/clk/imx/clk-lpcg-scu.c @@ -115,3 +115,11 @@ struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name, return hw; } + +void imx_clk_lpcg_scu_unregister(struct clk_hw *hw) +{ + struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw); + + clk_hw_unregister(&clk->hw); + kfree(clk); +} diff --git a/drivers/clk/imx/clk-scu.h b/drivers/clk/imx/clk-scu.h index 22976d64a96a..6a879526b3d5 100644 --- a/drivers/clk/imx/clk-scu.h +++ b/drivers/clk/imx/clk-scu.h @@ -47,4 +47,5 @@ static inline struct clk_hw *imx_clk_scu2(const char *name, const char * const * struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 bit_idx, bool hw_gate); +void imx_clk_lpcg_scu_unregister(struct clk_hw *hw); #endif From a4bfc85ccf374fb4ff10c806a270bf241598a70a Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Wed, 29 Jul 2020 16:00:16 +0800 Subject: [PATCH 007/134] clk: imx: lpcg: allow lpcg clk to take device pointer Used to support runtime pm. Reviewed-by: Stephen Boyd Signed-off-by: Dong Aisheng Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-lpcg-scu.c | 8 ++++---- drivers/clk/imx/clk-scu.h | 24 ++++++++++++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/drivers/clk/imx/clk-lpcg-scu.c b/drivers/clk/imx/clk-lpcg-scu.c index fab9c94a5e69..4363ab6f46d5 100644 --- a/drivers/clk/imx/clk-lpcg-scu.c +++ b/drivers/clk/imx/clk-lpcg-scu.c @@ -81,9 +81,9 @@ static const struct clk_ops clk_lpcg_scu_ops = { .disable = clk_lpcg_scu_disable, }; -struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name, - unsigned long flags, void __iomem *reg, - u8 bit_idx, bool hw_gate) +struct clk_hw *__imx_clk_lpcg_scu(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, bool hw_gate) { struct clk_lpcg_scu *clk; struct clk_init_data init; @@ -107,7 +107,7 @@ struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name, clk->hw.init = &init; hw = &clk->hw; - ret = clk_hw_register(NULL, hw); + ret = clk_hw_register(dev, hw); if (ret) { kfree(clk); hw = ERR_PTR(ret); diff --git a/drivers/clk/imx/clk-scu.h b/drivers/clk/imx/clk-scu.h index 6a879526b3d5..faee1ba5c4ee 100644 --- a/drivers/clk/imx/clk-scu.h +++ b/drivers/clk/imx/clk-scu.h @@ -25,6 +25,11 @@ struct clk_hw *__imx_clk_scu(struct device *dev, const char *name, void imx_clk_scu_unregister(void); +struct clk_hw *__imx_clk_lpcg_scu(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, bool hw_gate); +void imx_clk_lpcg_scu_unregister(struct clk_hw *hw); + static inline struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id, u8 clk_type, u8 clk_cells) { @@ -44,8 +49,19 @@ static inline struct clk_hw *imx_clk_scu2(const char *name, const char * const * return __imx_clk_scu(NULL, name, parents, num_parents, rsrc_id, clk_type); } -struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name, - unsigned long flags, void __iomem *reg, - u8 bit_idx, bool hw_gate); -void imx_clk_lpcg_scu_unregister(struct clk_hw *hw); +static inline struct clk_hw *imx_clk_lpcg_scu_dev(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, bool hw_gate) +{ + return __imx_clk_lpcg_scu(dev, name, parent_name, flags, reg, + bit_idx, hw_gate); +} + +static inline struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name, + unsigned long flags, void __iomem *reg, + u8 bit_idx, bool hw_gate) +{ + return __imx_clk_lpcg_scu(NULL, name, parent_name, flags, reg, + bit_idx, hw_gate); +} #endif From 18cdbad40c6c138edf62273417180227e12b198a Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Wed, 29 Jul 2020 16:00:17 +0800 Subject: [PATCH 008/134] clk: imx: clk-imx8qxp-lpcg: add runtime pm support add runtime pm support Reviewed-by: Stephen Boyd Signed-off-by: Dong Aisheng Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8qxp-lpcg.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/clk/imx/clk-imx8qxp-lpcg.c b/drivers/clk/imx/clk-imx8qxp-lpcg.c index 84ac374ae8ff..50ab66028f0b 100644 --- a/drivers/clk/imx/clk-imx8qxp-lpcg.c +++ b/drivers/clk/imx/clk-imx8qxp-lpcg.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "clk-scu.h" @@ -239,6 +240,12 @@ static int imx_lpcg_parse_clks_from_dt(struct platform_device *pdev, return -EINVAL; } + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, 500); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); + for (i = 0; i < count; i++) { idx = bit_offset[i] / 4; if (idx > IMX_LPCG_MAX_CLKS) { @@ -248,9 +255,9 @@ static int imx_lpcg_parse_clks_from_dt(struct platform_device *pdev, goto unreg; } - clk_hws[idx] = imx_clk_lpcg_scu(output_names[i], - parent_names[i], 0, base, - bit_offset[i], false); + clk_hws[idx] = imx_clk_lpcg_scu_dev(&pdev->dev, output_names[i], + parent_names[i], 0, base, + bit_offset[i], false); if (IS_ERR(clk_hws[idx])) { dev_warn(&pdev->dev, "failed to register clock %d\n", idx); @@ -261,8 +268,13 @@ static int imx_lpcg_parse_clks_from_dt(struct platform_device *pdev, ret = devm_of_clk_add_hw_provider(&pdev->dev, imx_lpcg_of_clk_src_get, clk_data); - if (!ret) - return 0; + if (ret) + goto unreg; + + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); + + return 0; unreg: while (--i >= 0) { @@ -271,6 +283,8 @@ unreg: imx_clk_lpcg_scu_unregister(clk_hws[idx]); } + pm_runtime_disable(&pdev->dev); + return ret; } From ea0c5cbaf8b70fd6fe0269fb0b951965c82229cc Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Wed, 29 Jul 2020 16:00:18 +0800 Subject: [PATCH 009/134] clk: imx: lpcg: add suspend/resume support LPCG clock state may be lost when it's power domain is completely off during system suspend/resume and we need save and restore the state properly. Reviewed-by: Stephen Boyd Signed-off-by: Dong Aisheng Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8qxp-lpcg.c | 1 + drivers/clk/imx/clk-lpcg-scu.c | 37 ++++++++++++++++++++++++++++++ drivers/clk/imx/clk-scu.h | 1 + 3 files changed, 39 insertions(+) diff --git a/drivers/clk/imx/clk-imx8qxp-lpcg.c b/drivers/clk/imx/clk-imx8qxp-lpcg.c index 50ab66028f0b..d3e905cf867d 100644 --- a/drivers/clk/imx/clk-imx8qxp-lpcg.c +++ b/drivers/clk/imx/clk-imx8qxp-lpcg.c @@ -364,6 +364,7 @@ static struct platform_driver imx8qxp_lpcg_clk_driver = { .driver = { .name = "imx8qxp-lpcg-clk", .of_match_table = imx8qxp_lpcg_match, + .pm = &imx_clk_lpcg_scu_pm_ops, .suppress_bind_attrs = true, }, .probe = imx8qxp_lpcg_clk_probe, diff --git a/drivers/clk/imx/clk-lpcg-scu.c b/drivers/clk/imx/clk-lpcg-scu.c index 4363ab6f46d5..77be7632866d 100644 --- a/drivers/clk/imx/clk-lpcg-scu.c +++ b/drivers/clk/imx/clk-lpcg-scu.c @@ -34,6 +34,9 @@ struct clk_lpcg_scu { void __iomem *reg; u8 bit_idx; bool hw_gate; + + /* for state save&restore */ + u32 state; }; #define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw) @@ -113,6 +116,9 @@ struct clk_hw *__imx_clk_lpcg_scu(struct device *dev, const char *name, hw = ERR_PTR(ret); } + if (dev) + dev_set_drvdata(dev, clk); + return hw; } @@ -123,3 +129,34 @@ void imx_clk_lpcg_scu_unregister(struct clk_hw *hw) clk_hw_unregister(&clk->hw); kfree(clk); } + +static int __maybe_unused imx_clk_lpcg_scu_suspend(struct device *dev) +{ + struct clk_lpcg_scu *clk = dev_get_drvdata(dev); + + clk->state = readl_relaxed(clk->reg); + dev_dbg(dev, "save lpcg state 0x%x\n", clk->state); + + return 0; +} + +static int __maybe_unused imx_clk_lpcg_scu_resume(struct device *dev) +{ + struct clk_lpcg_scu *clk = dev_get_drvdata(dev); + + /* + * FIXME: Sometimes writes don't work unless the CPU issues + * them twice + */ + + writel(clk->state, clk->reg); + writel(clk->state, clk->reg); + dev_dbg(dev, "restore lpcg state 0x%x\n", clk->state); + + return 0; +} + +const struct dev_pm_ops imx_clk_lpcg_scu_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_clk_lpcg_scu_suspend, + imx_clk_lpcg_scu_resume) +}; diff --git a/drivers/clk/imx/clk-scu.h b/drivers/clk/imx/clk-scu.h index faee1ba5c4ee..e8352164923e 100644 --- a/drivers/clk/imx/clk-scu.h +++ b/drivers/clk/imx/clk-scu.h @@ -11,6 +11,7 @@ #include extern struct list_head imx_scu_clks[]; +extern const struct dev_pm_ops imx_clk_lpcg_scu_pm_ops; int imx_clk_scu_init(struct device_node *np); struct clk_hw *imx_scu_of_clk_src_get(struct of_phandle_args *clkspec, From 7f2c2f38c1c0dbfc5b1e13aa57678daa753e1c96 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 22 Sep 2020 14:00:36 +0200 Subject: [PATCH 010/134] clk: renesas: rcar-gen3: Remove stp_ck handling for SDHI There is no case (and none foreseen) where we would need to disable the SDn clock. So, for simplicity, remove its handling. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20200922120036.10298-1-wsa+renesas@sang-engineering.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rcar-gen3-cpg.c | 51 ++++++++++++++--------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c index 488f8b3980c5..a7debddf7d09 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.c +++ b/drivers/clk/renesas/rcar-gen3-cpg.c @@ -224,10 +224,9 @@ static struct clk * __init cpg_z_clk_register(const char *name, #define CPG_SD_STP_MASK (CPG_SD_STP_HCK | CPG_SD_STP_CK) #define CPG_SD_FC_MASK (0x7 << 2 | 0x3 << 0) -#define CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) \ +#define CPG_SD_DIV_TABLE_DATA(stp_hck, sd_srcfc, sd_fc, sd_div) \ { \ .val = ((stp_hck) ? CPG_SD_STP_HCK : 0) | \ - ((stp_ck) ? CPG_SD_STP_CK : 0) | \ ((sd_srcfc) << 2) | \ ((sd_fc) << 0), \ .div = (sd_div), \ @@ -247,36 +246,36 @@ struct sd_clock { }; /* SDn divider - * sd_srcfc sd_fc div - * stp_hck stp_ck (div) (div) = sd_srcfc x sd_fc - *------------------------------------------------------------------- - * 0 0 0 (1) 1 (4) 4 : SDR104 / HS200 / HS400 (8 TAP) - * 0 0 1 (2) 1 (4) 8 : SDR50 - * 1 0 2 (4) 1 (4) 16 : HS / SDR25 - * 1 0 3 (8) 1 (4) 32 : NS / SDR12 - * 1 0 4 (16) 1 (4) 64 - * 0 0 0 (1) 0 (2) 2 - * 0 0 1 (2) 0 (2) 4 : SDR104 / HS200 / HS400 (4 TAP) - * 1 0 2 (4) 0 (2) 8 - * 1 0 3 (8) 0 (2) 16 - * 1 0 4 (16) 0 (2) 32 + * sd_srcfc sd_fc div + * stp_hck (div) (div) = sd_srcfc x sd_fc + *--------------------------------------------------------- + * 0 0 (1) 1 (4) 4 : SDR104 / HS200 / HS400 (8 TAP) + * 0 1 (2) 1 (4) 8 : SDR50 + * 1 2 (4) 1 (4) 16 : HS / SDR25 + * 1 3 (8) 1 (4) 32 : NS / SDR12 + * 1 4 (16) 1 (4) 64 + * 0 0 (1) 0 (2) 2 + * 0 1 (2) 0 (2) 4 : SDR104 / HS200 / HS400 (4 TAP) + * 1 2 (4) 0 (2) 8 + * 1 3 (8) 0 (2) 16 + * 1 4 (16) 0 (2) 32 * * NOTE: There is a quirk option to ignore the first row of the dividers * table when searching for suitable settings. This is because HS400 on * early ES versions of H3 and M3-W requires a specific setting to work. */ static const struct sd_div_table cpg_sd_div_table[] = { -/* CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) */ - CPG_SD_DIV_TABLE_DATA(0, 0, 0, 1, 4), - CPG_SD_DIV_TABLE_DATA(0, 0, 1, 1, 8), - CPG_SD_DIV_TABLE_DATA(1, 0, 2, 1, 16), - CPG_SD_DIV_TABLE_DATA(1, 0, 3, 1, 32), - CPG_SD_DIV_TABLE_DATA(1, 0, 4, 1, 64), - CPG_SD_DIV_TABLE_DATA(0, 0, 0, 0, 2), - CPG_SD_DIV_TABLE_DATA(0, 0, 1, 0, 4), - CPG_SD_DIV_TABLE_DATA(1, 0, 2, 0, 8), - CPG_SD_DIV_TABLE_DATA(1, 0, 3, 0, 16), - CPG_SD_DIV_TABLE_DATA(1, 0, 4, 0, 32), +/* CPG_SD_DIV_TABLE_DATA(stp_hck, sd_srcfc, sd_fc, sd_div) */ + CPG_SD_DIV_TABLE_DATA(0, 0, 1, 4), + CPG_SD_DIV_TABLE_DATA(0, 1, 1, 8), + CPG_SD_DIV_TABLE_DATA(1, 2, 1, 16), + CPG_SD_DIV_TABLE_DATA(1, 3, 1, 32), + CPG_SD_DIV_TABLE_DATA(1, 4, 1, 64), + CPG_SD_DIV_TABLE_DATA(0, 0, 0, 2), + CPG_SD_DIV_TABLE_DATA(0, 1, 0, 4), + CPG_SD_DIV_TABLE_DATA(1, 2, 0, 8), + CPG_SD_DIV_TABLE_DATA(1, 3, 0, 16), + CPG_SD_DIV_TABLE_DATA(1, 4, 0, 32), }; #define to_sd_clock(_hw) container_of(_hw, struct sd_clock, hw) From 6e0781e092a150b040cc305fd1832730cf78580a Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Mon, 26 Oct 2020 11:17:20 +0000 Subject: [PATCH 011/134] clk: rockchip: Add appropriate arch dependencies There's no point offering support for 32-bit platforms to users configuring a 64-bit kernel - and vice-versa - unless they are explicitly interested in compile-testing. Signed-off-by: Robin Murphy Link: https://lore.kernel.org/r/72abb0f794b8ed77e274e8ee21c22e0bd3223dfd.1603710913.git.robin.murphy@arm.com Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/Kconfig | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/clk/rockchip/Kconfig b/drivers/clk/rockchip/Kconfig index 47cd6c5de837..effd05032e85 100644 --- a/drivers/clk/rockchip/Kconfig +++ b/drivers/clk/rockchip/Kconfig @@ -11,67 +11,77 @@ config COMMON_CLK_ROCKCHIP if COMMON_CLK_ROCKCHIP config CLK_PX30 bool "Rockchip PX30 clock controller support" + depends on (ARM64 || COMPILE_TEST) default y help Build the driver for PX30 Clock Driver. config CLK_RV110X bool "Rockchip RV110x clock controller support" + depends on (ARM || COMPILE_TEST) default y help Build the driver for RV110x Clock Driver. config CLK_RK3036 bool "Rockchip RK3036 clock controller support" + depends on (ARM || COMPILE_TEST) default y help Build the driver for RK3036 Clock Driver. config CLK_RK312X bool "Rockchip RK312x clock controller support" + depends on (ARM || COMPILE_TEST) default y help Build the driver for RK312x Clock Driver. config CLK_RK3188 bool "Rockchip RK3188 clock controller support" + depends on (ARM || COMPILE_TEST) default y help Build the driver for RK3188 Clock Driver. config CLK_RK322X bool "Rockchip RK322x clock controller support" + depends on (ARM || COMPILE_TEST) default y help Build the driver for RK322x Clock Driver. config CLK_RK3288 bool "Rockchip RK3288 clock controller support" - depends on ARM + depends on (ARM || COMPILE_TEST) default y help Build the driver for RK3288 Clock Driver. config CLK_RK3308 bool "Rockchip RK3308 clock controller support" + depends on (ARM64 || COMPILE_TEST) default y help Build the driver for RK3308 Clock Driver. config CLK_RK3328 bool "Rockchip RK3328 clock controller support" + depends on (ARM64 || COMPILE_TEST) default y help Build the driver for RK3328 Clock Driver. config CLK_RK3368 bool "Rockchip RK3368 clock controller support" + depends on (ARM64 || COMPILE_TEST) default y help Build the driver for RK3368 Clock Driver. config CLK_RK3399 tristate "Rockchip RK3399 clock controller support" + depends on (ARM64 || COMPILE_TEST) default y help Build the driver for RK3399 Clock Driver. From 8404c66140e209794b15ee5529d4559334b3d364 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Tue, 27 Oct 2020 11:57:56 -0700 Subject: [PATCH 012/134] clk: imx: remove unneeded semicolon A semicolon is not needed after a switch statement. Signed-off-by: Tom Rix Reviewed-by: Abel Vesa Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-pll14xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c index aba36e4217d2..2b5ed86b9dbb 100644 --- a/drivers/clk/imx/clk-pll14xx.c +++ b/drivers/clk/imx/clk-pll14xx.c @@ -416,7 +416,7 @@ struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name, __func__, name); kfree(pll); return ERR_PTR(-EINVAL); - }; + } pll->base = base; pll->hw.init = &init; From f2644bd7413c8f2fcef208c576e83335709c5120 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 29 Oct 2020 22:40:07 +0000 Subject: [PATCH 013/134] clk: imx: remove redundant assignment to pointer np Pointer np is being initialized with a value that is never read and it is being updated with a value later on. The initialization is redundant and can be removed. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Reviewed-by: Dong Aisheng Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c index 12ce4770f702..3cb2bc46eae0 100644 --- a/drivers/clk/imx/clk-imx8mp.c +++ b/drivers/clk/imx/clk-imx8mp.c @@ -425,7 +425,7 @@ static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1]; static int imx8mp_clocks_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; + struct device_node *np; void __iomem *anatop_base, *ccm_base; int i; From 220175cd3979fdb860decf757cc7a5980fdd045f Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Fri, 30 Oct 2020 23:37:33 +0800 Subject: [PATCH 014/134] clk: imx: scu: fix build break when compiled as modules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After commit e0d0d4d86c76 ("clk: imx8qxp: Support building i.MX8QXP clock driver as module"), clk-scu.c and clk-imx8qxp.c are complied in one module, thus there can be only one module_init() in those two files. Commit 77d8f3068c63 ("clk: imx: scu: add two cells binding support") introduced another module_init() in clk_scu.c which caused the errors below. To fix the issue, we can remove the unnecessary builtin_platform_driver from clk_scu.c and directly register the driver in imx_clk_scu_init(). CC [M] drivers/clk/imx/clk-scu.o In file included from ../include/linux/of_device.h:6, from ../include/linux/of_platform.h:12, from ../drivers/clk/imx/clk-scu.c:11: ../drivers/clk/imx/clk-scu.c: In function ‘imx_clk_scu_init’: ../drivers/clk/imx/clk-scu.c:176:35: error: ‘imx_clk_scu_driver’ undeclared (first use in this function); did you mean ‘imx_clk_scu_init’? 176 | return platform_driver_register(&imx_clk_scu_driver); | ^~~~~~~~~~~~~~~~~~ ../include/linux/platform_device.h:218:29: note: in definition of macro ‘platform_driver_register’ 218 | __platform_driver_register(drv, THIS_MODULE) | ^~~ ../drivers/clk/imx/clk-scu.c:176:35: note: each undeclared identifier is reported only once for each function it appears in 176 | return platform_driver_register(&imx_clk_scu_driver); | ^~~~~~~~~~~~~~~~~~ ../include/linux/platform_device.h:218:29: note: in definition of macro ‘platform_driver_register’ 218 | __platform_driver_register(drv, THIS_MODULE) | ^~~ ../drivers/clk/imx/clk-scu.c:177:1: error: control reaches end of non-void function [-Werror=return-type] 177 | } | ^ At top level: ../drivers/clk/imx/clk-scu.c:470:31: warning: ‘imx_clk_scu_driver’ defined but not used [-Wunused-variable] 470 | static struct platform_driver imx_clk_scu_driver = { Reported-by: kernel test robot Fixes: 77d8f3068c63 ("clk: imx: scu: add two cells binding support") Signed-off-by: Dong Aisheng Acked-by: Stephen Boyd Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-scu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c index 229a290ca5b6..d0243c52ccbc 100644 --- a/drivers/clk/imx/clk-scu.c +++ b/drivers/clk/imx/clk-scu.c @@ -21,6 +21,7 @@ static struct imx_sc_ipc *ccm_ipc_handle; struct device_node *pd_np; +static struct platform_driver imx_clk_scu_driver; struct imx_scu_clk_node { const char *name; @@ -178,7 +179,7 @@ int imx_clk_scu_init(struct device_node *np) } } - return 0; + return platform_driver_register(&imx_clk_scu_driver); } /* @@ -542,7 +543,6 @@ static struct platform_driver imx_clk_scu_driver = { }, .probe = imx_clk_scu_probe, }; -builtin_platform_driver(imx_clk_scu_driver); static int imx_clk_scu_attach_pd(struct device *dev, u32 rsrc_id) { From 12309428c27737c21735fb28540c6c6f69f632f6 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Wed, 28 Oct 2020 14:58:58 +0200 Subject: [PATCH 015/134] clk: imx: gate2: Remove the IMX_CLK_GATE2_SINGLE_BIT special case This was a hack which would allow multiple HW gates to be controlled by a single bit. The only user of this is the imx_dev_clk_hw_gate_shared which is not used anywhere as of now. Basically, complicates the logic of the driver for no reason. Signed-off-by: Abel Vesa Reviewed-by: Sascha Hauer Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-gate2.c | 28 +++++++--------------------- drivers/clk/imx/clk.h | 5 +---- 2 files changed, 8 insertions(+), 25 deletions(-) diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c index 7eed7083f46e..49952eec4e28 100644 --- a/drivers/clk/imx/clk-gate2.c +++ b/drivers/clk/imx/clk-gate2.c @@ -49,14 +49,10 @@ static int clk_gate2_enable(struct clk_hw *hw) if (gate->share_count && (*gate->share_count)++ > 0) goto out; - if (gate->flags & IMX_CLK_GATE2_SINGLE_BIT) { - ret = clk_gate_ops.enable(hw); - } else { - reg = readl(gate->reg); - reg &= ~(3 << gate->bit_idx); - reg |= gate->cgr_val << gate->bit_idx; - writel(reg, gate->reg); - } + reg = readl(gate->reg); + reg &= ~(3 << gate->bit_idx); + reg |= gate->cgr_val << gate->bit_idx; + writel(reg, gate->reg); out: spin_unlock_irqrestore(gate->lock, flags); @@ -79,13 +75,9 @@ static void clk_gate2_disable(struct clk_hw *hw) goto out; } - if (gate->flags & IMX_CLK_GATE2_SINGLE_BIT) { - clk_gate_ops.disable(hw); - } else { - reg = readl(gate->reg); - reg &= ~(3 << gate->bit_idx); - writel(reg, gate->reg); - } + reg = readl(gate->reg); + reg &= ~(3 << gate->bit_idx); + writel(reg, gate->reg); out: spin_unlock_irqrestore(gate->lock, flags); @@ -105,9 +97,6 @@ static int clk_gate2_is_enabled(struct clk_hw *hw) { struct clk_gate2 *gate = to_clk_gate2(hw); - if (gate->flags & IMX_CLK_GATE2_SINGLE_BIT) - return clk_gate_ops.is_enabled(hw); - return clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx); } @@ -117,9 +106,6 @@ static void clk_gate2_disable_unused(struct clk_hw *hw) unsigned long flags; u32 reg; - if (gate->flags & IMX_CLK_GATE2_SINGLE_BIT) - return; - spin_lock_irqsave(gate->lock, flags); if (!gate->share_count || *gate->share_count == 0) { diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 3b796b3da249..87b2744f72f7 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -6,8 +6,6 @@ #include #include -#define IMX_CLK_GATE2_SINGLE_BIT 1 - extern spinlock_t imx_ccm_lock; void imx_check_clocks(struct clk *clks[], unsigned int count); @@ -384,8 +382,7 @@ static inline struct clk_hw *imx_dev_clk_hw_gate_shared(struct device *dev, unsigned int *share_count) { return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT | - CLK_OPS_PARENT_ENABLE, reg, shift, 0x3, - IMX_CLK_GATE2_SINGLE_BIT, + CLK_OPS_PARENT_ENABLE, reg, shift, 0x1, 0, &imx_ccm_lock, share_count); } From 040adb5fe95ad39c0a714cf3b05950974caf42ed Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Wed, 28 Oct 2020 14:58:59 +0200 Subject: [PATCH 016/134] clk: imx: gate2: Keep the register writing in on place Move all the register writing to the newly added clk_gate2_do_shared_clks and call that everywhere need needed. Cleans up the code a little bit. Signed-off-by: Abel Vesa Reviewed-by: Sascha Hauer Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-gate2.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c index 49952eec4e28..e1f6cd931a8d 100644 --- a/drivers/clk/imx/clk-gate2.c +++ b/drivers/clk/imx/clk-gate2.c @@ -37,10 +37,21 @@ struct clk_gate2 { #define to_clk_gate2(_hw) container_of(_hw, struct clk_gate2, hw) -static int clk_gate2_enable(struct clk_hw *hw) +static void clk_gate2_do_shared_clks(struct clk_hw *hw, bool enable) { struct clk_gate2 *gate = to_clk_gate2(hw); u32 reg; + + reg = readl(gate->reg); + reg &= ~(3 << gate->bit_idx); + if (enable) + reg |= gate->cgr_val << gate->bit_idx; + writel(reg, gate->reg); +} + +static int clk_gate2_enable(struct clk_hw *hw) +{ + struct clk_gate2 *gate = to_clk_gate2(hw); unsigned long flags; int ret = 0; @@ -49,11 +60,7 @@ static int clk_gate2_enable(struct clk_hw *hw) if (gate->share_count && (*gate->share_count)++ > 0) goto out; - reg = readl(gate->reg); - reg &= ~(3 << gate->bit_idx); - reg |= gate->cgr_val << gate->bit_idx; - writel(reg, gate->reg); - + clk_gate2_do_shared_clks(hw, true); out: spin_unlock_irqrestore(gate->lock, flags); @@ -63,7 +70,6 @@ out: static void clk_gate2_disable(struct clk_hw *hw) { struct clk_gate2 *gate = to_clk_gate2(hw); - u32 reg; unsigned long flags; spin_lock_irqsave(gate->lock, flags); @@ -75,10 +81,7 @@ static void clk_gate2_disable(struct clk_hw *hw) goto out; } - reg = readl(gate->reg); - reg &= ~(3 << gate->bit_idx); - writel(reg, gate->reg); - + clk_gate2_do_shared_clks(hw, false); out: spin_unlock_irqrestore(gate->lock, flags); } @@ -104,15 +107,11 @@ static void clk_gate2_disable_unused(struct clk_hw *hw) { struct clk_gate2 *gate = to_clk_gate2(hw); unsigned long flags; - u32 reg; spin_lock_irqsave(gate->lock, flags); - if (!gate->share_count || *gate->share_count == 0) { - reg = readl(gate->reg); - reg &= ~(3 << gate->bit_idx); - writel(reg, gate->reg); - } + if (!gate->share_count || *gate->share_count == 0) + clk_gate2_do_shared_clks(hw, false); spin_unlock_irqrestore(gate->lock, flags); } From 03681d06a555a6c5f39de48d68082e7444db329f Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Wed, 28 Oct 2020 14:59:00 +0200 Subject: [PATCH 017/134] clk: imx: gate2: Check if clock is enabled against cgr_val Seems the logic here was wrong all along. For example, if the cgr_val is 2 (0b10), the clk_gate2_reg_is_enabled would report the clock as disabled. So check against cgr_val instead. Signed-off-by: Abel Vesa Reviewed-by: Sascha Hauer Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-gate2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c index e1f6cd931a8d..40bcc2ddddba 100644 --- a/drivers/clk/imx/clk-gate2.c +++ b/drivers/clk/imx/clk-gate2.c @@ -86,11 +86,11 @@ out: spin_unlock_irqrestore(gate->lock, flags); } -static int clk_gate2_reg_is_enabled(void __iomem *reg, u8 bit_idx) +static int clk_gate2_reg_is_enabled(void __iomem *reg, u8 bit_idx, u8 cgr_val) { u32 val = readl(reg); - if (((val >> bit_idx) & 1) == 1) + if (((val >> bit_idx) & 3) == cgr_val) return 1; return 0; @@ -100,7 +100,7 @@ static int clk_gate2_is_enabled(struct clk_hw *hw) { struct clk_gate2 *gate = to_clk_gate2(hw); - return clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx); + return clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx, gate->cgr_val); } static void clk_gate2_disable_unused(struct clk_hw *hw) From bcd418a632b621510ebc731cb707d8fe3e873119 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Wed, 28 Oct 2020 14:59:01 +0200 Subject: [PATCH 018/134] clk: imx: gate2: Add cgr_mask for more flexible number of control bits On some i.MX8 platforms, there are HW gates that share the same bit. So in order to make this clock type more usable, use a mask to specify how many bits belong to those HW gates. Signed-off-by: Abel Vesa Reviewed-by: Sascha Hauer Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-gate2.c | 16 ++++++++++------ drivers/clk/imx/clk.h | 24 ++++++++++++------------ 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c index 40bcc2ddddba..7e4b5e82de7f 100644 --- a/drivers/clk/imx/clk-gate2.c +++ b/drivers/clk/imx/clk-gate2.c @@ -30,6 +30,7 @@ struct clk_gate2 { void __iomem *reg; u8 bit_idx; u8 cgr_val; + u8 cgr_mask; u8 flags; spinlock_t *lock; unsigned int *share_count; @@ -43,9 +44,9 @@ static void clk_gate2_do_shared_clks(struct clk_hw *hw, bool enable) u32 reg; reg = readl(gate->reg); - reg &= ~(3 << gate->bit_idx); + reg &= ~(gate->cgr_mask << gate->bit_idx); if (enable) - reg |= gate->cgr_val << gate->bit_idx; + reg |= (gate->cgr_val & gate->cgr_mask) << gate->bit_idx; writel(reg, gate->reg); } @@ -86,11 +87,12 @@ out: spin_unlock_irqrestore(gate->lock, flags); } -static int clk_gate2_reg_is_enabled(void __iomem *reg, u8 bit_idx, u8 cgr_val) +static int clk_gate2_reg_is_enabled(void __iomem *reg, u8 bit_idx, + u8 cgr_val, u8 cgr_mask) { u32 val = readl(reg); - if (((val >> bit_idx) & 3) == cgr_val) + if (((val >> bit_idx) & cgr_mask) == cgr_val) return 1; return 0; @@ -100,7 +102,8 @@ static int clk_gate2_is_enabled(struct clk_hw *hw) { struct clk_gate2 *gate = to_clk_gate2(hw); - return clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx, gate->cgr_val); + return clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx, + gate->cgr_val, gate->cgr_mask); } static void clk_gate2_disable_unused(struct clk_hw *hw) @@ -125,7 +128,7 @@ static const struct clk_ops clk_gate2_ops = { struct clk_hw *clk_hw_register_gate2(struct device *dev, const char *name, const char *parent_name, unsigned long flags, - void __iomem *reg, u8 bit_idx, u8 cgr_val, + void __iomem *reg, u8 bit_idx, u8 cgr_val, u8 cgr_mask, u8 clk_gate2_flags, spinlock_t *lock, unsigned int *share_count) { @@ -142,6 +145,7 @@ struct clk_hw *clk_hw_register_gate2(struct device *dev, const char *name, gate->reg = reg; gate->bit_idx = bit_idx; gate->cgr_val = cgr_val; + gate->cgr_mask = cgr_mask; gate->flags = clk_gate2_flags; gate->lock = lock; gate->share_count = share_count; diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 87b2744f72f7..3d8e40b4edbf 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -66,9 +66,9 @@ extern struct imx_pll14xx_clk imx_1443x_dram_pll; to_clk(imx_clk_hw_cpu(name, parent_name, div, mux, pll, step)) #define clk_register_gate2(dev, name, parent_name, flags, reg, bit_idx, \ - cgr_val, clk_gate_flags, lock, share_count) \ + cgr_val, cgr_mask, clk_gate_flags, lock, share_count) \ to_clk(clk_hw_register_gate2(dev, name, parent_name, flags, reg, bit_idx, \ - cgr_val, clk_gate_flags, lock, share_count)) + cgr_val, cgr_mask, clk_gate_flags, lock, share_count)) #define imx_clk_pllv3(type, name, parent_name, base, div_mask) \ to_clk(imx_clk_hw_pllv3(type, name, parent_name, base, div_mask)) @@ -196,7 +196,7 @@ struct clk_hw *imx_clk_hw_pllv4(const char *name, const char *parent_name, struct clk_hw *clk_hw_register_gate2(struct device *dev, const char *name, const char *parent_name, unsigned long flags, - void __iomem *reg, u8 bit_idx, u8 cgr_val, + void __iomem *reg, u8 bit_idx, u8 cgr_val, u8 cgr_mask, u8 clk_gate_flags, spinlock_t *lock, unsigned int *share_count); @@ -349,14 +349,14 @@ static inline struct clk_hw *imx_clk_hw_gate2(const char *name, const char *pare void __iomem *reg, u8 shift) { return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg, - shift, 0x3, 0, &imx_ccm_lock, NULL); + shift, 0x3, 0x3, 0, &imx_ccm_lock, NULL); } static inline struct clk_hw *imx_clk_hw_gate2_flags(const char *name, const char *parent, void __iomem *reg, u8 shift, unsigned long flags) { return clk_hw_register_gate2(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg, - shift, 0x3, 0, &imx_ccm_lock, NULL); + shift, 0x3, 0x3, 0, &imx_ccm_lock, NULL); } static inline struct clk_hw *imx_clk_hw_gate2_shared(const char *name, @@ -364,7 +364,7 @@ static inline struct clk_hw *imx_clk_hw_gate2_shared(const char *name, unsigned int *share_count) { return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg, - shift, 0x3, 0, &imx_ccm_lock, share_count); + shift, 0x3, 0x3, 0, &imx_ccm_lock, share_count); } static inline struct clk_hw *imx_clk_hw_gate2_shared2(const char *name, @@ -372,7 +372,7 @@ static inline struct clk_hw *imx_clk_hw_gate2_shared2(const char *name, unsigned int *share_count) { return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT | - CLK_OPS_PARENT_ENABLE, reg, shift, 0x3, 0, + CLK_OPS_PARENT_ENABLE, reg, shift, 0x3, 0x3, 0, &imx_ccm_lock, share_count); } @@ -382,15 +382,15 @@ static inline struct clk_hw *imx_dev_clk_hw_gate_shared(struct device *dev, unsigned int *share_count) { return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT | - CLK_OPS_PARENT_ENABLE, reg, shift, 0x1, 0, - &imx_ccm_lock, share_count); + CLK_OPS_PARENT_ENABLE, reg, shift, 0x1, + 0x1, 0, &imx_ccm_lock, share_count); } static inline struct clk *imx_clk_gate2_cgr(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 cgr_val) { return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg, - shift, cgr_val, 0, &imx_ccm_lock, NULL); + shift, cgr_val, 0x3, 0, &imx_ccm_lock, NULL); } static inline struct clk_hw *imx_clk_hw_gate3(const char *name, const char *parent, @@ -418,7 +418,7 @@ static inline struct clk_hw *imx_clk_hw_gate4(const char *name, const char *pare { return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, - reg, shift, 0x3, 0, &imx_ccm_lock, NULL); + reg, shift, 0x3, 0x3, 0, &imx_ccm_lock, NULL); } static inline struct clk_hw *imx_clk_hw_gate4_flags(const char *name, @@ -427,7 +427,7 @@ static inline struct clk_hw *imx_clk_hw_gate4_flags(const char *name, { return clk_hw_register_gate2(NULL, name, parent, flags | CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, - reg, shift, 0x3, 0, &imx_ccm_lock, NULL); + reg, shift, 0x3, 0x3, 0, &imx_ccm_lock, NULL); } #define imx_clk_gate4_flags(name, parent, reg, shift, flags) \ From 65188f07456d4a65b4a66069a701823878e098ff Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Wed, 28 Oct 2020 14:59:02 +0200 Subject: [PATCH 019/134] clk: imx: gate2: Add locking in is_enabled op Protect against enabling/disabling the gate while we're checking if it is enabled. Signed-off-by: Abel Vesa Reviewed-by: Sascha Hauer Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-gate2.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c index 7e4b5e82de7f..480a184207d5 100644 --- a/drivers/clk/imx/clk-gate2.c +++ b/drivers/clk/imx/clk-gate2.c @@ -101,9 +101,17 @@ static int clk_gate2_reg_is_enabled(void __iomem *reg, u8 bit_idx, static int clk_gate2_is_enabled(struct clk_hw *hw) { struct clk_gate2 *gate = to_clk_gate2(hw); + unsigned long flags; + int ret = 0; - return clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx, + spin_lock_irqsave(gate->lock, flags); + + ret = clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx, gate->cgr_val, gate->cgr_mask); + + spin_unlock_irqrestore(gate->lock, flags); + + return ret; } static void clk_gate2_disable_unused(struct clk_hw *hw) From 9d1c94a69d70f1b02bdf06b231cd16ad47ef06cd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Oct 2020 18:33:25 +0200 Subject: [PATCH 020/134] clk: fix a kernel-doc markup clk_get_duty_cycle -> clk_get_scaled_duty_cycle Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/b2336f3f3cdfe6e1a2d3a7a056ab7ccc7a81b945.1603469755.git.mchehab+huawei@kernel.org Signed-off-by: Stephen Boyd --- include/linux/clk.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/clk.h b/include/linux/clk.h index 7fd6a1febcf4..5f8d5f4931c0 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -150,7 +150,7 @@ int clk_get_phase(struct clk *clk); int clk_set_duty_cycle(struct clk *clk, unsigned int num, unsigned int den); /** - * clk_get_duty_cycle - return the duty cycle ratio of a clock signal + * clk_get_scaled_duty_cycle - return the duty cycle ratio of a clock signal * @clk: clock signal source * @scale: scaling factor to be applied to represent the ratio as an integer * From 61a31292002b85529021a46e6288b29caf674fbe Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Sat, 17 Oct 2020 00:13:32 +0530 Subject: [PATCH 021/134] clk: qcom: clk-alpha-pll: Add support for helper functions Introduce clk_alpha_pll_write_config and alpha_pll_check_rate_margin helper functions to be across PLL configure functions and PLL set rate functions. Signed-off-by: Taniya Das Link: https://lore.kernel.org/r/1602873815-1677-2-git-send-email-tdas@codeaurora.org Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-alpha-pll.c | 155 +++++++++++++------------------ 1 file changed, 66 insertions(+), 89 deletions(-) diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index 564431130a76..f3b8b54fefd5 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -207,6 +207,13 @@ static int wait_for_pll(struct clk_alpha_pll *pll, u32 mask, bool inverse, #define wait_for_pll_update_ack_clear(pll) \ wait_for_pll(pll, ALPHA_PLL_ACK_LATCH, 1, "update_ack_clear") +static void clk_alpha_pll_write_config(struct regmap *regmap, unsigned int reg, + unsigned int val) +{ + if (val) + regmap_write(regmap, reg, val); +} + void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct alpha_pll_config *config) { @@ -1004,33 +1011,19 @@ void clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, { u32 val, mask; - if (config->l) - regmap_write(regmap, PLL_L_VAL(pll), config->l); - - if (config->alpha) - regmap_write(regmap, PLL_FRAC(pll), config->alpha); - - if (config->config_ctl_val) - regmap_write(regmap, PLL_CONFIG_CTL(pll), + clk_alpha_pll_write_config(regmap, PLL_L_VAL(pll), config->l); + clk_alpha_pll_write_config(regmap, PLL_FRAC(pll), config->alpha); + clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL(pll), config->config_ctl_val); - - if (config->config_ctl_hi_val) - regmap_write(regmap, PLL_CONFIG_CTL_U(pll), + clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U(pll), config->config_ctl_hi_val); - - if (config->user_ctl_val) - regmap_write(regmap, PLL_USER_CTL(pll), config->user_ctl_val); - - if (config->user_ctl_hi_val) - regmap_write(regmap, PLL_USER_CTL_U(pll), + clk_alpha_pll_write_config(regmap, PLL_USER_CTL(pll), + config->user_ctl_val); + clk_alpha_pll_write_config(regmap, PLL_USER_CTL_U(pll), config->user_ctl_hi_val); - - if (config->test_ctl_val) - regmap_write(regmap, PLL_TEST_CTL(pll), + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL(pll), config->test_ctl_val); - - if (config->test_ctl_hi_val) - regmap_write(regmap, PLL_TEST_CTL_U(pll), + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U(pll), config->test_ctl_hi_val); if (config->post_div_mask) { @@ -1145,25 +1138,38 @@ static unsigned long alpha_pll_fabia_recalc_rate(struct clk_hw *hw, return alpha_pll_calc_rate(parent_rate, l, frac, alpha_width); } +/* + * Due to limited number of bits for fractional rate programming, the + * rounded up rate could be marginally higher than the requested rate. + */ +static int alpha_pll_check_rate_margin(struct clk_hw *hw, + unsigned long rrate, unsigned long rate) +{ + unsigned long rate_margin = rate + PLL_RATE_MARGIN; + + if (rrate > rate_margin || rrate < rate) { + pr_err("%s: Rounded rate %lu not within range [%lu, %lu)\n", + clk_hw_get_name(hw), rrate, rate, rate_margin); + return -EINVAL; + } + + return 0; +} + static int alpha_pll_fabia_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate) { struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); u32 l, alpha_width = pll_alpha_width(pll); + unsigned long rrate; + int ret; u64 a; - unsigned long rrate, max = rate + PLL_RATE_MARGIN; rrate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width); - /* - * Due to limited number of bits for fractional rate programming, the - * rounded up rate could be marginally higher than the requested rate. - */ - if (rrate > (rate + PLL_RATE_MARGIN) || rrate < rate) { - pr_err("%s: Rounded rate %lu not within range [%lu, %lu)\n", - clk_hw_get_name(hw), rrate, rate, max); - return -EINVAL; - } + ret = alpha_pll_check_rate_margin(hw, rrate, rate); + if (ret < 0) + return ret; regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l); regmap_write(pll->clkr.regmap, PLL_FRAC(pll), a); @@ -1206,12 +1212,10 @@ static int alpha_pll_fabia_prepare(struct clk_hw *hw) rrate = alpha_pll_round_rate(cal_freq, clk_hw_get_rate(parent_hw), &cal_l, &a, alpha_width); - /* - * Due to a limited number of bits for fractional rate programming, the - * rounded up rate could be marginally higher than the requested rate. - */ - if (rrate > (cal_freq + PLL_RATE_MARGIN) || rrate < cal_freq) - return -EINVAL; + + ret = alpha_pll_check_rate_margin(hw, rrate, cal_freq); + if (ret < 0) + return ret; /* Setup PLL for calibration frequency */ regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), cal_l); @@ -1388,49 +1392,27 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_fabia_ops); void clk_trion_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct alpha_pll_config *config) { - if (config->l) - regmap_write(regmap, PLL_L_VAL(pll), config->l); - + clk_alpha_pll_write_config(regmap, PLL_L_VAL(pll), config->l); regmap_write(regmap, PLL_CAL_L_VAL(pll), TRION_PLL_CAL_VAL); - - if (config->alpha) - regmap_write(regmap, PLL_ALPHA_VAL(pll), config->alpha); - - if (config->config_ctl_val) - regmap_write(regmap, PLL_CONFIG_CTL(pll), - config->config_ctl_val); - - if (config->config_ctl_hi_val) - regmap_write(regmap, PLL_CONFIG_CTL_U(pll), - config->config_ctl_hi_val); - - if (config->config_ctl_hi1_val) - regmap_write(regmap, PLL_CONFIG_CTL_U1(pll), - config->config_ctl_hi1_val); - - if (config->user_ctl_val) - regmap_write(regmap, PLL_USER_CTL(pll), - config->user_ctl_val); - - if (config->user_ctl_hi_val) - regmap_write(regmap, PLL_USER_CTL_U(pll), - config->user_ctl_hi_val); - - if (config->user_ctl_hi1_val) - regmap_write(regmap, PLL_USER_CTL_U1(pll), - config->user_ctl_hi1_val); - - if (config->test_ctl_val) - regmap_write(regmap, PLL_TEST_CTL(pll), - config->test_ctl_val); - - if (config->test_ctl_hi_val) - regmap_write(regmap, PLL_TEST_CTL_U(pll), - config->test_ctl_hi_val); - - if (config->test_ctl_hi1_val) - regmap_write(regmap, PLL_TEST_CTL_U1(pll), - config->test_ctl_hi1_val); + clk_alpha_pll_write_config(regmap, PLL_ALPHA_VAL(pll), config->alpha); + clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL(pll), + config->config_ctl_val); + clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U(pll), + config->config_ctl_hi_val); + clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U1(pll), + config->config_ctl_hi1_val); + clk_alpha_pll_write_config(regmap, PLL_USER_CTL(pll), + config->user_ctl_val); + clk_alpha_pll_write_config(regmap, PLL_USER_CTL_U(pll), + config->user_ctl_hi_val); + clk_alpha_pll_write_config(regmap, PLL_USER_CTL_U1(pll), + config->user_ctl_hi1_val); + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL(pll), + config->test_ctl_val); + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U(pll), + config->test_ctl_hi_val); + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U1(pll), + config->test_ctl_hi1_val); regmap_update_bits(regmap, PLL_MODE(pll), PLL_UPDATE_BYPASS, PLL_UPDATE_BYPASS); @@ -1490,14 +1472,9 @@ static int alpha_pll_trion_set_rate(struct clk_hw *hw, unsigned long rate, rrate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width); - /* - * Due to a limited number of bits for fractional rate programming, the - * rounded up rate could be marginally higher than the requested rate. - */ - if (rrate > (rate + PLL_RATE_MARGIN) || rrate < rate) { - pr_err("Call set rate on the PLL with rounded rates!\n"); - return -EINVAL; - } + ret = alpha_pll_check_rate_margin(hw, rrate, rate); + if (ret < 0) + return ret; regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l); regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a); From a2b57943a570a69679abf82e1de01c806db084d1 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Sat, 17 Oct 2020 00:13:33 +0530 Subject: [PATCH 022/134] clk: qcom: clk-alpha-pll: Add support for controlling Agera PLLs Add programming sequence support for managing the Agera PLLs. Signed-off-by: Taniya Das Link: https://lore.kernel.org/r/1602873815-1677-3-git-send-email-tdas@codeaurora.org Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-alpha-pll.c | 62 ++++++++++++++++++++++++++++++++ drivers/clk/qcom/clk-alpha-pll.h | 4 +++ 2 files changed, 66 insertions(+) diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index f3b8b54fefd5..21c357c26ec4 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -116,6 +116,16 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { [PLL_OFF_OPMODE] = 0x38, [PLL_OFF_ALPHA_VAL] = 0x40, }, + [CLK_ALPHA_PLL_TYPE_AGERA] = { + [PLL_OFF_L_VAL] = 0x04, + [PLL_OFF_ALPHA_VAL] = 0x08, + [PLL_OFF_USER_CTL] = 0x0c, + [PLL_OFF_CONFIG_CTL] = 0x10, + [PLL_OFF_CONFIG_CTL_U] = 0x14, + [PLL_OFF_TEST_CTL] = 0x18, + [PLL_OFF_TEST_CTL_U] = 0x1c, + [PLL_OFF_STATUS] = 0x2c, + }, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_regs); @@ -1538,3 +1548,55 @@ const struct clk_ops clk_alpha_pll_postdiv_lucid_ops = { .set_rate = clk_alpha_pll_postdiv_fabia_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_lucid_ops); + +void clk_agera_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, + const struct alpha_pll_config *config) +{ + clk_alpha_pll_write_config(regmap, PLL_L_VAL(pll), config->l); + clk_alpha_pll_write_config(regmap, PLL_ALPHA_VAL(pll), config->alpha); + clk_alpha_pll_write_config(regmap, PLL_USER_CTL(pll), + config->user_ctl_val); + clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL(pll), + config->config_ctl_val); + clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U(pll), + config->config_ctl_hi_val); + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL(pll), + config->test_ctl_val); + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U(pll), + config->test_ctl_hi_val); +} +EXPORT_SYMBOL_GPL(clk_agera_pll_configure); + +static int clk_alpha_pll_agera_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long prate) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 l, alpha_width = pll_alpha_width(pll); + int ret; + unsigned long rrate; + u64 a; + + rrate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width); + ret = alpha_pll_check_rate_margin(hw, rrate, rate); + if (ret < 0) + return ret; + + /* change L_VAL without having to go through the power on sequence */ + regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l); + regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a); + + if (clk_hw_is_enabled(hw)) + return wait_for_pll_enable_lock(pll); + + return 0; +} + +const struct clk_ops clk_alpha_pll_agera_ops = { + .enable = clk_alpha_pll_enable, + .disable = clk_alpha_pll_disable, + .is_enabled = clk_alpha_pll_is_enabled, + .recalc_rate = alpha_pll_fabia_recalc_rate, + .round_rate = clk_alpha_pll_round_rate, + .set_rate = clk_alpha_pll_agera_set_rate, +}; +EXPORT_SYMBOL_GPL(clk_alpha_pll_agera_ops); diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h index d3201b87c0cd..0ea30d2f3da1 100644 --- a/drivers/clk/qcom/clk-alpha-pll.h +++ b/drivers/clk/qcom/clk-alpha-pll.h @@ -15,6 +15,7 @@ enum { CLK_ALPHA_PLL_TYPE_FABIA, CLK_ALPHA_PLL_TYPE_TRION, CLK_ALPHA_PLL_TYPE_LUCID = CLK_ALPHA_PLL_TYPE_TRION, + CLK_ALPHA_PLL_TYPE_AGERA, CLK_ALPHA_PLL_TYPE_MAX, }; @@ -141,6 +142,7 @@ extern const struct clk_ops clk_alpha_pll_postdiv_trion_ops; extern const struct clk_ops clk_alpha_pll_lucid_ops; #define clk_alpha_pll_fixed_lucid_ops clk_alpha_pll_fixed_trion_ops extern const struct clk_ops clk_alpha_pll_postdiv_lucid_ops; +extern const struct clk_ops clk_alpha_pll_agera_ops; void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct alpha_pll_config *config); @@ -148,6 +150,8 @@ void clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct alpha_pll_config *config); void clk_trion_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct alpha_pll_config *config); +void clk_agera_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, + const struct alpha_pll_config *config); #define clk_lucid_pll_configure(pll, regmap, config) \ clk_trion_pll_configure(pll, regmap, config) From 57b971907eb07fbc8917f9f7a2df37da6304a296 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Sat, 17 Oct 2020 00:13:34 +0530 Subject: [PATCH 023/134] dt-bindings: clock: Add YAML schemas for the QCOM Camera clock bindings. The Camera Subsystem clock provider have a bunch of generic properties that are needed in a device tree. Add a YAML schemas for those. Add clock ids for camera clocks which are required to bring the camera subsystem out of reset. Signed-off-by: Taniya Das Link: https://lore.kernel.org/r/1602873815-1677-4-git-send-email-tdas@codeaurora.org Reviewed-by: Rob Herring Signed-off-by: Stephen Boyd --- .../bindings/clock/qcom,sc7180-camcc.yaml | 73 +++++++++++ include/dt-bindings/clock/qcom,camcc-sc7180.h | 121 ++++++++++++++++++ 2 files changed, 194 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,sc7180-camcc.yaml create mode 100644 include/dt-bindings/clock/qcom,camcc-sc7180.h diff --git a/Documentation/devicetree/bindings/clock/qcom,sc7180-camcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sc7180-camcc.yaml new file mode 100644 index 000000000000..f49027edfc44 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,sc7180-camcc.yaml @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,sc7180-camcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Camera Clock & Reset Controller Binding for SC7180 + +maintainers: + - Taniya Das + +description: | + Qualcomm camera clock control module which supports the clocks, resets and + power domains on SC7180. + + See also: + - dt-bindings/clock/qcom,camcc-sc7180.h + +properties: + compatible: + const: qcom,sc7180-camcc + + clocks: + items: + - description: Board XO source + - description: Camera_ahb clock from GCC + - description: Camera XO clock from GCC + + clock-names: + items: + - const: bi_tcxo + - const: iface + - const: xo + + '#clock-cells': + const: 1 + + '#reset-cells': + const: 1 + + '#power-domain-cells': + const: 1 + + reg: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - clock-names + - '#clock-cells' + - '#reset-cells' + - '#power-domain-cells' + +additionalProperties: false + +examples: + - | + #include + #include + clock-controller@ad00000 { + compatible = "qcom,sc7180-camcc"; + reg = <0x0ad00000 0x10000>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_CAMERA_AHB_CLK>, + <&gcc GCC_CAMERA_XO_CLK>; + clock-names = "bi_tcxo", "iface", "xo"; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; +... diff --git a/include/dt-bindings/clock/qcom,camcc-sc7180.h b/include/dt-bindings/clock/qcom,camcc-sc7180.h new file mode 100644 index 000000000000..ef7d3a041b88 --- /dev/null +++ b/include/dt-bindings/clock/qcom,camcc-sc7180.h @@ -0,0 +1,121 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _DT_BINDINGS_CLK_QCOM_CAM_CC_SC7180_H +#define _DT_BINDINGS_CLK_QCOM_CAM_CC_SC7180_H + +/* CAM_CC clocks */ +#define CAM_CC_PLL2_OUT_EARLY 0 +#define CAM_CC_PLL0 1 +#define CAM_CC_PLL1 2 +#define CAM_CC_PLL2 3 +#define CAM_CC_PLL2_OUT_AUX 4 +#define CAM_CC_PLL3 5 +#define CAM_CC_CAMNOC_AXI_CLK 6 +#define CAM_CC_CCI_0_CLK 7 +#define CAM_CC_CCI_0_CLK_SRC 8 +#define CAM_CC_CCI_1_CLK 9 +#define CAM_CC_CCI_1_CLK_SRC 10 +#define CAM_CC_CORE_AHB_CLK 11 +#define CAM_CC_CPAS_AHB_CLK 12 +#define CAM_CC_CPHY_RX_CLK_SRC 13 +#define CAM_CC_CSI0PHYTIMER_CLK 14 +#define CAM_CC_CSI0PHYTIMER_CLK_SRC 15 +#define CAM_CC_CSI1PHYTIMER_CLK 16 +#define CAM_CC_CSI1PHYTIMER_CLK_SRC 17 +#define CAM_CC_CSI2PHYTIMER_CLK 18 +#define CAM_CC_CSI2PHYTIMER_CLK_SRC 19 +#define CAM_CC_CSI3PHYTIMER_CLK 20 +#define CAM_CC_CSI3PHYTIMER_CLK_SRC 21 +#define CAM_CC_CSIPHY0_CLK 22 +#define CAM_CC_CSIPHY1_CLK 23 +#define CAM_CC_CSIPHY2_CLK 24 +#define CAM_CC_CSIPHY3_CLK 25 +#define CAM_CC_FAST_AHB_CLK_SRC 26 +#define CAM_CC_ICP_APB_CLK 27 +#define CAM_CC_ICP_ATB_CLK 28 +#define CAM_CC_ICP_CLK 29 +#define CAM_CC_ICP_CLK_SRC 30 +#define CAM_CC_ICP_CTI_CLK 31 +#define CAM_CC_ICP_TS_CLK 32 +#define CAM_CC_IFE_0_AXI_CLK 33 +#define CAM_CC_IFE_0_CLK 34 +#define CAM_CC_IFE_0_CLK_SRC 35 +#define CAM_CC_IFE_0_CPHY_RX_CLK 36 +#define CAM_CC_IFE_0_CSID_CLK 37 +#define CAM_CC_IFE_0_CSID_CLK_SRC 38 +#define CAM_CC_IFE_0_DSP_CLK 39 +#define CAM_CC_IFE_1_AXI_CLK 40 +#define CAM_CC_IFE_1_CLK 41 +#define CAM_CC_IFE_1_CLK_SRC 42 +#define CAM_CC_IFE_1_CPHY_RX_CLK 43 +#define CAM_CC_IFE_1_CSID_CLK 44 +#define CAM_CC_IFE_1_CSID_CLK_SRC 45 +#define CAM_CC_IFE_1_DSP_CLK 46 +#define CAM_CC_IFE_LITE_CLK 47 +#define CAM_CC_IFE_LITE_CLK_SRC 48 +#define CAM_CC_IFE_LITE_CPHY_RX_CLK 49 +#define CAM_CC_IFE_LITE_CSID_CLK 50 +#define CAM_CC_IFE_LITE_CSID_CLK_SRC 51 +#define CAM_CC_IPE_0_AHB_CLK 52 +#define CAM_CC_IPE_0_AREG_CLK 53 +#define CAM_CC_IPE_0_AXI_CLK 54 +#define CAM_CC_IPE_0_CLK 55 +#define CAM_CC_IPE_0_CLK_SRC 56 +#define CAM_CC_JPEG_CLK 57 +#define CAM_CC_JPEG_CLK_SRC 58 +#define CAM_CC_LRME_CLK 59 +#define CAM_CC_LRME_CLK_SRC 60 +#define CAM_CC_MCLK0_CLK 61 +#define CAM_CC_MCLK0_CLK_SRC 62 +#define CAM_CC_MCLK1_CLK 63 +#define CAM_CC_MCLK1_CLK_SRC 64 +#define CAM_CC_MCLK2_CLK 65 +#define CAM_CC_MCLK2_CLK_SRC 66 +#define CAM_CC_MCLK3_CLK 67 +#define CAM_CC_MCLK3_CLK_SRC 68 +#define CAM_CC_MCLK4_CLK 69 +#define CAM_CC_MCLK4_CLK_SRC 70 +#define CAM_CC_BPS_AHB_CLK 71 +#define CAM_CC_BPS_AREG_CLK 72 +#define CAM_CC_BPS_AXI_CLK 73 +#define CAM_CC_BPS_CLK 74 +#define CAM_CC_BPS_CLK_SRC 75 +#define CAM_CC_SLOW_AHB_CLK_SRC 76 +#define CAM_CC_SOC_AHB_CLK 77 +#define CAM_CC_SYS_TMR_CLK 78 + +/* CAM_CC power domains */ +#define BPS_GDSC 0 +#define IFE_0_GDSC 1 +#define IFE_1_GDSC 2 +#define IPE_0_GDSC 3 +#define TITAN_TOP_GDSC 4 + +/* CAM_CC resets */ +#define CAM_CC_BPS_BCR 0 +#define CAM_CC_CAMNOC_BCR 1 +#define CAM_CC_CCI_0_BCR 2 +#define CAM_CC_CCI_1_BCR 3 +#define CAM_CC_CPAS_BCR 4 +#define CAM_CC_CSI0PHY_BCR 5 +#define CAM_CC_CSI1PHY_BCR 6 +#define CAM_CC_CSI2PHY_BCR 7 +#define CAM_CC_CSI3PHY_BCR 8 +#define CAM_CC_ICP_BCR 9 +#define CAM_CC_IFE_0_BCR 10 +#define CAM_CC_IFE_1_BCR 11 +#define CAM_CC_IFE_LITE_BCR 12 +#define CAM_CC_IPE_0_BCR 13 +#define CAM_CC_JPEG_BCR 14 +#define CAM_CC_LRME_BCR 15 +#define CAM_CC_MCLK0_BCR 16 +#define CAM_CC_MCLK1_BCR 17 +#define CAM_CC_MCLK2_BCR 18 +#define CAM_CC_MCLK3_BCR 19 +#define CAM_CC_MCLK4_BCR 20 +#define CAM_CC_TITAN_TOP_BCR 21 + +#endif From 15d09e830bbc16880840ac8b01941465602807f4 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Sat, 17 Oct 2020 00:13:35 +0530 Subject: [PATCH 024/134] clk: qcom: camcc: Add camera clock controller driver for SC7180 Add support for the camera clock controller found on SC7180 based devices. This would allow camera drivers to probe and control their clocks. Signed-off-by: Taniya Das Link: https://lore.kernel.org/r/1602873815-1677-5-git-send-email-tdas@codeaurora.org [sboyd@kernel.org: Mark hw array static, add UL to big vco numbers] Signed-off-by: Stephen Boyd --- drivers/clk/qcom/Kconfig | 9 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/camcc-sc7180.c | 1736 +++++++++++++++++++++++++++++++ 3 files changed, 1746 insertions(+) create mode 100644 drivers/clk/qcom/camcc-sc7180.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 3a965bd326d5..886e8610b321 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -290,6 +290,15 @@ config QCS_GCC_404 Say Y if you want to use multimedia devices or peripheral devices such as UART, SPI, I2C, USB, SD/eMMC, PCIe etc. +config SC_CAMCC_7180 + tristate "SC7180 Camera Clock Controller" + select SC_GCC_7180 + help + Support for the camera clock controller on Qualcomm Technologies, Inc + SC7180 devices. + Say Y if you want to support camera devices and functionality such as + capturing pictures. + config SC_DISPCC_7180 tristate "SC7180 Display Clock Controller" select SC_GCC_7180 diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 11ae86febe87..ee02fafbae27 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o obj-$(CONFIG_QCS_GCC_404) += gcc-qcs404.o obj-$(CONFIG_QCS_Q6SSTOP_404) += q6sstop-qcs404.o obj-$(CONFIG_QCS_TURING_404) += turingcc-qcs404.o +obj-$(CONFIG_SC_CAMCC_7180) += camcc-sc7180.o obj-$(CONFIG_SC_DISPCC_7180) += dispcc-sc7180.o obj-$(CONFIG_SC_GCC_7180) += gcc-sc7180.o obj-$(CONFIG_SC_GPUCC_7180) += gpucc-sc7180.o diff --git a/drivers/clk/qcom/camcc-sc7180.c b/drivers/clk/qcom/camcc-sc7180.c new file mode 100644 index 000000000000..f51bf5b6decc --- /dev/null +++ b/drivers/clk/qcom/camcc-sc7180.c @@ -0,0 +1,1736 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "common.h" +#include "gdsc.h" +#include "reset.h" + +enum { + P_BI_TCXO, + P_CAM_CC_PLL0_OUT_EVEN, + P_CAM_CC_PLL1_OUT_EVEN, + P_CAM_CC_PLL2_OUT_AUX, + P_CAM_CC_PLL2_OUT_EARLY, + P_CAM_CC_PLL3_OUT_MAIN, + P_CORE_BI_PLL_TEST_SE, +}; + +static const struct pll_vco agera_vco[] = { + { 600000000, 3300000000UL, 0 }, +}; + +static const struct pll_vco fabia_vco[] = { + { 249600000, 2000000000UL, 0 }, +}; + +/* 600MHz configuration */ +static const struct alpha_pll_config cam_cc_pll0_config = { + .l = 0x1f, + .alpha = 0x4000, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002067, + .test_ctl_val = 0x40000000, + .user_ctl_hi_val = 0x00004805, + .user_ctl_val = 0x00000001, +}; + +static struct clk_alpha_pll cam_cc_pll0 = { + .offset = 0x0, + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_pll0", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "bi_tcxo", + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fabia_ops, + }, + }, +}; + +/* 860MHz configuration */ +static const struct alpha_pll_config cam_cc_pll1_config = { + .l = 0x2a, + .alpha = 0x1555, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002067, + .test_ctl_val = 0x40000000, + .user_ctl_hi_val = 0x00004805, +}; + +static struct clk_alpha_pll cam_cc_pll1 = { + .offset = 0x1000, + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_pll1", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "bi_tcxo", + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fabia_ops, + }, + }, +}; + +/* 1920MHz configuration */ +static const struct alpha_pll_config cam_cc_pll2_config = { + .l = 0x64, + .config_ctl_val = 0x20000800, + .config_ctl_hi_val = 0x400003D2, + .test_ctl_val = 0x04000400, + .test_ctl_hi_val = 0x00004000, + .user_ctl_val = 0x0000030F, +}; + +static struct clk_alpha_pll cam_cc_pll2 = { + .offset = 0x2000, + .vco_table = agera_vco, + .num_vco = ARRAY_SIZE(agera_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_AGERA], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_pll2", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "bi_tcxo", + }, + .num_parents = 1, + .ops = &clk_alpha_pll_agera_ops, + }, + }, +}; + +static struct clk_fixed_factor cam_cc_pll2_out_early = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_pll2_out_early", + .parent_names = (const char *[]){ "cam_cc_pll2" }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static const struct clk_div_table post_div_table_cam_cc_pll2_out_aux[] = { + { 0x3, 4 }, + { } +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll2_out_aux = { + .offset = 0x2000, + .post_div_shift = 8, + .post_div_table = post_div_table_cam_cc_pll2_out_aux, + .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll2_out_aux), + .width = 2, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_AGERA], + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_pll2_out_aux", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_pll2.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_ops, + }, +}; + +/* 1080MHz configuration */ +static const struct alpha_pll_config cam_cc_pll3_config = { + .l = 0x38, + .alpha = 0x4000, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002067, + .test_ctl_val = 0x40000000, + .user_ctl_hi_val = 0x00004805, +}; + +static struct clk_alpha_pll cam_cc_pll3 = { + .offset = 0x3000, + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_pll3", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "bi_tcxo", + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fabia_ops, + }, + }, +}; + +static const struct parent_map cam_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL1_OUT_EVEN, 2 }, + { P_CAM_CC_PLL0_OUT_EVEN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_0[] = { + { .fw_name = "bi_tcxo" }, + { .hw = &cam_cc_pll1.clkr.hw }, + { .hw = &cam_cc_pll0.clkr.hw }, + { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" }, +}; + +static const struct parent_map cam_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL2_OUT_AUX, 1 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_1[] = { + { .fw_name = "bi_tcxo" }, + { .hw = &cam_cc_pll2_out_aux.clkr.hw }, + { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" }, +}; + +static const struct parent_map cam_cc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL2_OUT_EARLY, 4 }, + { P_CAM_CC_PLL3_OUT_MAIN, 5 }, + { P_CAM_CC_PLL0_OUT_EVEN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_2[] = { + { .fw_name = "bi_tcxo" }, + { .hw = &cam_cc_pll2_out_early.hw }, + { .hw = &cam_cc_pll3.clkr.hw }, + { .hw = &cam_cc_pll0.clkr.hw }, + { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" }, +}; + +static const struct parent_map cam_cc_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL1_OUT_EVEN, 2 }, + { P_CAM_CC_PLL2_OUT_EARLY, 4 }, + { P_CAM_CC_PLL3_OUT_MAIN, 5 }, + { P_CAM_CC_PLL0_OUT_EVEN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_3[] = { + { .fw_name = "bi_tcxo" }, + { .hw = &cam_cc_pll1.clkr.hw }, + { .hw = &cam_cc_pll2_out_early.hw }, + { .hw = &cam_cc_pll3.clkr.hw }, + { .hw = &cam_cc_pll0.clkr.hw }, + { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" }, +}; + +static const struct parent_map cam_cc_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL3_OUT_MAIN, 5 }, + { P_CAM_CC_PLL0_OUT_EVEN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_4[] = { + { .fw_name = "bi_tcxo" }, + { .hw = &cam_cc_pll3.clkr.hw }, + { .hw = &cam_cc_pll0.clkr.hw }, + { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" }, +}; + +static const struct parent_map cam_cc_parent_map_5[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL0_OUT_EVEN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_5[] = { + { .fw_name = "bi_tcxo" }, + { .hw = &cam_cc_pll0.clkr.hw }, + { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" }, +}; + +static const struct parent_map cam_cc_parent_map_6[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL1_OUT_EVEN, 2 }, + { P_CAM_CC_PLL3_OUT_MAIN, 5 }, + { P_CAM_CC_PLL0_OUT_EVEN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_6[] = { + { .fw_name = "bi_tcxo" }, + { .hw = &cam_cc_pll1.clkr.hw }, + { .hw = &cam_cc_pll3.clkr.hw }, + { .hw = &cam_cc_pll0.clkr.hw }, + { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" }, +}; + +static const struct freq_tbl ftbl_cam_cc_bps_clk_src[] = { + F(200000000, P_CAM_CC_PLL0_OUT_EVEN, 3, 0, 0), + F(360000000, P_CAM_CC_PLL3_OUT_MAIN, 3, 0, 0), + F(432000000, P_CAM_CC_PLL3_OUT_MAIN, 2.5, 0, 0), + F(480000000, P_CAM_CC_PLL2_OUT_EARLY, 2, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_bps_clk_src = { + .cmd_rcgr = 0x6010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_2, + .freq_tbl = ftbl_cam_cc_bps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_bps_clk_src", + .parent_data = cam_cc_parent_data_2, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_cci_0_clk_src[] = { + F(37500000, P_CAM_CC_PLL0_OUT_EVEN, 16, 0, 0), + F(50000000, P_CAM_CC_PLL0_OUT_EVEN, 12, 0, 0), + F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_cci_0_clk_src = { + .cmd_rcgr = 0xb0d8, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_5, + .freq_tbl = ftbl_cam_cc_cci_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_cci_0_clk_src", + .parent_data = cam_cc_parent_data_5, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 cam_cc_cci_1_clk_src = { + .cmd_rcgr = 0xb14c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_5, + .freq_tbl = ftbl_cam_cc_cci_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_cci_1_clk_src", + .parent_data = cam_cc_parent_data_5, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_cphy_rx_clk_src[] = { + F(150000000, P_CAM_CC_PLL0_OUT_EVEN, 4, 0, 0), + F(270000000, P_CAM_CC_PLL3_OUT_MAIN, 4, 0, 0), + F(360000000, P_CAM_CC_PLL3_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_cphy_rx_clk_src = { + .cmd_rcgr = 0x9064, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_3, + .freq_tbl = ftbl_cam_cc_cphy_rx_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_cphy_rx_clk_src", + .parent_data = cam_cc_parent_data_3, + .num_parents = 6, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_csi0phytimer_clk_src[] = { + F(300000000, P_CAM_CC_PLL0_OUT_EVEN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_csi0phytimer_clk_src = { + .cmd_rcgr = 0x5004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi0phytimer_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 cam_cc_csi1phytimer_clk_src = { + .cmd_rcgr = 0x5028, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi1phytimer_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 cam_cc_csi2phytimer_clk_src = { + .cmd_rcgr = 0x504c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi2phytimer_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 cam_cc_csi3phytimer_clk_src = { + .cmd_rcgr = 0x5070, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi3phytimer_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_fast_ahb_clk_src[] = { + F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0), + F(200000000, P_CAM_CC_PLL0_OUT_EVEN, 3, 0, 0), + F(300000000, P_CAM_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(404000000, P_CAM_CC_PLL1_OUT_EVEN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_fast_ahb_clk_src = { + .cmd_rcgr = 0x603c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_fast_ahb_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_fast_ahb_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_icp_clk_src[] = { + F(240000000, P_CAM_CC_PLL0_OUT_EVEN, 2.5, 0, 0), + F(360000000, P_CAM_CC_PLL3_OUT_MAIN, 3, 0, 0), + F(432000000, P_CAM_CC_PLL3_OUT_MAIN, 2.5, 0, 0), + F(480000000, P_CAM_CC_PLL2_OUT_EARLY, 2, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_icp_clk_src = { + .cmd_rcgr = 0xb088, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_2, + .freq_tbl = ftbl_cam_cc_icp_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_icp_clk_src", + .parent_data = cam_cc_parent_data_2, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_ife_0_clk_src[] = { + F(240000000, P_CAM_CC_PLL0_OUT_EVEN, 2.5, 0, 0), + F(360000000, P_CAM_CC_PLL3_OUT_MAIN, 3, 0, 0), + F(432000000, P_CAM_CC_PLL3_OUT_MAIN, 2.5, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_ife_0_clk_src = { + .cmd_rcgr = 0x9010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_4, + .freq_tbl = ftbl_cam_cc_ife_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_0_clk_src", + .parent_data = cam_cc_parent_data_4, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_ife_0_csid_clk_src[] = { + F(150000000, P_CAM_CC_PLL0_OUT_EVEN, 4, 0, 0), + F(270000000, P_CAM_CC_PLL3_OUT_MAIN, 4, 0, 0), + F(360000000, P_CAM_CC_PLL3_OUT_MAIN, 3, 0, 0), + F(480000000, P_CAM_CC_PLL2_OUT_EARLY, 2, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_ife_0_csid_clk_src = { + .cmd_rcgr = 0x903c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_3, + .freq_tbl = ftbl_cam_cc_ife_0_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_0_csid_clk_src", + .parent_data = cam_cc_parent_data_3, + .num_parents = 6, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 cam_cc_ife_1_clk_src = { + .cmd_rcgr = 0xa010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_4, + .freq_tbl = ftbl_cam_cc_ife_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_1_clk_src", + .parent_data = cam_cc_parent_data_4, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 cam_cc_ife_1_csid_clk_src = { + .cmd_rcgr = 0xa034, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_3, + .freq_tbl = ftbl_cam_cc_ife_0_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_1_csid_clk_src", + .parent_data = cam_cc_parent_data_3, + .num_parents = 6, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 cam_cc_ife_lite_clk_src = { + .cmd_rcgr = 0xb004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_4, + .freq_tbl = ftbl_cam_cc_ife_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_lite_clk_src", + .parent_data = cam_cc_parent_data_4, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 cam_cc_ife_lite_csid_clk_src = { + .cmd_rcgr = 0xb024, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_3, + .freq_tbl = ftbl_cam_cc_ife_0_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_lite_csid_clk_src", + .parent_data = cam_cc_parent_data_3, + .num_parents = 6, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_ipe_0_clk_src[] = { + F(240000000, P_CAM_CC_PLL0_OUT_EVEN, 2.5, 0, 0), + F(360000000, P_CAM_CC_PLL3_OUT_MAIN, 3, 0, 0), + F(432000000, P_CAM_CC_PLL3_OUT_MAIN, 2.5, 0, 0), + F(540000000, P_CAM_CC_PLL3_OUT_MAIN, 2, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_ipe_0_clk_src = { + .cmd_rcgr = 0x7010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_2, + .freq_tbl = ftbl_cam_cc_ipe_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_0_clk_src", + .parent_data = cam_cc_parent_data_2, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_jpeg_clk_src[] = { + F(66666667, P_CAM_CC_PLL0_OUT_EVEN, 9, 0, 0), + F(133333333, P_CAM_CC_PLL0_OUT_EVEN, 4.5, 0, 0), + F(216000000, P_CAM_CC_PLL3_OUT_MAIN, 5, 0, 0), + F(320000000, P_CAM_CC_PLL2_OUT_EARLY, 3, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_jpeg_clk_src = { + .cmd_rcgr = 0xb04c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_2, + .freq_tbl = ftbl_cam_cc_jpeg_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_jpeg_clk_src", + .parent_data = cam_cc_parent_data_2, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_lrme_clk_src[] = { + F(200000000, P_CAM_CC_PLL0_OUT_EVEN, 3, 0, 0), + F(216000000, P_CAM_CC_PLL3_OUT_MAIN, 5, 0, 0), + F(300000000, P_CAM_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(404000000, P_CAM_CC_PLL1_OUT_EVEN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_lrme_clk_src = { + .cmd_rcgr = 0xb0f8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_6, + .freq_tbl = ftbl_cam_cc_lrme_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_lrme_clk_src", + .parent_data = cam_cc_parent_data_6, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_mclk0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(24000000, P_CAM_CC_PLL2_OUT_AUX, 10, 1, 2), + F(64000000, P_CAM_CC_PLL2_OUT_AUX, 7.5, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_mclk0_clk_src = { + .cmd_rcgr = 0x4004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_1, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk0_clk_src", + .parent_data = cam_cc_parent_data_1, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 cam_cc_mclk1_clk_src = { + .cmd_rcgr = 0x4024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_1, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk1_clk_src", + .parent_data = cam_cc_parent_data_1, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 cam_cc_mclk2_clk_src = { + .cmd_rcgr = 0x4044, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_1, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk2_clk_src", + .parent_data = cam_cc_parent_data_1, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 cam_cc_mclk3_clk_src = { + .cmd_rcgr = 0x4064, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_1, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk3_clk_src", + .parent_data = cam_cc_parent_data_1, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 cam_cc_mclk4_clk_src = { + .cmd_rcgr = 0x4084, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_1, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk4_clk_src", + .parent_data = cam_cc_parent_data_1, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_slow_ahb_clk_src[] = { + F(80000000, P_CAM_CC_PLL0_OUT_EVEN, 7.5, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_slow_ahb_clk_src = { + .cmd_rcgr = 0x6058, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_slow_ahb_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_slow_ahb_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch cam_cc_bps_ahb_clk = { + .halt_reg = 0x6070, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6070, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_bps_ahb_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_slow_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_bps_areg_clk = { + .halt_reg = 0x6054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_bps_areg_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_fast_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_bps_axi_clk = { + .halt_reg = 0x6038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_bps_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_bps_clk = { + .halt_reg = 0x6028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_bps_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_bps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_camnoc_axi_clk = { + .halt_reg = 0xb124, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb124, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_camnoc_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cci_0_clk = { + .halt_reg = 0xb0f0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb0f0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_cci_0_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_cci_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cci_1_clk = { + .halt_reg = 0xb164, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb164, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_cci_1_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_cci_1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_core_ahb_clk = { + .halt_reg = 0xb144, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0xb144, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_core_ahb_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_slow_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cpas_ahb_clk = { + .halt_reg = 0xb11c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb11c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_cpas_ahb_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_slow_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csi0phytimer_clk = { + .halt_reg = 0x501c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x501c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi0phytimer_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_csi0phytimer_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csi1phytimer_clk = { + .halt_reg = 0x5040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi1phytimer_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_csi1phytimer_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csi2phytimer_clk = { + .halt_reg = 0x5064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5064, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi2phytimer_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_csi2phytimer_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csi3phytimer_clk = { + .halt_reg = 0x5088, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5088, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi3phytimer_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_csi3phytimer_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csiphy0_clk = { + .halt_reg = 0x5020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csiphy0_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csiphy1_clk = { + .halt_reg = 0x5044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5044, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csiphy1_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csiphy2_clk = { + .halt_reg = 0x5068, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5068, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csiphy2_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csiphy3_clk = { + .halt_reg = 0x508c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x508c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csiphy3_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_icp_clk = { + .halt_reg = 0xb0a0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb0a0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_icp_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_icp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_0_axi_clk = { + .halt_reg = 0x9080, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9080, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_0_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_0_clk = { + .halt_reg = 0x9028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_0_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_ife_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_0_cphy_rx_clk = { + .halt_reg = 0x907c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x907c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_0_cphy_rx_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_0_csid_clk = { + .halt_reg = 0x9054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_0_csid_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_ife_0_csid_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_0_dsp_clk = { + .halt_reg = 0x9038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_0_dsp_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_ife_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_1_axi_clk = { + .halt_reg = 0xa058, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa058, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_1_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_1_clk = { + .halt_reg = 0xa028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_1_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_ife_1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_1_cphy_rx_clk = { + .halt_reg = 0xa054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_1_cphy_rx_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_1_csid_clk = { + .halt_reg = 0xa04c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa04c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_1_csid_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_ife_1_csid_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_1_dsp_clk = { + .halt_reg = 0xa030, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa030, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_1_dsp_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_ife_1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_lite_clk = { + .halt_reg = 0xb01c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb01c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_lite_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_ife_lite_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_lite_cphy_rx_clk = { + .halt_reg = 0xb044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb044, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_lite_cphy_rx_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_lite_csid_clk = { + .halt_reg = 0xb03c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb03c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_lite_csid_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_ife_lite_csid_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_0_ahb_clk = { + .halt_reg = 0x7040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_0_ahb_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_slow_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_0_areg_clk = { + .halt_reg = 0x703c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x703c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_0_areg_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_fast_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_0_axi_clk = { + .halt_reg = 0x7038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_0_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_0_clk = { + .halt_reg = 0x7028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_0_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_ipe_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_jpeg_clk = { + .halt_reg = 0xb064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb064, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_jpeg_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_jpeg_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_lrme_clk = { + .halt_reg = 0xb110, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb110, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_lrme_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_lrme_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk0_clk = { + .halt_reg = 0x401c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x401c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk0_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_mclk0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk1_clk = { + .halt_reg = 0x403c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x403c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk1_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_mclk1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk2_clk = { + .halt_reg = 0x405c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x405c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk2_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_mclk2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk3_clk = { + .halt_reg = 0x407c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x407c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk3_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_mclk3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk4_clk = { + .halt_reg = 0x409c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x409c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk4_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &cam_cc_mclk4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_soc_ahb_clk = { + .halt_reg = 0xb140, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb140, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_soc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_sys_tmr_clk = { + .halt_reg = 0xb0a8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb0a8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_sys_tmr_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc bps_gdsc = { + .gdscr = 0x6004, + .pd = { + .name = "bps_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = HW_CTRL, +}; + +static struct gdsc ife_0_gdsc = { + .gdscr = 0x9004, + .pd = { + .name = "ife_0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc ife_1_gdsc = { + .gdscr = 0xa004, + .pd = { + .name = "ife_1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc ipe_0_gdsc = { + .gdscr = 0x7004, + .pd = { + .name = "ipe_0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = HW_CTRL, +}; + +static struct gdsc titan_top_gdsc = { + .gdscr = 0xb134, + .pd = { + .name = "titan_top_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct clk_hw *cam_cc_sc7180_hws[] = { + [CAM_CC_PLL2_OUT_EARLY] = &cam_cc_pll2_out_early.hw, +}; + +static struct clk_regmap *cam_cc_sc7180_clocks[] = { + [CAM_CC_BPS_AHB_CLK] = &cam_cc_bps_ahb_clk.clkr, + [CAM_CC_BPS_AREG_CLK] = &cam_cc_bps_areg_clk.clkr, + [CAM_CC_BPS_AXI_CLK] = &cam_cc_bps_axi_clk.clkr, + [CAM_CC_BPS_CLK] = &cam_cc_bps_clk.clkr, + [CAM_CC_BPS_CLK_SRC] = &cam_cc_bps_clk_src.clkr, + [CAM_CC_CAMNOC_AXI_CLK] = &cam_cc_camnoc_axi_clk.clkr, + [CAM_CC_CCI_0_CLK] = &cam_cc_cci_0_clk.clkr, + [CAM_CC_CCI_0_CLK_SRC] = &cam_cc_cci_0_clk_src.clkr, + [CAM_CC_CCI_1_CLK] = &cam_cc_cci_1_clk.clkr, + [CAM_CC_CCI_1_CLK_SRC] = &cam_cc_cci_1_clk_src.clkr, + [CAM_CC_CORE_AHB_CLK] = &cam_cc_core_ahb_clk.clkr, + [CAM_CC_CPAS_AHB_CLK] = &cam_cc_cpas_ahb_clk.clkr, + [CAM_CC_CPHY_RX_CLK_SRC] = &cam_cc_cphy_rx_clk_src.clkr, + [CAM_CC_CSI0PHYTIMER_CLK] = &cam_cc_csi0phytimer_clk.clkr, + [CAM_CC_CSI0PHYTIMER_CLK_SRC] = &cam_cc_csi0phytimer_clk_src.clkr, + [CAM_CC_CSI1PHYTIMER_CLK] = &cam_cc_csi1phytimer_clk.clkr, + [CAM_CC_CSI1PHYTIMER_CLK_SRC] = &cam_cc_csi1phytimer_clk_src.clkr, + [CAM_CC_CSI2PHYTIMER_CLK] = &cam_cc_csi2phytimer_clk.clkr, + [CAM_CC_CSI2PHYTIMER_CLK_SRC] = &cam_cc_csi2phytimer_clk_src.clkr, + [CAM_CC_CSI3PHYTIMER_CLK] = &cam_cc_csi3phytimer_clk.clkr, + [CAM_CC_CSI3PHYTIMER_CLK_SRC] = &cam_cc_csi3phytimer_clk_src.clkr, + [CAM_CC_CSIPHY0_CLK] = &cam_cc_csiphy0_clk.clkr, + [CAM_CC_CSIPHY1_CLK] = &cam_cc_csiphy1_clk.clkr, + [CAM_CC_CSIPHY2_CLK] = &cam_cc_csiphy2_clk.clkr, + [CAM_CC_CSIPHY3_CLK] = &cam_cc_csiphy3_clk.clkr, + [CAM_CC_FAST_AHB_CLK_SRC] = &cam_cc_fast_ahb_clk_src.clkr, + [CAM_CC_ICP_CLK] = &cam_cc_icp_clk.clkr, + [CAM_CC_ICP_CLK_SRC] = &cam_cc_icp_clk_src.clkr, + [CAM_CC_IFE_0_AXI_CLK] = &cam_cc_ife_0_axi_clk.clkr, + [CAM_CC_IFE_0_CLK] = &cam_cc_ife_0_clk.clkr, + [CAM_CC_IFE_0_CLK_SRC] = &cam_cc_ife_0_clk_src.clkr, + [CAM_CC_IFE_0_CPHY_RX_CLK] = &cam_cc_ife_0_cphy_rx_clk.clkr, + [CAM_CC_IFE_0_CSID_CLK] = &cam_cc_ife_0_csid_clk.clkr, + [CAM_CC_IFE_0_CSID_CLK_SRC] = &cam_cc_ife_0_csid_clk_src.clkr, + [CAM_CC_IFE_0_DSP_CLK] = &cam_cc_ife_0_dsp_clk.clkr, + [CAM_CC_IFE_1_AXI_CLK] = &cam_cc_ife_1_axi_clk.clkr, + [CAM_CC_IFE_1_CLK] = &cam_cc_ife_1_clk.clkr, + [CAM_CC_IFE_1_CLK_SRC] = &cam_cc_ife_1_clk_src.clkr, + [CAM_CC_IFE_1_CPHY_RX_CLK] = &cam_cc_ife_1_cphy_rx_clk.clkr, + [CAM_CC_IFE_1_CSID_CLK] = &cam_cc_ife_1_csid_clk.clkr, + [CAM_CC_IFE_1_CSID_CLK_SRC] = &cam_cc_ife_1_csid_clk_src.clkr, + [CAM_CC_IFE_1_DSP_CLK] = &cam_cc_ife_1_dsp_clk.clkr, + [CAM_CC_IFE_LITE_CLK] = &cam_cc_ife_lite_clk.clkr, + [CAM_CC_IFE_LITE_CLK_SRC] = &cam_cc_ife_lite_clk_src.clkr, + [CAM_CC_IFE_LITE_CPHY_RX_CLK] = &cam_cc_ife_lite_cphy_rx_clk.clkr, + [CAM_CC_IFE_LITE_CSID_CLK] = &cam_cc_ife_lite_csid_clk.clkr, + [CAM_CC_IFE_LITE_CSID_CLK_SRC] = &cam_cc_ife_lite_csid_clk_src.clkr, + [CAM_CC_IPE_0_AHB_CLK] = &cam_cc_ipe_0_ahb_clk.clkr, + [CAM_CC_IPE_0_AREG_CLK] = &cam_cc_ipe_0_areg_clk.clkr, + [CAM_CC_IPE_0_AXI_CLK] = &cam_cc_ipe_0_axi_clk.clkr, + [CAM_CC_IPE_0_CLK] = &cam_cc_ipe_0_clk.clkr, + [CAM_CC_IPE_0_CLK_SRC] = &cam_cc_ipe_0_clk_src.clkr, + [CAM_CC_JPEG_CLK] = &cam_cc_jpeg_clk.clkr, + [CAM_CC_JPEG_CLK_SRC] = &cam_cc_jpeg_clk_src.clkr, + [CAM_CC_LRME_CLK] = &cam_cc_lrme_clk.clkr, + [CAM_CC_LRME_CLK_SRC] = &cam_cc_lrme_clk_src.clkr, + [CAM_CC_MCLK0_CLK] = &cam_cc_mclk0_clk.clkr, + [CAM_CC_MCLK0_CLK_SRC] = &cam_cc_mclk0_clk_src.clkr, + [CAM_CC_MCLK1_CLK] = &cam_cc_mclk1_clk.clkr, + [CAM_CC_MCLK1_CLK_SRC] = &cam_cc_mclk1_clk_src.clkr, + [CAM_CC_MCLK2_CLK] = &cam_cc_mclk2_clk.clkr, + [CAM_CC_MCLK2_CLK_SRC] = &cam_cc_mclk2_clk_src.clkr, + [CAM_CC_MCLK3_CLK] = &cam_cc_mclk3_clk.clkr, + [CAM_CC_MCLK3_CLK_SRC] = &cam_cc_mclk3_clk_src.clkr, + [CAM_CC_MCLK4_CLK] = &cam_cc_mclk4_clk.clkr, + [CAM_CC_MCLK4_CLK_SRC] = &cam_cc_mclk4_clk_src.clkr, + [CAM_CC_PLL0] = &cam_cc_pll0.clkr, + [CAM_CC_PLL1] = &cam_cc_pll1.clkr, + [CAM_CC_PLL2] = &cam_cc_pll2.clkr, + [CAM_CC_PLL2_OUT_AUX] = &cam_cc_pll2_out_aux.clkr, + [CAM_CC_PLL3] = &cam_cc_pll3.clkr, + [CAM_CC_SLOW_AHB_CLK_SRC] = &cam_cc_slow_ahb_clk_src.clkr, + [CAM_CC_SOC_AHB_CLK] = &cam_cc_soc_ahb_clk.clkr, + [CAM_CC_SYS_TMR_CLK] = &cam_cc_sys_tmr_clk.clkr, +}; +static struct gdsc *cam_cc_sc7180_gdscs[] = { + [BPS_GDSC] = &bps_gdsc, + [IFE_0_GDSC] = &ife_0_gdsc, + [IFE_1_GDSC] = &ife_1_gdsc, + [IPE_0_GDSC] = &ipe_0_gdsc, + [TITAN_TOP_GDSC] = &titan_top_gdsc, +}; + +static const struct regmap_config cam_cc_sc7180_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xd028, + .fast_io = true, +}; + +static const struct qcom_cc_desc cam_cc_sc7180_desc = { + .config = &cam_cc_sc7180_regmap_config, + .clk_hws = cam_cc_sc7180_hws, + .num_clk_hws = ARRAY_SIZE(cam_cc_sc7180_hws), + .clks = cam_cc_sc7180_clocks, + .num_clks = ARRAY_SIZE(cam_cc_sc7180_clocks), + .gdscs = cam_cc_sc7180_gdscs, + .num_gdscs = ARRAY_SIZE(cam_cc_sc7180_gdscs), +}; + +static const struct of_device_id cam_cc_sc7180_match_table[] = { + { .compatible = "qcom,sc7180-camcc" }, + { } +}; +MODULE_DEVICE_TABLE(of, cam_cc_sc7180_match_table); + +static int cam_cc_sc7180_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret; + + pm_runtime_enable(&pdev->dev); + ret = pm_clk_create(&pdev->dev); + if (ret < 0) + return ret; + + ret = pm_clk_add(&pdev->dev, "xo"); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to acquire XO clock\n"); + goto disable_pm_runtime; + } + + ret = pm_clk_add(&pdev->dev, "iface"); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to acquire iface clock\n"); + goto disable_pm_runtime; + } + + ret = pm_clk_runtime_resume(&pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "pm runtime resume failed\n"); + goto destroy_pm_clk; + } + + regmap = qcom_cc_map(pdev, &cam_cc_sc7180_desc); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + pm_clk_runtime_suspend(&pdev->dev); + goto destroy_pm_clk; + } + + clk_fabia_pll_configure(&cam_cc_pll0, regmap, &cam_cc_pll0_config); + clk_fabia_pll_configure(&cam_cc_pll1, regmap, &cam_cc_pll1_config); + clk_agera_pll_configure(&cam_cc_pll2, regmap, &cam_cc_pll2_config); + clk_fabia_pll_configure(&cam_cc_pll3, regmap, &cam_cc_pll3_config); + + ret = qcom_cc_really_probe(pdev, &cam_cc_sc7180_desc, regmap); + + pm_clk_runtime_suspend(&pdev->dev); + + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register CAM CC clocks\n"); + goto destroy_pm_clk; + } + + return 0; + +destroy_pm_clk: + pm_clk_destroy(&pdev->dev); + +disable_pm_runtime: + pm_runtime_disable(&pdev->dev); + + return ret; +} + +static const struct dev_pm_ops cam_cc_pm_ops = { + SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) +}; + +static struct platform_driver cam_cc_sc7180_driver = { + .probe = cam_cc_sc7180_probe, + .driver = { + .name = "cam_cc-sc7180", + .of_match_table = cam_cc_sc7180_match_table, + .pm = &cam_cc_pm_ops, + }, +}; + +static int __init cam_cc_sc7180_init(void) +{ + return platform_driver_register(&cam_cc_sc7180_driver); +} +subsys_initcall(cam_cc_sc7180_init); + +static void __exit cam_cc_sc7180_exit(void) +{ + platform_driver_unregister(&cam_cc_sc7180_driver); +} +module_exit(cam_cc_sc7180_exit); + +MODULE_DESCRIPTION("QTI CAM_CC SC7180 Driver"); +MODULE_LICENSE("GPL v2"); From 7635622b77b53985d816b7f7c1a04e718c9db814 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 19 Oct 2020 15:49:34 -0700 Subject: [PATCH 025/134] clk: qcom: lpasscc-sc7810: Use devm in probe Let's convert the lpass clock control driver to use devm. This is a few more lines of code, but it will be useful in a later patch which disentangles the two devices handled by this driver. Signed-off-by: Douglas Anderson Link: https://lore.kernel.org/r/20201019154857.v5.1.I4567b5e7e17bbb15ef063d447cb83fd43746cb18@changeid Signed-off-by: Stephen Boyd --- drivers/clk/qcom/lpasscorecc-sc7180.c | 38 +++++++++++++++------------ 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/drivers/clk/qcom/lpasscorecc-sc7180.c b/drivers/clk/qcom/lpasscorecc-sc7180.c index 228d08f5d26f..2d15e33ec837 100644 --- a/drivers/clk/qcom/lpasscorecc-sc7180.c +++ b/drivers/clk/qcom/lpasscorecc-sc7180.c @@ -356,6 +356,16 @@ static const struct qcom_cc_desc lpass_audio_hm_sc7180_desc = { .num_gdscs = ARRAY_SIZE(lpass_audio_hm_sc7180_gdscs), }; +static void lpass_pm_runtime_disable(void *data) +{ + pm_runtime_disable(data); +} + +static void lpass_pm_clk_destroy(void *data) +{ + pm_clk_destroy(data); +} + static int lpass_core_cc_sc7180_probe(struct platform_device *pdev) { const struct qcom_cc_desc *desc; @@ -418,34 +428,28 @@ static int lpass_core_sc7180_probe(struct platform_device *pdev) int ret; pm_runtime_enable(&pdev->dev); + ret = devm_add_action_or_reset(&pdev->dev, lpass_pm_runtime_disable, &pdev->dev); + if (ret) + return ret; + ret = pm_clk_create(&pdev->dev); if (ret) - goto disable_pm_runtime; + return ret; + ret = devm_add_action_or_reset(&pdev->dev, lpass_pm_clk_destroy, &pdev->dev); + if (ret) + return ret; ret = pm_clk_add(&pdev->dev, "iface"); if (ret < 0) { dev_err(&pdev->dev, "failed to acquire iface clock\n"); - goto destroy_pm_clk; + return ret; } - ret = -EINVAL; clk_probe = of_device_get_match_data(&pdev->dev); if (!clk_probe) - goto destroy_pm_clk; + return -EINVAL; - ret = clk_probe(pdev); - if (ret) - goto destroy_pm_clk; - - return 0; - -destroy_pm_clk: - pm_clk_destroy(&pdev->dev); - -disable_pm_runtime: - pm_runtime_disable(&pdev->dev); - - return ret; + return clk_probe(pdev); } static const struct dev_pm_ops lpass_core_cc_pm_ops = { From 4ee9fe3e292bafc915872fce5eacd2c185d7711f Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 19 Oct 2020 15:49:35 -0700 Subject: [PATCH 026/134] clk: qcom: lpass-sc7180: Disentangle the two clock devices The sc7180 lpass clock driver manages two different devices. These two devices were tangled together, using one probe and a lookup to figure out the real probe. I think it's cleaner to really separate the probe for these two devices since they're really different things, just both managed by the same driver. Signed-off-by: Douglas Anderson Link: https://lore.kernel.org/r/20201019154857.v5.2.I75c409497d4dea9daefa53ec5f93824081c4ecbe@changeid Reviewed-by: Taniya Das Signed-off-by: Stephen Boyd --- drivers/clk/qcom/lpasscorecc-sc7180.c | 107 ++++++++++++++++---------- 1 file changed, 66 insertions(+), 41 deletions(-) diff --git a/drivers/clk/qcom/lpasscorecc-sc7180.c b/drivers/clk/qcom/lpasscorecc-sc7180.c index 2d15e33ec837..1a3925badd7c 100644 --- a/drivers/clk/qcom/lpasscorecc-sc7180.c +++ b/drivers/clk/qcom/lpasscorecc-sc7180.c @@ -366,12 +366,39 @@ static void lpass_pm_clk_destroy(void *data) pm_clk_destroy(data); } +static int lpass_create_pm_clks(struct platform_device *pdev) +{ + int ret; + + pm_runtime_enable(&pdev->dev); + ret = devm_add_action_or_reset(&pdev->dev, lpass_pm_runtime_disable, &pdev->dev); + if (ret) + return ret; + + ret = pm_clk_create(&pdev->dev); + if (ret) + return ret; + ret = devm_add_action_or_reset(&pdev->dev, lpass_pm_clk_destroy, &pdev->dev); + if (ret) + return ret; + + ret = pm_clk_add(&pdev->dev, "iface"); + if (ret < 0) + dev_err(&pdev->dev, "failed to acquire iface clock\n"); + + return ret; +} + static int lpass_core_cc_sc7180_probe(struct platform_device *pdev) { const struct qcom_cc_desc *desc; struct regmap *regmap; int ret; + ret = lpass_create_pm_clks(pdev); + if (ret) + return ret; + lpass_core_cc_sc7180_regmap_config.name = "lpass_audio_cc"; desc = &lpass_audio_hm_sc7180_desc; ret = qcom_cc_probe_by_index(pdev, 1, desc); @@ -402,6 +429,11 @@ static int lpass_core_cc_sc7180_probe(struct platform_device *pdev) static int lpass_hm_core_probe(struct platform_device *pdev) { const struct qcom_cc_desc *desc; + int ret; + + ret = lpass_create_pm_clks(pdev); + if (ret) + return ret; lpass_core_cc_sc7180_regmap_config.name = "lpass_hm_core"; desc = &lpass_core_hm_sc7180_desc; @@ -409,55 +441,28 @@ static int lpass_hm_core_probe(struct platform_device *pdev) return qcom_cc_probe_by_index(pdev, 0, desc); } -static const struct of_device_id lpass_core_cc_sc7180_match_table[] = { +static const struct of_device_id lpass_hm_sc7180_match_table[] = { { .compatible = "qcom,sc7180-lpasshm", - .data = lpass_hm_core_probe, }, + { } +}; +MODULE_DEVICE_TABLE(of, lpass_hm_sc7180_match_table); + +static const struct of_device_id lpass_core_cc_sc7180_match_table[] = { { .compatible = "qcom,sc7180-lpasscorecc", - .data = lpass_core_cc_sc7180_probe, }, { } }; MODULE_DEVICE_TABLE(of, lpass_core_cc_sc7180_match_table); -static int lpass_core_sc7180_probe(struct platform_device *pdev) -{ - int (*clk_probe)(struct platform_device *p); - int ret; - - pm_runtime_enable(&pdev->dev); - ret = devm_add_action_or_reset(&pdev->dev, lpass_pm_runtime_disable, &pdev->dev); - if (ret) - return ret; - - ret = pm_clk_create(&pdev->dev); - if (ret) - return ret; - ret = devm_add_action_or_reset(&pdev->dev, lpass_pm_clk_destroy, &pdev->dev); - if (ret) - return ret; - - ret = pm_clk_add(&pdev->dev, "iface"); - if (ret < 0) { - dev_err(&pdev->dev, "failed to acquire iface clock\n"); - return ret; - } - - clk_probe = of_device_get_match_data(&pdev->dev); - if (!clk_probe) - return -EINVAL; - - return clk_probe(pdev); -} - static const struct dev_pm_ops lpass_core_cc_pm_ops = { SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) }; static struct platform_driver lpass_core_cc_sc7180_driver = { - .probe = lpass_core_sc7180_probe, + .probe = lpass_core_cc_sc7180_probe, .driver = { .name = "lpass_core_cc-sc7180", .of_match_table = lpass_core_cc_sc7180_match_table, @@ -465,17 +470,37 @@ static struct platform_driver lpass_core_cc_sc7180_driver = { }, }; -static int __init lpass_core_cc_sc7180_init(void) -{ - return platform_driver_register(&lpass_core_cc_sc7180_driver); -} -subsys_initcall(lpass_core_cc_sc7180_init); +static const struct dev_pm_ops lpass_hm_pm_ops = { + SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) +}; -static void __exit lpass_core_cc_sc7180_exit(void) +static struct platform_driver lpass_hm_sc7180_driver = { + .probe = lpass_hm_core_probe, + .driver = { + .name = "lpass_hm-sc7180", + .of_match_table = lpass_hm_sc7180_match_table, + .pm = &lpass_hm_pm_ops, + }, +}; + +static int __init lpass_sc7180_init(void) { + int ret; + + ret = platform_driver_register(&lpass_core_cc_sc7180_driver); + if (ret) + return ret; + + return platform_driver_register(&lpass_hm_sc7180_driver); +} +subsys_initcall(lpass_sc7180_init); + +static void __exit lpass_sc7180_exit(void) +{ + platform_driver_unregister(&lpass_hm_sc7180_driver); platform_driver_unregister(&lpass_core_cc_sc7180_driver); } -module_exit(lpass_core_cc_sc7180_exit); +module_exit(lpass_sc7180_exit); MODULE_DESCRIPTION("QTI LPASS_CORE_CC SC7180 Driver"); MODULE_LICENSE("GPL v2"); From a6dee2fe778b9f79f75bfc203945ace79172623e Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 26 Oct 2020 12:02:18 +0000 Subject: [PATCH 027/134] dt-bindings: clock: Add support for LPASS Audio Clock Controller Audio Clock controller is a block inside LPASS which controls 2 Glitch free muxes to LPASS codec Macros. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20201026120221.18984-2-srinivas.kandagatla@linaro.org Reviewed-by: Rob Herring Signed-off-by: Stephen Boyd --- .../bindings/clock/qcom,audiocc-sm8250.yaml | 58 +++++++++++++++++++ .../clock/qcom,sm8250-lpass-audiocc.h | 13 +++++ 2 files changed, 71 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,audiocc-sm8250.yaml create mode 100644 include/dt-bindings/clock/qcom,sm8250-lpass-audiocc.h diff --git a/Documentation/devicetree/bindings/clock/qcom,audiocc-sm8250.yaml b/Documentation/devicetree/bindings/clock/qcom,audiocc-sm8250.yaml new file mode 100644 index 000000000000..915d76206ad0 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,audiocc-sm8250.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,audiocc-sm8250.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Clock bindings for LPASS Audio Clock Controller on SM8250 SoCs + +maintainers: + - Srinivas Kandagatla + +description: | + The clock consumer should specify the desired clock by having the clock + ID in its "clocks" phandle cell. + See include/dt-bindings/clock/qcom,sm8250-lpass-audiocc.h for the full list + of Audio Clock controller clock IDs. + +properties: + compatible: + const: qcom,sm8250-lpass-audiocc + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + + clocks: + items: + - description: LPASS Core voting clock + - description: Glitch Free Mux register clock + + clock-names: + items: + - const: core + - const: bus + +required: + - compatible + - reg + - '#clock-cells' + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + #include + #include + clock-controller@3300000 { + #clock-cells = <1>; + compatible = "qcom,sm8250-lpass-audiocc"; + reg = <0x03300000 0x30000>; + clocks = <&q6afecc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6afecc LPASS_CLK_ID_TX_CORE_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>; + clock-names = "core", "bus"; + }; diff --git a/include/dt-bindings/clock/qcom,sm8250-lpass-audiocc.h b/include/dt-bindings/clock/qcom,sm8250-lpass-audiocc.h new file mode 100644 index 000000000000..a1aa6cb5d840 --- /dev/null +++ b/include/dt-bindings/clock/qcom,sm8250-lpass-audiocc.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _DT_BINDINGS_CLK_LPASS_AUDIOCC_SM8250_H +#define _DT_BINDINGS_CLK_LPASS_AUDIOCC_SM8250_H + +/* From AudioCC */ +#define LPASS_CDC_WSA_NPL 0 +#define LPASS_CDC_WSA_MCLK 1 +#define LPASS_CDC_RX_MCLK 2 +#define LPASS_CDC_RX_NPL 3 +#define LPASS_CDC_RX_MCLK_MCLK2 4 + +#endif /* _DT_BINDINGS_CLK_LPASS_AUDIOCC_SM8250_H */ From 7dbe5a7a3f990d642a3166b5d161db429d9f7271 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 26 Oct 2020 12:02:19 +0000 Subject: [PATCH 028/134] dt-bindings: clock: Add support for LPASS Always ON Controller Always ON Clock controller is a block inside LPASS which controls 1 Glitch free muxes to LPASS codec Macros. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20201026120221.18984-3-srinivas.kandagatla@linaro.org Reviewed-by: Rob Herring Signed-off-by: Stephen Boyd --- .../bindings/clock/qcom,aoncc-sm8250.yaml | 58 +++++++++++++++++++ .../clock/qcom,sm8250-lpass-aoncc.h | 11 ++++ 2 files changed, 69 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,aoncc-sm8250.yaml create mode 100644 include/dt-bindings/clock/qcom,sm8250-lpass-aoncc.h diff --git a/Documentation/devicetree/bindings/clock/qcom,aoncc-sm8250.yaml b/Documentation/devicetree/bindings/clock/qcom,aoncc-sm8250.yaml new file mode 100644 index 000000000000..c40a74b5d672 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,aoncc-sm8250.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,aoncc-sm8250.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Clock bindings for LPASS Always ON Clock Controller on SM8250 SoCs + +maintainers: + - Srinivas Kandagatla + +description: | + The clock consumer should specify the desired clock by having the clock + ID in its "clocks" phandle cell. + See include/dt-bindings/clock/qcom,sm8250-lpass-aoncc.h for the full list + of Audio Clock controller clock IDs. + +properties: + compatible: + const: qcom,sm8250-lpass-aon + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + + clocks: + items: + - description: LPASS Core voting clock + - description: Glitch Free Mux register clock + + clock-names: + items: + - const: core + - const: bus + +required: + - compatible + - reg + - '#clock-cells' + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + #include + #include + clock-controller@3800000 { + #clock-cells = <1>; + compatible = "qcom,sm8250-lpass-aon"; + reg = <0x03380000 0x40000>; + clocks = <&q6afecc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6afecc LPASS_CLK_ID_TX_CORE_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>; + clock-names = "core", "bus"; + }; diff --git a/include/dt-bindings/clock/qcom,sm8250-lpass-aoncc.h b/include/dt-bindings/clock/qcom,sm8250-lpass-aoncc.h new file mode 100644 index 000000000000..f5a1cfac8612 --- /dev/null +++ b/include/dt-bindings/clock/qcom,sm8250-lpass-aoncc.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _DT_BINDINGS_CLK_LPASS_AONCC_SM8250_H +#define _DT_BINDINGS_CLK_LPASS_AONCC_SM8250_H + +/* from AOCC */ +#define LPASS_CDC_VA_MCLK 0 +#define LPASS_CDC_TX_NPL 1 +#define LPASS_CDC_TX_MCLK 2 + +#endif /* _DT_BINDINGS_CLK_LPASS_AONCC_SM8250_H */ From a2d8f507803ee858c718b2a8d54c00ac9c5c5f09 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 26 Oct 2020 12:02:20 +0000 Subject: [PATCH 029/134] clk: qcom: Add support to LPASS AUDIO_CC Glitch Free Mux clocks GFM Muxes in AUDIO_CC control clocks to LPASS WSA and RX Codec Macros. This patch adds support to these muxes. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20201026120221.18984-4-srinivas.kandagatla@linaro.org Signed-off-by: Stephen Boyd --- drivers/clk/qcom/Kconfig | 6 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/lpass-gfm-sm8250.c | 257 ++++++++++++++++++++++++++++ 3 files changed, 264 insertions(+) create mode 100644 drivers/clk/qcom/lpass-gfm-sm8250.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 886e8610b321..48c624a1eff1 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -511,4 +511,10 @@ config KRAITCC Support for the Krait CPU clocks on Qualcomm devices. Say Y if you want to support CPU frequency scaling. +config CLK_GFM_LPASS_SM8250 + tristate "SM8250 GFM LPASS Clocks" + help + Support for the Glitch Free Mux (GFM) Low power audio + subsystem (LPASS) clocks found on SM8250 SoCs. + endif diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index ee02fafbae27..57b6349a3ee8 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -19,6 +19,7 @@ clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o # Keep alphabetically sorted by config obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o +obj-$(CONFIG_CLK_GFM_LPASS_SM8250) += lpass-gfm-sm8250.o obj-$(CONFIG_IPQ_APSS_PLL) += apss-ipq-pll.o obj-$(CONFIG_IPQ_APSS_6018) += apss-ipq6018.o obj-$(CONFIG_IPQ_GCC_4019) += gcc-ipq4019.o diff --git a/drivers/clk/qcom/lpass-gfm-sm8250.c b/drivers/clk/qcom/lpass-gfm-sm8250.c new file mode 100644 index 000000000000..48a73dd97d0d --- /dev/null +++ b/drivers/clk/qcom/lpass-gfm-sm8250.c @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * LPASS Audio CC and Always ON CC Glitch Free Mux clock driver + * + * Copyright (c) 2020 Linaro Ltd. + * Author: Srinivas Kandagatla + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct lpass_gfm { + struct device *dev; + void __iomem *base; +}; + +struct clk_gfm { + unsigned int mux_reg; + unsigned int mux_mask; + struct clk_hw hw; + struct lpass_gfm *priv; + void __iomem *gfm_mux; +}; + +#define GFM_MASK BIT(1) +#define to_clk_gfm(_hw) container_of(_hw, struct clk_gfm, hw) + +static u8 clk_gfm_get_parent(struct clk_hw *hw) +{ + struct clk_gfm *clk = to_clk_gfm(hw); + + return readl(clk->gfm_mux) & GFM_MASK; +} + +static int clk_gfm_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_gfm *clk = to_clk_gfm(hw); + unsigned int val; + + val = readl(clk->gfm_mux); + + if (index) + val |= GFM_MASK; + else + val &= ~GFM_MASK; + + writel(val, clk->gfm_mux); + + return 0; +} + +static const struct clk_ops clk_gfm_ops = { + .get_parent = clk_gfm_get_parent, + .set_parent = clk_gfm_set_parent, + .determine_rate = __clk_mux_determine_rate, +}; + +static struct clk_gfm lpass_gfm_wsa_mclk = { + .mux_reg = 0x220d8, + .mux_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "WSA_MCLK", + .ops = &clk_gfm_ops, + .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .parent_data = (const struct clk_parent_data[]){ + { + .index = 0, + .fw_name = "LPASS_CLK_ID_TX_CORE_MCLK", + }, { + .index = 1, + .fw_name = "LPASS_CLK_ID_WSA_CORE_MCLK", + }, + }, + .num_parents = 2, + }, +}; + +static struct clk_gfm lpass_gfm_wsa_npl = { + .mux_reg = 0x220d8, + .mux_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "WSA_NPL", + .ops = &clk_gfm_ops, + .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .parent_data = (const struct clk_parent_data[]){ + { + .index = 0, + .fw_name = "LPASS_CLK_ID_TX_CORE_NPL_MCLK", + }, { + .index = 1, + .fw_name = "LPASS_CLK_ID_WSA_CORE_NPL_MCLK", + }, + }, + .num_parents = 2, + }, +}; + +static struct clk_gfm lpass_gfm_rx_mclk_mclk2 = { + .mux_reg = 0x240d8, + .mux_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "RX_MCLK_MCLK2", + .ops = &clk_gfm_ops, + .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .parent_data = (const struct clk_parent_data[]){ + { + .index = 0, + .fw_name = "LPASS_CLK_ID_TX_CORE_MCLK", + }, { + .index = 1, + .fw_name = "LPASS_CLK_ID_RX_CORE_MCLK", + }, + }, + .num_parents = 2, + }, +}; + +static struct clk_gfm lpass_gfm_rx_npl = { + .mux_reg = 0x240d8, + .mux_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "RX_NPL", + .ops = &clk_gfm_ops, + .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .parent_data = (const struct clk_parent_data[]){ + { + .index = 0, + .fw_name = "LPASS_CLK_ID_TX_CORE_NPL_MCLK", + }, { + .index = 1, + .fw_name = "LPASS_CLK_ID_RX_CORE_NPL_MCLK", + }, + }, + .num_parents = 2, + }, +}; + +static struct clk_gfm *audiocc_gfm_clks[] = { + [LPASS_CDC_WSA_NPL] = &lpass_gfm_wsa_npl, + [LPASS_CDC_WSA_MCLK] = &lpass_gfm_wsa_mclk, + [LPASS_CDC_RX_NPL] = &lpass_gfm_rx_npl, + [LPASS_CDC_RX_MCLK_MCLK2] = &lpass_gfm_rx_mclk_mclk2, +}; + +static struct clk_hw_onecell_data audiocc_hw_onecell_data = { + .hws = { + [LPASS_CDC_WSA_NPL] = &lpass_gfm_wsa_npl.hw, + [LPASS_CDC_WSA_MCLK] = &lpass_gfm_wsa_mclk.hw, + [LPASS_CDC_RX_NPL] = &lpass_gfm_rx_npl.hw, + [LPASS_CDC_RX_MCLK_MCLK2] = &lpass_gfm_rx_mclk_mclk2.hw, + }, + .num = ARRAY_SIZE(audiocc_gfm_clks), +}; + +struct lpass_gfm_data { + struct clk_hw_onecell_data *onecell_data; + struct clk_gfm **gfm_clks; +}; + +static struct lpass_gfm_data audiocc_data = { + .onecell_data = &audiocc_hw_onecell_data, + .gfm_clks = audiocc_gfm_clks, +}; + +static int lpass_gfm_clk_driver_probe(struct platform_device *pdev) +{ + const struct lpass_gfm_data *data; + struct device *dev = &pdev->dev; + struct clk_gfm *gfm; + struct lpass_gfm *cc; + int err, i; + + data = of_device_get_match_data(dev); + if (!data) + return -EINVAL; + + cc = devm_kzalloc(dev, sizeof(*cc), GFP_KERNEL); + if (!cc) + return -ENOMEM; + + cc->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(cc->base)) + return PTR_ERR(cc->base); + + pm_runtime_enable(dev); + err = pm_clk_create(dev); + if (err) + goto pm_clk_err; + + err = of_pm_clk_add_clks(dev); + if (err < 0) { + dev_dbg(dev, "Failed to get lpass core voting clocks\n"); + goto clk_reg_err; + } + + for (i = 0; i < data->onecell_data->num; i++) { + if (!data->gfm_clks[i]) + continue; + + gfm = data->gfm_clks[i]; + gfm->priv = cc; + gfm->gfm_mux = cc->base; + gfm->gfm_mux = gfm->gfm_mux + data->gfm_clks[i]->mux_reg; + + err = devm_clk_hw_register(dev, &data->gfm_clks[i]->hw); + if (err) + goto clk_reg_err; + + } + + err = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + data->onecell_data); + if (err) + goto clk_reg_err; + + return 0; + +clk_reg_err: + pm_clk_destroy(dev); +pm_clk_err: + pm_runtime_disable(dev); + return err; +} + +static const struct of_device_id lpass_gfm_clk_match_table[] = { + { + .compatible = "qcom,sm8250-lpass-audiocc", + .data = &audiocc_data, + }, + { } +}; +MODULE_DEVICE_TABLE(of, lpass_gfm_clk_match_table); + +static const struct dev_pm_ops lpass_gfm_pm_ops = { + SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) +}; + +static struct platform_driver lpass_gfm_clk_driver = { + .probe = lpass_gfm_clk_driver_probe, + .driver = { + .name = "lpass-gfm-clk", + .of_match_table = lpass_gfm_clk_match_table, + .pm = &lpass_gfm_pm_ops, + }, +}; +module_platform_driver(lpass_gfm_clk_driver); +MODULE_LICENSE("GPL v2"); From 794aa56a78052d195641b1ce43e5538574bedf41 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 26 Oct 2020 12:02:21 +0000 Subject: [PATCH 030/134] clk: qcom: Add support to LPASS AON_CC Glitch Free Mux clocks LPASS Always ON Clock controller has one GFM mux to control VA and TX clocks to codec macro on LPASS. This patch adds support to this mux. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20201026120221.18984-5-srinivas.kandagatla@linaro.org Signed-off-by: Stephen Boyd --- drivers/clk/qcom/lpass-gfm-sm8250.c | 63 +++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/drivers/clk/qcom/lpass-gfm-sm8250.c b/drivers/clk/qcom/lpass-gfm-sm8250.c index 48a73dd97d0d..d366c7c2abc7 100644 --- a/drivers/clk/qcom/lpass-gfm-sm8250.c +++ b/drivers/clk/qcom/lpass-gfm-sm8250.c @@ -18,6 +18,7 @@ #include #include #include +#include struct lpass_gfm { struct device *dev; @@ -65,6 +66,46 @@ static const struct clk_ops clk_gfm_ops = { .determine_rate = __clk_mux_determine_rate, }; +static struct clk_gfm lpass_gfm_va_mclk = { + .mux_reg = 0x20000, + .mux_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "VA_MCLK", + .ops = &clk_gfm_ops, + .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .num_parents = 2, + .parent_data = (const struct clk_parent_data[]){ + { + .index = 0, + .fw_name = "LPASS_CLK_ID_TX_CORE_MCLK", + }, { + .index = 1, + .fw_name = "LPASS_CLK_ID_VA_CORE_MCLK", + }, + }, + }, +}; + +static struct clk_gfm lpass_gfm_tx_npl = { + .mux_reg = 0x20000, + .mux_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "TX_NPL", + .ops = &clk_gfm_ops, + .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .parent_data = (const struct clk_parent_data[]){ + { + .index = 0, + .fw_name = "LPASS_CLK_ID_TX_CORE_NPL_MCLK", + }, { + .index = 1, + .fw_name = "LPASS_CLK_ID_VA_CORE_2X_MCLK", + }, + }, + .num_parents = 2, + }, +}; + static struct clk_gfm lpass_gfm_wsa_mclk = { .mux_reg = 0x220d8, .mux_mask = BIT(0), @@ -145,6 +186,19 @@ static struct clk_gfm lpass_gfm_rx_npl = { }, }; +static struct clk_gfm *aoncc_gfm_clks[] = { + [LPASS_CDC_VA_MCLK] = &lpass_gfm_va_mclk, + [LPASS_CDC_TX_NPL] = &lpass_gfm_tx_npl, +}; + +static struct clk_hw_onecell_data aoncc_hw_onecell_data = { + .hws = { + [LPASS_CDC_VA_MCLK] = &lpass_gfm_va_mclk.hw, + [LPASS_CDC_TX_NPL] = &lpass_gfm_tx_npl.hw, + }, + .num = ARRAY_SIZE(aoncc_gfm_clks), +}; + static struct clk_gfm *audiocc_gfm_clks[] = { [LPASS_CDC_WSA_NPL] = &lpass_gfm_wsa_npl, [LPASS_CDC_WSA_MCLK] = &lpass_gfm_wsa_mclk, @@ -172,6 +226,11 @@ static struct lpass_gfm_data audiocc_data = { .gfm_clks = audiocc_gfm_clks, }; +static struct lpass_gfm_data aoncc_data = { + .onecell_data = &aoncc_hw_onecell_data, + .gfm_clks = aoncc_gfm_clks, +}; + static int lpass_gfm_clk_driver_probe(struct platform_device *pdev) { const struct lpass_gfm_data *data; @@ -233,6 +292,10 @@ pm_clk_err: } static const struct of_device_id lpass_gfm_clk_match_table[] = { + { + .compatible = "qcom,sm8250-lpass-aoncc", + .data = &aoncc_data, + }, { .compatible = "qcom,sm8250-lpass-audiocc", .data = &audiocc_data, From f2bd43f1c97f0ef6612cde87aa941248a91c59c6 Mon Sep 17 00:00:00 2001 From: Zou Wei Date: Tue, 3 Nov 2020 19:32:14 +0800 Subject: [PATCH 031/134] clk: imx: gate2: Remove unused variable ret This patch fixes below warning reported by coccicheck: ./clk-gate2.c:57:5-8: Unneeded variable: "ret". Return "0" on line 68 Reported-by: Hulk Robot Signed-off-by: Zou Wei Reviewed-by: Stephen Boyd Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-gate2.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c index 480a184207d5..f16c4019f402 100644 --- a/drivers/clk/imx/clk-gate2.c +++ b/drivers/clk/imx/clk-gate2.c @@ -54,7 +54,6 @@ static int clk_gate2_enable(struct clk_hw *hw) { struct clk_gate2 *gate = to_clk_gate2(hw); unsigned long flags; - int ret = 0; spin_lock_irqsave(gate->lock, flags); @@ -65,7 +64,7 @@ static int clk_gate2_enable(struct clk_hw *hw) out: spin_unlock_irqrestore(gate->lock, flags); - return ret; + return 0; } static void clk_gate2_disable(struct clk_hw *hw) From bdb08940236c2096ac60c99854ff8b8fdc4d8d02 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 3 Nov 2020 17:24:29 +0100 Subject: [PATCH 032/134] clk: imx8mm: drop of_match_ptr from of_device_id table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match only via the DT table so the table should be always used and the of_match_ptr does not have any sense (this also allows ACPI matching via PRP0001, even though it might be not relevant here). This fixes compile warning (!CONFIG_OF && !CONFIG_MODULES): drivers/clk/imx/clk-imx8mm.c:641:34: warning: ‘imx8mm_clk_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Acked-by: Stephen Boyd Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c index 0de0be0cf548..e27890b61fb6 100644 --- a/drivers/clk/imx/clk-imx8mm.c +++ b/drivers/clk/imx/clk-imx8mm.c @@ -653,7 +653,7 @@ static struct platform_driver imx8mm_clk_driver = { * reloading the driver will crash or break devices. */ .suppress_bind_attrs = true, - .of_match_table = of_match_ptr(imx8mm_clk_of_match), + .of_match_table = imx8mm_clk_of_match, }, }; module_platform_driver(imx8mm_clk_driver); From 8f8a3230929f4ddcd3a5adb659e4b3cf52d9d38e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 3 Nov 2020 17:24:30 +0100 Subject: [PATCH 033/134] clk: imx8mn: drop of_match_ptr from of_device_id table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match only via the DT table so the table should be always used and the of_match_ptr does not have any sense (this also allows ACPI matching via PRP0001, even though it might be not relevant here). This fixes compile warning (!CONFIG_OF && !CONFIG_MODULES): drivers/clk/imx/clk-imx8mn.c:592:34: warning: ‘imx8mn_clk_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Acked-by: Stephen Boyd Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c index e984de543f0b..18f81419f355 100644 --- a/drivers/clk/imx/clk-imx8mn.c +++ b/drivers/clk/imx/clk-imx8mn.c @@ -604,7 +604,7 @@ static struct platform_driver imx8mn_clk_driver = { * reloading the driver will crash or break devices. */ .suppress_bind_attrs = true, - .of_match_table = of_match_ptr(imx8mn_clk_of_match), + .of_match_table = imx8mn_clk_of_match, }, }; module_platform_driver(imx8mn_clk_driver); From f32e42f09270a5298653ed6d8079fa7fddb6b393 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 3 Nov 2020 17:24:31 +0100 Subject: [PATCH 034/134] clk: imx8mp: drop of_match_ptr from of_device_id table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match only via the DT table so the table should be always used and the of_match_ptr does not have any sense (this also allows ACPI matching via PRP0001, even though it might be not relevant here). This fixes compile warning (!CONFIG_OF && !CONFIG_MODULES): drivers/clk/imx/clk-imx8mp.c:751:34: warning: ‘imx8mp_clk_of_match’ defined but not used [-Wunused-const-variable=] Reported-by: kernel test robot Signed-off-by: Krzysztof Kozlowski Acked-by: Stephen Boyd Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c index 3cb2bc46eae0..165bfe23fb34 100644 --- a/drivers/clk/imx/clk-imx8mp.c +++ b/drivers/clk/imx/clk-imx8mp.c @@ -763,7 +763,7 @@ static struct platform_driver imx8mp_clk_driver = { * reloading the driver will crash or break devices. */ .suppress_bind_attrs = true, - .of_match_table = of_match_ptr(imx8mp_clk_of_match), + .of_match_table = imx8mp_clk_of_match, }, }; module_platform_driver(imx8mp_clk_driver); From 00cb754ac62253c84ea969c8d0d48884111ad909 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 3 Nov 2020 17:24:32 +0100 Subject: [PATCH 035/134] clk: imx8mq: drop of_match_ptr from of_device_id table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match only via the DT table so the table should be always used and the of_match_ptr does not have any sense (this also allows ACPI matching via PRP0001, even though it might be not relevant here). This fixes compile warning (!CONFIG_OF && !CONFIG_MODULES): drivers/clk/imx/clk-imx8mq.c:626:34: warning: ‘imx8mq_clk_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Acked-by: Stephen Boyd Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx8mq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c index 8265d1d48af4..75186888ecae 100644 --- a/drivers/clk/imx/clk-imx8mq.c +++ b/drivers/clk/imx/clk-imx8mq.c @@ -639,7 +639,7 @@ static struct platform_driver imx8mq_clk_driver = { * reloading the driver will crash or break devices. */ .suppress_bind_attrs = true, - .of_match_table = of_match_ptr(imx8mq_clk_of_match), + .of_match_table = imx8mq_clk_of_match, }, }; module_platform_driver(imx8mq_clk_driver); From 550b562a153f84282c60fc3cb0d98f4e5609f0b4 Mon Sep 17 00:00:00 2001 From: Zou Wei Date: Wed, 4 Nov 2020 19:19:31 +0800 Subject: [PATCH 036/134] clk: imx: scu: Make pd_np with static keyword Fix the following sparse warning: ./clk-scu.c:23:20: warning: symbol 'pd_np' was not declared. Should it be static? Reported-by: Hulk Robot Signed-off-by: Zou Wei Reviewed-by: Stephen Boyd Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-scu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c index d0243c52ccbc..d10f60e48ece 100644 --- a/drivers/clk/imx/clk-scu.c +++ b/drivers/clk/imx/clk-scu.c @@ -20,7 +20,7 @@ #define IMX_SIP_SET_CPUFREQ 0x00 static struct imx_sc_ipc *ccm_ipc_handle; -struct device_node *pd_np; +static struct device_node *pd_np; static struct platform_driver imx_clk_scu_driver; struct imx_scu_clk_node { From e4accab4e0b069bd4ddc1ac769a77b989bb9ed1c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 13 Nov 2020 13:14:19 +0300 Subject: [PATCH 037/134] clk: qcom: lpass-sc7180: Clean up on error in lpass_sc7180_init() Clean up the first driver if the second driver can't be registered. Fixes: 4ee9fe3e292b ("clk: qcom: lpass-sc7180: Disentangle the two clock devices") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/20201113101419.GC168908@mwanda Reviewed-by: Douglas Anderson Signed-off-by: Stephen Boyd --- drivers/clk/qcom/lpasscorecc-sc7180.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/clk/qcom/lpasscorecc-sc7180.c b/drivers/clk/qcom/lpasscorecc-sc7180.c index 1a3925badd7c..9081649f476f 100644 --- a/drivers/clk/qcom/lpasscorecc-sc7180.c +++ b/drivers/clk/qcom/lpasscorecc-sc7180.c @@ -491,7 +491,13 @@ static int __init lpass_sc7180_init(void) if (ret) return ret; - return platform_driver_register(&lpass_hm_sc7180_driver); + ret = platform_driver_register(&lpass_hm_sc7180_driver); + if (ret) { + platform_driver_unregister(&lpass_core_cc_sc7180_driver); + return ret; + } + + return 0; } subsys_initcall(lpass_sc7180_init); From 8d4025943e13010d753935e37ad085fca4906e6c Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Sat, 14 Nov 2020 09:44:08 -0800 Subject: [PATCH 038/134] clk: qcom: camcc-sc7180: Use runtime PM ops instead of clk ones Let's call pm_runtime_get() here instead of calling the PM clk APIs directly. This avoids a compilation problem on CONFIG_PM=n where the pm_clk_runtime_{resume,suspend}() functions don't exist and covers the intent, i.e. enable the clks for this device so we can program PLL settings. Reported-by: Randy Dunlap Reported-by: Geert Uytterhoeven Cc: Nathan Chancellor Cc: Stephen Rothwell Cc: Taniya Das Cc: "Rafael J. Wysocki" Acked-by: Randy Dunlap # build-tested Fixes: 15d09e830bbc ("clk: qcom: camcc: Add camera clock controller driver for SC7180") Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20201114174408.579047-1-sboyd@kernel.org --- drivers/clk/qcom/camcc-sc7180.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/clk/qcom/camcc-sc7180.c b/drivers/clk/qcom/camcc-sc7180.c index f51bf5b6decc..dbac5651ab85 100644 --- a/drivers/clk/qcom/camcc-sc7180.c +++ b/drivers/clk/qcom/camcc-sc7180.c @@ -1669,16 +1669,14 @@ static int cam_cc_sc7180_probe(struct platform_device *pdev) goto disable_pm_runtime; } - ret = pm_clk_runtime_resume(&pdev->dev); - if (ret < 0) { - dev_err(&pdev->dev, "pm runtime resume failed\n"); + ret = pm_runtime_get(&pdev->dev); + if (ret) goto destroy_pm_clk; - } regmap = qcom_cc_map(pdev, &cam_cc_sc7180_desc); if (IS_ERR(regmap)) { ret = PTR_ERR(regmap); - pm_clk_runtime_suspend(&pdev->dev); + pm_runtime_put(&pdev->dev); goto destroy_pm_clk; } @@ -1688,9 +1686,7 @@ static int cam_cc_sc7180_probe(struct platform_device *pdev) clk_fabia_pll_configure(&cam_cc_pll3, regmap, &cam_cc_pll3_config); ret = qcom_cc_really_probe(pdev, &cam_cc_sc7180_desc, regmap); - - pm_clk_runtime_suspend(&pdev->dev); - + pm_runtime_put(&pdev->dev); if (ret < 0) { dev_err(&pdev->dev, "Failed to register CAM CC clocks\n"); goto destroy_pm_clk; From 6a17849703581f11b499da8e1d6a2941b9e738dd Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Fri, 6 Nov 2020 10:48:20 +0100 Subject: [PATCH 039/134] clk: remove unneeded dead-store initialization make clang-analyzer on x86_64 defconfig caught my attention with: drivers/clk/clk.c:423:19: warning: Value stored to 'parent' during its initialization is never read [clang-analyzer-deadcode.DeadStores] struct clk_core *parent = ERR_PTR(-ENOENT); ^ Commit fc0c209c147f ("clk: Allow parents to be specified without string names") introduced clk_core_fill_parent_index() with this unneeded dead-store initialization. So, simply remove this unneeded dead-store initialization to make clang-analyzer happy. As compilers will detect this unneeded assignment and optimize this anyway, the resulting object code is identical before and after this change. No functional change. No change to object code. Signed-off-by: Lukas Bulwahn Link: https://lore.kernel.org/r/20201106094820.30167-1-lukas.bulwahn@gmail.com Reviewed-by: Nathan Chancellor Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index f83dac54ed85..ba35bf35bcd3 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -420,7 +420,7 @@ static struct clk_core *clk_core_get(struct clk_core *core, u8 p_index) static void clk_core_fill_parent_index(struct clk_core *core, u8 index) { struct clk_parent_map *entry = &core->parents[index]; - struct clk_core *parent = ERR_PTR(-ENOENT); + struct clk_core *parent; if (entry->hw) { parent = entry->hw->core; From e5a4b9b99e5b70a41578e78d30349315772add1b Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 21 Oct 2020 18:21:45 +0200 Subject: [PATCH 040/134] clk: avoid devm_clk_release name clash In clk-devres.c, devm_clk_release() is used to call clk_put() memory managed clock. In clk.c the same name, in a different scope is used to call clk_unregister(). As it stands, it is not really a problem but it does not readability, especially if we need to call clk_put() on managed clock in clk.c Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20201021162147.563655-2-jbrunet@baylibre.com Tested-by: Kevin Hilman Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index f83dac54ed85..f70dc0ef1cdd 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -4068,12 +4068,12 @@ void clk_hw_unregister(struct clk_hw *hw) } EXPORT_SYMBOL_GPL(clk_hw_unregister); -static void devm_clk_release(struct device *dev, void *res) +static void devm_clk_unregister_cb(struct device *dev, void *res) { clk_unregister(*(struct clk **)res); } -static void devm_clk_hw_release(struct device *dev, void *res) +static void devm_clk_hw_unregister_cb(struct device *dev, void *res) { clk_hw_unregister(*(struct clk_hw **)res); } @@ -4093,7 +4093,7 @@ struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw) struct clk *clk; struct clk **clkp; - clkp = devres_alloc(devm_clk_release, sizeof(*clkp), GFP_KERNEL); + clkp = devres_alloc(devm_clk_unregister_cb, sizeof(*clkp), GFP_KERNEL); if (!clkp) return ERR_PTR(-ENOMEM); @@ -4123,7 +4123,7 @@ int devm_clk_hw_register(struct device *dev, struct clk_hw *hw) struct clk_hw **hwp; int ret; - hwp = devres_alloc(devm_clk_hw_release, sizeof(*hwp), GFP_KERNEL); + hwp = devres_alloc(devm_clk_hw_unregister_cb, sizeof(*hwp), GFP_KERNEL); if (!hwp) return -ENOMEM; @@ -4167,7 +4167,7 @@ static int devm_clk_hw_match(struct device *dev, void *res, void *data) */ void devm_clk_unregister(struct device *dev, struct clk *clk) { - WARN_ON(devres_release(dev, devm_clk_release, devm_clk_match, clk)); + WARN_ON(devres_release(dev, devm_clk_unregister_cb, devm_clk_match, clk)); } EXPORT_SYMBOL_GPL(devm_clk_unregister); @@ -4182,7 +4182,7 @@ EXPORT_SYMBOL_GPL(devm_clk_unregister); */ void devm_clk_hw_unregister(struct device *dev, struct clk_hw *hw) { - WARN_ON(devres_release(dev, devm_clk_hw_release, devm_clk_hw_match, + WARN_ON(devres_release(dev, devm_clk_hw_unregister_cb, devm_clk_hw_match, hw)); } EXPORT_SYMBOL_GPL(devm_clk_hw_unregister); From 30d6f8c15d2cd877c1f3d47d8a1064649ebe58e2 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 21 Oct 2020 18:21:46 +0200 Subject: [PATCH 041/134] clk: add api to get clk consumer from clk_hw clk_register() is deprecated. Using 'clk' member of struct clk_hw is discouraged. With this constraint, it is difficult for driver to register clocks using the clk_hw API and then use the clock with the consumer API This adds a simple helper, clk_hw_get_clk(), to get a struct clk from a struct clk_hw. Like other clk_get() variant, each call to this helper must be balanced with a call to clk_put(). To make life easier on the consumers, a memory managed version is provided as well. Cc: Martin Blumenstingl Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20201021162147.563655-3-jbrunet@baylibre.com Tested-by: Kevin Hilman [sboyd@kernel.org: Fix kernel-doc] Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 61 ++++++++++++++++++++++++++++++++++++ include/linux/clk-provider.h | 5 +++ 2 files changed, 66 insertions(+) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index f70dc0ef1cdd..48931f442de8 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -3667,6 +3667,24 @@ struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw, return clk; } +/** + * clk_hw_get_clk - get clk consumer given an clk_hw + * @hw: clk_hw associated with the clk being consumed + * @con_id: connection ID string on device + * + * Returns: new clk consumer + * This is the function to be used by providers which need + * to get a consumer clk and act on the clock element + * Calls to this function must be balanced with calls clk_put() + */ +struct clk *clk_hw_get_clk(struct clk_hw *hw, const char *con_id) +{ + struct device *dev = hw->core->dev; + + return clk_hw_create_clk(dev, hw, dev_name(dev), con_id); +} +EXPORT_SYMBOL(clk_hw_get_clk); + static int clk_cpy_name(const char **dst_p, const char *src, bool must_exist) { const char *dst; @@ -4187,6 +4205,49 @@ void devm_clk_hw_unregister(struct device *dev, struct clk_hw *hw) } EXPORT_SYMBOL_GPL(devm_clk_hw_unregister); +static void devm_clk_release(struct device *dev, void *res) +{ + clk_put(*(struct clk **)res); +} + +/** + * devm_clk_hw_get_clk - resource managed clk_hw_get_clk() + * @dev: device that is registering this clock + * @hw: clk_hw associated with the clk being consumed + * @con_id: connection ID string on device + * + * Managed clk_hw_get_clk(). Clocks got with this function are + * automatically clk_put() on driver detach. See clk_put() + * for more information. + */ +struct clk *devm_clk_hw_get_clk(struct device *dev, struct clk_hw *hw, + const char *con_id) +{ + struct clk *clk; + struct clk **clkp; + + /* This should not happen because it would mean we have drivers + * passing around clk_hw pointers instead of having the caller use + * proper clk_get() style APIs + */ + WARN_ON_ONCE(dev != hw->core->dev); + + clkp = devres_alloc(devm_clk_release, sizeof(*clkp), GFP_KERNEL); + if (!clkp) + return ERR_PTR(-ENOMEM); + + clk = clk_hw_get_clk(hw, con_id); + if (!IS_ERR(clk)) { + *clkp = clk; + devres_add(dev, clkp); + } else { + devres_free(clkp); + } + + return clk; +} +EXPORT_SYMBOL_GPL(devm_clk_hw_get_clk); + /* * clkdev helpers */ diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 03a5de5f99f4..86b707520ec0 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -1088,6 +1088,11 @@ static inline struct clk_hw *__clk_get_hw(struct clk *clk) return (struct clk_hw *)clk; } #endif + +struct clk *clk_hw_get_clk(struct clk_hw *hw, const char *con_id); +struct clk *devm_clk_hw_get_clk(struct device *dev, struct clk_hw *hw, + const char *con_id); + unsigned int clk_hw_get_num_parents(const struct clk_hw *hw); struct clk_hw *clk_hw_get_parent(const struct clk_hw *hw); struct clk_hw *clk_hw_get_parent_by_index(const struct clk_hw *hw, From 8e677e7f0aa3b01c501a9a48a04a34173380ccfd Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 21 Oct 2020 18:21:47 +0200 Subject: [PATCH 042/134] clk: meson: g12: drop use of __clk_lookup() g12 clock controller used __clk_lookup() to get struct clk from a struct clk_hw. This type of hack is no longer required as CCF now provides the necessary functions to get this. Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20201021162147.563655-4-jbrunet@baylibre.com Tested-by: Kevin Hilman Signed-off-by: Stephen Boyd --- drivers/clk/meson/g12a.c | 68 +++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index b814d44917a5..235dcf72e34a 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -5156,10 +5156,11 @@ static const struct reg_sequence g12a_init_regs[] = { { .reg = HHI_MPLL_CNTL0, .def = 0x00000543 }, }; -static int meson_g12a_dvfs_setup_common(struct platform_device *pdev, +#define DVFS_CON_ID "dvfs" + +static int meson_g12a_dvfs_setup_common(struct device *dev, struct clk_hw **hws) { - const char *notifier_clk_name; struct clk *notifier_clk; struct clk_hw *xtal; int ret; @@ -5168,21 +5169,21 @@ static int meson_g12a_dvfs_setup_common(struct platform_device *pdev, /* Setup clock notifier for cpu_clk_postmux0 */ g12a_cpu_clk_postmux0_nb_data.xtal = xtal; - notifier_clk_name = clk_hw_get_name(&g12a_cpu_clk_postmux0.hw); - notifier_clk = __clk_lookup(notifier_clk_name); + notifier_clk = devm_clk_hw_get_clk(dev, &g12a_cpu_clk_postmux0.hw, + DVFS_CON_ID); ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_postmux0_nb_data.nb); if (ret) { - dev_err(&pdev->dev, "failed to register the cpu_clk_postmux0 notifier\n"); + dev_err(dev, "failed to register the cpu_clk_postmux0 notifier\n"); return ret; } /* Setup clock notifier for cpu_clk_dyn mux */ - notifier_clk_name = clk_hw_get_name(&g12a_cpu_clk_dyn.hw); - notifier_clk = __clk_lookup(notifier_clk_name); + notifier_clk = devm_clk_hw_get_clk(dev, &g12a_cpu_clk_dyn.hw, + DVFS_CON_ID); ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb); if (ret) { - dev_err(&pdev->dev, "failed to register the cpu_clk_dyn notifier\n"); + dev_err(dev, "failed to register the cpu_clk_dyn notifier\n"); return ret; } @@ -5192,33 +5193,33 @@ static int meson_g12a_dvfs_setup_common(struct platform_device *pdev, static int meson_g12b_dvfs_setup(struct platform_device *pdev) { struct clk_hw **hws = g12b_hw_onecell_data.hws; - const char *notifier_clk_name; + struct device *dev = &pdev->dev; struct clk *notifier_clk; struct clk_hw *xtal; int ret; - ret = meson_g12a_dvfs_setup_common(pdev, hws); + ret = meson_g12a_dvfs_setup_common(dev, hws); if (ret) return ret; xtal = clk_hw_get_parent_by_index(hws[CLKID_CPU_CLK_DYN1_SEL], 0); /* Setup clock notifier for cpu_clk mux */ - notifier_clk_name = clk_hw_get_name(&g12b_cpu_clk.hw); - notifier_clk = __clk_lookup(notifier_clk_name); + notifier_clk = devm_clk_hw_get_clk(dev, &g12b_cpu_clk.hw, + DVFS_CON_ID); ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb); if (ret) { - dev_err(&pdev->dev, "failed to register the cpu_clk notifier\n"); + dev_err(dev, "failed to register the cpu_clk notifier\n"); return ret; } /* Setup clock notifier for sys1_pll */ - notifier_clk_name = clk_hw_get_name(&g12b_sys1_pll.hw); - notifier_clk = __clk_lookup(notifier_clk_name); + notifier_clk = devm_clk_hw_get_clk(dev, &g12b_sys1_pll.hw, + DVFS_CON_ID); ret = clk_notifier_register(notifier_clk, &g12b_cpu_clk_sys1_pll_nb_data.nb); if (ret) { - dev_err(&pdev->dev, "failed to register the sys1_pll notifier\n"); + dev_err(dev, "failed to register the sys1_pll notifier\n"); return ret; } @@ -5226,40 +5227,37 @@ static int meson_g12b_dvfs_setup(struct platform_device *pdev) /* Setup clock notifier for cpub_clk_postmux0 */ g12b_cpub_clk_postmux0_nb_data.xtal = xtal; - notifier_clk_name = clk_hw_get_name(&g12b_cpub_clk_postmux0.hw); - notifier_clk = __clk_lookup(notifier_clk_name); + notifier_clk = devm_clk_hw_get_clk(dev, &g12b_cpub_clk_postmux0.hw, + DVFS_CON_ID); ret = clk_notifier_register(notifier_clk, &g12b_cpub_clk_postmux0_nb_data.nb); if (ret) { - dev_err(&pdev->dev, "failed to register the cpub_clk_postmux0 notifier\n"); + dev_err(dev, "failed to register the cpub_clk_postmux0 notifier\n"); return ret; } /* Setup clock notifier for cpub_clk_dyn mux */ - notifier_clk_name = clk_hw_get_name(&g12b_cpub_clk_dyn.hw); - notifier_clk = __clk_lookup(notifier_clk_name); + notifier_clk = devm_clk_hw_get_clk(dev, &g12b_cpub_clk_dyn.hw, "dvfs"); ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb); if (ret) { - dev_err(&pdev->dev, "failed to register the cpub_clk_dyn notifier\n"); + dev_err(dev, "failed to register the cpub_clk_dyn notifier\n"); return ret; } /* Setup clock notifier for cpub_clk mux */ - notifier_clk_name = clk_hw_get_name(&g12b_cpub_clk.hw); - notifier_clk = __clk_lookup(notifier_clk_name); + notifier_clk = devm_clk_hw_get_clk(dev, &g12b_cpub_clk.hw, DVFS_CON_ID); ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb); if (ret) { - dev_err(&pdev->dev, "failed to register the cpub_clk notifier\n"); + dev_err(dev, "failed to register the cpub_clk notifier\n"); return ret; } /* Setup clock notifier for sys_pll */ - notifier_clk_name = clk_hw_get_name(&g12a_sys_pll.hw); - notifier_clk = __clk_lookup(notifier_clk_name); + notifier_clk = devm_clk_hw_get_clk(dev, &g12a_sys_pll.hw, DVFS_CON_ID); ret = clk_notifier_register(notifier_clk, &g12b_cpub_clk_sys_pll_nb_data.nb); if (ret) { - dev_err(&pdev->dev, "failed to register the sys_pll notifier\n"); + dev_err(dev, "failed to register the sys_pll notifier\n"); return ret; } @@ -5269,29 +5267,27 @@ static int meson_g12b_dvfs_setup(struct platform_device *pdev) static int meson_g12a_dvfs_setup(struct platform_device *pdev) { struct clk_hw **hws = g12a_hw_onecell_data.hws; - const char *notifier_clk_name; + struct device *dev = &pdev->dev; struct clk *notifier_clk; int ret; - ret = meson_g12a_dvfs_setup_common(pdev, hws); + ret = meson_g12a_dvfs_setup_common(dev, hws); if (ret) return ret; /* Setup clock notifier for cpu_clk mux */ - notifier_clk_name = clk_hw_get_name(&g12a_cpu_clk.hw); - notifier_clk = __clk_lookup(notifier_clk_name); + notifier_clk = devm_clk_hw_get_clk(dev, &g12a_cpu_clk.hw, DVFS_CON_ID); ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb); if (ret) { - dev_err(&pdev->dev, "failed to register the cpu_clk notifier\n"); + dev_err(dev, "failed to register the cpu_clk notifier\n"); return ret; } /* Setup clock notifier for sys_pll */ - notifier_clk_name = clk_hw_get_name(&g12a_sys_pll.hw); - notifier_clk = __clk_lookup(notifier_clk_name); + notifier_clk = devm_clk_hw_get_clk(dev, &g12a_sys_pll.hw, DVFS_CON_ID); ret = clk_notifier_register(notifier_clk, &g12a_sys_pll_nb_data.nb); if (ret) { - dev_err(&pdev->dev, "failed to register the sys_pll notifier\n"); + dev_err(dev, "failed to register the sys_pll notifier\n"); return ret; } From 6d30d50d037dfa092f9d5d1fffa348ab4abb7163 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 21 Oct 2020 18:38:46 +0200 Subject: [PATCH 043/134] clk: add devm variant of clk_notifier_register Add a memory managed variant of clk_notifier_register() to make life easier on clock consumers using notifiers Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20201021163847.595189-2-jbrunet@baylibre.com Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 36 ++++++++++++++++++++++++++++++++++++ include/linux/clk.h | 10 ++++++++++ 2 files changed, 46 insertions(+) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 48931f442de8..6cf59e3c31b4 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -4395,6 +4395,42 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb) } EXPORT_SYMBOL_GPL(clk_notifier_unregister); +struct clk_notifier_devres { + struct clk *clk; + struct notifier_block *nb; +}; + +static void devm_clk_notifier_release(struct device *dev, void *res) +{ + struct clk_notifier_devres *devres = res; + + clk_notifier_unregister(devres->clk, devres->nb); +} + +int devm_clk_notifier_register(struct device *dev, struct clk *clk, + struct notifier_block *nb) +{ + struct clk_notifier_devres *devres; + int ret; + + devres = devres_alloc(devm_clk_notifier_release, + sizeof(*devres), GFP_KERNEL); + + if (!devres) + return -ENOMEM; + + ret = clk_notifier_register(clk, nb); + if (!ret) { + devres->clk = clk; + devres->nb = nb; + } else { + devres_free(devres); + } + + return ret; +} +EXPORT_SYMBOL_GPL(devm_clk_notifier_register); + #ifdef CONFIG_OF static void clk_core_reparent_orphans(void) { diff --git a/include/linux/clk.h b/include/linux/clk.h index 7fd6a1febcf4..f53afdf8198b 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -109,6 +109,16 @@ int clk_notifier_register(struct clk *clk, struct notifier_block *nb); */ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb); +/** + * devm_clk_notifier_register - register a managed rate-change notifier callback + * @dev: device for clock "consumer" + * @clk: clock whose rate we are interested in + * @nb: notifier block with callback function pointer + * + * Returns 0 on success, -EERROR otherwise + */ +int devm_clk_notifier_register(struct device *dev, struct clk *clk, struct notifier_block *nb); + /** * clk_get_accuracy - obtain the clock accuracy in ppb (parts per billion) * for a clock source. From e6fb7aee486c7fbd4d94f4894feaa6f0424c1740 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 21 Oct 2020 18:38:47 +0200 Subject: [PATCH 044/134] clk: meson: g12: use devm variant to register notifiers Until now, nothing was done to unregister the dvfs clock notifiers of the Amlogic g12 SoC family. This is not great but this driver was not really expected to be unloaded. With the ongoing effort to build everything as module for this platform, this needs to be cleanly handled. Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20201021163847.595189-3-jbrunet@baylibre.com Signed-off-by: Stephen Boyd --- drivers/clk/meson/g12a.c | 34 ++++++++++++++++++++-------------- include/linux/clk.h | 10 +++++++++- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index 235dcf72e34a..108e4491b1e2 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -5171,8 +5171,8 @@ static int meson_g12a_dvfs_setup_common(struct device *dev, g12a_cpu_clk_postmux0_nb_data.xtal = xtal; notifier_clk = devm_clk_hw_get_clk(dev, &g12a_cpu_clk_postmux0.hw, DVFS_CON_ID); - ret = clk_notifier_register(notifier_clk, - &g12a_cpu_clk_postmux0_nb_data.nb); + ret = devm_clk_notifier_register(dev, notifier_clk, + &g12a_cpu_clk_postmux0_nb_data.nb); if (ret) { dev_err(dev, "failed to register the cpu_clk_postmux0 notifier\n"); return ret; @@ -5181,7 +5181,8 @@ static int meson_g12a_dvfs_setup_common(struct device *dev, /* Setup clock notifier for cpu_clk_dyn mux */ notifier_clk = devm_clk_hw_get_clk(dev, &g12a_cpu_clk_dyn.hw, DVFS_CON_ID); - ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb); + ret = devm_clk_notifier_register(dev, notifier_clk, + &g12a_cpu_clk_mux_nb); if (ret) { dev_err(dev, "failed to register the cpu_clk_dyn notifier\n"); return ret; @@ -5207,7 +5208,8 @@ static int meson_g12b_dvfs_setup(struct platform_device *pdev) /* Setup clock notifier for cpu_clk mux */ notifier_clk = devm_clk_hw_get_clk(dev, &g12b_cpu_clk.hw, DVFS_CON_ID); - ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb); + ret = devm_clk_notifier_register(dev, notifier_clk, + &g12a_cpu_clk_mux_nb); if (ret) { dev_err(dev, "failed to register the cpu_clk notifier\n"); return ret; @@ -5216,8 +5218,8 @@ static int meson_g12b_dvfs_setup(struct platform_device *pdev) /* Setup clock notifier for sys1_pll */ notifier_clk = devm_clk_hw_get_clk(dev, &g12b_sys1_pll.hw, DVFS_CON_ID); - ret = clk_notifier_register(notifier_clk, - &g12b_cpu_clk_sys1_pll_nb_data.nb); + ret = devm_clk_notifier_register(dev, notifier_clk, + &g12b_cpu_clk_sys1_pll_nb_data.nb); if (ret) { dev_err(dev, "failed to register the sys1_pll notifier\n"); return ret; @@ -5229,8 +5231,8 @@ static int meson_g12b_dvfs_setup(struct platform_device *pdev) g12b_cpub_clk_postmux0_nb_data.xtal = xtal; notifier_clk = devm_clk_hw_get_clk(dev, &g12b_cpub_clk_postmux0.hw, DVFS_CON_ID); - ret = clk_notifier_register(notifier_clk, - &g12b_cpub_clk_postmux0_nb_data.nb); + ret = devm_clk_notifier_register(dev, notifier_clk, + &g12b_cpub_clk_postmux0_nb_data.nb); if (ret) { dev_err(dev, "failed to register the cpub_clk_postmux0 notifier\n"); return ret; @@ -5238,7 +5240,8 @@ static int meson_g12b_dvfs_setup(struct platform_device *pdev) /* Setup clock notifier for cpub_clk_dyn mux */ notifier_clk = devm_clk_hw_get_clk(dev, &g12b_cpub_clk_dyn.hw, "dvfs"); - ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb); + ret = devm_clk_notifier_register(dev, notifier_clk, + &g12a_cpu_clk_mux_nb); if (ret) { dev_err(dev, "failed to register the cpub_clk_dyn notifier\n"); return ret; @@ -5246,7 +5249,8 @@ static int meson_g12b_dvfs_setup(struct platform_device *pdev) /* Setup clock notifier for cpub_clk mux */ notifier_clk = devm_clk_hw_get_clk(dev, &g12b_cpub_clk.hw, DVFS_CON_ID); - ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb); + ret = devm_clk_notifier_register(dev, notifier_clk, + &g12a_cpu_clk_mux_nb); if (ret) { dev_err(dev, "failed to register the cpub_clk notifier\n"); return ret; @@ -5254,8 +5258,8 @@ static int meson_g12b_dvfs_setup(struct platform_device *pdev) /* Setup clock notifier for sys_pll */ notifier_clk = devm_clk_hw_get_clk(dev, &g12a_sys_pll.hw, DVFS_CON_ID); - ret = clk_notifier_register(notifier_clk, - &g12b_cpub_clk_sys_pll_nb_data.nb); + ret = devm_clk_notifier_register(dev, notifier_clk, + &g12b_cpub_clk_sys_pll_nb_data.nb); if (ret) { dev_err(dev, "failed to register the sys_pll notifier\n"); return ret; @@ -5277,7 +5281,8 @@ static int meson_g12a_dvfs_setup(struct platform_device *pdev) /* Setup clock notifier for cpu_clk mux */ notifier_clk = devm_clk_hw_get_clk(dev, &g12a_cpu_clk.hw, DVFS_CON_ID); - ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb); + ret = devm_clk_notifier_register(dev, notifier_clk, + &g12a_cpu_clk_mux_nb); if (ret) { dev_err(dev, "failed to register the cpu_clk notifier\n"); return ret; @@ -5285,7 +5290,8 @@ static int meson_g12a_dvfs_setup(struct platform_device *pdev) /* Setup clock notifier for sys_pll */ notifier_clk = devm_clk_hw_get_clk(dev, &g12a_sys_pll.hw, DVFS_CON_ID); - ret = clk_notifier_register(notifier_clk, &g12a_sys_pll_nb_data.nb); + ret = devm_clk_notifier_register(dev, notifier_clk, + &g12a_sys_pll_nb_data.nb); if (ret) { dev_err(dev, "failed to register the sys_pll notifier\n"); return ret; diff --git a/include/linux/clk.h b/include/linux/clk.h index f53afdf8198b..4ac766dc3daf 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -117,7 +117,8 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb); * * Returns 0 on success, -EERROR otherwise */ -int devm_clk_notifier_register(struct device *dev, struct clk *clk, struct notifier_block *nb); +int devm_clk_notifier_register(struct device *dev, struct clk *clk, + struct notifier_block *nb); /** * clk_get_accuracy - obtain the clock accuracy in ppb (parts per billion) @@ -196,6 +197,13 @@ static inline int clk_notifier_unregister(struct clk *clk, return -ENOTSUPP; } +static inline int devm_clk_notifier_register(struct device *dev, + struct clk *clk, + struct notifier_block *nb) +{ + return -ENOTSUPP; +} + static inline long clk_get_accuracy(struct clk *clk) { return -ENOTSUPP; From 3105c7c91feb176f8b918ebe13abd520f7651834 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 23 Oct 2020 16:19:25 +0300 Subject: [PATCH 045/134] clk: qcom: dispcc-sm8250: handle MMCX power domain On SM8250 MMCX power domain is required to access MMDS_GDSC registers. This power domain is expressed as mmcx-supply regulator property. Use this regulator as MDSS_GDSC supply. Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20201023131925.334864-6-dmitry.baryshkov@linaro.org Signed-off-by: Stephen Boyd --- drivers/clk/qcom/dispcc-sm8250.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/qcom/dispcc-sm8250.c b/drivers/clk/qcom/dispcc-sm8250.c index 07a98d3f882d..588575e1169d 100644 --- a/drivers/clk/qcom/dispcc-sm8250.c +++ b/drivers/clk/qcom/dispcc-sm8250.c @@ -963,6 +963,7 @@ static struct gdsc mdss_gdsc = { }, .pwrsts = PWRSTS_OFF_ON, .flags = HW_CTRL, + .supply = "mmcx", }; static struct clk_regmap *disp_cc_sm8250_clocks[] = { From 6160aca443148416994c022a35c77daeba948ea6 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Wed, 28 Oct 2020 17:48:20 -0700 Subject: [PATCH 046/134] clk: tegra: Do not return 0 on failure Return values from read_dt_param() will be either TRUE (1) or FALSE (0), while dfll_fetch_pwm_params() returns 0 on success or an ERR code on failure. So this patch fixes the bug of returning 0 on failure. Fixes: 36541f0499fe ("clk: tegra: dfll: support PWM regulator control") Cc: Signed-off-by: Nicolin Chen Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-dfll.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/tegra/clk-dfll.c b/drivers/clk/tegra/clk-dfll.c index cfbaa90c7adb..a5f526bb0483 100644 --- a/drivers/clk/tegra/clk-dfll.c +++ b/drivers/clk/tegra/clk-dfll.c @@ -1856,13 +1856,13 @@ static int dfll_fetch_pwm_params(struct tegra_dfll *td) &td->reg_init_uV); if (!ret) { dev_err(td->dev, "couldn't get initialized voltage\n"); - return ret; + return -EINVAL; } ret = read_dt_param(td, "nvidia,pwm-period-nanoseconds", &pwm_period); if (!ret) { dev_err(td->dev, "couldn't get PWM period\n"); - return ret; + return -EINVAL; } td->pwm_rate = (NSEC_PER_SEC / pwm_period) * (MAX_DFLL_VOLTAGES - 1); From 14ebb3154b8f3d562cb18331b08ff1a22609ae59 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 15 Sep 2020 14:45:52 +0200 Subject: [PATCH 047/134] clk: meson: axg: add Video Clocks Add the clocks entries used in the video clock path, the clock path is doubled to permit having different synchronized clocks for different parts of the video pipeline. The AXG only has a single ENCL CTS clock and even if VCLK exist along VCLK2, only VCLK2 is used since it clocks the MIPI DSI IP directly. All dividers are flagged with CLK_GET_RATE_NOCACHE, and all gates are flagged with CLK_IGNORE_UNUSED since they are currently directly handled by the Meson DRM Driver. Once the DRM Driver is fully migrated to using the Common Clock Framework to handle the video clock tree, the CLK_GET_RATE_NOCACHE and CLK_IGNORE_UNUSED will be dropped. Signed-off-by: Neil Armstrong Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20200915124553.8056-4-narmstrong@baylibre.com --- drivers/clk/meson/axg.c | 753 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/meson/axg.h | 21 +- 2 files changed, 773 insertions(+), 1 deletion(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 13fc0006f63d..a4e8949297cf 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -1026,6 +1026,683 @@ static struct clk_regmap axg_sd_emmc_c_clk0 = { }, }; +/* VPU Clock */ + +static const struct clk_hw *axg_vpu_parent_hws[] = { + &axg_fclk_div4.hw, + &axg_fclk_div3.hw, + &axg_fclk_div5.hw, + &axg_fclk_div7.hw, +}; + +static struct clk_regmap axg_vpu_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = axg_vpu_parent_hws, + .num_parents = ARRAY_SIZE(axg_vpu_parent_hws), + /* We need a specific parent for VPU clock source, let it be set in DT */ + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap axg_vpu_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VPU_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vpu_0_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_vpu_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VPU_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vpu_0_div.hw }, + .num_parents = 1, + /* + * We want to avoid CCF to disable the VPU clock if + * display has been set by Bootloader + */ + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vpu_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 0x3, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = axg_vpu_parent_hws, + .num_parents = ARRAY_SIZE(axg_vpu_parent_hws), + /* We need a specific parent for VPU clock source, let it be set in DT */ + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap axg_vpu_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VPU_CLK_CNTL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vpu_1_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_vpu_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VPU_CLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vpu_1_div.hw }, + .num_parents = 1, + /* + * We want to avoid CCF to disable the VPU clock if + * display has been set by Bootloader + */ + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vpu = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vpu_0.hw, + &axg_vpu_1.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +/* VAPB Clock */ + +static struct clk_regmap axg_vapb_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VAPBCLK_CNTL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = axg_vpu_parent_hws, + .num_parents = ARRAY_SIZE(axg_vpu_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap axg_vapb_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VAPBCLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vapb_0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_vapb_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VAPBCLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vapb_0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vapb_0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vapb_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VAPBCLK_CNTL, + .mask = 0x3, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = axg_vpu_parent_hws, + .num_parents = ARRAY_SIZE(axg_vpu_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap axg_vapb_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VAPBCLK_CNTL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vapb_1_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_vapb_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VAPBCLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "vapb_1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vapb_1_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vapb_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VAPBCLK_CNTL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vapb_0.hw, + &axg_vapb_1.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap axg_vapb = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VAPBCLK_CNTL, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data) { + .name = "vapb", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vapb_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +/* Video Clocks */ + +static const struct clk_hw *axg_vclk_parent_hws[] = { + &axg_gp0_pll.hw, + &axg_fclk_div4.hw, + &axg_fclk_div3.hw, + &axg_fclk_div5.hw, + &axg_fclk_div2.hw, + &axg_fclk_div7.hw, + &axg_mpll1.hw, +}; + +static struct clk_regmap axg_vclk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VID_CLK_CNTL, + .mask = 0x7, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = axg_vclk_parent_hws, + .num_parents = ARRAY_SIZE(axg_vclk_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap axg_vclk2_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VIID_CLK_CNTL, + .mask = 0x7, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = axg_vclk_parent_hws, + .num_parents = ARRAY_SIZE(axg_vclk_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap axg_vclk_input = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_DIV, + .bit_idx = 16, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_input", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk2_input = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_DIV, + .bit_idx = 16, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_input", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk2_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VID_CLK_DIV, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vclk_input.hw + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap axg_vclk2_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VIID_CLK_DIV, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vclk2_input.hw + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap axg_vclk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 19, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_CNTL, + .bit_idx = 19, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk2_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk_div1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk_div2_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div2_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk_div4_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div4_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk_div6_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div6_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk_div12_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div12_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk2_div1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_CNTL, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk2_div2_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_CNTL, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div2_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk2_div4_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_CNTL, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div4_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk2_div6_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_CNTL, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div6_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk2_div12_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_CNTL, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div12_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_fixed_factor axg_vclk_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vclk_div2_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_vclk_div4 = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div4", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vclk_div4_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_vclk_div6 = { + .mult = 1, + .div = 6, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div6", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vclk_div6_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_vclk_div12 = { + .mult = 1, + .div = 12, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div12", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vclk_div12_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_vclk2_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vclk2_div2_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_vclk2_div4 = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div4", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vclk2_div4_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_vclk2_div6 = { + .mult = 1, + .div = 6, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div6", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vclk2_div6_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_vclk2_div12 = { + .mult = 1, + .div = 12, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div12", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vclk2_div12_en.hw + }, + .num_parents = 1, + }, +}; + +static u32 mux_table_cts_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; +static const struct clk_hw *axg_cts_parent_hws[] = { + &axg_vclk_div1.hw, + &axg_vclk_div2.hw, + &axg_vclk_div4.hw, + &axg_vclk_div6.hw, + &axg_vclk_div12.hw, + &axg_vclk2_div1.hw, + &axg_vclk2_div2.hw, + &axg_vclk2_div4.hw, + &axg_vclk2_div6.hw, + &axg_vclk2_div12.hw, +}; + +static struct clk_regmap axg_cts_encl_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VIID_CLK_DIV, + .mask = 0xf, + .shift = 12, + .table = mux_table_cts_sel, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_encl_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = axg_cts_parent_hws, + .num_parents = ARRAY_SIZE(axg_cts_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap axg_cts_encl = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data) { + .name = "cts_encl", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_cts_encl_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + static u32 mux_table_gen_clk[] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, }; static const struct clk_parent_data gen_clk_parent_data[] = { @@ -1246,6 +1923,49 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = { [CLKID_HIFI_PLL_DCO] = &axg_hifi_pll_dco.hw, [CLKID_PCIE_PLL_DCO] = &axg_pcie_pll_dco.hw, [CLKID_PCIE_PLL_OD] = &axg_pcie_pll_od.hw, + [CLKID_VPU_0_DIV] = &axg_vpu_0_div.hw, + [CLKID_VPU_0_SEL] = &axg_vpu_0_sel.hw, + [CLKID_VPU_0] = &axg_vpu_0.hw, + [CLKID_VPU_1_DIV] = &axg_vpu_1_div.hw, + [CLKID_VPU_1_SEL] = &axg_vpu_1_sel.hw, + [CLKID_VPU_1] = &axg_vpu_1.hw, + [CLKID_VPU] = &axg_vpu.hw, + [CLKID_VAPB_0_DIV] = &axg_vapb_0_div.hw, + [CLKID_VAPB_0_SEL] = &axg_vapb_0_sel.hw, + [CLKID_VAPB_0] = &axg_vapb_0.hw, + [CLKID_VAPB_1_DIV] = &axg_vapb_1_div.hw, + [CLKID_VAPB_1_SEL] = &axg_vapb_1_sel.hw, + [CLKID_VAPB_1] = &axg_vapb_1.hw, + [CLKID_VAPB_SEL] = &axg_vapb_sel.hw, + [CLKID_VAPB] = &axg_vapb.hw, + [CLKID_VCLK] = &axg_vclk.hw, + [CLKID_VCLK2] = &axg_vclk2.hw, + [CLKID_VCLK_SEL] = &axg_vclk_sel.hw, + [CLKID_VCLK2_SEL] = &axg_vclk2_sel.hw, + [CLKID_VCLK_INPUT] = &axg_vclk_input.hw, + [CLKID_VCLK2_INPUT] = &axg_vclk2_input.hw, + [CLKID_VCLK_DIV] = &axg_vclk_div.hw, + [CLKID_VCLK2_DIV] = &axg_vclk2_div.hw, + [CLKID_VCLK_DIV2_EN] = &axg_vclk_div2_en.hw, + [CLKID_VCLK_DIV4_EN] = &axg_vclk_div4_en.hw, + [CLKID_VCLK_DIV6_EN] = &axg_vclk_div6_en.hw, + [CLKID_VCLK_DIV12_EN] = &axg_vclk_div12_en.hw, + [CLKID_VCLK2_DIV2_EN] = &axg_vclk2_div2_en.hw, + [CLKID_VCLK2_DIV4_EN] = &axg_vclk2_div4_en.hw, + [CLKID_VCLK2_DIV6_EN] = &axg_vclk2_div6_en.hw, + [CLKID_VCLK2_DIV12_EN] = &axg_vclk2_div12_en.hw, + [CLKID_VCLK_DIV1] = &axg_vclk_div1.hw, + [CLKID_VCLK_DIV2] = &axg_vclk_div2.hw, + [CLKID_VCLK_DIV4] = &axg_vclk_div4.hw, + [CLKID_VCLK_DIV6] = &axg_vclk_div6.hw, + [CLKID_VCLK_DIV12] = &axg_vclk_div12.hw, + [CLKID_VCLK2_DIV1] = &axg_vclk2_div1.hw, + [CLKID_VCLK2_DIV2] = &axg_vclk2_div2.hw, + [CLKID_VCLK2_DIV4] = &axg_vclk2_div4.hw, + [CLKID_VCLK2_DIV6] = &axg_vclk2_div6.hw, + [CLKID_VCLK2_DIV12] = &axg_vclk2_div12.hw, + [CLKID_CTS_ENCL_SEL] = &axg_cts_encl_sel.hw, + [CLKID_CTS_ENCL] = &axg_cts_encl.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -1341,6 +2061,39 @@ static struct clk_regmap *const axg_clk_regmaps[] = { &axg_hifi_pll_dco, &axg_pcie_pll_dco, &axg_pcie_pll_od, + &axg_vpu_0_div, + &axg_vpu_0_sel, + &axg_vpu_0, + &axg_vpu_1_div, + &axg_vpu_1_sel, + &axg_vpu_1, + &axg_vpu, + &axg_vapb_0_div, + &axg_vapb_0_sel, + &axg_vapb_0, + &axg_vapb_1_div, + &axg_vapb_1_sel, + &axg_vapb_1, + &axg_vapb_sel, + &axg_vapb, + &axg_vclk, + &axg_vclk2, + &axg_vclk_sel, + &axg_vclk2_sel, + &axg_vclk_input, + &axg_vclk2_input, + &axg_vclk_div, + &axg_vclk2_div, + &axg_vclk_div2_en, + &axg_vclk_div4_en, + &axg_vclk_div6_en, + &axg_vclk_div12_en, + &axg_vclk2_div2_en, + &axg_vclk2_div4_en, + &axg_vclk2_div6_en, + &axg_vclk2_div12_en, + &axg_cts_encl_sel, + &axg_cts_encl, }; static const struct meson_eeclkc_data axg_clkc_data = { diff --git a/drivers/clk/meson/axg.h b/drivers/clk/meson/axg.h index 0431dabac629..a8787b394a47 100644 --- a/drivers/clk/meson/axg.h +++ b/drivers/clk/meson/axg.h @@ -139,8 +139,27 @@ #define CLKID_HIFI_PLL_DCO 88 #define CLKID_PCIE_PLL_DCO 89 #define CLKID_PCIE_PLL_OD 90 +#define CLKID_VPU_0_DIV 91 +#define CLKID_VPU_1_DIV 94 +#define CLKID_VAPB_0_DIV 98 +#define CLKID_VAPB_1_DIV 101 +#define CLKID_VCLK_SEL 108 +#define CLKID_VCLK2_SEL 109 +#define CLKID_VCLK_INPUT 110 +#define CLKID_VCLK2_INPUT 111 +#define CLKID_VCLK_DIV 112 +#define CLKID_VCLK2_DIV 113 +#define CLKID_VCLK_DIV2_EN 114 +#define CLKID_VCLK_DIV4_EN 115 +#define CLKID_VCLK_DIV6_EN 116 +#define CLKID_VCLK_DIV12_EN 117 +#define CLKID_VCLK2_DIV2_EN 118 +#define CLKID_VCLK2_DIV4_EN 119 +#define CLKID_VCLK2_DIV6_EN 120 +#define CLKID_VCLK2_DIV12_EN 121 +#define CLKID_CTS_ENCL_SEL 132 -#define NR_CLKS 91 +#define NR_CLKS 134 /* include the CLKIDs that have been made part of the DT binding */ #include From e80d8510ffef3a9d2b2ce15882f5fd004d1e1645 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 15 Sep 2020 14:45:53 +0200 Subject: [PATCH 048/134] clk: meson: axg: add MIPI DSI Host clock This adds the MIPI DSI Host clock, used to measure the signal timings (ENC VSYNC or DW-MIPI-DSI eDPI timings). Signed-off-by: Neil Armstrong Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20200915124553.8056-5-narmstrong@baylibre.com --- drivers/clk/meson/axg.c | 66 +++++++++++++++++++++++++++++++++++++++++ drivers/clk/meson/axg.h | 4 ++- 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index a4e8949297cf..089a81ce2385 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -1703,6 +1703,66 @@ static struct clk_regmap axg_cts_encl = { }, }; +/* MIPI DSI Host Clock */ + +static u32 mux_table_axg_vdin_meas[] = { 0, 1, 2, 3, 6, 7 }; +static const struct clk_parent_data axg_vdin_meas_parent_data[] = { + { .fw_name = "xtal", }, + { .hw = &axg_fclk_div4.hw }, + { .hw = &axg_fclk_div3.hw }, + { .hw = &axg_fclk_div5.hw }, + { .hw = &axg_fclk_div2.hw }, + { .hw = &axg_fclk_div7.hw }, +}; + +static struct clk_regmap axg_vdin_meas_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VDIN_MEAS_CLK_CNTL, + .mask = 0x7, + .shift = 21, + .flags = CLK_MUX_ROUND_CLOSEST, + .table = mux_table_axg_vdin_meas, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdin_meas_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = axg_vdin_meas_parent_data, + .num_parents = ARRAY_SIZE(axg_vdin_meas_parent_data), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_vdin_meas_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VDIN_MEAS_CLK_CNTL, + .shift = 12, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdin_meas_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vdin_meas_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_vdin_meas = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VDIN_MEAS_CLK_CNTL, + .bit_idx = 20, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdin_meas", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vdin_meas_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static u32 mux_table_gen_clk[] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, }; static const struct clk_parent_data gen_clk_parent_data[] = { @@ -1966,6 +2026,9 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = { [CLKID_VCLK2_DIV12] = &axg_vclk2_div12.hw, [CLKID_CTS_ENCL_SEL] = &axg_cts_encl_sel.hw, [CLKID_CTS_ENCL] = &axg_cts_encl.hw, + [CLKID_VDIN_MEAS_SEL] = &axg_vdin_meas_sel.hw, + [CLKID_VDIN_MEAS_DIV] = &axg_vdin_meas_div.hw, + [CLKID_VDIN_MEAS] = &axg_vdin_meas.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -2094,6 +2157,9 @@ static struct clk_regmap *const axg_clk_regmaps[] = { &axg_vclk2_div12_en, &axg_cts_encl_sel, &axg_cts_encl, + &axg_vdin_meas_sel, + &axg_vdin_meas_div, + &axg_vdin_meas, }; static const struct meson_eeclkc_data axg_clkc_data = { diff --git a/drivers/clk/meson/axg.h b/drivers/clk/meson/axg.h index a8787b394a47..481b307ea3cb 100644 --- a/drivers/clk/meson/axg.h +++ b/drivers/clk/meson/axg.h @@ -158,8 +158,10 @@ #define CLKID_VCLK2_DIV6_EN 120 #define CLKID_VCLK2_DIV12_EN 121 #define CLKID_CTS_ENCL_SEL 132 +#define CLKID_VDIN_MEAS_SEL 134 +#define CLKID_VDIN_MEAS_DIV 135 -#define NR_CLKS 134 +#define NR_CLKS 137 /* include the CLKIDs that have been made part of the DT binding */ #include From bae69bfa3a586493469078ec4ca35499b754ba5c Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Wed, 18 Nov 2020 11:09:30 -0800 Subject: [PATCH 049/134] clk: meson: Kconfig: fix dependency for G12A When building only G12A, ensure that VID_PLL_DIV clock driver is selected, otherwise results in this build error: ERROR: modpost: "meson_vid_pll_div_ro_ops" [drivers/clk/meson/g12a.ko] undefined! Fixes: 085a4ea93d54 ("clk: meson: g12a: add peripheral clock controller") Signed-off-by: Kevin Hilman Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20201118190930.34352-1-khilman@baylibre.com --- drivers/clk/meson/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index 034da203e8e0..9a8a548d839d 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -110,6 +110,7 @@ config COMMON_CLK_G12A select COMMON_CLK_MESON_AO_CLKC select COMMON_CLK_MESON_EE_CLKC select COMMON_CLK_MESON_CPU_DYNDIV + select COMMON_CLK_MESON_VID_PLL_DIV select MFD_SYSCON help Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2 From 20425f6319480e84f48261fc7c0e4ce61a6d333e Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Wed, 18 Nov 2020 11:14:05 -0800 Subject: [PATCH 050/134] clk: meson: enable building as modules Make it possible to build all clk drivers as modules, but default remains built-in. No functional changes. Signed-off-by: Kevin Hilman Signed-off-by: Jerome Brunet Acked-by: Stephen Boyd Link: https://lore.kernel.org/r/20201118191405.36798-1-khilman@baylibre.com --- drivers/clk/meson/Kconfig | 6 +++--- drivers/clk/meson/axg-aoclk.c | 5 ++++- drivers/clk/meson/axg.c | 5 ++++- drivers/clk/meson/g12a-aoclk.c | 5 ++++- drivers/clk/meson/g12a.c | 5 ++++- drivers/clk/meson/gxbb-aoclk.c | 5 ++++- drivers/clk/meson/gxbb.c | 5 ++++- drivers/clk/meson/meson-aoclk.c | 4 ++++ drivers/clk/meson/meson-eeclk.c | 3 +++ 9 files changed, 34 insertions(+), 9 deletions(-) diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index 9a8a548d839d..fc002c155bc3 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -58,7 +58,7 @@ config COMMON_CLK_MESON8B want peripherals and CPU frequency scaling to work. config COMMON_CLK_GXBB - bool "GXBB and GXL SoC clock controllers support" + tristate "GXBB and GXL SoC clock controllers support" depends on ARM64 default y select COMMON_CLK_MESON_REGMAP @@ -74,7 +74,7 @@ config COMMON_CLK_GXBB Say Y if you want peripherals and CPU frequency scaling to work. config COMMON_CLK_AXG - bool "AXG SoC clock controllers support" + tristate "AXG SoC clock controllers support" depends on ARM64 default y select COMMON_CLK_MESON_REGMAP @@ -100,7 +100,7 @@ config COMMON_CLK_AXG_AUDIO aka axg, Say Y if you want audio subsystem to work. config COMMON_CLK_G12A - bool "G12 and SM1 SoC clock controllers support" + tristate "G12 and SM1 SoC clock controllers support" depends on ARM64 default y select COMMON_CLK_MESON_REGMAP diff --git a/drivers/clk/meson/axg-aoclk.c b/drivers/clk/meson/axg-aoclk.c index b488b40c9d0e..af6db437bcd8 100644 --- a/drivers/clk/meson/axg-aoclk.c +++ b/drivers/clk/meson/axg-aoclk.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "meson-aoclk.h" #include "axg-aoclk.h" @@ -326,6 +327,7 @@ static const struct of_device_id axg_aoclkc_match_table[] = { }, { } }; +MODULE_DEVICE_TABLE(of, axg_aoclkc_match_table); static struct platform_driver axg_aoclkc_driver = { .probe = meson_aoclkc_probe, @@ -335,4 +337,5 @@ static struct platform_driver axg_aoclkc_driver = { }, }; -builtin_platform_driver(axg_aoclkc_driver); +module_platform_driver(axg_aoclkc_driver); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 089a81ce2385..0e44695b8772 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "clk-regmap.h" #include "clk-pll.h" @@ -2173,6 +2174,7 @@ static const struct of_device_id clkc_match_table[] = { { .compatible = "amlogic,axg-clkc", .data = &axg_clkc_data }, {} }; +MODULE_DEVICE_TABLE(of, clkc_match_table); static struct platform_driver axg_driver = { .probe = meson_eeclkc_probe, @@ -2182,4 +2184,5 @@ static struct platform_driver axg_driver = { }, }; -builtin_platform_driver(axg_driver); +module_platform_driver(axg_driver); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/meson/g12a-aoclk.c b/drivers/clk/meson/g12a-aoclk.c index 62499563e4f5..b52990e574d2 100644 --- a/drivers/clk/meson/g12a-aoclk.c +++ b/drivers/clk/meson/g12a-aoclk.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "meson-aoclk.h" #include "g12a-aoclk.h" @@ -461,6 +462,7 @@ static const struct of_device_id g12a_aoclkc_match_table[] = { }, { } }; +MODULE_DEVICE_TABLE(of, g12a_aoclkc_match_table); static struct platform_driver g12a_aoclkc_driver = { .probe = meson_aoclkc_probe, @@ -470,4 +472,5 @@ static struct platform_driver g12a_aoclkc_driver = { }, }; -builtin_platform_driver(g12a_aoclkc_driver); +module_platform_driver(g12a_aoclkc_driver); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index 108e4491b1e2..3cb8196c8e29 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "clk-mpll.h" #include "clk-pll.h" @@ -5372,6 +5373,7 @@ static const struct of_device_id clkc_match_table[] = { }, {} }; +MODULE_DEVICE_TABLE(of, clkc_match_table); static struct platform_driver g12a_driver = { .probe = meson_g12a_probe, @@ -5381,4 +5383,5 @@ static struct platform_driver g12a_driver = { }, }; -builtin_platform_driver(g12a_driver); +module_platform_driver(g12a_driver); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/meson/gxbb-aoclk.c b/drivers/clk/meson/gxbb-aoclk.c index e940861a396b..fce95cf89836 100644 --- a/drivers/clk/meson/gxbb-aoclk.c +++ b/drivers/clk/meson/gxbb-aoclk.c @@ -5,6 +5,7 @@ */ #include #include +#include #include "meson-aoclk.h" #include "gxbb-aoclk.h" @@ -287,6 +288,7 @@ static const struct of_device_id gxbb_aoclkc_match_table[] = { }, { } }; +MODULE_DEVICE_TABLE(of, gxbb_aoclkc_match_table); static struct platform_driver gxbb_aoclkc_driver = { .probe = meson_aoclkc_probe, @@ -295,4 +297,5 @@ static struct platform_driver gxbb_aoclkc_driver = { .of_match_table = gxbb_aoclkc_match_table, }, }; -builtin_platform_driver(gxbb_aoclkc_driver); +module_platform_driver(gxbb_aoclkc_driver); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 0a68af6eec3d..d6eed760327d 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "gxbb.h" #include "clk-regmap.h" @@ -3519,6 +3520,7 @@ static const struct of_device_id clkc_match_table[] = { { .compatible = "amlogic,gxl-clkc", .data = &gxl_clkc_data }, {}, }; +MODULE_DEVICE_TABLE(of, clkc_match_table); static struct platform_driver gxbb_driver = { .probe = meson_eeclkc_probe, @@ -3528,4 +3530,5 @@ static struct platform_driver gxbb_driver = { }, }; -builtin_platform_driver(gxbb_driver); +module_platform_driver(gxbb_driver); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/meson/meson-aoclk.c b/drivers/clk/meson/meson-aoclk.c index 3a6d84cd6601..27cd2c1f3f61 100644 --- a/drivers/clk/meson/meson-aoclk.c +++ b/drivers/clk/meson/meson-aoclk.c @@ -14,6 +14,8 @@ #include #include #include +#include + #include #include "meson-aoclk.h" @@ -84,3 +86,5 @@ int meson_aoclkc_probe(struct platform_device *pdev) return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, (void *) data->hw_data); } +EXPORT_SYMBOL_GPL(meson_aoclkc_probe); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/meson/meson-eeclk.c b/drivers/clk/meson/meson-eeclk.c index a7cb1e7aedc4..8d5a5dab955a 100644 --- a/drivers/clk/meson/meson-eeclk.c +++ b/drivers/clk/meson/meson-eeclk.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "clk-regmap.h" #include "meson-eeclk.h" @@ -54,3 +55,5 @@ int meson_eeclkc_probe(struct platform_device *pdev) return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, data->hw_onecell_data); } +EXPORT_SYMBOL_GPL(meson_eeclkc_probe); +MODULE_LICENSE("GPL v2"); From e44cdff05145b84293e3f424daa17e4f3ce0109c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 19 Nov 2020 17:45:09 +0100 Subject: [PATCH 051/134] clk: samsung: Allow compile testing of Exynos, S3C64xx and S5Pv210 So far all Exynos, S3C64xx and S5Pv210 clock units were selected by respective SOC/ARCH Kconfig option. On a kernel built for selected SoCs, this allowed to build only limited set of matching clock drivers. However compile testing was not possible in such case as Makefile object depends on SOC/ARCH option. Add separate Kconfig options for each of them to be able to compile test. Link: https://lore.kernel.org/r/20201119164509.754851-1-krzk@kernel.org Signed-off-by: Krzysztof Kozlowski Acked-by: Chanwoo Choi Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/Kconfig | 67 ++++++++++++++++++++++++++++++++++-- drivers/clk/samsung/Makefile | 22 ++++++------ include/linux/clk/samsung.h | 4 +-- 3 files changed, 78 insertions(+), 15 deletions(-) diff --git a/drivers/clk/samsung/Kconfig b/drivers/clk/samsung/Kconfig index 57d4b3f20417..9323fcfac6cc 100644 --- a/drivers/clk/samsung/Kconfig +++ b/drivers/clk/samsung/Kconfig @@ -2,10 +2,73 @@ # Recent Exynos platforms should just select COMMON_CLK_SAMSUNG: config COMMON_CLK_SAMSUNG bool "Samsung Exynos clock controller support" if COMPILE_TEST - # Clocks on ARM64 SoCs (e.g. Exynos5433, Exynos7) are chosen by - # EXYNOS_ARM64_COMMON_CLK to avoid building them on ARMv7: + select S3C64XX_COMMON_CLK if ARM && ARCH_S3C64XX + select S5PV210_COMMON_CLK if ARM && ARCH_S5PV210 + select EXYNOS_3250_COMMON_CLK if ARM && SOC_EXYNOS3250 + select EXYNOS_4_COMMON_CLK if ARM && ARCH_EXYNOS4 + select EXYNOS_5250_COMMON_CLK if ARM && SOC_EXYNOS5250 + select EXYNOS_5260_COMMON_CLK if ARM && SOC_EXYNOS5260 + select EXYNOS_5410_COMMON_CLK if ARM && SOC_EXYNOS5410 + select EXYNOS_5420_COMMON_CLK if ARM && SOC_EXYNOS5420 select EXYNOS_ARM64_COMMON_CLK if ARM64 && ARCH_EXYNOS +config S3C64XX_COMMON_CLK + bool "Samsung S3C64xx clock controller support" if COMPILE_TEST + depends on COMMON_CLK_SAMSUNG + help + Support for the clock controller present on the Samsung S3C64xx SoCs. + Choose Y here only if you build for this SoC. + +config S5PV210_COMMON_CLK + bool "Samsung S5Pv210 clock controller support" if COMPILE_TEST + depends on COMMON_CLK_SAMSUNG + help + Support for the clock controller present on the Samsung S5Pv210 SoCs. + Choose Y here only if you build for this SoC. + +config EXYNOS_3250_COMMON_CLK + bool "Samsung Exynos3250 clock controller support" if COMPILE_TEST + depends on COMMON_CLK_SAMSUNG + help + Support for the clock controller present on the Samsung + Exynos3250 SoCs. Choose Y here only if you build for this SoC. + +config EXYNOS_4_COMMON_CLK + bool "Samsung Exynos4 clock controller support" if COMPILE_TEST + depends on COMMON_CLK_SAMSUNG + help + Support for the clock controller present on the Samsung + Exynos4212 and Exynos4412 SoCs. Choose Y here only if you build for + this SoC. + +config EXYNOS_5250_COMMON_CLK + bool "Samsung Exynos5250 clock controller support" if COMPILE_TEST + depends on COMMON_CLK_SAMSUNG + help + Support for the clock controller present on the Samsung + Exynos5250 SoCs. Choose Y here only if you build for this SoC. + +config EXYNOS_5260_COMMON_CLK + bool "Samsung Exynos5260 clock controller support" if COMPILE_TEST + depends on COMMON_CLK_SAMSUNG + help + Support for the clock controller present on the Samsung + Exynos5260 SoCs. Choose Y here only if you build for this SoC. + +config EXYNOS_5410_COMMON_CLK + bool "Samsung Exynos5410 clock controller support" if COMPILE_TEST + depends on COMMON_CLK_SAMSUNG + help + Support for the clock controller present on the Samsung + Exynos5410 SoCs. Choose Y here only if you build for this SoC. + +config EXYNOS_5420_COMMON_CLK + bool "Samsung Exynos5420 clock controller support" if COMPILE_TEST + depends on COMMON_CLK_SAMSUNG + help + Support for the clock controller present on the Samsung + Exynos5420 SoCs. Choose Y here only if you build for this SoC. + config EXYNOS_ARM64_COMMON_CLK bool "Samsung Exynos ARMv8-family clock controller support" if COMPILE_TEST depends on COMMON_CLK_SAMSUNG diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile index 1a4e6b787978..bb1433f11c88 100644 --- a/drivers/clk/samsung/Makefile +++ b/drivers/clk/samsung/Makefile @@ -4,15 +4,15 @@ # obj-$(CONFIG_COMMON_CLK) += clk.o clk-pll.o clk-cpu.o -obj-$(CONFIG_SOC_EXYNOS3250) += clk-exynos3250.o -obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4.o -obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4412-isp.o -obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o -obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5-subcmu.o -obj-$(CONFIG_SOC_EXYNOS5260) += clk-exynos5260.o -obj-$(CONFIG_SOC_EXYNOS5410) += clk-exynos5410.o -obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o -obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5-subcmu.o +obj-$(CONFIG_EXYNOS_3250_COMMON_CLK) += clk-exynos3250.o +obj-$(CONFIG_EXYNOS_4_COMMON_CLK) += clk-exynos4.o +obj-$(CONFIG_EXYNOS_4_COMMON_CLK) += clk-exynos4412-isp.o +obj-$(CONFIG_EXYNOS_5250_COMMON_CLK) += clk-exynos5250.o +obj-$(CONFIG_EXYNOS_5250_COMMON_CLK) += clk-exynos5-subcmu.o +obj-$(CONFIG_EXYNOS_5260_COMMON_CLK) += clk-exynos5260.o +obj-$(CONFIG_EXYNOS_5410_COMMON_CLK) += clk-exynos5410.o +obj-$(CONFIG_EXYNOS_5420_COMMON_CLK) += clk-exynos5420.o +obj-$(CONFIG_EXYNOS_5420_COMMON_CLK) += clk-exynos5-subcmu.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos5433.o obj-$(CONFIG_EXYNOS_AUDSS_CLK_CON) += clk-exynos-audss.o obj-$(CONFIG_ARCH_EXYNOS) += clk-exynos-clkout.o @@ -21,5 +21,5 @@ obj-$(CONFIG_S3C2410_COMMON_CLK)+= clk-s3c2410.o obj-$(CONFIG_S3C2410_COMMON_DCLK)+= clk-s3c2410-dclk.o obj-$(CONFIG_S3C2412_COMMON_CLK)+= clk-s3c2412.o obj-$(CONFIG_S3C2443_COMMON_CLK)+= clk-s3c2443.o -obj-$(CONFIG_ARCH_S3C64XX) += clk-s3c64xx.o -obj-$(CONFIG_ARCH_S5PV210) += clk-s5pv210.o clk-s5pv210-audss.o +obj-$(CONFIG_S3C64XX_COMMON_CLK) += clk-s3c64xx.o +obj-$(CONFIG_S5PV210_COMMON_CLK) += clk-s5pv210.o clk-s5pv210-audss.o diff --git a/include/linux/clk/samsung.h b/include/linux/clk/samsung.h index 79097e365f7f..38b774001712 100644 --- a/include/linux/clk/samsung.h +++ b/include/linux/clk/samsung.h @@ -10,7 +10,7 @@ struct device_node; -#ifdef CONFIG_ARCH_S3C64XX +#ifdef CONFIG_S3C64XX_COMMON_CLK void s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f, unsigned long xusbxti_f, bool s3c6400, void __iomem *base); @@ -19,7 +19,7 @@ static inline void s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f, unsigned long xusbxti_f, bool s3c6400, void __iomem *base) { } -#endif /* CONFIG_ARCH_S3C64XX */ +#endif /* CONFIG_S3C64XX_COMMON_CLK */ #ifdef CONFIG_S3C2410_COMMON_CLK void s3c2410_common_clk_init(struct device_node *np, unsigned long xti_f, From 44a9e78f9242872c889f176782777fa2ed535650 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 20 Nov 2020 16:57:31 +0100 Subject: [PATCH 052/134] clk: samsung: Prevent potential endless loop in the PLL ops The PLL status polling loops in the set_rate callbacks of some PLLs have no timeout detection and may become endless loops when something goes wrong with the PLL. For some PLLs there is already the ktime API based timeout detection, but it will not work in all conditions when .set_rate gets called. In particular, before the clocksource is initialized or when the timekeeping is suspended. This patch adds a common helper with the PLL status bit polling and timeout detection. For conditions where the timekeeping API should not be used a simple readl_relaxed/cpu_relax() busy loop is added with the iterations limit derived from measurements of readl_relaxed() execution time for various PLL types and Exynos SoCs variants. Actual PLL lock time depends on the P divider value, the VCO frequency and a constant PLL type specific LOCK_FACTOR and can be calculated as lock_time = Pdiv * LOCK_FACTOR / VCO_freq For the ktime API use cases a common timeout value of 20 ms is applied for all the PLLs with an assumption that maximum possible value of Pdiv is 64, maximum possible LOCK_FACTOR value is 3000 and minimum VCO frequency is 24 MHz. Link: https://lore.kernel.org/r/20201120155731.26898-1-s.nawrocki@samsung.com Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-pll.c | 147 ++++++++++++++++------------------ 1 file changed, 71 insertions(+), 76 deletions(-) diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index ac70ad785d8e..5873a9354b50 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -8,14 +8,17 @@ #include #include +#include #include #include +#include #include #include #include "clk.h" #include "clk-pll.h" -#define PLL_TIMEOUT_MS 10 +#define PLL_TIMEOUT_US 20000U +#define PLL_TIMEOUT_LOOPS 1000000U struct samsung_clk_pll { struct clk_hw hw; @@ -63,6 +66,53 @@ static long samsung_pll_round_rate(struct clk_hw *hw, return rate_table[i - 1].rate; } +static bool pll_early_timeout = true; + +static int __init samsung_pll_disable_early_timeout(void) +{ + pll_early_timeout = false; + return 0; +} +arch_initcall(samsung_pll_disable_early_timeout); + +/* Wait until the PLL is locked */ +static int samsung_pll_lock_wait(struct samsung_clk_pll *pll, + unsigned int reg_mask) +{ + int i, ret; + u32 val; + + /* + * This function might be called when the timekeeping API can't be used + * to detect timeouts. One situation is when the clocksource is not yet + * initialized, another when the timekeeping is suspended. udelay() also + * cannot be used when the clocksource is not running on arm64, since + * the current timer is used as cycle counter. So a simple busy loop + * is used here in that special cases. The limit of iterations has been + * derived from experimental measurements of various PLLs on multiple + * Exynos SoC variants. Single register read time was usually in range + * 0.4...1.5 us, never less than 0.4 us. + */ + if (pll_early_timeout || timekeeping_suspended) { + i = PLL_TIMEOUT_LOOPS; + while (i-- > 0) { + if (readl_relaxed(pll->con_reg) & reg_mask) + return 0; + + cpu_relax(); + } + ret = -ETIMEDOUT; + } else { + ret = readl_relaxed_poll_timeout_atomic(pll->con_reg, val, + val & reg_mask, 0, PLL_TIMEOUT_US); + } + + if (ret < 0) + pr_err("Could not lock PLL %s\n", clk_hw_get_name(&pll->hw)); + + return ret; +} + static int samsung_pll3xxx_enable(struct clk_hw *hw) { struct samsung_clk_pll *pll = to_clk_pll(hw); @@ -72,13 +122,7 @@ static int samsung_pll3xxx_enable(struct clk_hw *hw) tmp |= BIT(pll->enable_offs); writel_relaxed(tmp, pll->con_reg); - /* wait lock time */ - do { - cpu_relax(); - tmp = readl_relaxed(pll->con_reg); - } while (!(tmp & BIT(pll->lock_offs))); - - return 0; + return samsung_pll_lock_wait(pll, BIT(pll->lock_offs)); } static void samsung_pll3xxx_disable(struct clk_hw *hw) @@ -240,13 +284,10 @@ static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate, (rate->sdiv << PLL35XX_SDIV_SHIFT); writel_relaxed(tmp, pll->con_reg); - /* Wait until the PLL is locked if it is enabled. */ - if (tmp & BIT(pll->enable_offs)) { - do { - cpu_relax(); - tmp = readl_relaxed(pll->con_reg); - } while (!(tmp & BIT(pll->lock_offs))); - } + /* Wait for PLL lock if the PLL is enabled */ + if (tmp & BIT(pll->enable_offs)) + return samsung_pll_lock_wait(pll, BIT(pll->lock_offs)); + return 0; } @@ -318,7 +359,7 @@ static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate, unsigned long parent_rate) { struct samsung_clk_pll *pll = to_clk_pll(hw); - u32 tmp, pll_con0, pll_con1; + u32 pll_con0, pll_con1; const struct samsung_pll_rate_table *rate; rate = samsung_get_pll_settings(pll, drate); @@ -356,13 +397,8 @@ static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate, pll_con1 |= rate->kdiv << PLL36XX_KDIV_SHIFT; writel_relaxed(pll_con1, pll->con_reg + 4); - /* wait_lock_time */ - if (pll_con0 & BIT(pll->enable_offs)) { - do { - cpu_relax(); - tmp = readl_relaxed(pll->con_reg); - } while (!(tmp & BIT(pll->lock_offs))); - } + if (pll_con0 & BIT(pll->enable_offs)) + return samsung_pll_lock_wait(pll, BIT(pll->lock_offs)); return 0; } @@ -437,7 +473,6 @@ static int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate, struct samsung_clk_pll *pll = to_clk_pll(hw); const struct samsung_pll_rate_table *rate; u32 con0, con1; - ktime_t start; /* Get required rate settings from table */ rate = samsung_get_pll_settings(pll, drate); @@ -488,21 +523,8 @@ static int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate, writel_relaxed(con1, pll->con_reg + 0x4); writel_relaxed(con0, pll->con_reg); - /* Wait for locking. */ - start = ktime_get(); - while (!(readl_relaxed(pll->con_reg) & PLL45XX_LOCKED)) { - ktime_t delta = ktime_sub(ktime_get(), start); - - if (ktime_to_ms(delta) > PLL_TIMEOUT_MS) { - pr_err("%s: could not lock PLL %s\n", - __func__, clk_hw_get_name(hw)); - return -EFAULT; - } - - cpu_relax(); - } - - return 0; + /* Wait for PLL lock */ + return samsung_pll_lock_wait(pll, PLL45XX_LOCKED); } static const struct clk_ops samsung_pll45xx_clk_ops = { @@ -588,7 +610,6 @@ static int samsung_pll46xx_set_rate(struct clk_hw *hw, unsigned long drate, struct samsung_clk_pll *pll = to_clk_pll(hw); const struct samsung_pll_rate_table *rate; u32 con0, con1, lock; - ktime_t start; /* Get required rate settings from table */ rate = samsung_get_pll_settings(pll, drate); @@ -647,21 +668,8 @@ static int samsung_pll46xx_set_rate(struct clk_hw *hw, unsigned long drate, writel_relaxed(con0, pll->con_reg); writel_relaxed(con1, pll->con_reg + 0x4); - /* Wait for locking. */ - start = ktime_get(); - while (!(readl_relaxed(pll->con_reg) & PLL46XX_LOCKED)) { - ktime_t delta = ktime_sub(ktime_get(), start); - - if (ktime_to_ms(delta) > PLL_TIMEOUT_MS) { - pr_err("%s: could not lock PLL %s\n", - __func__, clk_hw_get_name(hw)); - return -EFAULT; - } - - cpu_relax(); - } - - return 0; + /* Wait for PLL lock */ + return samsung_pll_lock_wait(pll, PLL46XX_LOCKED); } static const struct clk_ops samsung_pll46xx_clk_ops = { @@ -1035,14 +1043,9 @@ static int samsung_pll2550xx_set_rate(struct clk_hw *hw, unsigned long drate, (rate->sdiv << PLL2550XX_S_SHIFT); writel_relaxed(tmp, pll->con_reg); - /* wait_lock_time */ - do { - cpu_relax(); - tmp = readl_relaxed(pll->con_reg); - } while (!(tmp & (PLL2550XX_LOCK_STAT_MASK - << PLL2550XX_LOCK_STAT_SHIFT))); - - return 0; + /* Wait for PLL lock */ + return samsung_pll_lock_wait(pll, + PLL2550XX_LOCK_STAT_MASK << PLL2550XX_LOCK_STAT_SHIFT); } static const struct clk_ops samsung_pll2550xx_clk_ops = { @@ -1132,13 +1135,9 @@ static int samsung_pll2650x_set_rate(struct clk_hw *hw, unsigned long drate, con1 |= ((rate->kdiv & PLL2650X_K_MASK) << PLL2650X_K_SHIFT); writel_relaxed(con1, pll->con_reg + 4); - do { - cpu_relax(); - con0 = readl_relaxed(pll->con_reg); - } while (!(con0 & (PLL2650X_LOCK_STAT_MASK - << PLL2650X_LOCK_STAT_SHIFT))); - - return 0; + /* Wait for PLL lock */ + return samsung_pll_lock_wait(pll, + PLL2650X_LOCK_STAT_MASK << PLL2650X_LOCK_STAT_SHIFT); } static const struct clk_ops samsung_pll2650x_clk_ops = { @@ -1196,7 +1195,7 @@ static int samsung_pll2650xx_set_rate(struct clk_hw *hw, unsigned long drate, unsigned long parent_rate) { struct samsung_clk_pll *pll = to_clk_pll(hw); - u32 tmp, pll_con0, pll_con2; + u32 pll_con0, pll_con2; const struct samsung_pll_rate_table *rate; rate = samsung_get_pll_settings(pll, drate); @@ -1229,11 +1228,7 @@ static int samsung_pll2650xx_set_rate(struct clk_hw *hw, unsigned long drate, writel_relaxed(pll_con0, pll->con_reg); writel_relaxed(pll_con2, pll->con_reg + 8); - do { - tmp = readl_relaxed(pll->con_reg); - } while (!(tmp & (0x1 << PLL2650XX_PLL_LOCKTIME_SHIFT))); - - return 0; + return samsung_pll_lock_wait(pll, 0x1 << PLL2650XX_PLL_LOCKTIME_SHIFT); } static const struct clk_ops samsung_pll2650xx_clk_ops = { From 8d5d3c7a5bdd32044f595575f1aa16cd3bdd93a8 Mon Sep 17 00:00:00 2001 From: Thara Gopinath Date: Thu, 19 Nov 2020 10:52:28 -0500 Subject: [PATCH 053/134] dt-bindings: clock: Add entry for crypto engine RPMH clock resource Add clock id forc CE clock resource which is required to bring up the crypto engine on sdm845. Reviewed-by: Bjorn Andersson Signed-off-by: Thara Gopinath Link: https://lore.kernel.org/r/20201119155233.3974286-2-thara.gopinath@linaro.org Signed-off-by: Stephen Boyd --- include/dt-bindings/clock/qcom,rpmh.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dt-bindings/clock/qcom,rpmh.h b/include/dt-bindings/clock/qcom,rpmh.h index 2e6c54e65455..30111c8f7fe9 100644 --- a/include/dt-bindings/clock/qcom,rpmh.h +++ b/include/dt-bindings/clock/qcom,rpmh.h @@ -21,5 +21,6 @@ #define RPMH_IPA_CLK 12 #define RPMH_LN_BB_CLK1 13 #define RPMH_LN_BB_CLK1_A 14 +#define RPMH_CE_CLK 15 #endif From dba6bc51975b54b0778678d581df5b423a5a0d81 Mon Sep 17 00:00:00 2001 From: Thara Gopinath Date: Thu, 19 Nov 2020 10:52:29 -0500 Subject: [PATCH 054/134] clk: qcom: rpmh: Add CE clock on sdm845. Qualcomm CE clock resource that is managed by BCM is required by crypto driver to access the core clock. Reviewed-by: Bjorn Andersson Signed-off-by: Thara Gopinath Link: https://lore.kernel.org/r/20201119155233.3974286-3-thara.gopinath@linaro.org Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-rpmh.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c index e2c669b08aff..7e2a4a9b9bf6 100644 --- a/drivers/clk/qcom/clk-rpmh.c +++ b/drivers/clk/qcom/clk-rpmh.c @@ -349,6 +349,7 @@ DEFINE_CLK_RPMH_VRM(sdm845, rf_clk2, rf_clk2_ao, "rfclka2", 1); DEFINE_CLK_RPMH_VRM(sdm845, rf_clk3, rf_clk3_ao, "rfclka3", 1); DEFINE_CLK_RPMH_VRM(sm8150, rf_clk3, rf_clk3_ao, "rfclka3", 1); DEFINE_CLK_RPMH_BCM(sdm845, ipa, "IP0"); +DEFINE_CLK_RPMH_BCM(sdm845, ce, "CE0"); static struct clk_hw *sdm845_rpmh_clocks[] = { [RPMH_CXO_CLK] = &sdm845_bi_tcxo.hw, @@ -364,6 +365,7 @@ static struct clk_hw *sdm845_rpmh_clocks[] = { [RPMH_RF_CLK3] = &sdm845_rf_clk3.hw, [RPMH_RF_CLK3_A] = &sdm845_rf_clk3_ao.hw, [RPMH_IPA_CLK] = &sdm845_ipa.hw, + [RPMH_CE_CLK] = &sdm845_ce.hw, }; static const struct clk_rpmh_desc clk_rpmh_sdm845 = { From 312489790cc6c760f8b7795b8f1ded45bafc318c Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 26 Nov 2020 15:15:59 +0100 Subject: [PATCH 055/134] dt-bindings: clk: g12a-clkc: add DSI Pixel clock bindings This adds the MIPI DSI Host Pixel Clock bindings. Signed-off-by: Neil Armstrong Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20201126141600.2084586-2-narmstrong@baylibre.com --- include/dt-bindings/clock/g12a-clkc.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/dt-bindings/clock/g12a-clkc.h b/include/dt-bindings/clock/g12a-clkc.h index 40d49940d8a8..a93b58c5e18e 100644 --- a/include/dt-bindings/clock/g12a-clkc.h +++ b/include/dt-bindings/clock/g12a-clkc.h @@ -147,5 +147,7 @@ #define CLKID_SPICC1_SCLK 261 #define CLKID_NNA_AXI_CLK 264 #define CLKID_NNA_CORE_CLK 267 +#define CLKID_MIPI_DSI_PXCLK_SEL 269 +#define CLKID_MIPI_DSI_PXCLK 270 #endif /* __G12A_CLKC_H */ From 88b9ae600138baff18c7f4c4870622584acc6111 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 26 Nov 2020 15:16:00 +0100 Subject: [PATCH 056/134] clk: meson: g12a: add MIPI DSI Host Pixel Clock This adds the MIPI DSI Host Pixel Clock, unlike AXG, the pixel clock can be different from the VPU ENCL output clock to feed the DSI Host controller with a different clock rate. Signed-off-by: Neil Armstrong Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20201126141600.2084586-3-narmstrong@baylibre.com --- drivers/clk/meson/g12a.c | 74 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/meson/g12a.h | 3 +- 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index 3cb8196c8e29..b080359b4645 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -3658,6 +3658,68 @@ static struct clk_regmap g12a_hdmi_tx = { }, }; +/* MIPI DSI Host Clocks */ + +static const struct clk_hw *g12a_mipi_dsi_pxclk_parent_hws[] = { + &g12a_vid_pll.hw, + &g12a_gp0_pll.hw, + &g12a_hifi_pll.hw, + &g12a_mpll1.hw, + &g12a_fclk_div2.hw, + &g12a_fclk_div2p5.hw, + &g12a_fclk_div3.hw, + &g12a_fclk_div7.hw, +}; + +static struct clk_regmap g12a_mipi_dsi_pxclk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MIPIDSI_PHY_CLK_CNTL, + .mask = 0x7, + .shift = 12, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "mipi_dsi_pxclk_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = g12a_mipi_dsi_pxclk_parent_hws, + .num_parents = ARRAY_SIZE(g12a_mipi_dsi_pxclk_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap g12a_mipi_dsi_pxclk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MIPIDSI_PHY_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "mipi_dsi_pxclk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mipi_dsi_pxclk_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_mipi_dsi_pxclk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MIPIDSI_PHY_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "mipi_dsi_pxclk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mipi_dsi_pxclk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + /* HDMI Clocks */ static const struct clk_parent_data g12a_hdmi_parent_data[] = { @@ -4403,6 +4465,9 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = { [CLKID_SPICC1_SCLK_SEL] = &g12a_spicc1_sclk_sel.hw, [CLKID_SPICC1_SCLK_DIV] = &g12a_spicc1_sclk_div.hw, [CLKID_SPICC1_SCLK] = &g12a_spicc1_sclk.hw, + [CLKID_MIPI_DSI_PXCLK_SEL] = &g12a_mipi_dsi_pxclk_sel.hw, + [CLKID_MIPI_DSI_PXCLK_DIV] = &g12a_mipi_dsi_pxclk_div.hw, + [CLKID_MIPI_DSI_PXCLK] = &g12a_mipi_dsi_pxclk.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -4658,6 +4723,9 @@ static struct clk_hw_onecell_data g12b_hw_onecell_data = { [CLKID_SPICC1_SCLK_SEL] = &g12a_spicc1_sclk_sel.hw, [CLKID_SPICC1_SCLK_DIV] = &g12a_spicc1_sclk_div.hw, [CLKID_SPICC1_SCLK] = &g12a_spicc1_sclk.hw, + [CLKID_MIPI_DSI_PXCLK_SEL] = &g12a_mipi_dsi_pxclk_sel.hw, + [CLKID_MIPI_DSI_PXCLK_DIV] = &g12a_mipi_dsi_pxclk_div.hw, + [CLKID_MIPI_DSI_PXCLK] = &g12a_mipi_dsi_pxclk.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -4904,6 +4972,9 @@ static struct clk_hw_onecell_data sm1_hw_onecell_data = { [CLKID_NNA_CORE_CLK_SEL] = &sm1_nna_core_clk_sel.hw, [CLKID_NNA_CORE_CLK_DIV] = &sm1_nna_core_clk_div.hw, [CLKID_NNA_CORE_CLK] = &sm1_nna_core_clk.hw, + [CLKID_MIPI_DSI_PXCLK_SEL] = &g12a_mipi_dsi_pxclk_sel.hw, + [CLKID_MIPI_DSI_PXCLK_DIV] = &g12a_mipi_dsi_pxclk_div.hw, + [CLKID_MIPI_DSI_PXCLK] = &g12a_mipi_dsi_pxclk.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -5151,6 +5222,9 @@ static struct clk_regmap *const g12a_clk_regmaps[] = { &sm1_nna_core_clk_sel, &sm1_nna_core_clk_div, &sm1_nna_core_clk, + &g12a_mipi_dsi_pxclk_sel, + &g12a_mipi_dsi_pxclk_div, + &g12a_mipi_dsi_pxclk, }; static const struct reg_sequence g12a_init_regs[] = { diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h index 69b6a69549c7..a97613df38b3 100644 --- a/drivers/clk/meson/g12a.h +++ b/drivers/clk/meson/g12a.h @@ -264,8 +264,9 @@ #define CLKID_NNA_AXI_CLK_DIV 263 #define CLKID_NNA_CORE_CLK_SEL 265 #define CLKID_NNA_CORE_CLK_DIV 266 +#define CLKID_MIPI_DSI_PXCLK_DIV 268 -#define NR_CLKS 268 +#define NR_CLKS 271 /* include the CLKIDs that have been made part of the DT binding */ #include From a886c310d9fcb0e66253d4af225cba13f9bdf5d2 Mon Sep 17 00:00:00 2001 From: Sivaram Nair Date: Wed, 21 Oct 2020 13:10:54 +0300 Subject: [PATCH 057/134] clk: tegra: bpmp: Clamp clock rates on requests BPMP firmware ABI expects the rate inputs in int64_t. However, tegra_bpmp_clk_round_rate() and tegra_bpmp_clk_set_rate() functions directly assign 'unsigned long' inputs to a int64_t value causing unexpected rounding errors. Fix this by clipping the input rate to S64_MAX. Signed-off-by: Sivaram Nair [mperttunen: slight cleanup] Signed-off-by: Mikko Perttunen Reviewed-by: Sivaram Nair Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-bpmp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/tegra/clk-bpmp.c b/drivers/clk/tegra/clk-bpmp.c index a66263b6490d..6ecf18f71c32 100644 --- a/drivers/clk/tegra/clk-bpmp.c +++ b/drivers/clk/tegra/clk-bpmp.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2016 NVIDIA Corporation + * Copyright (C) 2016-2020 NVIDIA Corporation */ #include @@ -174,7 +174,7 @@ static long tegra_bpmp_clk_round_rate(struct clk_hw *hw, unsigned long rate, int err; memset(&request, 0, sizeof(request)); - request.rate = rate; + request.rate = min_t(u64, rate, S64_MAX); memset(&msg, 0, sizeof(msg)); msg.cmd = CMD_CLK_ROUND_RATE; @@ -256,7 +256,7 @@ static int tegra_bpmp_clk_set_rate(struct clk_hw *hw, unsigned long rate, struct tegra_bpmp_clk_message msg; memset(&request, 0, sizeof(request)); - request.rate = rate; + request.rate = min_t(u64, rate, S64_MAX); memset(&msg, 0, sizeof(msg)); msg.cmd = CMD_CLK_SET_RATE; From 02d8e879e4101c2baa1f7a99c1a266742872a049 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 26 Nov 2020 23:24:00 +0000 Subject: [PATCH 058/134] clk: qcom: Kconfig: Fix spelling mistake "dyanmic" -> "dynamic" There is a spelling mistake in the Kconfig help text. Fix it. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20201126232400.15011-1-colin.king@canonical.com Signed-off-by: Stephen Boyd --- drivers/clk/qcom/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 48c624a1eff1..8c8b568609d4 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -44,7 +44,7 @@ config QCOM_CLK_APCC_MSM8996 help Support for the CPU clock controller on msm8996 devices. Say Y if you want to support CPU clock scaling using CPUfreq - drivers for dyanmic power management. + drivers for dynamic power management. config QCOM_CLK_RPM tristate "RPM based Clock Controller" From 7f5b57a095f3b9532793d143655e83433bb448af Mon Sep 17 00:00:00 2001 From: Xu Wang Date: Fri, 27 Nov 2020 09:05:51 +0000 Subject: [PATCH 059/134] clk: rockchip: Remove redundant null check before clk_prepare_enable Because clk_prepare_enable() already checked NULL clock parameter, so the additional check is unnecessary, just remove it. Signed-off-by: Xu Wang Acked-by: Stephen Boyd Link: https://lore.kernel.org/r/20201127090551.50254-1-vulab@iscas.ac.cn Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index b443169dd408..336481bc6cc7 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -603,8 +603,7 @@ void rockchip_clk_protect_critical(const char *const clocks[], for (i = 0; i < nclocks; i++) { struct clk *clk = __clk_lookup(clocks[i]); - if (clk) - clk_prepare_enable(clk); + clk_prepare_enable(clk); } } EXPORT_SYMBOL_GPL(rockchip_clk_protect_critical); From 5868491e1257786628fdd2457dfb77609f49f91d Mon Sep 17 00:00:00 2001 From: Johan Jonker Date: Wed, 18 Nov 2020 14:58:16 +0100 Subject: [PATCH 060/134] clk: rockchip: add CLK_SET_RATE_PARENT to sclk for rk3066a i2s and uart clocks Add CLK_SET_RATE_PARENT to sclk for rk3066a i2s and uart clocks, so that the parent COMPOSITE_FRACMUX and COMPOSITE_NOMUX also update. Signed-off-by: Johan Jonker Link: https://lore.kernel.org/r/20201118135822.9582-2-jbx6244@gmail.com Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3188.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c index 730020fcc7fe..db8c588139de 100644 --- a/drivers/clk/rockchip/clk-rk3188.c +++ b/drivers/clk/rockchip/clk-rk3188.c @@ -255,19 +255,19 @@ static struct rockchip_clk_branch common_spdif_fracmux __initdata = RK2928_CLKSEL_CON(5), 8, 2, MFLAGS); static struct rockchip_clk_branch common_uart0_fracmux __initdata = - MUX(SCLK_UART0, "sclk_uart0", mux_sclk_uart0_p, 0, + MUX(SCLK_UART0, "sclk_uart0", mux_sclk_uart0_p, CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(13), 8, 2, MFLAGS); static struct rockchip_clk_branch common_uart1_fracmux __initdata = - MUX(SCLK_UART1, "sclk_uart1", mux_sclk_uart1_p, 0, + MUX(SCLK_UART1, "sclk_uart1", mux_sclk_uart1_p, CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(14), 8, 2, MFLAGS); static struct rockchip_clk_branch common_uart2_fracmux __initdata = - MUX(SCLK_UART2, "sclk_uart2", mux_sclk_uart2_p, 0, + MUX(SCLK_UART2, "sclk_uart2", mux_sclk_uart2_p, CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(15), 8, 2, MFLAGS); static struct rockchip_clk_branch common_uart3_fracmux __initdata = - MUX(SCLK_UART3, "sclk_uart3", mux_sclk_uart3_p, 0, + MUX(SCLK_UART3, "sclk_uart3", mux_sclk_uart3_p, CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(16), 8, 2, MFLAGS); static struct rockchip_clk_branch common_clk_branches[] __initdata = { @@ -408,28 +408,28 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "uart0_pre", "uart_src", 0, RK2928_CLKSEL_CON(13), 0, 7, DFLAGS, RK2928_CLKGATE_CON(1), 8, GFLAGS), - COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_pre", 0, + COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_pre", CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(17), 0, RK2928_CLKGATE_CON(1), 9, GFLAGS, &common_uart0_fracmux), COMPOSITE_NOMUX(0, "uart1_pre", "uart_src", 0, RK2928_CLKSEL_CON(14), 0, 7, DFLAGS, RK2928_CLKGATE_CON(1), 10, GFLAGS), - COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_pre", 0, + COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_pre", CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(18), 0, RK2928_CLKGATE_CON(1), 11, GFLAGS, &common_uart1_fracmux), COMPOSITE_NOMUX(0, "uart2_pre", "uart_src", 0, RK2928_CLKSEL_CON(15), 0, 7, DFLAGS, RK2928_CLKGATE_CON(1), 12, GFLAGS), - COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_pre", 0, + COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_pre", CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(19), 0, RK2928_CLKGATE_CON(1), 13, GFLAGS, &common_uart2_fracmux), COMPOSITE_NOMUX(0, "uart3_pre", "uart_src", 0, RK2928_CLKSEL_CON(16), 0, 7, DFLAGS, RK2928_CLKGATE_CON(1), 14, GFLAGS), - COMPOSITE_FRACMUX(0, "uart3_frac", "uart3_pre", 0, + COMPOSITE_FRACMUX(0, "uart3_frac", "uart3_pre", CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(20), 0, RK2928_CLKGATE_CON(1), 15, GFLAGS, &common_uart3_fracmux), @@ -543,15 +543,15 @@ static struct clk_div_table div_aclk_cpu_t[] = { }; static struct rockchip_clk_branch rk3066a_i2s0_fracmux __initdata = - MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, 0, + MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(2), 8, 2, MFLAGS); static struct rockchip_clk_branch rk3066a_i2s1_fracmux __initdata = - MUX(SCLK_I2S1, "sclk_i2s1", mux_sclk_i2s1_p, 0, + MUX(SCLK_I2S1, "sclk_i2s1", mux_sclk_i2s1_p, CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(3), 8, 2, MFLAGS); static struct rockchip_clk_branch rk3066a_i2s2_fracmux __initdata = - MUX(SCLK_I2S2, "sclk_i2s2", mux_sclk_i2s2_p, 0, + MUX(SCLK_I2S2, "sclk_i2s2", mux_sclk_i2s2_p, CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(4), 8, 2, MFLAGS); static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = { @@ -615,21 +615,21 @@ static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "i2s0_pre", "i2s_src", 0, RK2928_CLKSEL_CON(2), 0, 7, DFLAGS, RK2928_CLKGATE_CON(0), 7, GFLAGS), - COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_pre", 0, + COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_pre", CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(6), 0, RK2928_CLKGATE_CON(0), 8, GFLAGS, &rk3066a_i2s0_fracmux), COMPOSITE_NOMUX(0, "i2s1_pre", "i2s_src", 0, RK2928_CLKSEL_CON(3), 0, 7, DFLAGS, RK2928_CLKGATE_CON(0), 9, GFLAGS), - COMPOSITE_FRACMUX(0, "i2s1_frac", "i2s1_pre", 0, + COMPOSITE_FRACMUX(0, "i2s1_frac", "i2s1_pre", CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(7), 0, RK2928_CLKGATE_CON(0), 10, GFLAGS, &rk3066a_i2s1_fracmux), COMPOSITE_NOMUX(0, "i2s2_pre", "i2s_src", 0, RK2928_CLKSEL_CON(4), 0, 7, DFLAGS, RK2928_CLKGATE_CON(0), 11, GFLAGS), - COMPOSITE_FRACMUX(0, "i2s2_frac", "i2s2_pre", 0, + COMPOSITE_FRACMUX(0, "i2s2_frac", "i2s2_pre", CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(8), 0, RK2928_CLKGATE_CON(0), 12, GFLAGS, &rk3066a_i2s2_fracmux), From caa2fd752ecb80faf7a2e1cdadc737187934675e Mon Sep 17 00:00:00 2001 From: Johan Jonker Date: Wed, 18 Nov 2020 14:58:17 +0100 Subject: [PATCH 061/134] clk: rockchip: fix i2s gate bits on rk3066 and rk3188 The Rockchip PX2/RK3066 uses these bits in CRU_CLKGATE7_CON: hclk_i2s_8ch_gate_en bit 4 (dtsi: i2s0) hclk_i2s0_2ch_gate_en bit 2 (dtsi: i2s1) hclk_i2s1_2ch_gate_en bit 3 (dtsi: i2s2) The Rockchip PX3/RK3188 uses this bit in CRU_CLKGATE7_CON: hclk_i2s_2ch_gate_en bit 2 (dtsi: i2s0) The bits got somehow mixed up in the clk-rk3188.c file. The labels in the dtsi files are not suppose to change. The sclk and hclk names should match for "trace_event=clk_disable,clk_enable", so remove GATE HCLK_I2S0 from the common clock tree and fix the bits in the rk3066 and rk3188 clock tree. Signed-off-by: Johan Jonker Link: https://lore.kernel.org/r/20201118135822.9582-3-jbx6244@gmail.com Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3188.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c index db8c588139de..0b76ad34de00 100644 --- a/drivers/clk/rockchip/clk-rk3188.c +++ b/drivers/clk/rockchip/clk-rk3188.c @@ -449,7 +449,6 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { /* hclk_cpu gates */ GATE(HCLK_ROM, "hclk_rom", "hclk_cpu", 0, RK2928_CLKGATE_CON(5), 6, GFLAGS), - GATE(HCLK_I2S0, "hclk_i2s0", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 2, GFLAGS), GATE(HCLK_SPDIF, "hclk_spdif", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 1, GFLAGS), GATE(0, "hclk_cpubus", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 8, GFLAGS), /* hclk_ahb2apb is part of a clk branch */ @@ -634,8 +633,9 @@ static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = { RK2928_CLKGATE_CON(0), 12, GFLAGS, &rk3066a_i2s2_fracmux), - GATE(HCLK_I2S1, "hclk_i2s1", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 3, GFLAGS), - GATE(HCLK_I2S2, "hclk_i2s2", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 4, GFLAGS), + GATE(HCLK_I2S0, "hclk_i2s0", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 4, GFLAGS), + GATE(HCLK_I2S1, "hclk_i2s1", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 2, GFLAGS), + GATE(HCLK_I2S2, "hclk_i2s2", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 3, GFLAGS), GATE(HCLK_CIF1, "hclk_cif1", "hclk_cpu", 0, RK2928_CLKGATE_CON(6), 6, GFLAGS), GATE(HCLK_HDMI, "hclk_hdmi", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS), @@ -728,6 +728,7 @@ static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = { RK2928_CLKGATE_CON(0), 10, GFLAGS, &rk3188_i2s0_fracmux), + GATE(HCLK_I2S0, "hclk_i2s0", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 2, GFLAGS), GATE(0, "hclk_imem0", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS), GATE(0, "hclk_imem1", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 15, GFLAGS), From 43d2479687c93ed9b93774ef9b46b37de5b3efcc Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Thu, 19 Nov 2020 19:43:02 +0800 Subject: [PATCH 062/134] clk: imx: scu: remove the calling of device_is_bound The device_is_bound() is invisible to drivers when built as modules. It's also not aimed to be used by drivers according to Greg K.H. Let's remove it from clk-scu driver and find another way to do proper driver loading sequence. Cc: Shawn Guo Cc: Sascha Hauer Cc: Stephen Boyd Fixes: 77d8f3068c63 ("clk: imx: scu: add two cells binding support") Reported-by: Sudip Mukherjee Signed-off-by: Dong Aisheng Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-scu.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c index d10f60e48ece..1f5518b7ab39 100644 --- a/drivers/clk/imx/clk-scu.c +++ b/drivers/clk/imx/clk-scu.c @@ -153,7 +153,6 @@ static inline struct clk_scu *to_clk_scu(struct clk_hw *hw) int imx_clk_scu_init(struct device_node *np) { - struct platform_device *pd_dev; u32 clk_cells; int ret, i; @@ -166,17 +165,11 @@ int imx_clk_scu_init(struct device_node *np) if (clk_cells == 2) { for (i = 0; i < IMX_SC_R_LAST; i++) INIT_LIST_HEAD(&imx_scu_clks[i]); - /* - * Note: SCU clock driver depends on SCU power domain to be ready - * first. As there're no power domains under scu clock node in dts, - * we can't use PROBE_DEFER automatically. - */ + + /* pd_np will be used to attach power domains later */ pd_np = of_find_compatible_node(NULL, NULL, "fsl,scu-pd"); - pd_dev = of_find_device_by_node(pd_np); - if (!pd_dev || !device_is_bound(&pd_dev->dev)) { - of_node_put(pd_np); - return -EPROBE_DEFER; - } + if (!pd_np) + return -EINVAL; } return platform_driver_register(&imx_clk_scu_driver); From 16a30ba15cd782e95fc57e87c2c4515778d3b493 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 10 Nov 2020 16:50:29 +0100 Subject: [PATCH 063/134] sh: boards: Replace by The SuperH/J2 DT platform code is not a clock provider, and just needs to call of_clk_init(). Hence it can include instead of . Signed-off-by: Geert Uytterhoeven Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20201110155029.3286090-1-geert+renesas@glider.be Signed-off-by: Stephen Boyd --- arch/sh/boards/of-generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sh/boards/of-generic.c b/arch/sh/boards/of-generic.c index bffbe69b2236..921d76fc3358 100644 --- a/arch/sh/boards/of-generic.c +++ b/arch/sh/boards/of-generic.c @@ -6,10 +6,10 @@ */ #include +#include #include #include #include -#include #include #include From 047b04201f628c038cdf4879ed51513215dd8780 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 10 Nov 2020 16:51:17 +0100 Subject: [PATCH 064/134] xtensa: Replace by The Xtensa time code is not a clock provider, and just needs to call of_clk_init(). Hence it can include instead of . Signed-off-by: Geert Uytterhoeven Reviewed-by: Stephen Boyd Acked-by: Max Filippov Link: https://lore.kernel.org/r/20201110155117.3286247-1-geert+renesas@glider.be Signed-off-by: Stephen Boyd --- arch/xtensa/kernel/time.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c index 77971fe4cc95..e8ceb1528608 100644 --- a/arch/xtensa/kernel/time.c +++ b/arch/xtensa/kernel/time.c @@ -13,7 +13,7 @@ */ #include -#include +#include #include #include #include From b8bcece8a77fe0deedb7afc115881468d9c1617c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 10 Nov 2020 16:47:50 +0100 Subject: [PATCH 065/134] clk: qoriq: Add platform dependencies The Freescale QorIQ clock controller is only present on Freescale E500MC and Layerscape SoCs. Add platform dependencies to the CLK_QORIQ config symbol, to avoid asking the user about it when configuring a kernel without E500MC or Layerscape support. Signed-off-by: Geert Uytterhoeven Acked-by: Arnd Bergmann Acked-by: Li Yang Link: https://lore.kernel.org/r/20201110154750.3285411-1-geert+renesas@glider.be Signed-off-by: Stephen Boyd --- drivers/clk/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c715d4681a0b..969080401a83 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -246,7 +246,8 @@ config COMMON_CLK_AXI_CLKGEN config CLK_QORIQ bool "Clock driver for Freescale QorIQ platforms" - depends on (PPC_E500MC || ARM || ARM64 || COMPILE_TEST) && OF + depends on OF + depends on PPC_E500MC || SOC_LS1021A || ARCH_LAYERSCAPE || COMPILE_TEST help This adds the clock driver support for Freescale QorIQ platforms using common clock framework. From e81bed419f032824e7ddf8b5630153be6637e480 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 5 Nov 2020 20:27:44 +0100 Subject: [PATCH 066/134] clk: fsl-sai: fix memory leak If the device is removed we don't unregister the composite clock. Fix that. Fixes: 9cd10205227c ("clk: fsl-sai: new driver") Signed-off-by: Michael Walle Link: https://lore.kernel.org/r/20201105192746.19564-2-michael@walle.cc Signed-off-by: Stephen Boyd --- drivers/clk/clk-fsl-sai.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/clk/clk-fsl-sai.c b/drivers/clk/clk-fsl-sai.c index 0221180a4dd7..1e81c8d8a6fd 100644 --- a/drivers/clk/clk-fsl-sai.c +++ b/drivers/clk/clk-fsl-sai.c @@ -68,9 +68,20 @@ static int fsl_sai_clk_probe(struct platform_device *pdev) if (IS_ERR(hw)) return PTR_ERR(hw); + platform_set_drvdata(pdev, hw); + return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw); } +static int fsl_sai_clk_remove(struct platform_device *pdev) +{ + struct clk_hw *hw = platform_get_drvdata(pdev); + + clk_hw_unregister_composite(hw); + + return 0; +} + static const struct of_device_id of_fsl_sai_clk_ids[] = { { .compatible = "fsl,vf610-sai-clock" }, { } @@ -79,6 +90,7 @@ MODULE_DEVICE_TABLE(of, of_fsl_sai_clk_ids); static struct platform_driver fsl_sai_clk_driver = { .probe = fsl_sai_clk_probe, + .remove = fsl_sai_clk_remove, .driver = { .name = "fsl-sai-clk", .of_match_table = of_fsl_sai_clk_ids, From 0eba770790426553f45b8643bcd77b854e045057 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 5 Nov 2020 20:27:45 +0100 Subject: [PATCH 067/134] clk: composite: add devm_clk_hw_register_composite_pdata() This will simplify drivers which would only unregister the clk in their remove() op. Signed-off-by: Michael Walle Link: https://lore.kernel.org/r/20201105192746.19564-3-michael@walle.cc Signed-off-by: Stephen Boyd --- drivers/clk/clk-composite.c | 50 ++++++++++++++++++++++++++++++++++++ include/linux/clk-provider.h | 7 +++++ 2 files changed, 57 insertions(+) diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c index 2ddb54f7d3ab..0506046a5f4b 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -4,6 +4,7 @@ */ #include +#include #include #include @@ -405,3 +406,52 @@ void clk_hw_unregister_composite(struct clk_hw *hw) kfree(composite); } EXPORT_SYMBOL_GPL(clk_hw_unregister_composite); + +static void devm_clk_hw_release_composite(struct device *dev, void *res) +{ + clk_hw_unregister_composite(*(struct clk_hw **)res); +} + +static struct clk_hw *__devm_clk_hw_register_composite(struct device *dev, + const char *name, const char * const *parent_names, + const struct clk_parent_data *pdata, int num_parents, + struct clk_hw *mux_hw, const struct clk_ops *mux_ops, + struct clk_hw *rate_hw, const struct clk_ops *rate_ops, + struct clk_hw *gate_hw, const struct clk_ops *gate_ops, + unsigned long flags) +{ + struct clk_hw **ptr, *hw; + + ptr = devres_alloc(devm_clk_hw_release_composite, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + hw = __clk_hw_register_composite(dev, name, parent_names, pdata, + num_parents, mux_hw, mux_ops, rate_hw, + rate_ops, gate_hw, gate_ops, flags); + + if (!IS_ERR(hw)) { + *ptr = hw; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return hw; +} + +struct clk_hw *devm_clk_hw_register_composite_pdata(struct device *dev, + const char *name, + const struct clk_parent_data *parent_data, + int num_parents, + struct clk_hw *mux_hw, const struct clk_ops *mux_ops, + struct clk_hw *rate_hw, const struct clk_ops *rate_ops, + struct clk_hw *gate_hw, const struct clk_ops *gate_ops, + unsigned long flags) +{ + return __devm_clk_hw_register_composite(dev, name, NULL, parent_data, + num_parents, mux_hw, mux_ops, + rate_hw, rate_ops, gate_hw, + gate_ops, flags); +} diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 03a5de5f99f4..33db52ff83a0 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -1062,6 +1062,13 @@ struct clk_hw *clk_hw_register_composite_pdata(struct device *dev, struct clk_hw *rate_hw, const struct clk_ops *rate_ops, struct clk_hw *gate_hw, const struct clk_ops *gate_ops, unsigned long flags); +struct clk_hw *devm_clk_hw_register_composite_pdata(struct device *dev, + const char *name, const struct clk_parent_data *parent_data, + int num_parents, + struct clk_hw *mux_hw, const struct clk_ops *mux_ops, + struct clk_hw *rate_hw, const struct clk_ops *rate_ops, + struct clk_hw *gate_hw, const struct clk_ops *gate_ops, + unsigned long flags); void clk_hw_unregister_composite(struct clk_hw *hw); struct clk *clk_register(struct device *dev, struct clk_hw *hw); From fb8715157b6a16cf93a14109ebc8a6440a182a82 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 5 Nov 2020 20:27:46 +0100 Subject: [PATCH 068/134] clk: fsl-sai: use devm_clk_hw_register_composite_pdata() Simplify the driver by using that helper and drop the remove() function. Signed-off-by: Michael Walle Link: https://lore.kernel.org/r/20201105192746.19564-4-michael@walle.cc Signed-off-by: Stephen Boyd --- drivers/clk/clk-fsl-sai.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/drivers/clk/clk-fsl-sai.c b/drivers/clk/clk-fsl-sai.c index 1e81c8d8a6fd..6238fcea0467 100644 --- a/drivers/clk/clk-fsl-sai.c +++ b/drivers/clk/clk-fsl-sai.c @@ -58,30 +58,19 @@ static int fsl_sai_clk_probe(struct platform_device *pdev) /* set clock direction, we are the BCLK master */ writel(CR2_BCD, base + I2S_CR2); - hw = clk_hw_register_composite_pdata(dev, dev->of_node->name, - &pdata, 1, NULL, NULL, - &sai_clk->div.hw, - &clk_divider_ops, - &sai_clk->gate.hw, - &clk_gate_ops, - CLK_SET_RATE_GATE); + hw = devm_clk_hw_register_composite_pdata(dev, dev->of_node->name, + &pdata, 1, NULL, NULL, + &sai_clk->div.hw, + &clk_divider_ops, + &sai_clk->gate.hw, + &clk_gate_ops, + CLK_SET_RATE_GATE); if (IS_ERR(hw)) return PTR_ERR(hw); - platform_set_drvdata(pdev, hw); - return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw); } -static int fsl_sai_clk_remove(struct platform_device *pdev) -{ - struct clk_hw *hw = platform_get_drvdata(pdev); - - clk_hw_unregister_composite(hw); - - return 0; -} - static const struct of_device_id of_fsl_sai_clk_ids[] = { { .compatible = "fsl,vf610-sai-clock" }, { } @@ -90,7 +79,6 @@ MODULE_DEVICE_TABLE(of, of_fsl_sai_clk_ids); static struct platform_driver fsl_sai_clk_driver = { .probe = fsl_sai_clk_probe, - .remove = fsl_sai_clk_remove, .driver = { .name = "fsl-sai-clk", .of_match_table = of_fsl_sai_clk_ids, From 4cb15934ba05b49784d9d47778af308e7ea50b69 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Sun, 8 Nov 2020 19:51:07 +0100 Subject: [PATCH 069/134] clk: qoriq: provide constants for the type To avoid future mistakes in the device tree for the clockgen module, add constants for the clockgen subtype as well as a macro for the PLL divider. Signed-off-by: Michael Walle Acked-by: Rob Herring Link: https://lore.kernel.org/r/20201108185113.31377-4-michael@walle.cc Signed-off-by: Stephen Boyd --- drivers/clk/clk-qoriq.c | 13 +++++++------ include/dt-bindings/clock/fsl,qoriq-clockgen.h | 15 +++++++++++++++ 2 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 include/dt-bindings/clock/fsl,qoriq-clockgen.h diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c index 46101c6a20f2..70aa521e7e7f 100644 --- a/drivers/clk/clk-qoriq.c +++ b/drivers/clk/clk-qoriq.c @@ -7,6 +7,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include @@ -1368,33 +1369,33 @@ static struct clk *clockgen_clk_get(struct of_phandle_args *clkspec, void *data) idx = clkspec->args[1]; switch (type) { - case 0: + case QORIQ_CLK_SYSCLK: if (idx != 0) goto bad_args; clk = cg->sysclk; break; - case 1: + case QORIQ_CLK_CMUX: if (idx >= ARRAY_SIZE(cg->cmux)) goto bad_args; clk = cg->cmux[idx]; break; - case 2: + case QORIQ_CLK_HWACCEL: if (idx >= ARRAY_SIZE(cg->hwaccel)) goto bad_args; clk = cg->hwaccel[idx]; break; - case 3: + case QORIQ_CLK_FMAN: if (idx >= ARRAY_SIZE(cg->fman)) goto bad_args; clk = cg->fman[idx]; break; - case 4: + case QORIQ_CLK_PLATFORM_PLL: pll = &cg->pll[PLATFORM_PLL]; if (idx >= ARRAY_SIZE(pll->div)) goto bad_args; clk = pll->div[idx].clk; break; - case 5: + case QORIQ_CLK_CORECLK: if (idx != 0) goto bad_args; clk = cg->coreclk; diff --git a/include/dt-bindings/clock/fsl,qoriq-clockgen.h b/include/dt-bindings/clock/fsl,qoriq-clockgen.h new file mode 100644 index 000000000000..ddec7d0bdc7f --- /dev/null +++ b/include/dt-bindings/clock/fsl,qoriq-clockgen.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef DT_CLOCK_FSL_QORIQ_CLOCKGEN_H +#define DT_CLOCK_FSL_QORIQ_CLOCKGEN_H + +#define QORIQ_CLK_SYSCLK 0 +#define QORIQ_CLK_CMUX 1 +#define QORIQ_CLK_HWACCEL 2 +#define QORIQ_CLK_FMAN 3 +#define QORIQ_CLK_PLATFORM_PLL 4 +#define QORIQ_CLK_CORECLK 5 + +#define QORIQ_CLK_PLL_DIV(x) ((x) - 1) + +#endif /* DT_CLOCK_FSL_QORIQ_CLOCKGEN_H */ From 26792699fe3681102aa85f4ae6d39e80a6a7e6b6 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Sun, 8 Nov 2020 19:51:09 +0100 Subject: [PATCH 070/134] clk: divider: add devm_clk_hw_register_divider_table() This will simplify drivers which would only unregister the clk in their remove() op. Signed-off-by: Michael Walle Link: https://lore.kernel.org/r/20201108185113.31377-6-michael@walle.cc Signed-off-by: Stephen Boyd --- drivers/clk/clk-divider.c | 34 ++++++++++++++++++++++++++++++++++ include/linux/clk-provider.h | 27 +++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 8de12cb0c43d..c499799693cc 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -578,3 +579,36 @@ void clk_hw_unregister_divider(struct clk_hw *hw) kfree(div); } EXPORT_SYMBOL_GPL(clk_hw_unregister_divider); + +static void devm_clk_hw_release_divider(struct device *dev, void *res) +{ + clk_hw_unregister_divider(*(struct clk_hw **)res); +} + +struct clk_hw *__devm_clk_hw_register_divider(struct device *dev, + struct device_node *np, const char *name, + const char *parent_name, const struct clk_hw *parent_hw, + const struct clk_parent_data *parent_data, unsigned long flags, + void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, + const struct clk_div_table *table, spinlock_t *lock) +{ + struct clk_hw **ptr, *hw; + + ptr = devres_alloc(devm_clk_hw_release_divider, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + hw = __clk_hw_register_divider(dev, np, name, parent_name, parent_hw, + parent_data, flags, reg, shift, width, + clk_divider_flags, table, lock); + + if (!IS_ERR(hw)) { + *ptr = hw; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return hw; +} +EXPORT_SYMBOL_GPL(__devm_clk_hw_register_divider); diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 33db52ff83a0..5f896df01f83 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -639,6 +639,12 @@ struct clk_hw *__clk_hw_register_divider(struct device *dev, const struct clk_parent_data *parent_data, unsigned long flags, void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, const struct clk_div_table *table, spinlock_t *lock); +struct clk_hw *__devm_clk_hw_register_divider(struct device *dev, + struct device_node *np, const char *name, + const char *parent_name, const struct clk_hw *parent_hw, + const struct clk_parent_data *parent_data, unsigned long flags, + void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, + const struct clk_div_table *table, spinlock_t *lock); struct clk *clk_register_divider_table(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, @@ -779,6 +785,27 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name, (parent_data), (flags), (reg), (shift), \ (width), (clk_divider_flags), (table), \ (lock)) +/** + * devm_clk_hw_register_divider_table - register a table based divider clock + * with the clock framework (devres variant) + * @dev: device registering this clock + * @name: name of this clock + * @parent_name: name of clock's parent + * @flags: framework-specific flags + * @reg: register address to adjust divider + * @shift: number of bits to shift the bitfield + * @width: width of the bitfield + * @clk_divider_flags: divider-specific flags for this clock + * @table: array of divider/value pairs ending with a div set to 0 + * @lock: shared register lock for this clock + */ +#define devm_clk_hw_register_divider_table(dev, name, parent_name, flags, \ + reg, shift, width, \ + clk_divider_flags, table, lock) \ + __devm_clk_hw_register_divider((dev), NULL, (name), (parent_name), \ + NULL, NULL, (flags), (reg), (shift), \ + (width), (clk_divider_flags), (table), \ + (lock)) void clk_unregister_divider(struct clk *clk); void clk_hw_unregister_divider(struct clk_hw *hw); From e577af82c72fa928a4ab670fe5ac2b0b7b14fceb Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Sun, 8 Nov 2020 19:51:10 +0100 Subject: [PATCH 071/134] dt-bindings: clock: document the fsl-flexspi-clk device Signed-off-by: Michael Walle Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20201108185113.31377-7-michael@walle.cc [sboyd@kernel.org: DT bindings aren't drivers] Signed-off-by: Stephen Boyd --- .../bindings/clock/fsl,flexspi-clock.yaml | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/fsl,flexspi-clock.yaml diff --git a/Documentation/devicetree/bindings/clock/fsl,flexspi-clock.yaml b/Documentation/devicetree/bindings/clock/fsl,flexspi-clock.yaml new file mode 100644 index 000000000000..1fa390ee7b9b --- /dev/null +++ b/Documentation/devicetree/bindings/clock/fsl,flexspi-clock.yaml @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/fsl,flexspi-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale FlexSPI clock driver for Layerscape SoCs + +maintainers: + - Michael Walle + +description: + The Freescale Layerscape SoCs have a special FlexSPI clock which is + derived from the platform PLL. + +properties: + compatible: + enum: + - fsl,ls1028a-flexspi-clk + - fsl,lx2160a-flexspi-clk + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + '#clock-cells': + const: 0 + + clock-output-names: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - '#clock-cells' + +additionalProperties: false + +examples: + - | + dcfg { + #address-cells = <1>; + #size-cells = <1>; + + fspi_clk: clock-controller@900 { + compatible = "fsl,ls1028a-flexspi-clk"; + reg = <0x900 0x4>; + #clock-cells = <0>; + clocks = <&parentclk>; + clock-output-names = "fspi_clk"; + }; + }; From fcf77be87eacb8f305528d24d892dfcf15cf0341 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Sun, 8 Nov 2020 19:51:11 +0100 Subject: [PATCH 072/134] clk: fsl-flexspi: new driver Add support for the FlexSPI clock on Freescale Layerscape SoCs. The clock is a simple divider based one and is located inside the device configuration space (DCFG). This will allow switching the SCK frequencies for the FlexSPI interface on the LS1028A and the LX2160A. Signed-off-by: Michael Walle Link: https://lore.kernel.org/r/20201108185113.31377-8-michael@walle.cc [sboyd@kernel.org: Drop modalias, add module table] Signed-off-by: Stephen Boyd --- drivers/clk/Kconfig | 8 +++ drivers/clk/Makefile | 1 + drivers/clk/clk-fsl-flexspi.c | 106 ++++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 drivers/clk/clk-fsl-flexspi.c diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 969080401a83..85856cff506c 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -188,6 +188,14 @@ config COMMON_CLK_CS2000_CP help If you say yes here you get support for the CS2000 clock multiplier. +config COMMON_CLK_FSL_FLEXSPI + tristate "Clock driver for FlexSPI on Layerscape SoCs" + depends on ARCH_LAYERSCAPE || COMPILE_TEST + default ARCH_LAYERSCAPE && SPI_NXP_FLEXSPI + help + On Layerscape SoCs there is a special clock for the FlexSPI + interface. + config COMMON_CLK_FSL_SAI bool "Clock driver for BCLK of Freescale SAI cores" depends on ARCH_LAYERSCAPE || COMPILE_TEST diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index da8fcf147eb1..dbdc590e7de3 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o obj-$(CONFIG_ARCH_SPARX5) += clk-sparx5.o obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o +obj-$(CONFIG_COMMON_CLK_FSL_FLEXSPI) += clk-fsl-flexspi.o obj-$(CONFIG_COMMON_CLK_FSL_SAI) += clk-fsl-sai.o obj-$(CONFIG_COMMON_CLK_GEMINI) += clk-gemini.o obj-$(CONFIG_COMMON_CLK_ASPEED) += clk-aspeed.o diff --git a/drivers/clk/clk-fsl-flexspi.c b/drivers/clk/clk-fsl-flexspi.c new file mode 100644 index 000000000000..8432d681e2d9 --- /dev/null +++ b/drivers/clk/clk-fsl-flexspi.c @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Layerscape FlexSPI clock driver + * + * Copyright 2020 Michael Walle + */ + +#include +#include +#include +#include + +static const struct clk_div_table ls1028a_flexspi_divs[] = { + { .val = 0, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 2, .div = 3, }, + { .val = 3, .div = 4, }, + { .val = 4, .div = 5, }, + { .val = 5, .div = 6, }, + { .val = 6, .div = 7, }, + { .val = 7, .div = 8, }, + { .val = 11, .div = 12, }, + { .val = 15, .div = 16, }, + { .val = 16, .div = 20, }, + { .val = 17, .div = 24, }, + { .val = 18, .div = 28, }, + { .val = 19, .div = 32, }, + { .val = 20, .div = 80, }, + {} +}; + +static const struct clk_div_table lx2160a_flexspi_divs[] = { + { .val = 1, .div = 2, }, + { .val = 3, .div = 4, }, + { .val = 5, .div = 6, }, + { .val = 7, .div = 8, }, + { .val = 11, .div = 12, }, + { .val = 15, .div = 16, }, + { .val = 16, .div = 20, }, + { .val = 17, .div = 24, }, + { .val = 18, .div = 28, }, + { .val = 19, .div = 32, }, + { .val = 20, .div = 80, }, + {} +}; + +static int fsl_flexspi_clk_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + const char *clk_name = np->name; + const char *clk_parent; + struct resource *res; + void __iomem *reg; + struct clk_hw *hw; + const struct clk_div_table *divs; + + divs = device_get_match_data(dev); + if (!divs) + return -ENOENT; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENOENT; + + /* + * Can't use devm_ioremap_resource() or devm_of_iomap() because the + * resource might already be taken by the parent device. + */ + reg = devm_ioremap(dev, res->start, resource_size(res)); + if (!reg) + return -ENOMEM; + + clk_parent = of_clk_get_parent_name(np, 0); + if (!clk_parent) + return -EINVAL; + + of_property_read_string(np, "clock-output-names", &clk_name); + + hw = devm_clk_hw_register_divider_table(dev, clk_name, clk_parent, 0, + reg, 0, 5, 0, divs, NULL); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw); +} + +static const struct of_device_id fsl_flexspi_clk_dt_ids[] = { + { .compatible = "fsl,ls1028a-flexspi-clk", .data = &ls1028a_flexspi_divs }, + { .compatible = "fsl,lx2160a-flexspi-clk", .data = &lx2160a_flexspi_divs }, + {} +}; +MODULE_DEVICE_TABLE(of, fsl_flexspi_clk_dt_ids); + +static struct platform_driver fsl_flexspi_clk_driver = { + .driver = { + .name = "fsl-flexspi-clk", + .of_match_table = fsl_flexspi_clk_dt_ids, + }, + .probe = fsl_flexspi_clk_probe, +}; +module_platform_driver(fsl_flexspi_clk_driver); + +MODULE_DESCRIPTION("FlexSPI clock driver for Layerscape SoCs"); +MODULE_AUTHOR("Michael Walle "); +MODULE_LICENSE("GPL"); From a13ae5a3797aa86623c906604fb5a884b832a685 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 26 Nov 2020 12:58:39 +0530 Subject: [PATCH 073/134] dt-bindings: clock: Add SDX55 GCC clock bindings Add device tree bindings for global clock controller on SDX55 SoCs. Signed-off-by: Vinod Koul Signed-off-by: Manivannan Sadhasivam Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20201126072844.35370-2-manivannan.sadhasivam@linaro.org Signed-off-by: Stephen Boyd --- .../bindings/clock/qcom,gcc-sdx55.yaml | 77 ++++++++++++ include/dt-bindings/clock/qcom,gcc-sdx55.h | 112 ++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,gcc-sdx55.yaml create mode 100644 include/dt-bindings/clock/qcom,gcc-sdx55.h diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc-sdx55.yaml b/Documentation/devicetree/bindings/clock/qcom,gcc-sdx55.yaml new file mode 100644 index 000000000000..1121b3934cb9 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,gcc-sdx55.yaml @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,gcc-sdx55.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Global Clock & Reset Controller Binding for SDX55 + +maintainers: + - Vinod Koul + - Manivannan Sadhasivam + +description: | + Qualcomm global clock control module which supports the clocks, resets and + power domains on SDX55 + + See also: + - dt-bindings/clock/qcom,gcc-sdx55.h + +properties: + compatible: + const: qcom,gcc-sdx55 + + clocks: + items: + - description: Board XO source + - description: Sleep clock source + - description: PLL test clock source (Optional clock) + minItems: 2 + maxItems: 3 + + clock-names: + items: + - const: bi_tcxo + - const: sleep_clk + - const: core_bi_pll_test_se # Optional clock + minItems: 2 + maxItems: 3 + + '#clock-cells': + const: 1 + + '#reset-cells': + const: 1 + + '#power-domain-cells': + const: 1 + + reg: + maxItems: 1 + +required: + - compatible + - clocks + - clock-names + - reg + - '#clock-cells' + - '#reset-cells' + - '#power-domain-cells' + +additionalProperties: false + +examples: + - | + #include + clock-controller@100000 { + compatible = "qcom,gcc-sdx55"; + reg = <0x00100000 0x1f0000>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&sleep_clk>, <&pll_test_clk>; + clock-names = "bi_tcxo", "sleep_clk", "core_bi_pll_test_se"; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + +... diff --git a/include/dt-bindings/clock/qcom,gcc-sdx55.h b/include/dt-bindings/clock/qcom,gcc-sdx55.h new file mode 100644 index 000000000000..c372451b3461 --- /dev/null +++ b/include/dt-bindings/clock/qcom,gcc-sdx55.h @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2020, Linaro Ltd. + */ + +#ifndef _DT_BINDINGS_CLK_QCOM_GCC_SDX55_H +#define _DT_BINDINGS_CLK_QCOM_GCC_SDX55_H + +#define GPLL0 3 +#define GPLL0_OUT_EVEN 4 +#define GPLL4 5 +#define GPLL4_OUT_EVEN 6 +#define GPLL5 7 +#define GCC_AHB_PCIE_LINK_CLK 8 +#define GCC_BLSP1_AHB_CLK 9 +#define GCC_BLSP1_QUP1_I2C_APPS_CLK 10 +#define GCC_BLSP1_QUP1_I2C_APPS_CLK_SRC 11 +#define GCC_BLSP1_QUP1_SPI_APPS_CLK 12 +#define GCC_BLSP1_QUP1_SPI_APPS_CLK_SRC 13 +#define GCC_BLSP1_QUP2_I2C_APPS_CLK 14 +#define GCC_BLSP1_QUP2_I2C_APPS_CLK_SRC 15 +#define GCC_BLSP1_QUP2_SPI_APPS_CLK 16 +#define GCC_BLSP1_QUP2_SPI_APPS_CLK_SRC 17 +#define GCC_BLSP1_QUP3_I2C_APPS_CLK 18 +#define GCC_BLSP1_QUP3_I2C_APPS_CLK_SRC 19 +#define GCC_BLSP1_QUP3_SPI_APPS_CLK 20 +#define GCC_BLSP1_QUP3_SPI_APPS_CLK_SRC 21 +#define GCC_BLSP1_QUP4_I2C_APPS_CLK 22 +#define GCC_BLSP1_QUP4_I2C_APPS_CLK_SRC 23 +#define GCC_BLSP1_QUP4_SPI_APPS_CLK 24 +#define GCC_BLSP1_QUP4_SPI_APPS_CLK_SRC 25 +#define GCC_BLSP1_UART1_APPS_CLK 26 +#define GCC_BLSP1_UART1_APPS_CLK_SRC 27 +#define GCC_BLSP1_UART2_APPS_CLK 28 +#define GCC_BLSP1_UART2_APPS_CLK_SRC 29 +#define GCC_BLSP1_UART3_APPS_CLK 30 +#define GCC_BLSP1_UART3_APPS_CLK_SRC 31 +#define GCC_BLSP1_UART4_APPS_CLK 32 +#define GCC_BLSP1_UART4_APPS_CLK_SRC 33 +#define GCC_BOOT_ROM_AHB_CLK 34 +#define GCC_CE1_AHB_CLK 35 +#define GCC_CE1_AXI_CLK 36 +#define GCC_CE1_CLK 37 +#define GCC_CPUSS_AHB_CLK 38 +#define GCC_CPUSS_AHB_CLK_SRC 39 +#define GCC_CPUSS_GNOC_CLK 40 +#define GCC_CPUSS_RBCPR_CLK 41 +#define GCC_CPUSS_RBCPR_CLK_SRC 42 +#define GCC_EMAC_CLK_SRC 43 +#define GCC_EMAC_PTP_CLK_SRC 44 +#define GCC_ETH_AXI_CLK 45 +#define GCC_ETH_PTP_CLK 46 +#define GCC_ETH_RGMII_CLK 47 +#define GCC_ETH_SLAVE_AHB_CLK 48 +#define GCC_GP1_CLK 49 +#define GCC_GP1_CLK_SRC 50 +#define GCC_GP2_CLK 51 +#define GCC_GP2_CLK_SRC 52 +#define GCC_GP3_CLK 53 +#define GCC_GP3_CLK_SRC 54 +#define GCC_PCIE_0_CLKREF_CLK 55 +#define GCC_PCIE_AUX_CLK 56 +#define GCC_PCIE_AUX_PHY_CLK_SRC 57 +#define GCC_PCIE_CFG_AHB_CLK 58 +#define GCC_PCIE_MSTR_AXI_CLK 59 +#define GCC_PCIE_PIPE_CLK 60 +#define GCC_PCIE_RCHNG_PHY_CLK 61 +#define GCC_PCIE_RCHNG_PHY_CLK_SRC 62 +#define GCC_PCIE_SLEEP_CLK 63 +#define GCC_PCIE_SLV_AXI_CLK 64 +#define GCC_PCIE_SLV_Q2A_AXI_CLK 65 +#define GCC_PDM2_CLK 66 +#define GCC_PDM2_CLK_SRC 67 +#define GCC_PDM_AHB_CLK 68 +#define GCC_PDM_XO4_CLK 69 +#define GCC_SDCC1_AHB_CLK 70 +#define GCC_SDCC1_APPS_CLK 71 +#define GCC_SDCC1_APPS_CLK_SRC 72 +#define GCC_SYS_NOC_CPUSS_AHB_CLK 73 +#define GCC_USB30_MASTER_CLK 74 +#define GCC_USB30_MASTER_CLK_SRC 75 +#define GCC_USB30_MOCK_UTMI_CLK 76 +#define GCC_USB30_MOCK_UTMI_CLK_SRC 77 +#define GCC_USB30_MSTR_AXI_CLK 78 +#define GCC_USB30_SLEEP_CLK 79 +#define GCC_USB30_SLV_AHB_CLK 80 +#define GCC_USB3_PHY_AUX_CLK 81 +#define GCC_USB3_PHY_AUX_CLK_SRC 82 +#define GCC_USB3_PHY_PIPE_CLK 83 +#define GCC_USB3_PRIM_CLKREF_CLK 84 +#define GCC_USB_PHY_CFG_AHB2PHY_CLK 85 +#define GCC_XO_DIV4_CLK 86 +#define GCC_XO_PCIE_LINK_CLK 87 + +#define GCC_EMAC_BCR 0 +#define GCC_PCIE_BCR 1 +#define GCC_PCIE_LINK_DOWN_BCR 2 +#define GCC_PCIE_NOCSR_COM_PHY_BCR 3 +#define GCC_PCIE_PHY_BCR 4 +#define GCC_PCIE_PHY_CFG_AHB_BCR 5 +#define GCC_PCIE_PHY_COM_BCR 6 +#define GCC_PCIE_PHY_NOCSR_COM_PHY_BCR 7 +#define GCC_PDM_BCR 8 +#define GCC_QUSB2PHY_BCR 9 +#define GCC_TCSR_PCIE_BCR 10 +#define GCC_USB30_BCR 11 +#define GCC_USB3_PHY_BCR 12 +#define GCC_USB3PHY_PHY_BCR 13 +#define GCC_USB_PHY_CFG_AHB2PHY_BCR 14 + +#endif From 3fade566c07abd54ad8324326a4a14f2b6c13e3d Mon Sep 17 00:00:00 2001 From: Naveen Yadav Date: Thu, 26 Nov 2020 12:58:40 +0530 Subject: [PATCH 074/134] clk: qcom: Add SDX55 GCC support Add Global Clock Controller (GCC) support for SDX55 SoCs from Qualcomm. Signed-off-by: Naveen Yadav [mani: converted to parent_data, commented critical clocks, cleanups] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Vinod Koul Link: https://lore.kernel.org/r/20201126072844.35370-3-manivannan.sadhasivam@linaro.org Signed-off-by: Stephen Boyd --- drivers/clk/qcom/Kconfig | 7 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gcc-sdx55.c | 1626 ++++++++++++++++++++++++++++++++++ 3 files changed, 1634 insertions(+) create mode 100644 drivers/clk/qcom/gcc-sdx55.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 8c8b568609d4..3555eac37495 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -422,6 +422,13 @@ config SDM_LPASSCC_845 Say Y if you want to use the LPASS branch clocks of the LPASS clock controller to reset the LPASS subsystem. +config SDX_GCC_55 + tristate "SDX55 Global Clock Controller" + help + Support for the global clock controller on SDX55 devices. + Say Y if you want to use peripheral devices such as UART, + SPI, I2C, USB, SD/UFS, PCIe etc. + config SM_DISPCC_8250 tristate "SM8150 and SM8250 Display Clock Controller" depends on SM_GCC_8150 || SM_GCC_8250 diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 57b6349a3ee8..9e5e0e3cb7b4 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -66,6 +66,7 @@ obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o obj-$(CONFIG_SDM_GPUCC_845) += gpucc-sdm845.o obj-$(CONFIG_SDM_LPASSCC_845) += lpasscc-sdm845.o obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o +obj-$(CONFIG_SDX_GCC_55) += gcc-sdx55.o obj-$(CONFIG_SM_DISPCC_8250) += dispcc-sm8250.o obj-$(CONFIG_SM_GCC_8150) += gcc-sm8150.o obj-$(CONFIG_SM_GCC_8250) += gcc-sm8250.o diff --git a/drivers/clk/qcom/gcc-sdx55.c b/drivers/clk/qcom/gcc-sdx55.c new file mode 100644 index 000000000000..bf114165e24b --- /dev/null +++ b/drivers/clk/qcom/gcc-sdx55.c @@ -0,0 +1,1626 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2020, Linaro Ltd. + */ + +#include +#include +#include +#include + +#include + +#include "common.h" +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "reset.h" + +enum { + P_BI_TCXO, + P_CORE_BI_PLL_TEST_SE, + P_GPLL0_OUT_EVEN, + P_GPLL0_OUT_MAIN, + P_GPLL4_OUT_EVEN, + P_GPLL5_OUT_MAIN, + P_SLEEP_CLK, +}; + +static const struct pll_vco lucid_vco[] = { + { 249600000, 2000000000, 0 }, +}; + +static struct clk_alpha_pll gpll0 = { + .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .vco_table = lucid_vco, + .num_vco = ARRAY_SIZE(lucid_vco), + .clkr = { + .enable_reg = 0x6d000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpll0", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "bi_tcxo", + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_lucid_even[] = { + { 0x0, 1 }, + { 0x1, 2 }, + { 0x3, 4 }, + { 0x7, 8 }, + { } +}; + +static struct clk_alpha_pll_postdiv gpll0_out_even = { + .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .post_div_shift = 8, + .post_div_table = post_div_table_lucid_even, + .num_post_div = ARRAY_SIZE(post_div_table_lucid_even), + .width = 4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpll0_out_even", + .parent_data = &(const struct clk_parent_data){ + .hw = &gpll0.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_lucid_ops, + }, +}; + +static struct clk_alpha_pll gpll4 = { + .offset = 0x76000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .vco_table = lucid_vco, + .num_vco = ARRAY_SIZE(lucid_vco), + .clkr = { + .enable_reg = 0x6d000, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gpll4", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "bi_tcxo", + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ops, + }, + }, +}; + +static struct clk_alpha_pll_postdiv gpll4_out_even = { + .offset = 0x76000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .post_div_shift = 8, + .post_div_table = post_div_table_lucid_even, + .num_post_div = ARRAY_SIZE(post_div_table_lucid_even), + .width = 4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpll4_out_even", + .parent_data = &(const struct clk_parent_data){ + .hw = &gpll4.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_lucid_ops, + }, +}; + +static struct clk_alpha_pll gpll5 = { + .offset = 0x74000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .vco_table = lucid_vco, + .num_vco = ARRAY_SIZE(lucid_vco), + .clkr = { + .enable_reg = 0x6d000, + .enable_mask = BIT(5), + .hw.init = &(struct clk_init_data){ + .name = "gpll5", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "bi_tcxo", + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ops, + }, + }, +}; + +static const struct parent_map gcc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL0_OUT_EVEN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const struct clk_parent_data gcc_parents_0[] = { + { .fw_name = "bi_tcxo" }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll0_out_even.clkr.hw }, + { .fw_name = "core_bi_pll_test_se" }, +}; + +static const struct clk_parent_data gcc_parents_0_ao[] = { + { .fw_name = "bi_tcxo_ao" }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll0_out_even.clkr.hw }, + { .fw_name = "core_bi_pll_test_se" }, +}; + +static const struct parent_map gcc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL4_OUT_EVEN, 2 }, + { P_GPLL5_OUT_MAIN, 5 }, + { P_GPLL0_OUT_EVEN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const struct clk_parent_data gcc_parents_2[] = { + { .fw_name = "bi_tcxo" }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll4_out_even.clkr.hw }, + { .hw = &gpll5.clkr.hw }, + { .hw = &gpll0_out_even.clkr.hw }, + { .fw_name = "core_bi_pll_test_se" }, +}; + +static const struct parent_map gcc_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_SLEEP_CLK, 5 }, + { P_GPLL0_OUT_EVEN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const struct clk_parent_data gcc_parents_3[] = { + { .fw_name = "bi_tcxo" }, + { .hw = &gpll0.clkr.hw }, + { .fw_name = "sleep_clk", .name = "sleep_clk" }, + { .hw = &gpll0_out_even.clkr.hw }, + { .fw_name = "core_bi_pll_test_se" }, +}; + +static const struct parent_map gcc_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_SLEEP_CLK, 5 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const struct clk_parent_data gcc_parents_4[] = { + { .fw_name = "bi_tcxo" }, + { .fw_name = "sleep_clk", .name = "sleep_clk" }, + { .fw_name = "core_bi_pll_test_se" }, +}; + +static const struct parent_map gcc_parent_map_5[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL4_OUT_EVEN, 2 }, + { P_GPLL0_OUT_EVEN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const struct clk_parent_data gcc_parents_5[] = { + { .fw_name = "bi_tcxo" }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll4_out_even.clkr.hw }, + { .hw = &gpll0_out_even.clkr.hw }, + { .fw_name = "core_bi_pll_test_se" }, +}; + +static const struct freq_tbl ftbl_gcc_blsp1_qup1_i2c_apps_clk_src[] = { + F(9600000, P_BI_TCXO, 2, 0, 0), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_blsp1_qup1_i2c_apps_clk_src = { + .cmd_rcgr = 0x11024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup1_i2c_apps_clk_src", + .parent_data = gcc_parents_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_blsp1_qup1_spi_apps_clk_src[] = { + F(960000, P_BI_TCXO, 10, 1, 2), + F(4800000, P_BI_TCXO, 4, 0, 0), + F(9600000, P_BI_TCXO, 2, 0, 0), + F(15000000, P_GPLL0_OUT_EVEN, 5, 1, 4), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(24000000, P_GPLL0_OUT_MAIN, 12.5, 1, 2), + F(25000000, P_GPLL0_OUT_MAIN, 12, 1, 2), + F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_blsp1_qup1_spi_apps_clk_src = { + .cmd_rcgr = 0x1100c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup1_spi_apps_clk_src", + .parent_data = gcc_parents_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_blsp1_qup2_i2c_apps_clk_src = { + .cmd_rcgr = 0x13024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup2_i2c_apps_clk_src", + .parent_data = gcc_parents_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_blsp1_qup2_spi_apps_clk_src = { + .cmd_rcgr = 0x1300c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup2_spi_apps_clk_src", + .parent_data = gcc_parents_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_blsp1_qup3_i2c_apps_clk_src = { + .cmd_rcgr = 0x15024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup3_i2c_apps_clk_src", + .parent_data = gcc_parents_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_blsp1_qup3_spi_apps_clk_src = { + .cmd_rcgr = 0x1500c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup3_spi_apps_clk_src", + .parent_data = gcc_parents_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_blsp1_qup4_i2c_apps_clk_src = { + .cmd_rcgr = 0x17024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup4_i2c_apps_clk_src", + .parent_data = gcc_parents_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_blsp1_qup4_spi_apps_clk_src = { + .cmd_rcgr = 0x1700c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup4_spi_apps_clk_src", + .parent_data = gcc_parents_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_blsp1_uart1_apps_clk_src[] = { + F(3686400, P_GPLL0_OUT_EVEN, 1, 192, 15625), + F(7372800, P_GPLL0_OUT_EVEN, 1, 384, 15625), + F(9600000, P_BI_TCXO, 2, 0, 0), + F(14745600, P_GPLL0_OUT_EVEN, 1, 768, 15625), + F(16000000, P_GPLL0_OUT_EVEN, 1, 4, 75), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(19354839, P_GPLL0_OUT_MAIN, 15.5, 1, 2), + F(20000000, P_GPLL0_OUT_MAIN, 15, 1, 2), + F(20689655, P_GPLL0_OUT_MAIN, 14.5, 1, 2), + F(21428571, P_GPLL0_OUT_MAIN, 14, 1, 2), + F(22222222, P_GPLL0_OUT_MAIN, 13.5, 1, 2), + F(23076923, P_GPLL0_OUT_MAIN, 13, 1, 2), + F(24000000, P_GPLL0_OUT_MAIN, 5, 1, 5), + F(25000000, P_GPLL0_OUT_MAIN, 12, 1, 2), + F(26086957, P_GPLL0_OUT_MAIN, 11.5, 1, 2), + F(27272727, P_GPLL0_OUT_MAIN, 11, 1, 2), + F(28571429, P_GPLL0_OUT_MAIN, 10.5, 1, 2), + F(32000000, P_GPLL0_OUT_MAIN, 1, 4, 75), + F(40000000, P_GPLL0_OUT_MAIN, 15, 0, 0), + F(46400000, P_GPLL0_OUT_MAIN, 1, 29, 375), + F(48000000, P_GPLL0_OUT_MAIN, 12.5, 0, 0), + F(51200000, P_GPLL0_OUT_MAIN, 1, 32, 375), + F(56000000, P_GPLL0_OUT_MAIN, 1, 7, 75), + F(58982400, P_GPLL0_OUT_MAIN, 1, 1536, 15625), + F(60000000, P_GPLL0_OUT_MAIN, 10, 0, 0), + F(63157895, P_GPLL0_OUT_MAIN, 9.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_blsp1_uart1_apps_clk_src = { + .cmd_rcgr = 0x1200c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_uart1_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart1_apps_clk_src", + .parent_data = gcc_parents_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_blsp1_uart2_apps_clk_src = { + .cmd_rcgr = 0x1400c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_uart1_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart2_apps_clk_src", + .parent_data = gcc_parents_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_blsp1_uart3_apps_clk_src = { + .cmd_rcgr = 0x1600c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_uart1_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart3_apps_clk_src", + .parent_data = gcc_parents_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_blsp1_uart4_apps_clk_src = { + .cmd_rcgr = 0x1800c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_uart1_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart4_apps_clk_src", + .parent_data = gcc_parents_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_cpuss_ahb_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(133333333, P_GPLL0_OUT_MAIN, 4.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_cpuss_ahb_clk_src = { + .cmd_rcgr = 0x24010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_cpuss_ahb_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_ahb_clk_src", + .parent_data = gcc_parents_0_ao, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_cpuss_rbcpr_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_cpuss_rbcpr_clk_src = { + .cmd_rcgr = 0x2402c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_cpuss_rbcpr_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_rbcpr_clk_src", + .parent_data = gcc_parents_0_ao, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_emac_clk_src[] = { + F(2500000, P_BI_TCXO, 1, 25, 192), + F(5000000, P_BI_TCXO, 1, 25, 96), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(250000000, P_GPLL4_OUT_EVEN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_emac_clk_src = { + .cmd_rcgr = 0x47020, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_5, + .freq_tbl = ftbl_gcc_emac_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_emac_clk_src", + .parent_data = gcc_parents_5, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_emac_ptp_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(230400000, P_GPLL5_OUT_MAIN, 3.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_emac_ptp_clk_src = { + .cmd_rcgr = 0x47038, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_emac_ptp_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_emac_ptp_clk_src", + .parent_data = gcc_parents_2, + .num_parents = 6, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_gp1_clk_src = { + .cmd_rcgr = 0x2b004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_gp1_clk_src", + .parent_data = gcc_parents_3, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_gp2_clk_src = { + .cmd_rcgr = 0x2c004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_gp2_clk_src", + .parent_data = gcc_parents_3, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_gp3_clk_src = { + .cmd_rcgr = 0x2d004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_gp3_clk_src", + .parent_data = gcc_parents_3, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_aux_phy_clk_src = { + .cmd_rcgr = 0x37034, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_cpuss_rbcpr_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_aux_phy_clk_src", + .parent_data = gcc_parents_4, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie_rchng_phy_clk_src[] = { + F(100000000, P_GPLL0_OUT_EVEN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie_rchng_phy_clk_src = { + .cmd_rcgr = 0x37050, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_pcie_rchng_phy_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_rchng_phy_clk_src", + .parent_data = gcc_parents_3, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = { + F(9600000, P_BI_TCXO, 2, 0, 0), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(60000000, P_GPLL0_OUT_MAIN, 10, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pdm2_clk_src = { + .cmd_rcgr = 0x19010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pdm2_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_pdm2_clk_src", + .parent_data = gcc_parents_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_sdcc1_apps_clk_src = { + .cmd_rcgr = 0xf00c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_apps_clk_src", + .parent_data = gcc_parents_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb30_master_clk_src[] = { + F(200000000, P_GPLL0_OUT_EVEN, 1.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb30_master_clk_src = { + .cmd_rcgr = 0xb024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_master_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_master_clk_src", + .parent_data = gcc_parents_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb30_mock_utmi_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb30_mock_utmi_clk_src = { + .cmd_rcgr = 0xb03c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_mock_utmi_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_mock_utmi_clk_src", + .parent_data = gcc_parents_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb3_phy_aux_clk_src[] = { + F(1000000, P_BI_TCXO, 1, 5, 96), + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb3_phy_aux_clk_src = { + .cmd_rcgr = 0xb064, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_usb3_phy_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_phy_aux_clk_src", + .parent_data = gcc_parents_4, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_ahb_pcie_link_clk = { + .halt_reg = 0x22004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x22004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ahb_pcie_link_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_ahb_clk = { + .halt_reg = 0x10004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d008, + .enable_mask = BIT(14), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = { + .halt_reg = 0x11008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x11008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup1_i2c_apps_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_blsp1_qup1_i2c_apps_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = { + .halt_reg = 0x11004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x11004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup1_spi_apps_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_blsp1_qup1_spi_apps_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = { + .halt_reg = 0x13008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup2_i2c_apps_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_blsp1_qup2_i2c_apps_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = { + .halt_reg = 0x13004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup2_spi_apps_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_blsp1_qup2_spi_apps_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup3_i2c_apps_clk = { + .halt_reg = 0x15008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x15008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup3_i2c_apps_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_blsp1_qup3_i2c_apps_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup3_spi_apps_clk = { + .halt_reg = 0x15004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x15004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup3_spi_apps_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_blsp1_qup3_spi_apps_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup4_i2c_apps_clk = { + .halt_reg = 0x17008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup4_i2c_apps_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_blsp1_qup4_i2c_apps_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup4_spi_apps_clk = { + .halt_reg = 0x17004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup4_spi_apps_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_blsp1_qup4_spi_apps_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart1_apps_clk = { + .halt_reg = 0x12004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x12004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart1_apps_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_blsp1_uart1_apps_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart2_apps_clk = { + .halt_reg = 0x14004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x14004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart2_apps_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_blsp1_uart2_apps_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart3_apps_clk = { + .halt_reg = 0x16004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x16004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart3_apps_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_blsp1_uart3_apps_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart4_apps_clk = { + .halt_reg = 0x18004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x18004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart4_apps_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_blsp1_uart4_apps_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_boot_rom_ahb_clk = { + .halt_reg = 0x1c004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x1c004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x6d008, + .enable_mask = BIT(10), + .hw.init = &(struct clk_init_data){ + .name = "gcc_boot_rom_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ce1_ahb_clk = { + .halt_reg = 0x2100c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2100c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x6d008, + .enable_mask = BIT(3), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ce1_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ce1_axi_clk = { + .halt_reg = 0x21008, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d008, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ce1_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ce1_clk = { + .halt_reg = 0x21004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d008, + .enable_mask = BIT(5), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ce1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cpuss_rbcpr_clk = { + .halt_reg = 0x24008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x24008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_rbcpr_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_cpuss_rbcpr_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_eth_axi_clk = { + .halt_reg = 0x4701c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4701c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_eth_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_eth_ptp_clk = { + .halt_reg = 0x47018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x47018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_eth_ptp_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_emac_ptp_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_eth_rgmii_clk = { + .halt_reg = 0x47010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x47010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_eth_rgmii_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_emac_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_eth_slave_ahb_clk = { + .halt_reg = 0x47014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x47014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_eth_slave_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp1_clk = { + .halt_reg = 0x2b000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp1_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_gp1_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp2_clk = { + .halt_reg = 0x2c000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2c000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp2_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_gp2_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp3_clk = { + .halt_reg = 0x2d000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2d000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp3_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_gp3_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_clkref_clk = { + .halt_reg = 0x88004, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x88004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_clkref_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_aux_clk = { + .halt_reg = 0x37024, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x6d010, + .enable_mask = BIT(3), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_aux_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_cfg_ahb_clk = { + .halt_reg = 0x3701c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d010, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_mstr_axi_clk = { + .halt_reg = 0x37018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d010, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_pipe_clk = { + .halt_reg = 0x3702c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x6d010, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_rchng_phy_clk = { + .halt_reg = 0x37020, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d010, + .enable_mask = BIT(7), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_rchng_phy_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_pcie_rchng_phy_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_sleep_clk = { + .halt_reg = 0x37028, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d010, + .enable_mask = BIT(6), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_sleep_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_pcie_aux_phy_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_slv_axi_clk = { + .halt_reg = 0x37014, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x37014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x6d010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_slv_q2a_axi_clk = { + .halt_reg = 0x37010, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d010, + .enable_mask = BIT(5), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm2_clk = { + .halt_reg = 0x1900c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1900c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pdm2_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_pdm2_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm_ahb_clk = { + .halt_reg = 0x19004, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x19004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x19004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pdm_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm_xo4_clk = { + .halt_reg = 0x19008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x19008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pdm_xo4_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_ahb_clk = { + .halt_reg = 0xf008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_apps_clk = { + .halt_reg = 0xf004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_apps_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_sdcc1_apps_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_master_clk = { + .halt_reg = 0xb010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_master_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_usb30_master_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_mock_utmi_clk = { + .halt_reg = 0xb020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_mock_utmi_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_usb30_mock_utmi_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_mstr_axi_clk = { + .halt_reg = 0xb014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_sleep_clk = { + .halt_reg = 0xb01c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb01c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_slv_ahb_clk = { + .halt_reg = 0xb018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_slv_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_phy_aux_clk = { + .halt_reg = 0xb058, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb058, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_phy_aux_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_usb3_phy_aux_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_phy_pipe_clk = { + .halt_reg = 0xb05c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0xb05c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_phy_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_clkref_clk = { + .halt_reg = 0x88000, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x88000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_prim_clkref_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb_phy_cfg_ahb2phy_clk = { + .halt_reg = 0xe004, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0xe004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xe004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb_phy_cfg_ahb2phy_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_xo_pcie_link_clk = { + .halt_reg = 0x22008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x22008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_xo_pcie_link_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap *gcc_sdx55_clocks[] = { + [GCC_AHB_PCIE_LINK_CLK] = &gcc_ahb_pcie_link_clk.clkr, + [GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr, + [GCC_BLSP1_QUP1_I2C_APPS_CLK] = &gcc_blsp1_qup1_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP1_I2C_APPS_CLK_SRC] = + &gcc_blsp1_qup1_i2c_apps_clk_src.clkr, + [GCC_BLSP1_QUP1_SPI_APPS_CLK] = &gcc_blsp1_qup1_spi_apps_clk.clkr, + [GCC_BLSP1_QUP1_SPI_APPS_CLK_SRC] = + &gcc_blsp1_qup1_spi_apps_clk_src.clkr, + [GCC_BLSP1_QUP2_I2C_APPS_CLK] = &gcc_blsp1_qup2_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP2_I2C_APPS_CLK_SRC] = + &gcc_blsp1_qup2_i2c_apps_clk_src.clkr, + [GCC_BLSP1_QUP2_SPI_APPS_CLK] = &gcc_blsp1_qup2_spi_apps_clk.clkr, + [GCC_BLSP1_QUP2_SPI_APPS_CLK_SRC] = + &gcc_blsp1_qup2_spi_apps_clk_src.clkr, + [GCC_BLSP1_QUP3_I2C_APPS_CLK] = &gcc_blsp1_qup3_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP3_I2C_APPS_CLK_SRC] = + &gcc_blsp1_qup3_i2c_apps_clk_src.clkr, + [GCC_BLSP1_QUP3_SPI_APPS_CLK] = &gcc_blsp1_qup3_spi_apps_clk.clkr, + [GCC_BLSP1_QUP3_SPI_APPS_CLK_SRC] = + &gcc_blsp1_qup3_spi_apps_clk_src.clkr, + [GCC_BLSP1_QUP4_I2C_APPS_CLK] = &gcc_blsp1_qup4_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP4_I2C_APPS_CLK_SRC] = + &gcc_blsp1_qup4_i2c_apps_clk_src.clkr, + [GCC_BLSP1_QUP4_SPI_APPS_CLK] = &gcc_blsp1_qup4_spi_apps_clk.clkr, + [GCC_BLSP1_QUP4_SPI_APPS_CLK_SRC] = + &gcc_blsp1_qup4_spi_apps_clk_src.clkr, + [GCC_BLSP1_UART1_APPS_CLK] = &gcc_blsp1_uart1_apps_clk.clkr, + [GCC_BLSP1_UART1_APPS_CLK_SRC] = &gcc_blsp1_uart1_apps_clk_src.clkr, + [GCC_BLSP1_UART2_APPS_CLK] = &gcc_blsp1_uart2_apps_clk.clkr, + [GCC_BLSP1_UART2_APPS_CLK_SRC] = &gcc_blsp1_uart2_apps_clk_src.clkr, + [GCC_BLSP1_UART3_APPS_CLK] = &gcc_blsp1_uart3_apps_clk.clkr, + [GCC_BLSP1_UART3_APPS_CLK_SRC] = &gcc_blsp1_uart3_apps_clk_src.clkr, + [GCC_BLSP1_UART4_APPS_CLK] = &gcc_blsp1_uart4_apps_clk.clkr, + [GCC_BLSP1_UART4_APPS_CLK_SRC] = &gcc_blsp1_uart4_apps_clk_src.clkr, + [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr, + [GCC_CE1_AHB_CLK] = &gcc_ce1_ahb_clk.clkr, + [GCC_CE1_AXI_CLK] = &gcc_ce1_axi_clk.clkr, + [GCC_CE1_CLK] = &gcc_ce1_clk.clkr, + [GCC_CPUSS_AHB_CLK_SRC] = &gcc_cpuss_ahb_clk_src.clkr, + [GCC_CPUSS_RBCPR_CLK] = &gcc_cpuss_rbcpr_clk.clkr, + [GCC_CPUSS_RBCPR_CLK_SRC] = &gcc_cpuss_rbcpr_clk_src.clkr, + [GCC_EMAC_CLK_SRC] = &gcc_emac_clk_src.clkr, + [GCC_EMAC_PTP_CLK_SRC] = &gcc_emac_ptp_clk_src.clkr, + [GCC_ETH_AXI_CLK] = &gcc_eth_axi_clk.clkr, + [GCC_ETH_PTP_CLK] = &gcc_eth_ptp_clk.clkr, + [GCC_ETH_RGMII_CLK] = &gcc_eth_rgmii_clk.clkr, + [GCC_ETH_SLAVE_AHB_CLK] = &gcc_eth_slave_ahb_clk.clkr, + [GCC_GP1_CLK] = &gcc_gp1_clk.clkr, + [GCC_GP1_CLK_SRC] = &gcc_gp1_clk_src.clkr, + [GCC_GP2_CLK] = &gcc_gp2_clk.clkr, + [GCC_GP2_CLK_SRC] = &gcc_gp2_clk_src.clkr, + [GCC_GP3_CLK] = &gcc_gp3_clk.clkr, + [GCC_GP3_CLK_SRC] = &gcc_gp3_clk_src.clkr, + [GCC_PCIE_0_CLKREF_CLK] = &gcc_pcie_0_clkref_clk.clkr, + [GCC_PCIE_AUX_CLK] = &gcc_pcie_aux_clk.clkr, + [GCC_PCIE_AUX_PHY_CLK_SRC] = &gcc_pcie_aux_phy_clk_src.clkr, + [GCC_PCIE_CFG_AHB_CLK] = &gcc_pcie_cfg_ahb_clk.clkr, + [GCC_PCIE_MSTR_AXI_CLK] = &gcc_pcie_mstr_axi_clk.clkr, + [GCC_PCIE_PIPE_CLK] = &gcc_pcie_pipe_clk.clkr, + [GCC_PCIE_RCHNG_PHY_CLK] = &gcc_pcie_rchng_phy_clk.clkr, + [GCC_PCIE_RCHNG_PHY_CLK_SRC] = &gcc_pcie_rchng_phy_clk_src.clkr, + [GCC_PCIE_SLEEP_CLK] = &gcc_pcie_sleep_clk.clkr, + [GCC_PCIE_SLV_AXI_CLK] = &gcc_pcie_slv_axi_clk.clkr, + [GCC_PCIE_SLV_Q2A_AXI_CLK] = &gcc_pcie_slv_q2a_axi_clk.clkr, + [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr, + [GCC_PDM2_CLK_SRC] = &gcc_pdm2_clk_src.clkr, + [GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr, + [GCC_PDM_XO4_CLK] = &gcc_pdm_xo4_clk.clkr, + [GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr, + [GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr, + [GCC_SDCC1_APPS_CLK_SRC] = &gcc_sdcc1_apps_clk_src.clkr, + [GCC_USB30_MASTER_CLK] = &gcc_usb30_master_clk.clkr, + [GCC_USB30_MASTER_CLK_SRC] = &gcc_usb30_master_clk_src.clkr, + [GCC_USB30_MOCK_UTMI_CLK] = &gcc_usb30_mock_utmi_clk.clkr, + [GCC_USB30_MOCK_UTMI_CLK_SRC] = &gcc_usb30_mock_utmi_clk_src.clkr, + [GCC_USB30_MSTR_AXI_CLK] = &gcc_usb30_mstr_axi_clk.clkr, + [GCC_USB30_SLEEP_CLK] = &gcc_usb30_sleep_clk.clkr, + [GCC_USB30_SLV_AHB_CLK] = &gcc_usb30_slv_ahb_clk.clkr, + [GCC_USB3_PHY_AUX_CLK] = &gcc_usb3_phy_aux_clk.clkr, + [GCC_USB3_PHY_AUX_CLK_SRC] = &gcc_usb3_phy_aux_clk_src.clkr, + [GCC_USB3_PHY_PIPE_CLK] = &gcc_usb3_phy_pipe_clk.clkr, + [GCC_USB3_PRIM_CLKREF_CLK] = &gcc_usb3_prim_clkref_clk.clkr, + [GCC_USB_PHY_CFG_AHB2PHY_CLK] = &gcc_usb_phy_cfg_ahb2phy_clk.clkr, + [GCC_XO_PCIE_LINK_CLK] = &gcc_xo_pcie_link_clk.clkr, + [GPLL0] = &gpll0.clkr, + [GPLL0_OUT_EVEN] = &gpll0_out_even.clkr, + [GPLL4] = &gpll4.clkr, + [GPLL4_OUT_EVEN] = &gpll4_out_even.clkr, + [GPLL5] = &gpll5.clkr, +}; + +static const struct qcom_reset_map gcc_sdx55_resets[] = { + [GCC_EMAC_BCR] = { 0x47000 }, + [GCC_PCIE_BCR] = { 0x37000 }, + [GCC_PCIE_LINK_DOWN_BCR] = { 0x77000 }, + [GCC_PCIE_PHY_BCR] = { 0x39000 }, + [GCC_PCIE_PHY_COM_BCR] = { 0x78004 }, + [GCC_QUSB2PHY_BCR] = { 0xd000 }, + [GCC_USB30_BCR] = { 0xb000 }, + [GCC_USB3_PHY_BCR] = { 0xc000 }, + [GCC_USB3PHY_PHY_BCR] = { 0xc004 }, + [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0xe000 }, +}; + +static const struct regmap_config gcc_sdx55_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x9b040, + .fast_io = true, +}; + +static const struct qcom_cc_desc gcc_sdx55_desc = { + .config = &gcc_sdx55_regmap_config, + .clks = gcc_sdx55_clocks, + .num_clks = ARRAY_SIZE(gcc_sdx55_clocks), + .resets = gcc_sdx55_resets, + .num_resets = ARRAY_SIZE(gcc_sdx55_resets), +}; + +static const struct of_device_id gcc_sdx55_match_table[] = { + { .compatible = "qcom,gcc-sdx55" }, + { } +}; +MODULE_DEVICE_TABLE(of, gcc_sdx55_match_table); + +static int gcc_sdx55_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + + regmap = qcom_cc_map(pdev, &gcc_sdx55_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + /* + * Keep the clocks always-ON as they are critical to the functioning + * of the system: + * GCC_SYS_NOC_CPUSS_AHB_CLK, GCC_CPUSS_AHB_CLK, GCC_CPUSS_GNOC_CLK + */ + regmap_update_bits(regmap, 0x6d008, BIT(0), BIT(0)); + regmap_update_bits(regmap, 0x6d008, BIT(21), BIT(21)); + regmap_update_bits(regmap, 0x6d008, BIT(22), BIT(22)); + + return qcom_cc_really_probe(pdev, &gcc_sdx55_desc, regmap); +} + +static struct platform_driver gcc_sdx55_driver = { + .probe = gcc_sdx55_probe, + .driver = { + .name = "gcc-sdx55", + .of_match_table = gcc_sdx55_match_table, + }, +}; + +static int __init gcc_sdx55_init(void) +{ + return platform_driver_register(&gcc_sdx55_driver); +} +subsys_initcall(gcc_sdx55_init); + +static void __exit gcc_sdx55_exit(void) +{ + platform_driver_unregister(&gcc_sdx55_driver); +} +module_exit(gcc_sdx55_exit); + +MODULE_DESCRIPTION("QTI GCC SDX55 Driver"); +MODULE_LICENSE("GPL v2"); From 2e2639b7ef1641252e838b5181c0b8fec8b6c067 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 26 Nov 2020 12:58:41 +0530 Subject: [PATCH 075/134] dt-bindings: clock: Introduce RPMHCC bindings for SDX55 Add compatible for SDX55 RPMHCC and DT include. Signed-off-by: Vinod Koul Signed-off-by: Manivannan Sadhasivam Reviewed-by: Bjorn Andersson Acked-by: Rob Herring Link: https://lore.kernel.org/r/20201126072844.35370-4-manivannan.sadhasivam@linaro.org Signed-off-by: Stephen Boyd --- Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml | 1 + include/dt-bindings/clock/qcom,rpmh.h | 1 + 2 files changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml b/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml index a46a3a799a70..a54930f111ba 100644 --- a/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml @@ -19,6 +19,7 @@ properties: enum: - qcom,sc7180-rpmh-clk - qcom,sdm845-rpmh-clk + - qcom,sdx55-rpmh-clk - qcom,sm8150-rpmh-clk - qcom,sm8250-rpmh-clk diff --git a/include/dt-bindings/clock/qcom,rpmh.h b/include/dt-bindings/clock/qcom,rpmh.h index 30111c8f7fe9..0662a583e93b 100644 --- a/include/dt-bindings/clock/qcom,rpmh.h +++ b/include/dt-bindings/clock/qcom,rpmh.h @@ -22,5 +22,6 @@ #define RPMH_LN_BB_CLK1 13 #define RPMH_LN_BB_CLK1_A 14 #define RPMH_CE_CLK 15 +#define RPMH_QPIC_CLK 16 #endif From afacfbbe1016a692b1fea4ed4c3f1d6f6a4ef4e5 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 26 Nov 2020 12:58:42 +0530 Subject: [PATCH 076/134] clk: qcom: Add support for SDX55 RPMh clocks Add support for following clocks maintained by RPMh in SDX55 SoCs. * BI TCXO * RF_CLK1 * RF_CLK1_AO * RF_CLK2 * RF_CLK2_AO * QPIC (Qualcomm Technologies, Inc. Parallel Interface Controller) Signed-off-by: Manivannan Sadhasivam Reviewed-by: Vinod Koul Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/r/20201126072844.35370-5-manivannan.sadhasivam@linaro.org Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-rpmh.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c index 7e2a4a9b9bf6..f47595a04885 100644 --- a/drivers/clk/qcom/clk-rpmh.c +++ b/drivers/clk/qcom/clk-rpmh.c @@ -434,6 +434,25 @@ static const struct clk_rpmh_desc clk_rpmh_sm8250 = { .num_clks = ARRAY_SIZE(sm8250_rpmh_clocks), }; +DEFINE_CLK_RPMH_VRM(sdx55, rf_clk1, rf_clk1_ao, "rfclkd1", 1); +DEFINE_CLK_RPMH_VRM(sdx55, rf_clk2, rf_clk2_ao, "rfclkd2", 1); +DEFINE_CLK_RPMH_BCM(sdx55, qpic_clk, "QP0"); + +static struct clk_hw *sdx55_rpmh_clocks[] = { + [RPMH_CXO_CLK] = &sdm845_bi_tcxo.hw, + [RPMH_CXO_CLK_A] = &sdm845_bi_tcxo_ao.hw, + [RPMH_RF_CLK1] = &sdx55_rf_clk1.hw, + [RPMH_RF_CLK1_A] = &sdx55_rf_clk1_ao.hw, + [RPMH_RF_CLK2] = &sdx55_rf_clk2.hw, + [RPMH_RF_CLK2_A] = &sdx55_rf_clk2_ao.hw, + [RPMH_QPIC_CLK] = &sdx55_qpic_clk.hw, +}; + +static const struct clk_rpmh_desc clk_rpmh_sdx55 = { + .clks = sdx55_rpmh_clocks, + .num_clks = ARRAY_SIZE(sdx55_rpmh_clocks), +}; + static struct clk_hw *of_clk_rpmh_hw_get(struct of_phandle_args *clkspec, void *data) { @@ -519,6 +538,7 @@ static int clk_rpmh_probe(struct platform_device *pdev) static const struct of_device_id clk_rpmh_match_table[] = { { .compatible = "qcom,sc7180-rpmh-clk", .data = &clk_rpmh_sc7180}, { .compatible = "qcom,sdm845-rpmh-clk", .data = &clk_rpmh_sdm845}, + { .compatible = "qcom,sdx55-rpmh-clk", .data = &clk_rpmh_sdx55}, { .compatible = "qcom,sm8150-rpmh-clk", .data = &clk_rpmh_sm8150}, { .compatible = "qcom,sm8250-rpmh-clk", .data = &clk_rpmh_sm8250}, { } From bdf7805b8c0e45ade8d26e5bd4616ddcbb3fcc36 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 26 Nov 2020 12:58:43 +0530 Subject: [PATCH 077/134] dt-bindings: clock: Add GDSC in SDX55 GCC Add GDSC instances in SDX55 GCC block. Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20201126072844.35370-6-manivannan.sadhasivam@linaro.org Acked-by: Rob Herring Signed-off-by: Stephen Boyd --- include/dt-bindings/clock/qcom,gcc-sdx55.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/dt-bindings/clock/qcom,gcc-sdx55.h b/include/dt-bindings/clock/qcom,gcc-sdx55.h index c372451b3461..fb9a5942f793 100644 --- a/include/dt-bindings/clock/qcom,gcc-sdx55.h +++ b/include/dt-bindings/clock/qcom,gcc-sdx55.h @@ -109,4 +109,9 @@ #define GCC_USB3PHY_PHY_BCR 13 #define GCC_USB_PHY_CFG_AHB2PHY_BCR 14 +/* GCC power domains */ +#define USB30_GDSC 0 +#define PCIE_GDSC 1 +#define EMAC_GDSC 2 + #endif From 063930ed2df5dbe07e994009a7e05e773f10b23a Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 26 Nov 2020 12:58:44 +0530 Subject: [PATCH 078/134] clk: qcom: Add GDSC support for SDX55 GCC Add GDSC support to control the power supply of power domains in SDX55 GCC. Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20201126072844.35370-7-manivannan.sadhasivam@linaro.org Signed-off-by: Stephen Boyd --- drivers/clk/qcom/Kconfig | 1 + drivers/clk/qcom/gcc-sdx55.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 3555eac37495..d32bb12cd8d0 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -424,6 +424,7 @@ config SDM_LPASSCC_845 config SDX_GCC_55 tristate "SDX55 Global Clock Controller" + select QCOM_GDSC help Support for the global clock controller on SDX55 devices. Say Y if you want to use peripheral devices such as UART, diff --git a/drivers/clk/qcom/gcc-sdx55.c b/drivers/clk/qcom/gcc-sdx55.c index bf114165e24b..e3b9030b2bae 100644 --- a/drivers/clk/qcom/gcc-sdx55.c +++ b/drivers/clk/qcom/gcc-sdx55.c @@ -17,6 +17,7 @@ #include "clk-pll.h" #include "clk-rcg.h" #include "clk-regmap.h" +#include "gdsc.h" #include "reset.h" enum { @@ -1455,6 +1456,30 @@ static struct clk_branch gcc_xo_pcie_link_clk = { }, }; +static struct gdsc usb30_gdsc = { + .gdscr = 0x0b004, + .pd = { + .name = "usb30_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc pcie_gdsc = { + .gdscr = 0x37004, + .pd = { + .name = "pcie_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc emac_gdsc = { + .gdscr = 0x47004, + .pd = { + .name = "emac_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + static struct clk_regmap *gcc_sdx55_clocks[] = { [GCC_AHB_PCIE_LINK_CLK] = &gcc_ahb_pcie_link_clk.clkr, [GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr, @@ -1560,6 +1585,12 @@ static const struct qcom_reset_map gcc_sdx55_resets[] = { [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0xe000 }, }; +static struct gdsc *gcc_sdx55_gdscs[] = { + [USB30_GDSC] = &usb30_gdsc, + [PCIE_GDSC] = &pcie_gdsc, + [EMAC_GDSC] = &emac_gdsc, +}; + static const struct regmap_config gcc_sdx55_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -1574,6 +1605,8 @@ static const struct qcom_cc_desc gcc_sdx55_desc = { .num_clks = ARRAY_SIZE(gcc_sdx55_clocks), .resets = gcc_sdx55_resets, .num_resets = ARRAY_SIZE(gcc_sdx55_resets), + .gdscs = gcc_sdx55_gdscs, + .num_gdscs = ARRAY_SIZE(gcc_sdx55_gdscs), }; static const struct of_device_id gcc_sdx55_match_table[] = { From 0ca995f5c7110c13795cf82c18639175e2ee20f2 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 24 Sep 2020 13:18:08 +0200 Subject: [PATCH 079/134] clk: renesas: r8a779a0: Make rcar_r8a779a0_cpg_clk_register() static When compiling with clang: drivers/clk/renesas/r8a779a0-cpg-mssr.c:156:21: warning: no previous prototype for function 'rcar_r8a779a0_cpg_clk_register' [-Wmissing-prototypes] struct clk * __init rcar_r8a779a0_cpg_clk_register(struct device *dev, ^ drivers/clk/renesas/r8a779a0-cpg-mssr.c:156:1: note: declare 'static' if the function is not intended to be used outside of this translation unit struct clk * __init rcar_r8a779a0_cpg_clk_register(struct device *dev, ^ static Similarly, with sparse: drivers/clk/renesas/r8a779a0-cpg-mssr.c:156:12: warning: symbol 'rcar_r8a779a0_cpg_clk_register' was not declared. Should it be static? There are no users of rcar_r8a779a0_cpg_clk_register() outside this file, so it should be static. Fixes: 17bcc8035d2d19fc ("clk: renesas: cpg-mssr: Add support for R-Car V3U") Reported-by: kernel test robot Signed-off-by: Geert Uytterhoeven Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20200924111808.15358-1-geert+renesas@glider.be --- drivers/clk/renesas/r8a779a0-cpg-mssr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/renesas/r8a779a0-cpg-mssr.c b/drivers/clk/renesas/r8a779a0-cpg-mssr.c index 17ebbac7ddfb..7e25b3b8945b 100644 --- a/drivers/clk/renesas/r8a779a0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779a0-cpg-mssr.c @@ -153,7 +153,7 @@ static const struct rcar_r8a779a0_cpg_pll_config *cpg_pll_config __initdata; static unsigned int cpg_clk_extalr __initdata; static u32 cpg_mode __initdata; -struct clk * __init rcar_r8a779a0_cpg_clk_register(struct device *dev, +static struct clk * __init rcar_r8a779a0_cpg_clk_register(struct device *dev, const struct cpg_core_clk *core, const struct cpg_mssr_info *info, struct clk **clks, void __iomem *base, struct raw_notifier_head *notifiers) From 043585760f5191926467862c01a0893c2fefb359 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 25 Sep 2020 13:07:13 +0200 Subject: [PATCH 080/134] MAINTAINERS: Update git repo for Renesas clock drivers Align the clock branch name with other renesas-* branches pulled by subsystem maintainers. Signed-off-by: Geert Uytterhoeven Acked-by: Stephen Boyd Link: https://lore.kernel.org/r/20200925110713.2652-1-geert+renesas@glider.be --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index e73636b75f29..595e1023b398 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14888,7 +14888,7 @@ RENESAS CLOCK DRIVERS M: Geert Uytterhoeven L: linux-renesas-soc@vger.kernel.org S: Supported -T: git git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers.git clk-renesas +T: git git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers.git renesas-clk F: Documentation/devicetree/bindings/clock/renesas,* F: drivers/clk/renesas/ From 23378e70ca286de32cedcf6505af734b034148dc Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Fri, 16 Oct 2020 13:11:53 +0200 Subject: [PATCH 081/134] clk: renesas: r8a779a0: Add CSI4[0-3] clocks Add definitions of the CSI-2 receiver clocks for R-Car V3U. Signed-off-by: Jacopo Mondi Link: https://lore.kernel.org/r/20201016111158.17521-2-jacopo+renesas@jmondi.org Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a779a0-cpg-mssr.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/clk/renesas/r8a779a0-cpg-mssr.c b/drivers/clk/renesas/r8a779a0-cpg-mssr.c index 7e25b3b8945b..bd54a28c50ee 100644 --- a/drivers/clk/renesas/r8a779a0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779a0-cpg-mssr.c @@ -141,6 +141,10 @@ static const struct cpg_core_clk r8a779a0_core_clks[] __initconst = { }; static const struct mssr_mod_clk r8a779a0_mod_clks[] __initconst = { + DEF_MOD("csi40", 331, R8A779A0_CLK_CSI0), + DEF_MOD("csi41", 400, R8A779A0_CLK_CSI0), + DEF_MOD("csi42", 401, R8A779A0_CLK_CSI0), + DEF_MOD("csi43", 402, R8A779A0_CLK_CSI0), DEF_MOD("scif0", 702, R8A779A0_CLK_S1D8), DEF_MOD("scif1", 703, R8A779A0_CLK_S1D8), DEF_MOD("scif3", 704, R8A779A0_CLK_S1D8), From 874d4eee5421d08fd220adffc32da307f8b7c964 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Fri, 16 Oct 2020 13:11:56 +0200 Subject: [PATCH 082/134] clk: renesas: r8a779a0: Add VIN clocks Add definitions of the VIN instance clocks for R-Car V3U. Signed-off-by: Jacopo Mondi Link: https://lore.kernel.org/r/20201016111158.17521-5-jacopo+renesas@jmondi.org Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a779a0-cpg-mssr.c | 32 +++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/clk/renesas/r8a779a0-cpg-mssr.c b/drivers/clk/renesas/r8a779a0-cpg-mssr.c index bd54a28c50ee..2a00eb82013f 100644 --- a/drivers/clk/renesas/r8a779a0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779a0-cpg-mssr.c @@ -149,6 +149,38 @@ static const struct mssr_mod_clk r8a779a0_mod_clks[] __initconst = { DEF_MOD("scif1", 703, R8A779A0_CLK_S1D8), DEF_MOD("scif3", 704, R8A779A0_CLK_S1D8), DEF_MOD("scif4", 705, R8A779A0_CLK_S1D8), + DEF_MOD("vin00", 730, R8A779A0_CLK_S1D1), + DEF_MOD("vin01", 731, R8A779A0_CLK_S1D1), + DEF_MOD("vin02", 800, R8A779A0_CLK_S1D1), + DEF_MOD("vin03", 801, R8A779A0_CLK_S1D1), + DEF_MOD("vin04", 802, R8A779A0_CLK_S1D1), + DEF_MOD("vin05", 803, R8A779A0_CLK_S1D1), + DEF_MOD("vin06", 804, R8A779A0_CLK_S1D1), + DEF_MOD("vin07", 805, R8A779A0_CLK_S1D1), + DEF_MOD("vin10", 806, R8A779A0_CLK_S1D1), + DEF_MOD("vin11", 807, R8A779A0_CLK_S1D1), + DEF_MOD("vin12", 808, R8A779A0_CLK_S1D1), + DEF_MOD("vin13", 809, R8A779A0_CLK_S1D1), + DEF_MOD("vin14", 810, R8A779A0_CLK_S1D1), + DEF_MOD("vin15", 811, R8A779A0_CLK_S1D1), + DEF_MOD("vin16", 812, R8A779A0_CLK_S1D1), + DEF_MOD("vin17", 813, R8A779A0_CLK_S1D1), + DEF_MOD("vin20", 814, R8A779A0_CLK_S1D1), + DEF_MOD("vin21", 815, R8A779A0_CLK_S1D1), + DEF_MOD("vin22", 816, R8A779A0_CLK_S1D1), + DEF_MOD("vin23", 817, R8A779A0_CLK_S1D1), + DEF_MOD("vin24", 818, R8A779A0_CLK_S1D1), + DEF_MOD("vin25", 819, R8A779A0_CLK_S1D1), + DEF_MOD("vin26", 820, R8A779A0_CLK_S1D1), + DEF_MOD("vin27", 821, R8A779A0_CLK_S1D1), + DEF_MOD("vin30", 822, R8A779A0_CLK_S1D1), + DEF_MOD("vin31", 823, R8A779A0_CLK_S1D1), + DEF_MOD("vin32", 824, R8A779A0_CLK_S1D1), + DEF_MOD("vin33", 825, R8A779A0_CLK_S1D1), + DEF_MOD("vin34", 826, R8A779A0_CLK_S1D1), + DEF_MOD("vin35", 827, R8A779A0_CLK_S1D1), + DEF_MOD("vin36", 828, R8A779A0_CLK_S1D1), + DEF_MOD("vin37", 829, R8A779A0_CLK_S1D1), }; static spinlock_t cpg_lock; From 13d2617bf224351e78141183ca51971df83a9dd5 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 16 Oct 2020 13:17:07 +0100 Subject: [PATCH 083/134] clk: renesas: r8a774a1: Add RPC clocks Describe the RPCSRC internal clock and the RPC[D2] clocks derived from it, as well as the RPC-IF module clock, in the RZ/G2M (R8A774A1) CPG/MSSR driver. Inspired by commit 94e3935b5756 ("clk: renesas: r8a77980: Add RPC clocks"). Signed-off-by: Biju Das Signed-off-by: Lad Prabhakar Link: https://lore.kernel.org/r/20201016121709.8447-3-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a774a1-cpg-mssr.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/clk/renesas/r8a774a1-cpg-mssr.c b/drivers/clk/renesas/r8a774a1-cpg-mssr.c index fd54b9f625da..4a43ebec7d5e 100644 --- a/drivers/clk/renesas/r8a774a1-cpg-mssr.c +++ b/drivers/clk/renesas/r8a774a1-cpg-mssr.c @@ -41,6 +41,7 @@ enum clk_ids { CLK_S2, CLK_S3, CLK_SDSRC, + CLK_RPCSRC, CLK_RINT, /* Module Clocks */ @@ -67,6 +68,12 @@ static const struct cpg_core_clk r8a774a1_core_clks[] __initconst = { DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1), DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1), DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1), + DEF_BASE(".rpcsrc", CLK_RPCSRC, CLK_TYPE_GEN3_RPCSRC, CLK_PLL1), + + DEF_BASE("rpc", R8A774A1_CLK_RPC, CLK_TYPE_GEN3_RPC, + CLK_RPCSRC), + DEF_BASE("rpcd2", R8A774A1_CLK_RPCD2, CLK_TYPE_GEN3_RPCD2, + R8A774A1_CLK_RPC), DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32), @@ -200,6 +207,7 @@ static const struct mssr_mod_clk r8a774a1_mod_clks[] __initconst = { DEF_MOD("can-fd", 914, R8A774A1_CLK_S3D2), DEF_MOD("can-if1", 915, R8A774A1_CLK_S3D4), DEF_MOD("can-if0", 916, R8A774A1_CLK_S3D4), + DEF_MOD("rpc-if", 917, R8A774A1_CLK_RPCD2), DEF_MOD("i2c6", 918, R8A774A1_CLK_S0D6), DEF_MOD("i2c5", 919, R8A774A1_CLK_S0D6), DEF_MOD("i2c-dvfs", 926, R8A774A1_CLK_CP), From fb9805c51793339e0affbc8e3ce2b3210b41c9fa Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 16 Oct 2020 13:17:08 +0100 Subject: [PATCH 084/134] clk: renesas: r8a774b1: Add RPC clocks Describe the RPCSRC internal clock and the RPC[D2] clocks derived from it, as well as the RPC-IF module clock, in the RZ/G2N (R8A774B1) CPG/MSSR driver. Inspired by commit 94e3935b5756 ("clk: renesas: r8a77980: Add RPC clocks"). Signed-off-by: Biju Das Signed-off-by: Lad Prabhakar Link: https://lore.kernel.org/r/20201016121709.8447-4-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a774b1-cpg-mssr.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/clk/renesas/r8a774b1-cpg-mssr.c b/drivers/clk/renesas/r8a774b1-cpg-mssr.c index f436691271ec..6f04c40fe237 100644 --- a/drivers/clk/renesas/r8a774b1-cpg-mssr.c +++ b/drivers/clk/renesas/r8a774b1-cpg-mssr.c @@ -40,6 +40,7 @@ enum clk_ids { CLK_S2, CLK_S3, CLK_SDSRC, + CLK_RPCSRC, CLK_RINT, /* Module Clocks */ @@ -65,6 +66,12 @@ static const struct cpg_core_clk r8a774b1_core_clks[] __initconst = { DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1), DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1), DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1), + DEF_BASE(".rpcsrc", CLK_RPCSRC, CLK_TYPE_GEN3_RPCSRC, CLK_PLL1), + + DEF_BASE("rpc", R8A774B1_CLK_RPC, CLK_TYPE_GEN3_RPC, + CLK_RPCSRC), + DEF_BASE("rpcd2", R8A774B1_CLK_RPCD2, CLK_TYPE_GEN3_RPCD2, + R8A774B1_CLK_RPC), DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32), @@ -196,6 +203,7 @@ static const struct mssr_mod_clk r8a774b1_mod_clks[] __initconst = { DEF_MOD("can-fd", 914, R8A774B1_CLK_S3D2), DEF_MOD("can-if1", 915, R8A774B1_CLK_S3D4), DEF_MOD("can-if0", 916, R8A774B1_CLK_S3D4), + DEF_MOD("rpc-if", 917, R8A774B1_CLK_RPCD2), DEF_MOD("i2c6", 918, R8A774B1_CLK_S0D6), DEF_MOD("i2c5", 919, R8A774B1_CLK_S0D6), DEF_MOD("i2c-dvfs", 926, R8A774B1_CLK_CP), From 4ef39a80da8b15ed933d387bc02ec14df4f4f1a7 Mon Sep 17 00:00:00 2001 From: Yejune Deng Date: Tue, 3 Nov 2020 11:44:53 +0800 Subject: [PATCH 085/134] clk: renesas: rcar-usb2-clock-sel: Replace devm_reset_control_array_get() devm_reset_control_array_get_shared() looks more readable Signed-off-by: Yejune Deng Link: https://lore.kernel.org/r/1604375093-6451-1-git-send-email-yejune.deng@gmail.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rcar-usb2-clock-sel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/renesas/rcar-usb2-clock-sel.c b/drivers/clk/renesas/rcar-usb2-clock-sel.c index d4c02986c34e..3abafd78f7c8 100644 --- a/drivers/clk/renesas/rcar-usb2-clock-sel.c +++ b/drivers/clk/renesas/rcar-usb2-clock-sel.c @@ -160,7 +160,7 @@ static int rcar_usb2_clock_sel_probe(struct platform_device *pdev) if (ret < 0) return ret; - priv->rsts = devm_reset_control_array_get(dev, true, false); + priv->rsts = devm_reset_control_array_get_shared(dev); if (IS_ERR(priv->rsts)) return PTR_ERR(priv->rsts); From b5fb3b8859a491ff31e933927809f17a4e39459f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 3 Nov 2020 17:24:34 +0100 Subject: [PATCH 086/134] clk: renesas: cpg-mssr: fix kerneldoc of cpg_mssr_priv The struct cpg_mssr_priv missed proper formatting: drivers/clk/renesas/renesas-cpg-mssr.c:142: warning: cannot understand function prototype: 'struct cpg_mssr_priv ' Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201103162435.13689-7-krzk@kernel.org Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/renesas-cpg-mssr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index 94db88370337..1c3215dc4877 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -119,7 +119,8 @@ static const u16 srstclr_for_v3u[] = { }; /** - * Clock Pulse Generator / Module Standby and Software Reset Private Data + * struct cpg_mssr_priv - Clock Pulse Generator / Module Standby + * and Software Reset Private Data * * @rcdev: Optional reset controller entity * @dev: CPG/MSSR device From 14653942de7f63e21ece32e3901f09a248598a43 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 9 Nov 2020 16:26:14 +0100 Subject: [PATCH 087/134] clk: renesas: r8a779a0: Fix R and OSC clocks The R-Car V3U clock driver defines the R and OSC clocks using R-Car Gen3 clock types. However, The R-Car V3U clock driver does not use the R-Car Gen3 clock driver core, hence registering the R and OSC clocks fails: renesas-cpg-mssr e6150000.clock-controller: Failed to register core clock osc: -22 renesas-cpg-mssr e6150000.clock-controller: Failed to register core clock r: -22 Fix this by introducing clock definition macros specific to R-Car V3U. Note that rcar_r8a779a0_cpg_clk_register() already handled the related clock types. Drop the now unneeded include of rcar-gen3-cpg.h. Fixes: 17bcc8035d2d19fc ("clk: renesas: cpg-mssr: Add support for R-Car V3U") Signed-off-by: Geert Uytterhoeven Tested-by: Yoshihiro Shimoda Reviewed-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/20201109152614.2465483-1-geert+renesas@glider.be --- drivers/clk/renesas/r8a779a0-cpg-mssr.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/clk/renesas/r8a779a0-cpg-mssr.c b/drivers/clk/renesas/r8a779a0-cpg-mssr.c index 2a00eb82013f..aa5389b04d74 100644 --- a/drivers/clk/renesas/r8a779a0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779a0-cpg-mssr.c @@ -26,7 +26,6 @@ #include #include "renesas-cpg-mssr.h" -#include "rcar-gen3-cpg.h" enum rcar_r8a779a0_clk_types { CLK_TYPE_R8A779A0_MAIN = CLK_TYPE_CUSTOM, @@ -84,6 +83,14 @@ enum clk_ids { DEF_BASE(_name, _id, CLK_TYPE_R8A779A0_PLL2X_3X, CLK_MAIN, \ .offset = _offset) +#define DEF_MDSEL(_name, _id, _md, _parent0, _div0, _parent1, _div1) \ + DEF_BASE(_name, _id, CLK_TYPE_R8A779A0_MDSEL, \ + (_parent0) << 16 | (_parent1), \ + .div = (_div0) << 16 | (_div1), .offset = _md) + +#define DEF_OSC(_name, _id, _parent, _div) \ + DEF_BASE(_name, _id, CLK_TYPE_R8A779A0_OSC, _parent, .div = _div) + static const struct cpg_core_clk r8a779a0_core_clks[] __initconst = { /* External Clock Inputs */ DEF_INPUT("extal", CLK_EXTAL), @@ -136,8 +143,8 @@ static const struct cpg_core_clk r8a779a0_core_clks[] __initconst = { DEF_DIV6P1("canfd", R8A779A0_CLK_CANFD, CLK_PLL5_DIV4, 0x878), DEF_DIV6P1("csi0", R8A779A0_CLK_CSI0, CLK_PLL5_DIV4, 0x880), - DEF_GEN3_OSC("osc", R8A779A0_CLK_OSC, CLK_EXTAL, 8), - DEF_GEN3_MDSEL("r", R8A779A0_CLK_R, 29, CLK_EXTALR, 1, CLK_OCO, 1), + DEF_OSC("osc", R8A779A0_CLK_OSC, CLK_EXTAL, 8), + DEF_MDSEL("r", R8A779A0_CLK_R, 29, CLK_EXTALR, 1, CLK_OCO, 1), }; static const struct mssr_mod_clk r8a779a0_mod_clks[] __initconst = { From 40745482eec81bea686cd1b38693191dc7e9ac66 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Mon, 16 Nov 2020 10:10:02 +0000 Subject: [PATCH 088/134] clk: renesas: r8a774c0: Add RPC clocks Describe the RPCSRC internal clock and the RPC[D2] clocks derived from it, as well as the RPC-IF module clock, in the RZ/G2E (R8A774C0) CPG/MSSR driver. Add new clk type CLK_TYPE_GEN3_E3_RPCSRC to register rpcsrc as a fixed clock on R-Car Gen3 E3 (and also RZ/G2E which is identical to E3 SoC), parent and the divider is set based on the register value CPG_RPCCKCR[4:3] which has been set prior to booting the kernel. Signed-off-by: Lad Prabhakar Reviewed-by: Biju Das Link: https://lore.kernel.org/r/20201116101002.5986-1-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a774c0-cpg-mssr.c | 9 ++++++++ drivers/clk/renesas/rcar-gen3-cpg.c | 28 +++++++++++++++++++++++++ drivers/clk/renesas/rcar-gen3-cpg.h | 5 +++++ 3 files changed, 42 insertions(+) diff --git a/drivers/clk/renesas/r8a774c0-cpg-mssr.c b/drivers/clk/renesas/r8a774c0-cpg-mssr.c index 9fc9fa9e531a..ed3a2cf0e0bb 100644 --- a/drivers/clk/renesas/r8a774c0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a774c0-cpg-mssr.c @@ -44,6 +44,7 @@ enum clk_ids { CLK_S2, CLK_S3, CLK_SDSRC, + CLK_RPCSRC, CLK_RINT, CLK_OCO, @@ -74,6 +75,13 @@ static const struct cpg_core_clk r8a774c0_core_clks[] __initconst = { DEF_FIXED(".s3", CLK_S3, CLK_PLL1, 6, 1), DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1, 2, 1), + DEF_FIXED_RPCSRC_E3(".rpcsrc", CLK_RPCSRC, CLK_PLL0, CLK_PLL1), + + DEF_BASE("rpc", R8A774C0_CLK_RPC, CLK_TYPE_GEN3_RPC, + CLK_RPCSRC), + DEF_BASE("rpcd2", R8A774C0_CLK_RPCD2, CLK_TYPE_GEN3_RPCD2, + R8A774C0_CLK_RPC), + DEF_DIV6_RO(".r", CLK_RINT, CLK_EXTAL, CPG_RCKCR, 32), DEF_RATE(".oco", CLK_OCO, 8 * 1000 * 1000), @@ -199,6 +207,7 @@ static const struct mssr_mod_clk r8a774c0_mod_clks[] __initconst = { DEF_MOD("can-fd", 914, R8A774C0_CLK_S3D2), DEF_MOD("can-if1", 915, R8A774C0_CLK_S3D4), DEF_MOD("can-if0", 916, R8A774C0_CLK_S3D4), + DEF_MOD("rpc-if", 917, R8A774C0_CLK_RPCD2), DEF_MOD("i2c6", 918, R8A774C0_CLK_S3D2), DEF_MOD("i2c5", 919, R8A774C0_CLK_S3D2), DEF_MOD("i2c-dvfs", 926, R8A774C0_CLK_CP), diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c index a7debddf7d09..063b61151488 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.c +++ b/drivers/clk/renesas/rcar-gen3-cpg.c @@ -695,6 +695,34 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev, cpg_rpcsrc_div_table, &cpg_lock); + case CLK_TYPE_GEN3_E3_RPCSRC: + /* + * Register RPCSRC as fixed factor clock based on the + * MD[4:1] pins and CPG_RPCCKCR[4:3] register value for + * which has been set prior to booting the kernel. + */ + value = (readl(base + CPG_RPCCKCR) & GENMASK(4, 3)) >> 3; + + switch (value) { + case 0: + div = 5; + break; + case 1: + div = 3; + break; + case 2: + parent = clks[core->parent >> 16]; + if (IS_ERR(parent)) + return ERR_CAST(parent); + div = core->div; + break; + case 3: + default: + div = 2; + break; + } + break; + case CLK_TYPE_GEN3_RPC: return cpg_rpc_clk_register(core->name, base, __clk_get_name(parent), notifiers); diff --git a/drivers/clk/renesas/rcar-gen3-cpg.h b/drivers/clk/renesas/rcar-gen3-cpg.h index c4ac80cac6a0..3d949c4a3244 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.h +++ b/drivers/clk/renesas/rcar-gen3-cpg.h @@ -24,6 +24,7 @@ enum rcar_gen3_clk_types { CLK_TYPE_GEN3_OSC, /* OSC EXTAL predivider and fixed divider */ CLK_TYPE_GEN3_RCKSEL, /* Select parent/divider using RCKCR.CKSEL */ CLK_TYPE_GEN3_RPCSRC, + CLK_TYPE_GEN3_E3_RPCSRC, CLK_TYPE_GEN3_RPC, CLK_TYPE_GEN3_RPCD2, @@ -54,6 +55,10 @@ enum rcar_gen3_clk_types { #define DEF_GEN3_Z(_name, _id, _type, _parent, _div, _offset) \ DEF_BASE(_name, _id, _type, _parent, .div = _div, .offset = _offset) +#define DEF_FIXED_RPCSRC_E3(_name, _id, _parent0, _parent1) \ + DEF_BASE(_name, _id, CLK_TYPE_GEN3_E3_RPCSRC, \ + (_parent0) << 16 | (_parent1), .div = 8) + struct rcar_gen3_cpg_pll_config { u8 extal_div; u8 pll1_mult; From fd0d8ed7c1b430f7e4a0a823a924ae3c849d74a3 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 19 Nov 2020 13:50:53 +0100 Subject: [PATCH 089/134] clk: renesas: sh73a0: Stop using __raw_*() I/O accessors There is no reason to keep on using the __raw_{read,write}l() I/O accessors in Renesas ARM driver code. Switch to using the plain {read,write}l() I/O accessors, to have a chance that this works on big-endian. Suggested-by: Arnd Bergmann Signed-off-by: Geert Uytterhoeven Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20201119125053.4065746-1-geert+renesas@glider.be --- drivers/clk/renesas/clk-sh73a0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/renesas/clk-sh73a0.c b/drivers/clk/renesas/clk-sh73a0.c index 5f25a70bc61c..4146c1d717b9 100644 --- a/drivers/clk/renesas/clk-sh73a0.c +++ b/drivers/clk/renesas/clk-sh73a0.c @@ -121,7 +121,7 @@ sh73a0_cpg_register_clock(struct device_node *np, struct sh73a0_cpg *cpg, (phy_no ? CPG_DSI1PHYCR : CPG_DSI0PHYCR); parent_name = phy_no ? "dsi1pck" : "dsi0pck"; - mult = __raw_readl(dsi_reg); + mult = readl(dsi_reg); if (!(mult & 0x8000)) mult = 1; else From f5c50b1fed55332beb88e81e9e17c49673b77344 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Thu, 5 Nov 2020 11:32:04 +0900 Subject: [PATCH 090/134] dt-bindings: clock: renesas: rcar-usb2-clock-sel: Convert bindings to json-schema Convert Renesas R-Car USB 2.0 clock selector bindings documentation to json-schema. Signed-off-by: Yoshihiro Shimoda Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/1604543524-31482-1-git-send-email-yoshihiro.shimoda.uh@renesas.com Signed-off-by: Geert Uytterhoeven --- .../clock/renesas,rcar-usb2-clock-sel.txt | 68 ------------ .../clock/renesas,rcar-usb2-clock-sel.yaml | 100 ++++++++++++++++++ 2 files changed, 100 insertions(+), 68 deletions(-) delete mode 100644 Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.txt create mode 100644 Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.yaml diff --git a/Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.txt b/Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.txt deleted file mode 100644 index da92f5748dee..000000000000 --- a/Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.txt +++ /dev/null @@ -1,68 +0,0 @@ -* Renesas R-Car USB 2.0 clock selector - -This file provides information on what the device node for the R-Car USB 2.0 -clock selector. - -If you connect an external clock to the USB_EXTAL pin only, you should set -the clock rate to "usb_extal" node only. -If you connect an oscillator to both the USB_XTAL and USB_EXTAL, this module -is not needed because this is default setting. (Of course, you can set the -clock rates to both "usb_extal" and "usb_xtal" nodes. - -Case 1: An external clock connects to R-Car SoC - +----------+ +--- R-Car ---------------------+ - |External |---|USB_EXTAL ---> all usb channels| - |clock | |USB_XTAL | - +----------+ +-------------------------------+ -In this case, we need this driver with "usb_extal" clock. - -Case 2: An oscillator connects to R-Car SoC - +----------+ +--- R-Car ---------------------+ - |Oscillator|---|USB_EXTAL -+-> all usb channels| - | |---|USB_XTAL --+ | - +----------+ +-------------------------------+ -In this case, we don't need this selector. - -Required properties: -- compatible: "renesas,r8a7795-rcar-usb2-clock-sel" if the device is a part of - an R8A7795 SoC. - "renesas,r8a7796-rcar-usb2-clock-sel" if the device if a part of - an R8A77960 SoC. - "renesas,r8a77961-rcar-usb2-clock-sel" if the device if a part of - an R8A77961 SoC. - "renesas,rcar-gen3-usb2-clock-sel" for a generic R-Car Gen3 - compatible device. - - When compatible with the generic version, nodes must list the - SoC-specific version corresponding to the platform first - followed by the generic version. - -- reg: offset and length of the USB 2.0 clock selector register block. -- clocks: A list of phandles and specifier pairs. -- clock-names: Name of the clocks. - - The functional clock of USB 2.0 host side must be "ehci_ohci" - - The functional clock of HS-USB side must be "hs-usb-if" - - The USB_EXTAL clock pin must be "usb_extal" - - The USB_XTAL clock pin must be "usb_xtal" -- #clock-cells: Must be 0 -- power-domains: A phandle and symbolic PM domain specifier. - See power/renesas,rcar-sysc.yaml. -- resets: A list of phandles and specifier pairs. -- reset-names: Name of the resets. - - The reset of USB 2.0 host side must be "ehci_ohci" - - The reset of HS-USB side must be "hs-usb-if" - -Example (R-Car H3): - - usb2_clksel: clock-controller@e6590630 { - compatible = "renesas,r8a7795-rcar-usb2-clock-sel", - "renesas,rcar-gen3-usb2-clock-sel"; - reg = <0 0xe6590630 0 0x02>; - clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>, - <&usb_extal>, <&usb_xtal>; - clock-names = "ehci_ohci", "hs-usb-if", "usb_extal", "usb_xtal"; - #clock-cells = <0>; - power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; - resets = <&cpg 703>, <&cpg 704>; - reset-names = "ehci_ohci", "hs-usb-if"; - }; diff --git a/Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.yaml b/Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.yaml new file mode 100644 index 000000000000..5be1229b3d6e --- /dev/null +++ b/Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.yaml @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/clock/renesas,rcar-usb2-clock-sel.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Renesas R-Car USB 2.0 clock selector + +maintainers: + - Yoshihiro Shimoda + +description: | + If you connect an external clock to the USB_EXTAL pin only, you should set + the clock rate to "usb_extal" node only. + If you connect an oscillator to both the USB_XTAL and USB_EXTAL, this module + is not needed because this is default setting. (Of course, you can set the + clock rates to both "usb_extal" and "usb_xtal" nodes. + + Case 1: An external clock connects to R-Car SoC + +----------+ +--- R-Car ---------------------+ + |External |---|USB_EXTAL ---> all usb channels| + |clock | |USB_XTAL | + +----------+ +-------------------------------+ + + In this case, we need this driver with "usb_extal" clock. + + Case 2: An oscillator connects to R-Car SoC + +----------+ +--- R-Car ---------------------+ + |Oscillator|---|USB_EXTAL -+-> all usb channels| + | |---|USB_XTAL --+ | + +----------+ +-------------------------------+ + In this case, we don't need this selector. + +properties: + compatible: + items: + - enum: + - renesas,r8a7795-rcar-usb2-clock-sel # R-Car H3 + - renesas,r8a7796-rcar-usb2-clock-sel # R-Car M3-W + - renesas,r8a77961-rcar-usb2-clock-sel # R-Car M3-W+ + - const: renesas,rcar-gen3-usb2-clock-sel + + reg: + maxItems: 1 + + clocks: + minItems: 4 + maxItems: 4 + + clock-names: + items: + - const: ehci_ohci + - const: hs-usb-if + - const: usb_extal + - const: usb_xtal + + '#clock-cells': + const: 0 + + power-domains: + maxItems: 1 + + resets: + minItems: 2 + maxItems: 2 + + reset-names: + items: + - const: ehci_ohci + - const: hs-usb-if + +required: + - compatible + - reg + - clocks + - clock-names + - '#clock-cells' + - power-domains + - resets + - reset-names + +additionalProperties: false + +examples: + - | + #include + #include + + usb2_clksel: clock-controller@e6590630 { + compatible = "renesas,r8a7795-rcar-usb2-clock-sel", + "renesas,rcar-gen3-usb2-clock-sel"; + reg = <0xe6590630 0x02>; + clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>, + <&usb_extal>, <&usb_xtal>; + clock-names = "ehci_ohci", "hs-usb-if", "usb_extal", "usb_xtal"; + #clock-cells = <0>; + power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 703>, <&cpg 704>; + reset-names = "ehci_ohci", "hs-usb-if"; + }; From 967069aa4de65fc525c67b4b7b72b6ded6bd92a0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 3 Nov 2020 17:24:28 +0100 Subject: [PATCH 091/134] clk: pwm: drop of_match_ptr from of_device_id table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match only via the DT table so the table should be always used and the of_match_ptr does not have any sense (this also allows ACPI matching via PRP0001, even though it might be not relevant here). This fixes compile warning (!CONFIG_OF && !CONFIG_MODULES): drivers/clk/clk-pwm.c:139:34: warning: ‘clk_pwm_dt_ids’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201103162435.13689-1-krzk@kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/clk-pwm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-pwm.c b/drivers/clk/clk-pwm.c index 86f2e2d3fc02..da2c8eddfd9f 100644 --- a/drivers/clk/clk-pwm.c +++ b/drivers/clk/clk-pwm.c @@ -147,7 +147,7 @@ static struct platform_driver clk_pwm_driver = { .remove = clk_pwm_remove, .driver = { .name = "pwm-clock", - .of_match_table = of_match_ptr(clk_pwm_dt_ids), + .of_match_table = clk_pwm_dt_ids, }, }; From 975d25cbb505e92644de2e603965bb5e17215012 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 3 Nov 2020 17:24:35 +0100 Subject: [PATCH 092/134] clk: scpi: mark scpi_clk_match as maybe unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The scpi_clk_match (struct of_device_id) is referenced only with CONFIG_OF builds thus mark it as __maybe_unused: drivers/clk/clk-scpi.c:132:34: warning: ‘scpi_clk_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201103162435.13689-8-krzk@kernel.org Acked-by: Sudeep Holla Signed-off-by: Stephen Boyd --- drivers/clk/clk-scpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-scpi.c b/drivers/clk/clk-scpi.c index 5a9b140dd8c8..a39af7616b13 100644 --- a/drivers/clk/clk-scpi.c +++ b/drivers/clk/clk-scpi.c @@ -129,7 +129,7 @@ static const struct clk_ops scpi_dvfs_ops = { .set_rate = scpi_dvfs_set_rate, }; -static const struct of_device_id scpi_clk_match[] = { +static const struct of_device_id scpi_clk_match[] __maybe_unused = { { .compatible = "arm,scpi-dvfs-clocks", .data = &scpi_dvfs_ops, }, { .compatible = "arm,scpi-variable-clocks", .data = &scpi_clk_ops, }, {} From 6d37a8d192830267e6b10a6d57ae28d2e89097e7 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Thu, 10 Dec 2020 10:22:38 -0800 Subject: [PATCH 093/134] clk: qcom: gcc-sc7180: Use floor ops for sdcc clks I would repeat the same commit message that was in commit 5e4b7e82d497 ("clk: qcom: gcc-sdm845: Use floor ops for sdcc clks") but it seems silly to do so when you could just go read that commit. NOTE: this is actually extra terrible because we're missing the 50 MHz rate in the table (see the next patch AKA ("clk: qcom: gcc-sc7180: Add 50 MHz clock rate for SDC2")). That means then when you run an older SD card it'll try to clock it at 100 MHz when it's only specced to run at 50 MHz max. As you can probably guess that doesn't work super well. Signed-off-by: Douglas Anderson Fixes: 17269568f726 ("clk: qcom: Add Global Clock controller (GCC) driver for SC7180") Link: https://lore.kernel.org/r/20201210102234.1.I096779f219625148900fc984dd0084ed1ba87c7f@changeid Signed-off-by: Stephen Boyd --- drivers/clk/qcom/gcc-sc7180.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/qcom/gcc-sc7180.c b/drivers/clk/qcom/gcc-sc7180.c index 68d8f7aaf64e..b080739ab0c3 100644 --- a/drivers/clk/qcom/gcc-sc7180.c +++ b/drivers/clk/qcom/gcc-sc7180.c @@ -642,7 +642,7 @@ static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = { .name = "gcc_sdcc1_ice_core_clk_src", .parent_data = gcc_parent_data_0, .num_parents = 4, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_floor_ops, }, }; @@ -666,7 +666,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { .name = "gcc_sdcc2_apps_clk_src", .parent_data = gcc_parent_data_5, .num_parents = 5, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_floor_ops, }, }; From 043577518f027544e8f9e9568140a1fe87ee01a0 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Thu, 10 Dec 2020 10:22:39 -0800 Subject: [PATCH 094/134] clk: qcom: gcc-sc7180: Add 50 MHz clock rate for SDC2 50 MHz is an incredibly common clock rate for SD cards to run at. It's "high speed" mode in SD (not very fast these days, but it used to be) or: #define HIGH_SPEED_MAX_DTR 50000000 If we don't support this then older "high speed" cards can only run at 25 MHz or at half their normal speed. There doesn't seem to be any reason to skip this clock rate, so add it. Fixes: 17269568f726 ("clk: qcom: Add Global Clock controller (GCC) driver for SC7180") Signed-off-by: Douglas Anderson Link: https://lore.kernel.org/r/20201210102234.2.I26dcc0cee374f5571d9929c9985f463773167e68@changeid Reviewed-by: Bjorn Andersson Signed-off-by: Stephen Boyd --- drivers/clk/qcom/gcc-sc7180.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/qcom/gcc-sc7180.c b/drivers/clk/qcom/gcc-sc7180.c index b080739ab0c3..d82d725ac231 100644 --- a/drivers/clk/qcom/gcc-sc7180.c +++ b/drivers/clk/qcom/gcc-sc7180.c @@ -651,6 +651,7 @@ static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { F(9600000, P_BI_TCXO, 2, 0, 0), F(19200000, P_BI_TCXO, 1, 0, 0), F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), F(100000000, P_GPLL0_OUT_EVEN, 3, 0, 0), F(202000000, P_GPLL7_OUT_MAIN, 4, 0, 0), { } From ce8c195e652fa69f669789de37712a519b09155f Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Fri, 20 Nov 2020 22:10:17 +0530 Subject: [PATCH 095/134] clk: qcom: lpasscc: Introduce pm autosuspend for SC7180 The LPASSCC driver's suspend/resume is invoked multiple number of times and thus allow the device to autosuspend for 500ms. Signed-off-by: Taniya Das Link: https://lore.kernel.org/r/1605890417-721-1-git-send-email-tdas@codeaurora.org Signed-off-by: Stephen Boyd --- drivers/clk/qcom/lpasscorecc-sc7180.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/clk/qcom/lpasscorecc-sc7180.c b/drivers/clk/qcom/lpasscorecc-sc7180.c index 9081649f476f..2e0ecc38efdd 100644 --- a/drivers/clk/qcom/lpasscorecc-sc7180.c +++ b/drivers/clk/qcom/lpasscorecc-sc7180.c @@ -370,7 +370,10 @@ static int lpass_create_pm_clks(struct platform_device *pdev) { int ret; + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, 500); pm_runtime_enable(&pdev->dev); + ret = devm_add_action_or_reset(&pdev->dev, lpass_pm_runtime_disable, &pdev->dev); if (ret) return ret; @@ -423,7 +426,12 @@ static int lpass_core_cc_sc7180_probe(struct platform_device *pdev) clk_fabia_pll_configure(&lpass_lpaaudio_dig_pll, regmap, &lpass_lpaaudio_dig_pll_config); - return qcom_cc_really_probe(pdev, &lpass_core_cc_sc7180_desc, regmap); + ret = qcom_cc_really_probe(pdev, &lpass_core_cc_sc7180_desc, regmap); + + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); + + return ret; } static int lpass_hm_core_probe(struct platform_device *pdev) From eb50f3f42cb6de3820736206ac5019583f6856b1 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Tue, 8 Dec 2020 12:16:58 +0530 Subject: [PATCH 096/134] dt-bindings: clock: Add RPMHCC bindings for SM8350 Add bindings and update documentation for clock rpmh driver on SM8350. Reviewed-by: Bjorn Andersson Signed-off-by: Vinod Koul Link: https://lore.kernel.org/r/20201208064702.3654324-2-vkoul@kernel.org Acked-by: Rob Herring Signed-off-by: Stephen Boyd --- Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml b/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml index a54930f111ba..12c9cbc0ebf9 100644 --- a/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml @@ -22,6 +22,7 @@ properties: - qcom,sdx55-rpmh-clk - qcom,sm8150-rpmh-clk - qcom,sm8250-rpmh-clk + - qcom,sm8350-rpmh-clk clocks: maxItems: 1 From f7b36cc19efb4765467af7cce3a91269fbb529b1 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Tue, 8 Dec 2020 12:16:59 +0530 Subject: [PATCH 097/134] clk: qcom: rpmh: add support for SM8350 rpmh clocks This adds the RPMH clocks present in SM8350 SoC Reviewed-by: Bjorn Andersson Signed-off-by: Vinod Koul Link: https://lore.kernel.org/r/20201208064702.3654324-3-vkoul@kernel.org [sboyd@kernel.org: Move sdx55 to the right place] Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-rpmh.c | 58 +++++++++++++++++++++------ include/dt-bindings/clock/qcom,rpmh.h | 8 ++++ 2 files changed, 54 insertions(+), 12 deletions(-) diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c index f47595a04885..6a2a13c5058e 100644 --- a/drivers/clk/qcom/clk-rpmh.c +++ b/drivers/clk/qcom/clk-rpmh.c @@ -373,6 +373,25 @@ static const struct clk_rpmh_desc clk_rpmh_sdm845 = { .num_clks = ARRAY_SIZE(sdm845_rpmh_clocks), }; +DEFINE_CLK_RPMH_VRM(sdx55, rf_clk1, rf_clk1_ao, "rfclkd1", 1); +DEFINE_CLK_RPMH_VRM(sdx55, rf_clk2, rf_clk2_ao, "rfclkd2", 1); +DEFINE_CLK_RPMH_BCM(sdx55, qpic_clk, "QP0"); + +static struct clk_hw *sdx55_rpmh_clocks[] = { + [RPMH_CXO_CLK] = &sdm845_bi_tcxo.hw, + [RPMH_CXO_CLK_A] = &sdm845_bi_tcxo_ao.hw, + [RPMH_RF_CLK1] = &sdx55_rf_clk1.hw, + [RPMH_RF_CLK1_A] = &sdx55_rf_clk1_ao.hw, + [RPMH_RF_CLK2] = &sdx55_rf_clk2.hw, + [RPMH_RF_CLK2_A] = &sdx55_rf_clk2_ao.hw, + [RPMH_QPIC_CLK] = &sdx55_qpic_clk.hw, +}; + +static const struct clk_rpmh_desc clk_rpmh_sdx55 = { + .clks = sdx55_rpmh_clocks, + .num_clks = ARRAY_SIZE(sdx55_rpmh_clocks), +}; + static struct clk_hw *sm8150_rpmh_clocks[] = { [RPMH_CXO_CLK] = &sdm845_bi_tcxo.hw, [RPMH_CXO_CLK_A] = &sdm845_bi_tcxo_ao.hw, @@ -434,23 +453,37 @@ static const struct clk_rpmh_desc clk_rpmh_sm8250 = { .num_clks = ARRAY_SIZE(sm8250_rpmh_clocks), }; -DEFINE_CLK_RPMH_VRM(sdx55, rf_clk1, rf_clk1_ao, "rfclkd1", 1); -DEFINE_CLK_RPMH_VRM(sdx55, rf_clk2, rf_clk2_ao, "rfclkd2", 1); -DEFINE_CLK_RPMH_BCM(sdx55, qpic_clk, "QP0"); +DEFINE_CLK_RPMH_VRM(sm8350, div_clk1, div_clk1_ao, "divclka1", 2); +DEFINE_CLK_RPMH_VRM(sm8350, rf_clk4, rf_clk4_ao, "rfclka4", 1); +DEFINE_CLK_RPMH_VRM(sm8350, rf_clk5, rf_clk5_ao, "rfclka5", 1); +DEFINE_CLK_RPMH_BCM(sm8350, pka, "PKA0"); +DEFINE_CLK_RPMH_BCM(sm8350, hwkm, "HK0"); -static struct clk_hw *sdx55_rpmh_clocks[] = { +static struct clk_hw *sm8350_rpmh_clocks[] = { [RPMH_CXO_CLK] = &sdm845_bi_tcxo.hw, [RPMH_CXO_CLK_A] = &sdm845_bi_tcxo_ao.hw, - [RPMH_RF_CLK1] = &sdx55_rf_clk1.hw, - [RPMH_RF_CLK1_A] = &sdx55_rf_clk1_ao.hw, - [RPMH_RF_CLK2] = &sdx55_rf_clk2.hw, - [RPMH_RF_CLK2_A] = &sdx55_rf_clk2_ao.hw, - [RPMH_QPIC_CLK] = &sdx55_qpic_clk.hw, + [RPMH_DIV_CLK1] = &sm8350_div_clk1.hw, + [RPMH_DIV_CLK1_A] = &sm8350_div_clk1_ao.hw, + [RPMH_LN_BB_CLK1] = &sm8250_ln_bb_clk1.hw, + [RPMH_LN_BB_CLK1_A] = &sm8250_ln_bb_clk1_ao.hw, + [RPMH_LN_BB_CLK2] = &sdm845_ln_bb_clk2.hw, + [RPMH_LN_BB_CLK2_A] = &sdm845_ln_bb_clk2_ao.hw, + [RPMH_RF_CLK1] = &sdm845_rf_clk1.hw, + [RPMH_RF_CLK1_A] = &sdm845_rf_clk1_ao.hw, + [RPMH_RF_CLK3] = &sdm845_rf_clk3.hw, + [RPMH_RF_CLK3_A] = &sdm845_rf_clk3_ao.hw, + [RPMH_RF_CLK4] = &sm8350_rf_clk4.hw, + [RPMH_RF_CLK4_A] = &sm8350_rf_clk4_ao.hw, + [RPMH_RF_CLK5] = &sm8350_rf_clk5.hw, + [RPMH_RF_CLK5_A] = &sm8350_rf_clk5_ao.hw, + [RPMH_IPA_CLK] = &sdm845_ipa.hw, + [RPMH_PKA_CLK] = &sm8350_pka.hw, + [RPMH_HWKM_CLK] = &sm8350_hwkm.hw, }; -static const struct clk_rpmh_desc clk_rpmh_sdx55 = { - .clks = sdx55_rpmh_clocks, - .num_clks = ARRAY_SIZE(sdx55_rpmh_clocks), +static const struct clk_rpmh_desc clk_rpmh_sm8350 = { + .clks = sm8350_rpmh_clocks, + .num_clks = ARRAY_SIZE(sm8350_rpmh_clocks), }; static struct clk_hw *of_clk_rpmh_hw_get(struct of_phandle_args *clkspec, @@ -541,6 +574,7 @@ static const struct of_device_id clk_rpmh_match_table[] = { { .compatible = "qcom,sdx55-rpmh-clk", .data = &clk_rpmh_sdx55}, { .compatible = "qcom,sm8150-rpmh-clk", .data = &clk_rpmh_sm8150}, { .compatible = "qcom,sm8250-rpmh-clk", .data = &clk_rpmh_sm8250}, + { .compatible = "qcom,sm8350-rpmh-clk", .data = &clk_rpmh_sm8350}, { } }; MODULE_DEVICE_TABLE(of, clk_rpmh_match_table); diff --git a/include/dt-bindings/clock/qcom,rpmh.h b/include/dt-bindings/clock/qcom,rpmh.h index 0662a583e93b..583a99161aaa 100644 --- a/include/dt-bindings/clock/qcom,rpmh.h +++ b/include/dt-bindings/clock/qcom,rpmh.h @@ -23,5 +23,13 @@ #define RPMH_LN_BB_CLK1_A 14 #define RPMH_CE_CLK 15 #define RPMH_QPIC_CLK 16 +#define RPMH_DIV_CLK1 17 +#define RPMH_DIV_CLK1_A 18 +#define RPMH_RF_CLK4 19 +#define RPMH_RF_CLK4_A 20 +#define RPMH_RF_CLK5 21 +#define RPMH_RF_CLK5_A 22 +#define RPMH_PKA_CLK 23 +#define RPMH_HWKM_CLK 24 #endif From 5bf5861d6ea6c3f4b38fc8fda2062b2dc44ac63d Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 26 Oct 2020 01:42:12 +0300 Subject: [PATCH 098/134] clk: tegra: Fix duplicated SE clock entry The periph_clks[] array contains duplicated entry for Security Engine clock which was meant to be defined for T210, but it wasn't added properly. This patch corrects the T210 SE entry and fixes the following error message on T114/T124: "Tegra clk 127: register failed with -17". Fixes: dc37fec48314 ("clk: tegra: periph: Add new periph clks and muxes for Tegra210") Tested-by Nicolas Chauvet Reported-by Nicolas Chauvet Signed-off-by: Dmitry Osipenko Link: https://lore.kernel.org/r/20201025224212.7790-1-digetx@gmail.com Acked-by: Thierry Reding Signed-off-by: Stephen Boyd --- drivers/clk/tegra/clk-id.h | 1 + drivers/clk/tegra/clk-tegra-periph.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h index ff7da2d3e94d..24413812ec5b 100644 --- a/drivers/clk/tegra/clk-id.h +++ b/drivers/clk/tegra/clk-id.h @@ -227,6 +227,7 @@ enum clk_id { tegra_clk_sdmmc4, tegra_clk_sdmmc4_8, tegra_clk_se, + tegra_clk_se_10, tegra_clk_soc_therm, tegra_clk_soc_therm_8, tegra_clk_sor0, diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c index 2b2a3b81c16b..60cc34f90cb9 100644 --- a/drivers/clk/tegra/clk-tegra-periph.c +++ b/drivers/clk/tegra/clk-tegra-periph.c @@ -630,7 +630,7 @@ static struct tegra_periph_init_data periph_clks[] = { INT8("host1x", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_HOST1X, 28, 0, tegra_clk_host1x_8), INT8("host1x", mux_pllc4_out1_pllc_pllc4_out2_pllp_clkm_plla_pllc4_out0, CLK_SOURCE_HOST1X, 28, 0, tegra_clk_host1x_9), INT8("se", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SE, 127, TEGRA_PERIPH_ON_APB, tegra_clk_se), - INT8("se", mux_pllp_pllc2_c_c3_clkm, CLK_SOURCE_SE, 127, TEGRA_PERIPH_ON_APB, tegra_clk_se), + INT8("se", mux_pllp_pllc2_c_c3_clkm, CLK_SOURCE_SE, 127, TEGRA_PERIPH_ON_APB, tegra_clk_se_10), INT8("2d", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_2D, 21, 0, tegra_clk_gr2d_8), INT8("3d", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_3D, 24, 0, tegra_clk_gr3d_8), INT8("vic03", mux_pllm_pllc_pllp_plla_pllc2_c3_clkm, CLK_SOURCE_VIC03, 178, 0, tegra_clk_vic03), From a00a3f29b2a6572108572359558c441da51dad70 Mon Sep 17 00:00:00 2001 From: Zong Li Date: Thu, 26 Nov 2020 11:00:43 +0800 Subject: [PATCH 099/134] dt-bindings: fu740: prci: add YAML documentation for the FU740 PRCI Add YAML DT binding documentation for the SiFive FU740 PRCI. The link of unmatched board as follow, the U740-C000 manual would be present in the same page later. https://www.sifive.com/boards/hifive-unmatched Passes dt_binding_check. Signed-off-by: Zong Li Link: https://lore.kernel.org/r/20201126030043.67390-1-zong.li@sifive.com Reviewed-by: Rob Herring Signed-off-by: Stephen Boyd --- .../bindings/clock/sifive/fu740-prci.yaml | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/sifive/fu740-prci.yaml diff --git a/Documentation/devicetree/bindings/clock/sifive/fu740-prci.yaml b/Documentation/devicetree/bindings/clock/sifive/fu740-prci.yaml new file mode 100644 index 000000000000..e17143cac316 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/sifive/fu740-prci.yaml @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2020 SiFive, Inc. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/sifive/fu740-prci.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: SiFive FU740 Power Reset Clock Interrupt Controller (PRCI) + +maintainers: + - Zong Li + - Paul Walmsley + +description: + On the FU740 family of SoCs, most system-wide clock and reset integration + is via the PRCI IP block. + The clock consumer should specify the desired clock via the clock ID + macros defined in include/dt-bindings/clock/sifive-fu740-prci.h. + These macros begin with PRCI_CLK_. + + The hfclk and rtcclk nodes are required, and represent physical + crystals or resonators located on the PCB. These nodes should be present + underneath /, rather than /soc. + +properties: + compatible: + const: sifive,fu740-c000-prci + + reg: + maxItems: 1 + + clocks: + items: + - description: high frequency clock. + - description: RTL clock. + + clock-names: + items: + - const: hfclk + - const: rtcclk + + "#clock-cells": + const: 1 + +required: + - compatible + - reg + - clocks + - "#clock-cells" + +additionalProperties: false + +examples: + - | + prci: clock-controller@10000000 { + compatible = "sifive,fu740-c000-prci"; + reg = <0x10000000 0x1000>; + clocks = <&hfclk>, <&rtcclk>; + #clock-cells = <1>; + }; From c816e1ddf2b60b31d121118488c5a854d9a2fad9 Mon Sep 17 00:00:00 2001 From: Zong Li Date: Wed, 9 Dec 2020 17:49:12 +0800 Subject: [PATCH 100/134] clk: sifive: Extract prci core to common base Extract common core of prci driver to an independent file, it could allow other chips to reuse it. Separate SoCs-dependent code 'fu540' from prci core, then we can easily add 'fu740' later. Almost these changes are code movement. The different is adding the private data for each SoC use, so it needs to get match data in probe callback function, then use the data for initialization. Signed-off-by: Zong Li Reviewed-by: Pragnesh Patel Acked-by: Palmer Dabbelt Link: https://lore.kernel.org/r/20201209094916.17383-2-zong.li@sifive.com [sboyd@kernel.org: Include header to silence sparse] Signed-off-by: Stephen Boyd --- drivers/clk/sifive/Makefile | 2 +- drivers/clk/sifive/fu540-prci.c | 599 ++----------------------------- drivers/clk/sifive/fu540-prci.h | 21 ++ drivers/clk/sifive/sifive-prci.c | 395 ++++++++++++++++++++ drivers/clk/sifive/sifive-prci.h | 201 +++++++++++ 5 files changed, 644 insertions(+), 574 deletions(-) create mode 100644 drivers/clk/sifive/fu540-prci.h create mode 100644 drivers/clk/sifive/sifive-prci.c create mode 100644 drivers/clk/sifive/sifive-prci.h diff --git a/drivers/clk/sifive/Makefile b/drivers/clk/sifive/Makefile index 0797f14fef6b..51b6ebc359e4 100644 --- a/drivers/clk/sifive/Makefile +++ b/drivers/clk/sifive/Makefile @@ -1,2 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_CLK_SIFIVE_FU540_PRCI) += fu540-prci.o +obj-$(CONFIG_CLK_SIFIVE_FU540_PRCI) += sifive-prci.o fu540-prci.o diff --git a/drivers/clk/sifive/fu540-prci.c b/drivers/clk/sifive/fu540-prci.c index a8901f90a61a..83ced24b0b94 100644 --- a/drivers/clk/sifive/fu540-prci.c +++ b/drivers/clk/sifive/fu540-prci.c @@ -1,17 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2018-2019 SiFive, Inc. - * Wesley Terpstra - * Paul Walmsley - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Copyright (C) 2018-2019 Wesley Terpstra + * Copyright (C) 2018-2019 Paul Walmsley + * Copyright (C) 2020 Zong Li * * The FU540 PRCI implements clock and reset control for the SiFive * FU540-C000 chip. This driver assumes that it has sole control @@ -24,449 +16,19 @@ * - SiFive FU540-C000 manual v1p0, Chapter 7 "Clocking and Reset" */ -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -/* - * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects: - * hfclk and rtcclk - */ -#define EXPECTED_CLK_PARENT_COUNT 2 +#include -/* - * Register offsets and bitmasks - */ +#include "fu540-prci.h" +#include "sifive-prci.h" -/* COREPLLCFG0 */ -#define PRCI_COREPLLCFG0_OFFSET 0x4 -# define PRCI_COREPLLCFG0_DIVR_SHIFT 0 -# define PRCI_COREPLLCFG0_DIVR_MASK (0x3f << PRCI_COREPLLCFG0_DIVR_SHIFT) -# define PRCI_COREPLLCFG0_DIVF_SHIFT 6 -# define PRCI_COREPLLCFG0_DIVF_MASK (0x1ff << PRCI_COREPLLCFG0_DIVF_SHIFT) -# define PRCI_COREPLLCFG0_DIVQ_SHIFT 15 -# define PRCI_COREPLLCFG0_DIVQ_MASK (0x7 << PRCI_COREPLLCFG0_DIVQ_SHIFT) -# define PRCI_COREPLLCFG0_RANGE_SHIFT 18 -# define PRCI_COREPLLCFG0_RANGE_MASK (0x7 << PRCI_COREPLLCFG0_RANGE_SHIFT) -# define PRCI_COREPLLCFG0_BYPASS_SHIFT 24 -# define PRCI_COREPLLCFG0_BYPASS_MASK (0x1 << PRCI_COREPLLCFG0_BYPASS_SHIFT) -# define PRCI_COREPLLCFG0_FSE_SHIFT 25 -# define PRCI_COREPLLCFG0_FSE_MASK (0x1 << PRCI_COREPLLCFG0_FSE_SHIFT) -# define PRCI_COREPLLCFG0_LOCK_SHIFT 31 -# define PRCI_COREPLLCFG0_LOCK_MASK (0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT) - -/* DDRPLLCFG0 */ -#define PRCI_DDRPLLCFG0_OFFSET 0xc -# define PRCI_DDRPLLCFG0_DIVR_SHIFT 0 -# define PRCI_DDRPLLCFG0_DIVR_MASK (0x3f << PRCI_DDRPLLCFG0_DIVR_SHIFT) -# define PRCI_DDRPLLCFG0_DIVF_SHIFT 6 -# define PRCI_DDRPLLCFG0_DIVF_MASK (0x1ff << PRCI_DDRPLLCFG0_DIVF_SHIFT) -# define PRCI_DDRPLLCFG0_DIVQ_SHIFT 15 -# define PRCI_DDRPLLCFG0_DIVQ_MASK (0x7 << PRCI_DDRPLLCFG0_DIVQ_SHIFT) -# define PRCI_DDRPLLCFG0_RANGE_SHIFT 18 -# define PRCI_DDRPLLCFG0_RANGE_MASK (0x7 << PRCI_DDRPLLCFG0_RANGE_SHIFT) -# define PRCI_DDRPLLCFG0_BYPASS_SHIFT 24 -# define PRCI_DDRPLLCFG0_BYPASS_MASK (0x1 << PRCI_DDRPLLCFG0_BYPASS_SHIFT) -# define PRCI_DDRPLLCFG0_FSE_SHIFT 25 -# define PRCI_DDRPLLCFG0_FSE_MASK (0x1 << PRCI_DDRPLLCFG0_FSE_SHIFT) -# define PRCI_DDRPLLCFG0_LOCK_SHIFT 31 -# define PRCI_DDRPLLCFG0_LOCK_MASK (0x1 << PRCI_DDRPLLCFG0_LOCK_SHIFT) - -/* DDRPLLCFG1 */ -#define PRCI_DDRPLLCFG1_OFFSET 0x10 -# define PRCI_DDRPLLCFG1_CKE_SHIFT 24 -# define PRCI_DDRPLLCFG1_CKE_MASK (0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT) - -/* GEMGXLPLLCFG0 */ -#define PRCI_GEMGXLPLLCFG0_OFFSET 0x1c -# define PRCI_GEMGXLPLLCFG0_DIVR_SHIFT 0 -# define PRCI_GEMGXLPLLCFG0_DIVR_MASK (0x3f << PRCI_GEMGXLPLLCFG0_DIVR_SHIFT) -# define PRCI_GEMGXLPLLCFG0_DIVF_SHIFT 6 -# define PRCI_GEMGXLPLLCFG0_DIVF_MASK (0x1ff << PRCI_GEMGXLPLLCFG0_DIVF_SHIFT) -# define PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT 15 -# define PRCI_GEMGXLPLLCFG0_DIVQ_MASK (0x7 << PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT) -# define PRCI_GEMGXLPLLCFG0_RANGE_SHIFT 18 -# define PRCI_GEMGXLPLLCFG0_RANGE_MASK (0x7 << PRCI_GEMGXLPLLCFG0_RANGE_SHIFT) -# define PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT 24 -# define PRCI_GEMGXLPLLCFG0_BYPASS_MASK (0x1 << PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT) -# define PRCI_GEMGXLPLLCFG0_FSE_SHIFT 25 -# define PRCI_GEMGXLPLLCFG0_FSE_MASK (0x1 << PRCI_GEMGXLPLLCFG0_FSE_SHIFT) -# define PRCI_GEMGXLPLLCFG0_LOCK_SHIFT 31 -# define PRCI_GEMGXLPLLCFG0_LOCK_MASK (0x1 << PRCI_GEMGXLPLLCFG0_LOCK_SHIFT) - -/* GEMGXLPLLCFG1 */ -#define PRCI_GEMGXLPLLCFG1_OFFSET 0x20 -# define PRCI_GEMGXLPLLCFG1_CKE_SHIFT 24 -# define PRCI_GEMGXLPLLCFG1_CKE_MASK (0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT) - -/* CORECLKSEL */ -#define PRCI_CORECLKSEL_OFFSET 0x24 -# define PRCI_CORECLKSEL_CORECLKSEL_SHIFT 0 -# define PRCI_CORECLKSEL_CORECLKSEL_MASK (0x1 << PRCI_CORECLKSEL_CORECLKSEL_SHIFT) - -/* DEVICESRESETREG */ -#define PRCI_DEVICESRESETREG_OFFSET 0x28 -# define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT 0 -# define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT) -# define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT 1 -# define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT) -# define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT 2 -# define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT) -# define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT 3 -# define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT) -# define PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT 5 -# define PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT) - -/* CLKMUXSTATUSREG */ -#define PRCI_CLKMUXSTATUSREG_OFFSET 0x2c -# define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT 1 -# define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK (0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT) - -/* - * Private structures - */ - -/** - * struct __prci_data - per-device-instance data - * @va: base virtual address of the PRCI IP block - * @hw_clks: encapsulates struct clk_hw records - * - * PRCI per-device instance data - */ -struct __prci_data { - void __iomem *va; - struct clk_hw_onecell_data hw_clks; -}; - -/** - * struct __prci_wrpll_data - WRPLL configuration and integration data - * @c: WRPLL current configuration record - * @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL) - * @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL) - * @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address - * - * @enable_bypass and @disable_bypass are used for WRPLL instances - * that contain a separate external glitchless clock mux downstream - * from the PLL. The WRPLL internal bypass mux is not glitchless. - */ -struct __prci_wrpll_data { - struct wrpll_cfg c; - void (*enable_bypass)(struct __prci_data *pd); - void (*disable_bypass)(struct __prci_data *pd); - u8 cfg0_offs; -}; - -/** - * struct __prci_clock - describes a clock device managed by PRCI - * @name: user-readable clock name string - should match the manual - * @parent_name: parent name for this clock - * @ops: struct clk_ops for the Linux clock framework to use for control - * @hw: Linux-private clock data - * @pwd: WRPLL-specific data, associated with this clock (if not NULL) - * @pd: PRCI-specific data associated with this clock (if not NULL) - * - * PRCI clock data. Used by the PRCI driver to register PRCI-provided - * clocks to the Linux clock infrastructure. - */ -struct __prci_clock { - const char *name; - const char *parent_name; - const struct clk_ops *ops; - struct clk_hw hw; - struct __prci_wrpll_data *pwd; - struct __prci_data *pd; -}; - -#define clk_hw_to_prci_clock(pwd) container_of(pwd, struct __prci_clock, hw) - -/* - * Private functions - */ - -/** - * __prci_readl() - read from a PRCI register - * @pd: PRCI context - * @offs: register offset to read from (in bytes, from PRCI base address) - * - * Read the register located at offset @offs from the base virtual - * address of the PRCI register target described by @pd, and return - * the value to the caller. - * - * Context: Any context. - * - * Return: the contents of the register described by @pd and @offs. - */ -static u32 __prci_readl(struct __prci_data *pd, u32 offs) -{ - return readl_relaxed(pd->va + offs); -} - -static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd) -{ - writel_relaxed(v, pd->va + offs); -} - -/* WRPLL-related private functions */ - -/** - * __prci_wrpll_unpack() - unpack WRPLL configuration registers into parameters - * @c: ptr to a struct wrpll_cfg record to write config into - * @r: value read from the PRCI PLL configuration register - * - * Given a value @r read from an FU540 PRCI PLL configuration register, - * split it into fields and populate it into the WRPLL configuration record - * pointed to by @c. - * - * The COREPLLCFG0 macros are used below, but the other *PLLCFG0 macros - * have the same register layout. - * - * Context: Any context. - */ -static void __prci_wrpll_unpack(struct wrpll_cfg *c, u32 r) -{ - u32 v; - - v = r & PRCI_COREPLLCFG0_DIVR_MASK; - v >>= PRCI_COREPLLCFG0_DIVR_SHIFT; - c->divr = v; - - v = r & PRCI_COREPLLCFG0_DIVF_MASK; - v >>= PRCI_COREPLLCFG0_DIVF_SHIFT; - c->divf = v; - - v = r & PRCI_COREPLLCFG0_DIVQ_MASK; - v >>= PRCI_COREPLLCFG0_DIVQ_SHIFT; - c->divq = v; - - v = r & PRCI_COREPLLCFG0_RANGE_MASK; - v >>= PRCI_COREPLLCFG0_RANGE_SHIFT; - c->range = v; - - c->flags &= (WRPLL_FLAGS_INT_FEEDBACK_MASK | - WRPLL_FLAGS_EXT_FEEDBACK_MASK); - - /* external feedback mode not supported */ - c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK; -} - -/** - * __prci_wrpll_pack() - pack PLL configuration parameters into a register value - * @c: pointer to a struct wrpll_cfg record containing the PLL's cfg - * - * Using a set of WRPLL configuration values pointed to by @c, - * assemble a PRCI PLL configuration register value, and return it to - * the caller. - * - * Context: Any context. Caller must ensure that the contents of the - * record pointed to by @c do not change during the execution - * of this function. - * - * Returns: a value suitable for writing into a PRCI PLL configuration - * register - */ -static u32 __prci_wrpll_pack(const struct wrpll_cfg *c) -{ - u32 r = 0; - - r |= c->divr << PRCI_COREPLLCFG0_DIVR_SHIFT; - r |= c->divf << PRCI_COREPLLCFG0_DIVF_SHIFT; - r |= c->divq << PRCI_COREPLLCFG0_DIVQ_SHIFT; - r |= c->range << PRCI_COREPLLCFG0_RANGE_SHIFT; - - /* external feedback mode not supported */ - r |= PRCI_COREPLLCFG0_FSE_MASK; - - return r; -} - -/** - * __prci_wrpll_read_cfg() - read the WRPLL configuration from the PRCI - * @pd: PRCI context - * @pwd: PRCI WRPLL metadata - * - * Read the current configuration of the PLL identified by @pwd from - * the PRCI identified by @pd, and store it into the local configuration - * cache in @pwd. - * - * Context: Any context. Caller must prevent the records pointed to by - * @pd and @pwd from changing during execution. - */ -static void __prci_wrpll_read_cfg(struct __prci_data *pd, - struct __prci_wrpll_data *pwd) -{ - __prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs)); -} - -/** - * __prci_wrpll_write_cfg() - write WRPLL configuration into the PRCI - * @pd: PRCI context - * @pwd: PRCI WRPLL metadata - * @c: WRPLL configuration record to write - * - * Write the WRPLL configuration described by @c into the WRPLL - * configuration register identified by @pwd in the PRCI instance - * described by @c. Make a cached copy of the WRPLL's current - * configuration so it can be used by other code. - * - * Context: Any context. Caller must prevent the records pointed to by - * @pd and @pwd from changing during execution. - */ -static void __prci_wrpll_write_cfg(struct __prci_data *pd, - struct __prci_wrpll_data *pwd, - struct wrpll_cfg *c) -{ - __prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd); - - memcpy(&pwd->c, c, sizeof(*c)); -} - -/* Core clock mux control */ - -/** - * __prci_coreclksel_use_hfclk() - switch the CORECLK mux to output HFCLK - * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg - * - * Switch the CORECLK mux to the HFCLK input source; return once complete. - * - * Context: Any context. Caller must prevent concurrent changes to the - * PRCI_CORECLKSEL_OFFSET register. - */ -static void __prci_coreclksel_use_hfclk(struct __prci_data *pd) -{ - u32 r; - - r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); - r |= PRCI_CORECLKSEL_CORECLKSEL_MASK; - __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd); - - r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */ -} - -/** - * __prci_coreclksel_use_corepll() - switch the CORECLK mux to output COREPLL - * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg - * - * Switch the CORECLK mux to the PLL output clock; return once complete. - * - * Context: Any context. Caller must prevent concurrent changes to the - * PRCI_CORECLKSEL_OFFSET register. - */ -static void __prci_coreclksel_use_corepll(struct __prci_data *pd) -{ - u32 r; - - r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); - r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK; - __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd); - - r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */ -} - -/* - * Linux clock framework integration - * - * See the Linux clock framework documentation for more information on - * these functions. - */ - -static unsigned long sifive_fu540_prci_wrpll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct __prci_clock *pc = clk_hw_to_prci_clock(hw); - struct __prci_wrpll_data *pwd = pc->pwd; - - return wrpll_calc_output_rate(&pwd->c, parent_rate); -} - -static long sifive_fu540_prci_wrpll_round_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long *parent_rate) -{ - struct __prci_clock *pc = clk_hw_to_prci_clock(hw); - struct __prci_wrpll_data *pwd = pc->pwd; - struct wrpll_cfg c; - - memcpy(&c, &pwd->c, sizeof(c)); - - wrpll_configure_for_rate(&c, rate, *parent_rate); - - return wrpll_calc_output_rate(&c, *parent_rate); -} - -static int sifive_fu540_prci_wrpll_set_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long parent_rate) -{ - struct __prci_clock *pc = clk_hw_to_prci_clock(hw); - struct __prci_wrpll_data *pwd = pc->pwd; - struct __prci_data *pd = pc->pd; - int r; - - r = wrpll_configure_for_rate(&pwd->c, rate, parent_rate); - if (r) - return r; - - if (pwd->enable_bypass) - pwd->enable_bypass(pd); - - __prci_wrpll_write_cfg(pd, pwd, &pwd->c); - - udelay(wrpll_calc_max_lock_us(&pwd->c)); - - if (pwd->disable_bypass) - pwd->disable_bypass(pd); - - return 0; -} - -static const struct clk_ops sifive_fu540_prci_wrpll_clk_ops = { - .set_rate = sifive_fu540_prci_wrpll_set_rate, - .round_rate = sifive_fu540_prci_wrpll_round_rate, - .recalc_rate = sifive_fu540_prci_wrpll_recalc_rate, -}; - -static const struct clk_ops sifive_fu540_prci_wrpll_ro_clk_ops = { - .recalc_rate = sifive_fu540_prci_wrpll_recalc_rate, -}; - -/* TLCLKSEL clock integration */ - -static unsigned long sifive_fu540_prci_tlclksel_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct __prci_clock *pc = clk_hw_to_prci_clock(hw); - struct __prci_data *pd = pc->pd; - u32 v; - u8 div; - - v = __prci_readl(pd, PRCI_CLKMUXSTATUSREG_OFFSET); - v &= PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK; - div = v ? 1 : 2; - - return div_u64(parent_rate, div); -} - -static const struct clk_ops sifive_fu540_prci_tlclksel_clk_ops = { - .recalc_rate = sifive_fu540_prci_tlclksel_recalc_rate, -}; - -/* - * PRCI integration data for each WRPLL instance - */ +/* PRCI integration data for each WRPLL instance */ static struct __prci_wrpll_data __prci_corepll_data = { .cfg0_offs = PRCI_COREPLLCFG0_OFFSET, - .enable_bypass = __prci_coreclksel_use_hfclk, - .disable_bypass = __prci_coreclksel_use_corepll, + .enable_bypass = sifive_prci_coreclksel_use_hfclk, + .disable_bypass = sifive_prci_coreclksel_use_corepll, }; static struct __prci_wrpll_data __prci_ddrpll_data = { @@ -477,11 +39,24 @@ static struct __prci_wrpll_data __prci_gemgxlpll_data = { .cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET, }; -/* - * List of clock controls provided by the PRCI - */ +/* Linux clock framework integration */ -static struct __prci_clock __prci_init_clocks[] = { +static const struct clk_ops sifive_fu540_prci_wrpll_clk_ops = { + .set_rate = sifive_prci_wrpll_set_rate, + .round_rate = sifive_prci_wrpll_round_rate, + .recalc_rate = sifive_prci_wrpll_recalc_rate, +}; + +static const struct clk_ops sifive_fu540_prci_wrpll_ro_clk_ops = { + .recalc_rate = sifive_prci_wrpll_recalc_rate, +}; + +static const struct clk_ops sifive_fu540_prci_tlclksel_clk_ops = { + .recalc_rate = sifive_prci_tlclksel_recalc_rate, +}; + +/* List of clock controls provided by the PRCI */ +struct __prci_clock __prci_init_clocks_fu540[] = { [PRCI_CLK_COREPLL] = { .name = "corepll", .parent_name = "hfclk", @@ -506,125 +81,3 @@ static struct __prci_clock __prci_init_clocks[] = { .ops = &sifive_fu540_prci_tlclksel_clk_ops, }, }; - -/** - * __prci_register_clocks() - register clock controls in the PRCI with Linux - * @dev: Linux struct device * - * - * Register the list of clock controls described in __prci_init_plls[] with - * the Linux clock framework. - * - * Return: 0 upon success or a negative error code upon failure. - */ -static int __prci_register_clocks(struct device *dev, struct __prci_data *pd) -{ - struct clk_init_data init = { }; - struct __prci_clock *pic; - int parent_count, i, r; - - parent_count = of_clk_get_parent_count(dev->of_node); - if (parent_count != EXPECTED_CLK_PARENT_COUNT) { - dev_err(dev, "expected only two parent clocks, found %d\n", - parent_count); - return -EINVAL; - } - - /* Register PLLs */ - for (i = 0; i < ARRAY_SIZE(__prci_init_clocks); ++i) { - pic = &__prci_init_clocks[i]; - - init.name = pic->name; - init.parent_names = &pic->parent_name; - init.num_parents = 1; - init.ops = pic->ops; - pic->hw.init = &init; - - pic->pd = pd; - - if (pic->pwd) - __prci_wrpll_read_cfg(pd, pic->pwd); - - r = devm_clk_hw_register(dev, &pic->hw); - if (r) { - dev_warn(dev, "Failed to register clock %s: %d\n", - init.name, r); - return r; - } - - r = clk_hw_register_clkdev(&pic->hw, pic->name, dev_name(dev)); - if (r) { - dev_warn(dev, "Failed to register clkdev for %s: %d\n", - init.name, r); - return r; - } - - pd->hw_clks.hws[i] = &pic->hw; - } - - pd->hw_clks.num = i; - - r = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, - &pd->hw_clks); - if (r) { - dev_err(dev, "could not add hw_provider: %d\n", r); - return r; - } - - return 0; -} - -/* - * Linux device model integration - * - * See the Linux device model documentation for more information about - * these functions. - */ -static int sifive_fu540_prci_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct resource *res; - struct __prci_data *pd; - int r; - - pd = devm_kzalloc(dev, - struct_size(pd, hw_clks.hws, - ARRAY_SIZE(__prci_init_clocks)), - GFP_KERNEL); - if (!pd) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pd->va = devm_ioremap_resource(dev, res); - if (IS_ERR(pd->va)) - return PTR_ERR(pd->va); - - r = __prci_register_clocks(dev, pd); - if (r) { - dev_err(dev, "could not register clocks: %d\n", r); - return r; - } - - dev_dbg(dev, "SiFive FU540 PRCI probed\n"); - - return 0; -} - -static const struct of_device_id sifive_fu540_prci_of_match[] = { - { .compatible = "sifive,fu540-c000-prci", }, - {} -}; -MODULE_DEVICE_TABLE(of, sifive_fu540_prci_of_match); - -static struct platform_driver sifive_fu540_prci_driver = { - .driver = { - .name = "sifive-fu540-prci", - .of_match_table = sifive_fu540_prci_of_match, - }, - .probe = sifive_fu540_prci_probe, -}; - -static int __init sifive_fu540_prci_init(void) -{ - return platform_driver_register(&sifive_fu540_prci_driver); -} -core_initcall(sifive_fu540_prci_init); diff --git a/drivers/clk/sifive/fu540-prci.h b/drivers/clk/sifive/fu540-prci.h new file mode 100644 index 000000000000..c8271efa7bdc --- /dev/null +++ b/drivers/clk/sifive/fu540-prci.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 SiFive, Inc. + * Zong Li + */ + +#ifndef __SIFIVE_CLK_FU540_PRCI_H +#define __SIFIVE_CLK_FU540_PRCI_H + +#include "sifive-prci.h" + +#define NUM_CLOCK_FU540 4 + +extern struct __prci_clock __prci_init_clocks_fu540[NUM_CLOCK_FU540]; + +static const struct prci_clk_desc prci_clk_fu540 = { + .clks = __prci_init_clocks_fu540, + .num_clks = ARRAY_SIZE(__prci_init_clocks_fu540), +}; + +#endif /* __SIFIVE_CLK_FU540_PRCI_H */ diff --git a/drivers/clk/sifive/sifive-prci.c b/drivers/clk/sifive/sifive-prci.c new file mode 100644 index 000000000000..70653d33f33f --- /dev/null +++ b/drivers/clk/sifive/sifive-prci.c @@ -0,0 +1,395 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 SiFive, Inc. + * Copyright (C) 2020 Zong Li + */ + +#include +#include +#include +#include +#include "sifive-prci.h" +#include "fu540-prci.h" + +/* + * Private functions + */ + +/** + * __prci_readl() - read from a PRCI register + * @pd: PRCI context + * @offs: register offset to read from (in bytes, from PRCI base address) + * + * Read the register located at offset @offs from the base virtual + * address of the PRCI register target described by @pd, and return + * the value to the caller. + * + * Context: Any context. + * + * Return: the contents of the register described by @pd and @offs. + */ +static u32 __prci_readl(struct __prci_data *pd, u32 offs) +{ + return readl_relaxed(pd->va + offs); +} + +static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd) +{ + writel_relaxed(v, pd->va + offs); +} + +/* WRPLL-related private functions */ + +/** + * __prci_wrpll_unpack() - unpack WRPLL configuration registers into parameters + * @c: ptr to a struct wrpll_cfg record to write config into + * @r: value read from the PRCI PLL configuration register + * + * Given a value @r read from an FU740 PRCI PLL configuration register, + * split it into fields and populate it into the WRPLL configuration record + * pointed to by @c. + * + * The COREPLLCFG0 macros are used below, but the other *PLLCFG0 macros + * have the same register layout. + * + * Context: Any context. + */ +static void __prci_wrpll_unpack(struct wrpll_cfg *c, u32 r) +{ + u32 v; + + v = r & PRCI_COREPLLCFG0_DIVR_MASK; + v >>= PRCI_COREPLLCFG0_DIVR_SHIFT; + c->divr = v; + + v = r & PRCI_COREPLLCFG0_DIVF_MASK; + v >>= PRCI_COREPLLCFG0_DIVF_SHIFT; + c->divf = v; + + v = r & PRCI_COREPLLCFG0_DIVQ_MASK; + v >>= PRCI_COREPLLCFG0_DIVQ_SHIFT; + c->divq = v; + + v = r & PRCI_COREPLLCFG0_RANGE_MASK; + v >>= PRCI_COREPLLCFG0_RANGE_SHIFT; + c->range = v; + + c->flags &= + (WRPLL_FLAGS_INT_FEEDBACK_MASK | WRPLL_FLAGS_EXT_FEEDBACK_MASK); + + /* external feedback mode not supported */ + c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK; +} + +/** + * __prci_wrpll_pack() - pack PLL configuration parameters into a register value + * @c: pointer to a struct wrpll_cfg record containing the PLL's cfg + * + * Using a set of WRPLL configuration values pointed to by @c, + * assemble a PRCI PLL configuration register value, and return it to + * the caller. + * + * Context: Any context. Caller must ensure that the contents of the + * record pointed to by @c do not change during the execution + * of this function. + * + * Returns: a value suitable for writing into a PRCI PLL configuration + * register + */ +static u32 __prci_wrpll_pack(const struct wrpll_cfg *c) +{ + u32 r = 0; + + r |= c->divr << PRCI_COREPLLCFG0_DIVR_SHIFT; + r |= c->divf << PRCI_COREPLLCFG0_DIVF_SHIFT; + r |= c->divq << PRCI_COREPLLCFG0_DIVQ_SHIFT; + r |= c->range << PRCI_COREPLLCFG0_RANGE_SHIFT; + + /* external feedback mode not supported */ + r |= PRCI_COREPLLCFG0_FSE_MASK; + + return r; +} + +/** + * __prci_wrpll_read_cfg() - read the WRPLL configuration from the PRCI + * @pd: PRCI context + * @pwd: PRCI WRPLL metadata + * + * Read the current configuration of the PLL identified by @pwd from + * the PRCI identified by @pd, and store it into the local configuration + * cache in @pwd. + * + * Context: Any context. Caller must prevent the records pointed to by + * @pd and @pwd from changing during execution. + */ +static void __prci_wrpll_read_cfg(struct __prci_data *pd, + struct __prci_wrpll_data *pwd) +{ + __prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs)); +} + +/** + * __prci_wrpll_write_cfg() - write WRPLL configuration into the PRCI + * @pd: PRCI context + * @pwd: PRCI WRPLL metadata + * @c: WRPLL configuration record to write + * + * Write the WRPLL configuration described by @c into the WRPLL + * configuration register identified by @pwd in the PRCI instance + * described by @c. Make a cached copy of the WRPLL's current + * configuration so it can be used by other code. + * + * Context: Any context. Caller must prevent the records pointed to by + * @pd and @pwd from changing during execution. + */ +static void __prci_wrpll_write_cfg(struct __prci_data *pd, + struct __prci_wrpll_data *pwd, + struct wrpll_cfg *c) +{ + __prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd); + + memcpy(&pwd->c, c, sizeof(*c)); +} + +/* + * Linux clock framework integration + * + * See the Linux clock framework documentation for more information on + * these functions. + */ + +unsigned long sifive_prci_wrpll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct __prci_clock *pc = clk_hw_to_prci_clock(hw); + struct __prci_wrpll_data *pwd = pc->pwd; + + return wrpll_calc_output_rate(&pwd->c, parent_rate); +} + +long sifive_prci_wrpll_round_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long *parent_rate) +{ + struct __prci_clock *pc = clk_hw_to_prci_clock(hw); + struct __prci_wrpll_data *pwd = pc->pwd; + struct wrpll_cfg c; + + memcpy(&c, &pwd->c, sizeof(c)); + + wrpll_configure_for_rate(&c, rate, *parent_rate); + + return wrpll_calc_output_rate(&c, *parent_rate); +} + +int sifive_prci_wrpll_set_rate(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate) +{ + struct __prci_clock *pc = clk_hw_to_prci_clock(hw); + struct __prci_wrpll_data *pwd = pc->pwd; + struct __prci_data *pd = pc->pd; + int r; + + r = wrpll_configure_for_rate(&pwd->c, rate, parent_rate); + if (r) + return r; + + if (pwd->enable_bypass) + pwd->enable_bypass(pd); + + __prci_wrpll_write_cfg(pd, pwd, &pwd->c); + + udelay(wrpll_calc_max_lock_us(&pwd->c)); + + if (pwd->disable_bypass) + pwd->disable_bypass(pd); + + return 0; +} + +/* TLCLKSEL clock integration */ + +unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct __prci_clock *pc = clk_hw_to_prci_clock(hw); + struct __prci_data *pd = pc->pd; + u32 v; + u8 div; + + v = __prci_readl(pd, PRCI_CLKMUXSTATUSREG_OFFSET); + v &= PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK; + div = v ? 1 : 2; + + return div_u64(parent_rate, div); +} + +/* + * Core clock mux control + */ + +/** + * sifive_prci_coreclksel_use_hfclk() - switch the CORECLK mux to output HFCLK + * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg + * + * Switch the CORECLK mux to the HFCLK input source; return once complete. + * + * Context: Any context. Caller must prevent concurrent changes to the + * PRCI_CORECLKSEL_OFFSET register. + */ +void sifive_prci_coreclksel_use_hfclk(struct __prci_data *pd) +{ + u32 r; + + r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); + r |= PRCI_CORECLKSEL_CORECLKSEL_MASK; + __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd); + + r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */ +} + +/** + * sifive_prci_coreclksel_use_corepll() - switch the CORECLK mux to output + * COREPLL + * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg + * + * Switch the CORECLK mux to the COREPLL output clock; return once complete. + * + * Context: Any context. Caller must prevent concurrent changes to the + * PRCI_CORECLKSEL_OFFSET register. + */ +void sifive_prci_coreclksel_use_corepll(struct __prci_data *pd) +{ + u32 r; + + r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); + r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK; + __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd); + + r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */ +} + +/** + * __prci_register_clocks() - register clock controls in the PRCI + * @dev: Linux struct device + * @pd: The pointer for PRCI per-device instance data + * @desc: The pointer for the information of clocks of each SoCs + * + * Register the list of clock controls described in __prci_init_clocks[] with + * the Linux clock framework. + * + * Return: 0 upon success or a negative error code upon failure. + */ +static int __prci_register_clocks(struct device *dev, struct __prci_data *pd, + const struct prci_clk_desc *desc) +{ + struct clk_init_data init = { }; + struct __prci_clock *pic; + int parent_count, i, r; + + parent_count = of_clk_get_parent_count(dev->of_node); + if (parent_count != EXPECTED_CLK_PARENT_COUNT) { + dev_err(dev, "expected only two parent clocks, found %d\n", + parent_count); + return -EINVAL; + } + + /* Register PLLs */ + for (i = 0; i < desc->num_clks; ++i) { + pic = &(desc->clks[i]); + + init.name = pic->name; + init.parent_names = &pic->parent_name; + init.num_parents = 1; + init.ops = pic->ops; + pic->hw.init = &init; + + pic->pd = pd; + + if (pic->pwd) + __prci_wrpll_read_cfg(pd, pic->pwd); + + r = devm_clk_hw_register(dev, &pic->hw); + if (r) { + dev_warn(dev, "Failed to register clock %s: %d\n", + init.name, r); + return r; + } + + r = clk_hw_register_clkdev(&pic->hw, pic->name, dev_name(dev)); + if (r) { + dev_warn(dev, "Failed to register clkdev for %s: %d\n", + init.name, r); + return r; + } + + pd->hw_clks.hws[i] = &pic->hw; + } + + pd->hw_clks.num = i; + + r = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + &pd->hw_clks); + if (r) { + dev_err(dev, "could not add hw_provider: %d\n", r); + return r; + } + + return 0; +} + +/** + * sifive_prci_init() - initialize prci data and check parent count + * @pdev: platform device pointer for the prci + * + * Return: 0 upon success or a negative error code upon failure. + */ +static int sifive_prci_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + struct __prci_data *pd; + const struct prci_clk_desc *desc; + int r; + + desc = of_device_get_match_data(&pdev->dev); + + pd = devm_kzalloc(dev, struct_size(pd, hw_clks.hws, desc->num_clks), GFP_KERNEL); + if (!pd) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pd->va = devm_ioremap_resource(dev, res); + if (IS_ERR(pd->va)) + return PTR_ERR(pd->va); + + r = __prci_register_clocks(dev, pd, desc); + if (r) { + dev_err(dev, "could not register clocks: %d\n", r); + return r; + } + + dev_dbg(dev, "SiFive PRCI probed\n"); + + return 0; +} + +static const struct of_device_id sifive_prci_of_match[] = { + {.compatible = "sifive,fu540-c000-prci", .data = &prci_clk_fu540}, + {} +}; + +static struct platform_driver sifive_prci_driver = { + .driver = { + .name = "sifive-clk-prci", + .of_match_table = sifive_prci_of_match, + }, + .probe = sifive_prci_probe, +}; + +static int __init sifive_prci_init(void) +{ + return platform_driver_register(&sifive_prci_driver); +} +core_initcall(sifive_prci_init); diff --git a/drivers/clk/sifive/sifive-prci.h b/drivers/clk/sifive/sifive-prci.h new file mode 100644 index 000000000000..280df63b4b92 --- /dev/null +++ b/drivers/clk/sifive/sifive-prci.h @@ -0,0 +1,201 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018-2019 SiFive, Inc. + * Wesley Terpstra + * Paul Walmsley + * Zong Li + */ + +#ifndef __SIFIVE_CLK_SIFIVE_PRCI_H +#define __SIFIVE_CLK_SIFIVE_PRCI_H + +#include +#include +#include + +/* + * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects: + * hfclk and rtcclk + */ +#define EXPECTED_CLK_PARENT_COUNT 2 + +/* + * Register offsets and bitmasks + */ + +/* COREPLLCFG0 */ +#define PRCI_COREPLLCFG0_OFFSET 0x4 +#define PRCI_COREPLLCFG0_DIVR_SHIFT 0 +#define PRCI_COREPLLCFG0_DIVR_MASK (0x3f << PRCI_COREPLLCFG0_DIVR_SHIFT) +#define PRCI_COREPLLCFG0_DIVF_SHIFT 6 +#define PRCI_COREPLLCFG0_DIVF_MASK (0x1ff << PRCI_COREPLLCFG0_DIVF_SHIFT) +#define PRCI_COREPLLCFG0_DIVQ_SHIFT 15 +#define PRCI_COREPLLCFG0_DIVQ_MASK (0x7 << PRCI_COREPLLCFG0_DIVQ_SHIFT) +#define PRCI_COREPLLCFG0_RANGE_SHIFT 18 +#define PRCI_COREPLLCFG0_RANGE_MASK (0x7 << PRCI_COREPLLCFG0_RANGE_SHIFT) +#define PRCI_COREPLLCFG0_BYPASS_SHIFT 24 +#define PRCI_COREPLLCFG0_BYPASS_MASK (0x1 << PRCI_COREPLLCFG0_BYPASS_SHIFT) +#define PRCI_COREPLLCFG0_FSE_SHIFT 25 +#define PRCI_COREPLLCFG0_FSE_MASK (0x1 << PRCI_COREPLLCFG0_FSE_SHIFT) +#define PRCI_COREPLLCFG0_LOCK_SHIFT 31 +#define PRCI_COREPLLCFG0_LOCK_MASK (0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT) + +/* DDRPLLCFG0 */ +#define PRCI_DDRPLLCFG0_OFFSET 0xc +#define PRCI_DDRPLLCFG0_DIVR_SHIFT 0 +#define PRCI_DDRPLLCFG0_DIVR_MASK (0x3f << PRCI_DDRPLLCFG0_DIVR_SHIFT) +#define PRCI_DDRPLLCFG0_DIVF_SHIFT 6 +#define PRCI_DDRPLLCFG0_DIVF_MASK (0x1ff << PRCI_DDRPLLCFG0_DIVF_SHIFT) +#define PRCI_DDRPLLCFG0_DIVQ_SHIFT 15 +#define PRCI_DDRPLLCFG0_DIVQ_MASK (0x7 << PRCI_DDRPLLCFG0_DIVQ_SHIFT) +#define PRCI_DDRPLLCFG0_RANGE_SHIFT 18 +#define PRCI_DDRPLLCFG0_RANGE_MASK (0x7 << PRCI_DDRPLLCFG0_RANGE_SHIFT) +#define PRCI_DDRPLLCFG0_BYPASS_SHIFT 24 +#define PRCI_DDRPLLCFG0_BYPASS_MASK (0x1 << PRCI_DDRPLLCFG0_BYPASS_SHIFT) +#define PRCI_DDRPLLCFG0_FSE_SHIFT 25 +#define PRCI_DDRPLLCFG0_FSE_MASK (0x1 << PRCI_DDRPLLCFG0_FSE_SHIFT) +#define PRCI_DDRPLLCFG0_LOCK_SHIFT 31 +#define PRCI_DDRPLLCFG0_LOCK_MASK (0x1 << PRCI_DDRPLLCFG0_LOCK_SHIFT) + +/* DDRPLLCFG1 */ +#define PRCI_DDRPLLCFG1_OFFSET 0x10 +#define PRCI_DDRPLLCFG1_CKE_SHIFT 24 +#define PRCI_DDRPLLCFG1_CKE_MASK (0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT) + +/* GEMGXLPLLCFG0 */ +#define PRCI_GEMGXLPLLCFG0_OFFSET 0x1c +#define PRCI_GEMGXLPLLCFG0_DIVR_SHIFT 0 +#define PRCI_GEMGXLPLLCFG0_DIVR_MASK (0x3f << PRCI_GEMGXLPLLCFG0_DIVR_SHIFT) +#define PRCI_GEMGXLPLLCFG0_DIVF_SHIFT 6 +#define PRCI_GEMGXLPLLCFG0_DIVF_MASK (0x1ff << PRCI_GEMGXLPLLCFG0_DIVF_SHIFT) +#define PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT 15 +#define PRCI_GEMGXLPLLCFG0_DIVQ_MASK (0x7 << PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT) +#define PRCI_GEMGXLPLLCFG0_RANGE_SHIFT 18 +#define PRCI_GEMGXLPLLCFG0_RANGE_MASK (0x7 << PRCI_GEMGXLPLLCFG0_RANGE_SHIFT) +#define PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT 24 +#define PRCI_GEMGXLPLLCFG0_BYPASS_MASK (0x1 << PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT) +#define PRCI_GEMGXLPLLCFG0_FSE_SHIFT 25 +#define PRCI_GEMGXLPLLCFG0_FSE_MASK (0x1 << PRCI_GEMGXLPLLCFG0_FSE_SHIFT) +#define PRCI_GEMGXLPLLCFG0_LOCK_SHIFT 31 +#define PRCI_GEMGXLPLLCFG0_LOCK_MASK (0x1 << PRCI_GEMGXLPLLCFG0_LOCK_SHIFT) + +/* GEMGXLPLLCFG1 */ +#define PRCI_GEMGXLPLLCFG1_OFFSET 0x20 +#define PRCI_GEMGXLPLLCFG1_CKE_SHIFT 24 +#define PRCI_GEMGXLPLLCFG1_CKE_MASK (0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT) + +/* CORECLKSEL */ +#define PRCI_CORECLKSEL_OFFSET 0x24 +#define PRCI_CORECLKSEL_CORECLKSEL_SHIFT 0 +#define PRCI_CORECLKSEL_CORECLKSEL_MASK \ + (0x1 << PRCI_CORECLKSEL_CORECLKSEL_SHIFT) + +/* DEVICESRESETREG */ +#define PRCI_DEVICESRESETREG_OFFSET 0x28 +#define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT 0 +#define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK \ + (0x1 << PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT) +#define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT 1 +#define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK \ + (0x1 << PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT) +#define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT 2 +#define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK \ + (0x1 << PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT) +#define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT 3 +#define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK \ + (0x1 << PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT) +#define PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT 5 +#define PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK \ + (0x1 << PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT) +#define PRCI_DEVICESRESETREG_CHIPLINK_RST_N_SHIFT 6 +#define PRCI_DEVICESRESETREG_CHIPLINK_RST_N_MASK \ + (0x1 << PRCI_DEVICESRESETREG_CHIPLINK_RST_N_SHIFT) + +/* CLKMUXSTATUSREG */ +#define PRCI_CLKMUXSTATUSREG_OFFSET 0x2c +#define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT 1 +#define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK \ + (0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT) + +/* + * Private structures + */ + +/** + * struct __prci_data - per-device-instance data + * @va: base virtual address of the PRCI IP block + * @hw_clks: encapsulates struct clk_hw records + * + * PRCI per-device instance data + */ +struct __prci_data { + void __iomem *va; + struct clk_hw_onecell_data hw_clks; +}; + +/** + * struct __prci_wrpll_data - WRPLL configuration and integration data + * @c: WRPLL current configuration record + * @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL) + * @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL) + * @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address + * + * @enable_bypass and @disable_bypass are used for WRPLL instances + * that contain a separate external glitchless clock mux downstream + * from the PLL. The WRPLL internal bypass mux is not glitchless. + */ +struct __prci_wrpll_data { + struct wrpll_cfg c; + void (*enable_bypass)(struct __prci_data *pd); + void (*disable_bypass)(struct __prci_data *pd); + u8 cfg0_offs; +}; + +/** + * struct __prci_clock - describes a clock device managed by PRCI + * @name: user-readable clock name string - should match the manual + * @parent_name: parent name for this clock + * @ops: struct clk_ops for the Linux clock framework to use for control + * @hw: Linux-private clock data + * @pwd: WRPLL-specific data, associated with this clock (if not NULL) + * @pd: PRCI-specific data associated with this clock (if not NULL) + * + * PRCI clock data. Used by the PRCI driver to register PRCI-provided + * clocks to the Linux clock infrastructure. + */ +struct __prci_clock { + const char *name; + const char *parent_name; + const struct clk_ops *ops; + struct clk_hw hw; + struct __prci_wrpll_data *pwd; + struct __prci_data *pd; +}; + +#define clk_hw_to_prci_clock(pwd) container_of(pwd, struct __prci_clock, hw) + +/* + * struct prci_clk_desc - describes the information of clocks of each SoCs + * @clks: point to a array of __prci_clock + * @num_clks: the number of element of clks + */ +struct prci_clk_desc { + struct __prci_clock *clks; + size_t num_clks; +}; + +/* Core clock mux control */ +void sifive_prci_coreclksel_use_hfclk(struct __prci_data *pd); +void sifive_prci_coreclksel_use_corepll(struct __prci_data *pd); + +/* Linux clock framework integration */ +long sifive_prci_wrpll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate); +int sifive_prci_wrpll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate); +unsigned long sifive_prci_wrpll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate); +unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate); + +#endif /* __SIFIVE_CLK_SIFIVE_PRCI_H */ From 28108fc8a056f0fd26be17727eff212fae67a247 Mon Sep 17 00:00:00 2001 From: Zong Li Date: Wed, 9 Dec 2020 17:49:13 +0800 Subject: [PATCH 101/134] clk: sifive: Use common name for prci configuration Use generic name CLK_SIFIVE_PRCI instead of CLK_SIFIVE_FU540_PRCI. This patch is prepared for fu740 support. Signed-off-by: Zong Li Reviewed-by: Palmer Dabbelt Acked-by: Palmer Dabbelt Reviewed-by: Pragnesh Patel Link: https://lore.kernel.org/r/20201209094916.17383-3-zong.li@sifive.com Signed-off-by: Stephen Boyd --- arch/riscv/Kconfig.socs | 2 +- drivers/clk/sifive/Kconfig | 6 +++--- drivers/clk/sifive/Makefile | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs index 8a55f6156661..3284d5c291be 100644 --- a/arch/riscv/Kconfig.socs +++ b/arch/riscv/Kconfig.socs @@ -5,7 +5,7 @@ config SOC_SIFIVE select SERIAL_SIFIVE if TTY select SERIAL_SIFIVE_CONSOLE if TTY select CLK_SIFIVE - select CLK_SIFIVE_FU540_PRCI + select CLK_SIFIVE_PRCI select SIFIVE_PLIC help This enables support for SiFive SoC platform hardware. diff --git a/drivers/clk/sifive/Kconfig b/drivers/clk/sifive/Kconfig index f3b4eb9cb0f5..ab48cf7e0105 100644 --- a/drivers/clk/sifive/Kconfig +++ b/drivers/clk/sifive/Kconfig @@ -8,12 +8,12 @@ menuconfig CLK_SIFIVE if CLK_SIFIVE -config CLK_SIFIVE_FU540_PRCI - bool "PRCI driver for SiFive FU540 SoCs" +config CLK_SIFIVE_PRCI + bool "PRCI driver for SiFive SoCs" select CLK_ANALOGBITS_WRPLL_CLN28HPC help Supports the Power Reset Clock interface (PRCI) IP block found in - FU540 SoCs. If this kernel is meant to run on a SiFive FU540 SoC, + FU540 SoCs. If this kernel is meant to run on a SiFive FU540 SoC, enable this driver. endif diff --git a/drivers/clk/sifive/Makefile b/drivers/clk/sifive/Makefile index 51b6ebc359e4..3074cdbc6009 100644 --- a/drivers/clk/sifive/Makefile +++ b/drivers/clk/sifive/Makefile @@ -1,2 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_CLK_SIFIVE_FU540_PRCI) += sifive-prci.o fu540-prci.o +obj-$(CONFIG_CLK_SIFIVE_PRCI) += sifive-prci.o fu540-prci.o From efc91ae43c8d4bbf64e4b9a28113b24a74ffd58d Mon Sep 17 00:00:00 2001 From: Zong Li Date: Wed, 9 Dec 2020 17:49:14 +0800 Subject: [PATCH 102/134] clk: sifive: Add a driver for the SiFive FU740 PRCI IP block Add driver code for the SiFive FU740 PRCI IP block. This IP block handles reset and clock control for the SiFive FU740 device and implements SoC-level clock tree controls and dividers. The link of unmatched as follow, and the U740-C000 manual would be present in the same page as soon. https://www.sifive.com/boards/hifive-unmatched This driver contains bug fixes and contributions from Henry Styles Erik Danie Pragnesh Patel Signed-off-by: Zong Li Reviewed-by: Pragnesh Patel Acked-by: Palmer Dabbelt Cc: Henry Styles Cc: Erik Danie Cc: Pragnesh Patel Link: https://lore.kernel.org/r/20201209094916.17383-4-zong.li@sifive.com [sboyd@kernel.org: Include header to silence sparse] Signed-off-by: Stephen Boyd --- drivers/clk/sifive/Kconfig | 4 +- drivers/clk/sifive/Makefile | 2 +- drivers/clk/sifive/fu740-prci.c | 114 +++++++++++++++++ drivers/clk/sifive/fu740-prci.h | 21 +++ drivers/clk/sifive/sifive-prci.c | 120 ++++++++++++++++++ drivers/clk/sifive/sifive-prci.h | 88 +++++++++++++ include/dt-bindings/clock/sifive-fu740-prci.h | 23 ++++ 7 files changed, 369 insertions(+), 3 deletions(-) create mode 100644 drivers/clk/sifive/fu740-prci.c create mode 100644 drivers/clk/sifive/fu740-prci.h create mode 100644 include/dt-bindings/clock/sifive-fu740-prci.h diff --git a/drivers/clk/sifive/Kconfig b/drivers/clk/sifive/Kconfig index ab48cf7e0105..1c14eb20c066 100644 --- a/drivers/clk/sifive/Kconfig +++ b/drivers/clk/sifive/Kconfig @@ -13,7 +13,7 @@ config CLK_SIFIVE_PRCI select CLK_ANALOGBITS_WRPLL_CLN28HPC help Supports the Power Reset Clock interface (PRCI) IP block found in - FU540 SoCs. If this kernel is meant to run on a SiFive FU540 SoC, - enable this driver. + FU540/FU740 SoCs. If this kernel is meant to run on a SiFive FU540/ + FU740 SoCs, enable this driver. endif diff --git a/drivers/clk/sifive/Makefile b/drivers/clk/sifive/Makefile index 3074cdbc6009..7b06fc04e6b3 100644 --- a/drivers/clk/sifive/Makefile +++ b/drivers/clk/sifive/Makefile @@ -1,2 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_CLK_SIFIVE_PRCI) += sifive-prci.o fu540-prci.o +obj-$(CONFIG_CLK_SIFIVE_PRCI) += sifive-prci.o fu540-prci.o fu740-prci.o diff --git a/drivers/clk/sifive/fu740-prci.c b/drivers/clk/sifive/fu740-prci.c new file mode 100644 index 000000000000..69208dd1a757 --- /dev/null +++ b/drivers/clk/sifive/fu740-prci.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 SiFive, Inc. + * Copyright (C) 2020 Zong Li + */ + +#include + +#include + +#include "fu540-prci.h" +#include "sifive-prci.h" + +/* PRCI integration data for each WRPLL instance */ + +static struct __prci_wrpll_data __prci_corepll_data = { + .cfg0_offs = PRCI_COREPLLCFG0_OFFSET, + .enable_bypass = sifive_prci_coreclksel_use_hfclk, + .disable_bypass = sifive_prci_coreclksel_use_final_corepll, +}; + +static struct __prci_wrpll_data __prci_ddrpll_data = { + .cfg0_offs = PRCI_DDRPLLCFG0_OFFSET, +}; + +static struct __prci_wrpll_data __prci_gemgxlpll_data = { + .cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET, +}; + +static struct __prci_wrpll_data __prci_dvfscorepll_data = { + .cfg0_offs = PRCI_DVFSCOREPLLCFG0_OFFSET, + .enable_bypass = sifive_prci_corepllsel_use_corepll, + .disable_bypass = sifive_prci_corepllsel_use_dvfscorepll, +}; + +static struct __prci_wrpll_data __prci_hfpclkpll_data = { + .cfg0_offs = PRCI_HFPCLKPLLCFG0_OFFSET, + .enable_bypass = sifive_prci_hfpclkpllsel_use_hfclk, + .disable_bypass = sifive_prci_hfpclkpllsel_use_hfpclkpll, +}; + +static struct __prci_wrpll_data __prci_cltxpll_data = { + .cfg0_offs = PRCI_CLTXPLLCFG0_OFFSET, +}; + +/* Linux clock framework integration */ + +static const struct clk_ops sifive_fu740_prci_wrpll_clk_ops = { + .set_rate = sifive_prci_wrpll_set_rate, + .round_rate = sifive_prci_wrpll_round_rate, + .recalc_rate = sifive_prci_wrpll_recalc_rate, +}; + +static const struct clk_ops sifive_fu740_prci_wrpll_ro_clk_ops = { + .recalc_rate = sifive_prci_wrpll_recalc_rate, +}; + +static const struct clk_ops sifive_fu740_prci_tlclksel_clk_ops = { + .recalc_rate = sifive_prci_tlclksel_recalc_rate, +}; + +static const struct clk_ops sifive_fu740_prci_hfpclkplldiv_clk_ops = { + .recalc_rate = sifive_prci_hfpclkplldiv_recalc_rate, +}; + +/* List of clock controls provided by the PRCI */ +struct __prci_clock __prci_init_clocks_fu740[] = { + [PRCI_CLK_COREPLL] = { + .name = "corepll", + .parent_name = "hfclk", + .ops = &sifive_fu740_prci_wrpll_clk_ops, + .pwd = &__prci_corepll_data, + }, + [PRCI_CLK_DDRPLL] = { + .name = "ddrpll", + .parent_name = "hfclk", + .ops = &sifive_fu740_prci_wrpll_ro_clk_ops, + .pwd = &__prci_ddrpll_data, + }, + [PRCI_CLK_GEMGXLPLL] = { + .name = "gemgxlpll", + .parent_name = "hfclk", + .ops = &sifive_fu740_prci_wrpll_clk_ops, + .pwd = &__prci_gemgxlpll_data, + }, + [PRCI_CLK_DVFSCOREPLL] = { + .name = "dvfscorepll", + .parent_name = "hfclk", + .ops = &sifive_fu740_prci_wrpll_clk_ops, + .pwd = &__prci_dvfscorepll_data, + }, + [PRCI_CLK_HFPCLKPLL] = { + .name = "hfpclkpll", + .parent_name = "hfclk", + .ops = &sifive_fu740_prci_wrpll_clk_ops, + .pwd = &__prci_hfpclkpll_data, + }, + [PRCI_CLK_CLTXPLL] = { + .name = "cltxpll", + .parent_name = "hfclk", + .ops = &sifive_fu740_prci_wrpll_clk_ops, + .pwd = &__prci_cltxpll_data, + }, + [PRCI_CLK_TLCLK] = { + .name = "tlclk", + .parent_name = "corepll", + .ops = &sifive_fu740_prci_tlclksel_clk_ops, + }, + [PRCI_CLK_PCLK] = { + .name = "pclk", + .parent_name = "hfpclkpll", + .ops = &sifive_fu740_prci_hfpclkplldiv_clk_ops, + }, +}; diff --git a/drivers/clk/sifive/fu740-prci.h b/drivers/clk/sifive/fu740-prci.h new file mode 100644 index 000000000000..13ef971f7764 --- /dev/null +++ b/drivers/clk/sifive/fu740-prci.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 SiFive, Inc. + * Zong Li + */ + +#ifndef __SIFIVE_CLK_FU740_PRCI_H +#define __SIFIVE_CLK_FU740_PRCI_H + +#include "sifive-prci.h" + +#define NUM_CLOCK_FU740 8 + +extern struct __prci_clock __prci_init_clocks_fu740[NUM_CLOCK_FU740]; + +static const struct prci_clk_desc prci_clk_fu740 = { + .clks = __prci_init_clocks_fu740, + .num_clks = ARRAY_SIZE(__prci_init_clocks_fu740), +}; + +#endif /* __SIFIVE_CLK_FU740_PRCI_H */ diff --git a/drivers/clk/sifive/sifive-prci.c b/drivers/clk/sifive/sifive-prci.c index 70653d33f33f..cc4b4c6b4437 100644 --- a/drivers/clk/sifive/sifive-prci.c +++ b/drivers/clk/sifive/sifive-prci.c @@ -10,6 +10,7 @@ #include #include "sifive-prci.h" #include "fu540-prci.h" +#include "fu740-prci.h" /* * Private functions @@ -225,6 +226,18 @@ unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw, return div_u64(parent_rate, div); } +/* HFPCLK clock integration */ + +unsigned long sifive_prci_hfpclkplldiv_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct __prci_clock *pc = clk_hw_to_prci_clock(hw); + struct __prci_data *pd = pc->pd; + u32 div = __prci_readl(pd, PRCI_HFPCLKPLLDIV_OFFSET); + + return div_u64(parent_rate, div + 2); +} + /* * Core clock mux control */ @@ -270,6 +283,112 @@ void sifive_prci_coreclksel_use_corepll(struct __prci_data *pd) r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */ } +/** + * sifive_prci_coreclksel_use_final_corepll() - switch the CORECLK mux to output + * FINAL_COREPLL + * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg + * + * Switch the CORECLK mux to the final COREPLL output clock; return once + * complete. + * + * Context: Any context. Caller must prevent concurrent changes to the + * PRCI_CORECLKSEL_OFFSET register. + */ +void sifive_prci_coreclksel_use_final_corepll(struct __prci_data *pd) +{ + u32 r; + + r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); + r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK; + __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd); + + r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */ +} + +/** + * sifive_prci_corepllsel_use_dvfscorepll() - switch the COREPLL mux to + * output DVFS_COREPLL + * @pd: struct __prci_data * for the PRCI containing the COREPLL mux reg + * + * Switch the COREPLL mux to the DVFSCOREPLL output clock; return once complete. + * + * Context: Any context. Caller must prevent concurrent changes to the + * PRCI_COREPLLSEL_OFFSET register. + */ +void sifive_prci_corepllsel_use_dvfscorepll(struct __prci_data *pd) +{ + u32 r; + + r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET); + r |= PRCI_COREPLLSEL_COREPLLSEL_MASK; + __prci_writel(r, PRCI_COREPLLSEL_OFFSET, pd); + + r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET); /* barrier */ +} + +/** + * sifive_prci_corepllsel_use_corepll() - switch the COREPLL mux to + * output COREPLL + * @pd: struct __prci_data * for the PRCI containing the COREPLL mux reg + * + * Switch the COREPLL mux to the COREPLL output clock; return once complete. + * + * Context: Any context. Caller must prevent concurrent changes to the + * PRCI_COREPLLSEL_OFFSET register. + */ +void sifive_prci_corepllsel_use_corepll(struct __prci_data *pd) +{ + u32 r; + + r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET); + r &= ~PRCI_COREPLLSEL_COREPLLSEL_MASK; + __prci_writel(r, PRCI_COREPLLSEL_OFFSET, pd); + + r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET); /* barrier */ +} + +/** + * sifive_prci_hfpclkpllsel_use_hfclk() - switch the HFPCLKPLL mux to + * output HFCLK + * @pd: struct __prci_data * for the PRCI containing the HFPCLKPLL mux reg + * + * Switch the HFPCLKPLL mux to the HFCLK input source; return once complete. + * + * Context: Any context. Caller must prevent concurrent changes to the + * PRCI_HFPCLKPLLSEL_OFFSET register. + */ +void sifive_prci_hfpclkpllsel_use_hfclk(struct __prci_data *pd) +{ + u32 r; + + r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET); + r |= PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK; + __prci_writel(r, PRCI_HFPCLKPLLSEL_OFFSET, pd); + + r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET); /* barrier */ +} + +/** + * sifive_prci_hfpclkpllsel_use_hfpclkpll() - switch the HFPCLKPLL mux to + * output HFPCLKPLL + * @pd: struct __prci_data * for the PRCI containing the HFPCLKPLL mux reg + * + * Switch the HFPCLKPLL mux to the HFPCLKPLL output clock; return once complete. + * + * Context: Any context. Caller must prevent concurrent changes to the + * PRCI_HFPCLKPLLSEL_OFFSET register. + */ +void sifive_prci_hfpclkpllsel_use_hfpclkpll(struct __prci_data *pd) +{ + u32 r; + + r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET); + r &= ~PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK; + __prci_writel(r, PRCI_HFPCLKPLLSEL_OFFSET, pd); + + r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET); /* barrier */ +} + /** * __prci_register_clocks() - register clock controls in the PRCI * @dev: Linux struct device @@ -377,6 +496,7 @@ static int sifive_prci_probe(struct platform_device *pdev) static const struct of_device_id sifive_prci_of_match[] = { {.compatible = "sifive,fu540-c000-prci", .data = &prci_clk_fu540}, + {.compatible = "sifive,fu740-c000-prci", .data = &prci_clk_fu740}, {} }; diff --git a/drivers/clk/sifive/sifive-prci.h b/drivers/clk/sifive/sifive-prci.h index 280df63b4b92..7e509dfb72d1 100644 --- a/drivers/clk/sifive/sifive-prci.h +++ b/drivers/clk/sifive/sifive-prci.h @@ -117,6 +117,87 @@ #define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK \ (0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT) +/* CLTXPLLCFG0 */ +#define PRCI_CLTXPLLCFG0_OFFSET 0x30 +#define PRCI_CLTXPLLCFG0_DIVR_SHIFT 0 +#define PRCI_CLTXPLLCFG0_DIVR_MASK (0x3f << PRCI_CLTXPLLCFG0_DIVR_SHIFT) +#define PRCI_CLTXPLLCFG0_DIVF_SHIFT 6 +#define PRCI_CLTXPLLCFG0_DIVF_MASK (0x1ff << PRCI_CLTXPLLCFG0_DIVF_SHIFT) +#define PRCI_CLTXPLLCFG0_DIVQ_SHIFT 15 +#define PRCI_CLTXPLLCFG0_DIVQ_MASK (0x7 << PRCI_CLTXPLLCFG0_DIVQ_SHIFT) +#define PRCI_CLTXPLLCFG0_RANGE_SHIFT 18 +#define PRCI_CLTXPLLCFG0_RANGE_MASK (0x7 << PRCI_CLTXPLLCFG0_RANGE_SHIFT) +#define PRCI_CLTXPLLCFG0_BYPASS_SHIFT 24 +#define PRCI_CLTXPLLCFG0_BYPASS_MASK (0x1 << PRCI_CLTXPLLCFG0_BYPASS_SHIFT) +#define PRCI_CLTXPLLCFG0_FSE_SHIFT 25 +#define PRCI_CLTXPLLCFG0_FSE_MASK (0x1 << PRCI_CLTXPLLCFG0_FSE_SHIFT) +#define PRCI_CLTXPLLCFG0_LOCK_SHIFT 31 +#define PRCI_CLTXPLLCFG0_LOCK_MASK (0x1 << PRCI_CLTXPLLCFG0_LOCK_SHIFT) + +/* CLTXPLLCFG1 */ +#define PRCI_CLTXPLLCFG1_OFFSET 0x34 +#define PRCI_CLTXPLLCFG1_CKE_SHIFT 31 +#define PRCI_CLTXPLLCFG1_CKE_MASK (0x1 << PRCI_CLTXPLLCFG1_CKE_SHIFT) + +/* DVFSCOREPLLCFG0 */ +#define PRCI_DVFSCOREPLLCFG0_OFFSET 0x38 + +/* DVFSCOREPLLCFG1 */ +#define PRCI_DVFSCOREPLLCFG1_OFFSET 0x3c +#define PRCI_DVFSCOREPLLCFG1_CKE_SHIFT 31 +#define PRCI_DVFSCOREPLLCFG1_CKE_MASK (0x1 << PRCI_DVFSCOREPLLCFG1_CKE_SHIFT) + +/* COREPLLSEL */ +#define PRCI_COREPLLSEL_OFFSET 0x40 +#define PRCI_COREPLLSEL_COREPLLSEL_SHIFT 0 +#define PRCI_COREPLLSEL_COREPLLSEL_MASK \ + (0x1 << PRCI_COREPLLSEL_COREPLLSEL_SHIFT) + +/* HFPCLKPLLCFG0 */ +#define PRCI_HFPCLKPLLCFG0_OFFSET 0x50 +#define PRCI_HFPCLKPLL_CFG0_DIVR_SHIFT 0 +#define PRCI_HFPCLKPLL_CFG0_DIVR_MASK \ + (0x3f << PRCI_HFPCLKPLLCFG0_DIVR_SHIFT) +#define PRCI_HFPCLKPLL_CFG0_DIVF_SHIFT 6 +#define PRCI_HFPCLKPLL_CFG0_DIVF_MASK \ + (0x1ff << PRCI_HFPCLKPLLCFG0_DIVF_SHIFT) +#define PRCI_HFPCLKPLL_CFG0_DIVQ_SHIFT 15 +#define PRCI_HFPCLKPLL_CFG0_DIVQ_MASK \ + (0x7 << PRCI_HFPCLKPLLCFG0_DIVQ_SHIFT) +#define PRCI_HFPCLKPLL_CFG0_RANGE_SHIFT 18 +#define PRCI_HFPCLKPLL_CFG0_RANGE_MASK \ + (0x7 << PRCI_HFPCLKPLLCFG0_RANGE_SHIFT) +#define PRCI_HFPCLKPLL_CFG0_BYPASS_SHIFT 24 +#define PRCI_HFPCLKPLL_CFG0_BYPASS_MASK \ + (0x1 << PRCI_HFPCLKPLLCFG0_BYPASS_SHIFT) +#define PRCI_HFPCLKPLL_CFG0_FSE_SHIFT 25 +#define PRCI_HFPCLKPLL_CFG0_FSE_MASK \ + (0x1 << PRCI_HFPCLKPLLCFG0_FSE_SHIFT) +#define PRCI_HFPCLKPLL_CFG0_LOCK_SHIFT 31 +#define PRCI_HFPCLKPLL_CFG0_LOCK_MASK \ + (0x1 << PRCI_HFPCLKPLLCFG0_LOCK_SHIFT) + +/* HFPCLKPLLCFG1 */ +#define PRCI_HFPCLKPLLCFG1_OFFSET 0x54 +#define PRCI_HFPCLKPLLCFG1_CKE_SHIFT 31 +#define PRCI_HFPCLKPLLCFG1_CKE_MASK \ + (0x1 << PRCI_HFPCLKPLLCFG1_CKE_SHIFT) + +/* HFPCLKPLLSEL */ +#define PRCI_HFPCLKPLLSEL_OFFSET 0x58 +#define PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_SHIFT 0 +#define PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK \ + (0x1 << PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_SHIFT) + +/* HFPCLKPLLDIV */ +#define PRCI_HFPCLKPLLDIV_OFFSET 0x5c + +/* PRCIPLL */ +#define PRCI_PRCIPLL_OFFSET 0xe0 + +/* PROCMONCFG */ +#define PRCI_PROCMONCFG_OFFSET 0xf0 + /* * Private structures */ @@ -187,6 +268,11 @@ struct prci_clk_desc { /* Core clock mux control */ void sifive_prci_coreclksel_use_hfclk(struct __prci_data *pd); void sifive_prci_coreclksel_use_corepll(struct __prci_data *pd); +void sifive_prci_coreclksel_use_final_corepll(struct __prci_data *pd); +void sifive_prci_corepllsel_use_dvfscorepll(struct __prci_data *pd); +void sifive_prci_corepllsel_use_corepll(struct __prci_data *pd); +void sifive_prci_hfpclkpllsel_use_hfclk(struct __prci_data *pd); +void sifive_prci_hfpclkpllsel_use_hfpclkpll(struct __prci_data *pd); /* Linux clock framework integration */ long sifive_prci_wrpll_round_rate(struct clk_hw *hw, unsigned long rate, @@ -197,5 +283,7 @@ unsigned long sifive_prci_wrpll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate); unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw, unsigned long parent_rate); +unsigned long sifive_prci_hfpclkplldiv_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate); #endif /* __SIFIVE_CLK_SIFIVE_PRCI_H */ diff --git a/include/dt-bindings/clock/sifive-fu740-prci.h b/include/dt-bindings/clock/sifive-fu740-prci.h new file mode 100644 index 000000000000..cd7706ea5677 --- /dev/null +++ b/include/dt-bindings/clock/sifive-fu740-prci.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ +/* + * Copyright (C) 2019 SiFive, Inc. + * Wesley Terpstra + * Paul Walmsley + * Zong Li + */ + +#ifndef __DT_BINDINGS_CLOCK_SIFIVE_FU740_PRCI_H +#define __DT_BINDINGS_CLOCK_SIFIVE_FU740_PRCI_H + +/* Clock indexes for use by Device Tree data and the PRCI driver */ + +#define PRCI_CLK_COREPLL 0 +#define PRCI_CLK_DDRPLL 1 +#define PRCI_CLK_GEMGXLPLL 2 +#define PRCI_CLK_DVFSCOREPLL 3 +#define PRCI_CLK_HFPCLKPLL 4 +#define PRCI_CLK_CLTXPLL 5 +#define PRCI_CLK_TLCLK 6 +#define PRCI_CLK_PCLK 7 + +#endif /* __DT_BINDINGS_CLOCK_SIFIVE_FU740_PRCI_H */ From 263ac3908516abb0392747bbf595af2b13df5fa2 Mon Sep 17 00:00:00 2001 From: Zong Li Date: Wed, 9 Dec 2020 17:49:15 +0800 Subject: [PATCH 103/134] clk: sifive: Fix the wrong bit field shift The clk enable bit should be 31 instead of 24. Signed-off-by: Zong Li Reported-by: Pragnesh Patel Link: https://lore.kernel.org/r/20201209094916.17383-5-zong.li@sifive.com Signed-off-by: Stephen Boyd --- drivers/clk/sifive/sifive-prci.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/sifive/sifive-prci.h b/drivers/clk/sifive/sifive-prci.h index 7e509dfb72d1..88493f3b9edf 100644 --- a/drivers/clk/sifive/sifive-prci.h +++ b/drivers/clk/sifive/sifive-prci.h @@ -59,7 +59,7 @@ /* DDRPLLCFG1 */ #define PRCI_DDRPLLCFG1_OFFSET 0x10 -#define PRCI_DDRPLLCFG1_CKE_SHIFT 24 +#define PRCI_DDRPLLCFG1_CKE_SHIFT 31 #define PRCI_DDRPLLCFG1_CKE_MASK (0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT) /* GEMGXLPLLCFG0 */ @@ -81,7 +81,7 @@ /* GEMGXLPLLCFG1 */ #define PRCI_GEMGXLPLLCFG1_OFFSET 0x20 -#define PRCI_GEMGXLPLLCFG1_CKE_SHIFT 24 +#define PRCI_GEMGXLPLLCFG1_CKE_SHIFT 31 #define PRCI_GEMGXLPLLCFG1_CKE_MASK (0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT) /* CORECLKSEL */ From 732374a0b440d9a79c8412f318a25cd37ba6f4e2 Mon Sep 17 00:00:00 2001 From: Pragnesh Patel Date: Wed, 9 Dec 2020 17:49:16 +0800 Subject: [PATCH 104/134] clk: sifive: Add clock enable and disable ops Add new functions "sifive_prci_clock_enable(), sifive_prci_clock_disable() and sifive_clk_is_enabled()" to enable or disable the PRCI clock Signed-off-by: Pragnesh Patel Tested-by: Zong Li Link: https://lore.kernel.org/r/20201209094916.17383-6-zong.li@sifive.com Signed-off-by: Stephen Boyd --- drivers/clk/sifive/fu540-prci.c | 6 +++ drivers/clk/sifive/fu740-prci.c | 9 ++++ drivers/clk/sifive/sifive-prci.c | 77 ++++++++++++++++++++++++++++---- drivers/clk/sifive/sifive-prci.h | 10 +++++ 4 files changed, 93 insertions(+), 9 deletions(-) diff --git a/drivers/clk/sifive/fu540-prci.c b/drivers/clk/sifive/fu540-prci.c index 83ced24b0b94..29bab915003c 100644 --- a/drivers/clk/sifive/fu540-prci.c +++ b/drivers/clk/sifive/fu540-prci.c @@ -27,16 +27,19 @@ static struct __prci_wrpll_data __prci_corepll_data = { .cfg0_offs = PRCI_COREPLLCFG0_OFFSET, + .cfg1_offs = PRCI_COREPLLCFG1_OFFSET, .enable_bypass = sifive_prci_coreclksel_use_hfclk, .disable_bypass = sifive_prci_coreclksel_use_corepll, }; static struct __prci_wrpll_data __prci_ddrpll_data = { .cfg0_offs = PRCI_DDRPLLCFG0_OFFSET, + .cfg1_offs = PRCI_DDRPLLCFG1_OFFSET, }; static struct __prci_wrpll_data __prci_gemgxlpll_data = { .cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET, + .cfg1_offs = PRCI_GEMGXLPLLCFG1_OFFSET, }; /* Linux clock framework integration */ @@ -45,6 +48,9 @@ static const struct clk_ops sifive_fu540_prci_wrpll_clk_ops = { .set_rate = sifive_prci_wrpll_set_rate, .round_rate = sifive_prci_wrpll_round_rate, .recalc_rate = sifive_prci_wrpll_recalc_rate, + .enable = sifive_prci_clock_enable, + .disable = sifive_prci_clock_disable, + .is_enabled = sifive_clk_is_enabled, }; static const struct clk_ops sifive_fu540_prci_wrpll_ro_clk_ops = { diff --git a/drivers/clk/sifive/fu740-prci.c b/drivers/clk/sifive/fu740-prci.c index 69208dd1a757..764d1097aa51 100644 --- a/drivers/clk/sifive/fu740-prci.c +++ b/drivers/clk/sifive/fu740-prci.c @@ -15,32 +15,38 @@ static struct __prci_wrpll_data __prci_corepll_data = { .cfg0_offs = PRCI_COREPLLCFG0_OFFSET, + .cfg1_offs = PRCI_COREPLLCFG1_OFFSET, .enable_bypass = sifive_prci_coreclksel_use_hfclk, .disable_bypass = sifive_prci_coreclksel_use_final_corepll, }; static struct __prci_wrpll_data __prci_ddrpll_data = { .cfg0_offs = PRCI_DDRPLLCFG0_OFFSET, + .cfg1_offs = PRCI_DDRPLLCFG1_OFFSET, }; static struct __prci_wrpll_data __prci_gemgxlpll_data = { .cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET, + .cfg1_offs = PRCI_GEMGXLPLLCFG1_OFFSET, }; static struct __prci_wrpll_data __prci_dvfscorepll_data = { .cfg0_offs = PRCI_DVFSCOREPLLCFG0_OFFSET, + .cfg1_offs = PRCI_DVFSCOREPLLCFG1_OFFSET, .enable_bypass = sifive_prci_corepllsel_use_corepll, .disable_bypass = sifive_prci_corepllsel_use_dvfscorepll, }; static struct __prci_wrpll_data __prci_hfpclkpll_data = { .cfg0_offs = PRCI_HFPCLKPLLCFG0_OFFSET, + .cfg1_offs = PRCI_HFPCLKPLLCFG1_OFFSET, .enable_bypass = sifive_prci_hfpclkpllsel_use_hfclk, .disable_bypass = sifive_prci_hfpclkpllsel_use_hfpclkpll, }; static struct __prci_wrpll_data __prci_cltxpll_data = { .cfg0_offs = PRCI_CLTXPLLCFG0_OFFSET, + .cfg1_offs = PRCI_CLTXPLLCFG1_OFFSET, }; /* Linux clock framework integration */ @@ -49,6 +55,9 @@ static const struct clk_ops sifive_fu740_prci_wrpll_clk_ops = { .set_rate = sifive_prci_wrpll_set_rate, .round_rate = sifive_prci_wrpll_round_rate, .recalc_rate = sifive_prci_wrpll_recalc_rate, + .enable = sifive_prci_clock_enable, + .disable = sifive_prci_clock_disable, + .is_enabled = sifive_clk_is_enabled, }; static const struct clk_ops sifive_fu740_prci_wrpll_ro_clk_ops = { diff --git a/drivers/clk/sifive/sifive-prci.c b/drivers/clk/sifive/sifive-prci.c index cc4b4c6b4437..c78b042750e2 100644 --- a/drivers/clk/sifive/sifive-prci.c +++ b/drivers/clk/sifive/sifive-prci.c @@ -113,7 +113,7 @@ static u32 __prci_wrpll_pack(const struct wrpll_cfg *c) } /** - * __prci_wrpll_read_cfg() - read the WRPLL configuration from the PRCI + * __prci_wrpll_read_cfg0() - read the WRPLL configuration from the PRCI * @pd: PRCI context * @pwd: PRCI WRPLL metadata * @@ -124,14 +124,14 @@ static u32 __prci_wrpll_pack(const struct wrpll_cfg *c) * Context: Any context. Caller must prevent the records pointed to by * @pd and @pwd from changing during execution. */ -static void __prci_wrpll_read_cfg(struct __prci_data *pd, - struct __prci_wrpll_data *pwd) +static void __prci_wrpll_read_cfg0(struct __prci_data *pd, + struct __prci_wrpll_data *pwd) { __prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs)); } /** - * __prci_wrpll_write_cfg() - write WRPLL configuration into the PRCI + * __prci_wrpll_write_cfg0() - write WRPLL configuration into the PRCI * @pd: PRCI context * @pwd: PRCI WRPLL metadata * @c: WRPLL configuration record to write @@ -144,15 +144,29 @@ static void __prci_wrpll_read_cfg(struct __prci_data *pd, * Context: Any context. Caller must prevent the records pointed to by * @pd and @pwd from changing during execution. */ -static void __prci_wrpll_write_cfg(struct __prci_data *pd, - struct __prci_wrpll_data *pwd, - struct wrpll_cfg *c) +static void __prci_wrpll_write_cfg0(struct __prci_data *pd, + struct __prci_wrpll_data *pwd, + struct wrpll_cfg *c) { __prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd); memcpy(&pwd->c, c, sizeof(*c)); } +/** + * __prci_wrpll_write_cfg1() - write Clock enable/disable configuration + * into the PRCI + * @pd: PRCI context + * @pwd: PRCI WRPLL metadata + * @enable: Clock enable or disable value + */ +static void __prci_wrpll_write_cfg1(struct __prci_data *pd, + struct __prci_wrpll_data *pwd, + u32 enable) +{ + __prci_writel(enable, pwd->cfg1_offs, pd); +} + /* * Linux clock framework integration * @@ -199,16 +213,61 @@ int sifive_prci_wrpll_set_rate(struct clk_hw *hw, if (pwd->enable_bypass) pwd->enable_bypass(pd); - __prci_wrpll_write_cfg(pd, pwd, &pwd->c); + __prci_wrpll_write_cfg0(pd, pwd, &pwd->c); udelay(wrpll_calc_max_lock_us(&pwd->c)); + return 0; +} + +int sifive_clk_is_enabled(struct clk_hw *hw) +{ + struct __prci_clock *pc = clk_hw_to_prci_clock(hw); + struct __prci_wrpll_data *pwd = pc->pwd; + struct __prci_data *pd = pc->pd; + u32 r; + + r = __prci_readl(pd, pwd->cfg1_offs); + + if (r & PRCI_COREPLLCFG1_CKE_MASK) + return 1; + else + return 0; +} + +int sifive_prci_clock_enable(struct clk_hw *hw) +{ + struct __prci_clock *pc = clk_hw_to_prci_clock(hw); + struct __prci_wrpll_data *pwd = pc->pwd; + struct __prci_data *pd = pc->pd; + + if (sifive_clk_is_enabled(hw)) + return 0; + + __prci_wrpll_write_cfg1(pd, pwd, PRCI_COREPLLCFG1_CKE_MASK); + if (pwd->disable_bypass) pwd->disable_bypass(pd); return 0; } +void sifive_prci_clock_disable(struct clk_hw *hw) +{ + struct __prci_clock *pc = clk_hw_to_prci_clock(hw); + struct __prci_wrpll_data *pwd = pc->pwd; + struct __prci_data *pd = pc->pd; + u32 r; + + if (pwd->enable_bypass) + pwd->enable_bypass(pd); + + r = __prci_readl(pd, pwd->cfg1_offs); + r &= ~PRCI_COREPLLCFG1_CKE_MASK; + + __prci_wrpll_write_cfg1(pd, pwd, r); +} + /* TLCLKSEL clock integration */ unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw, @@ -427,7 +486,7 @@ static int __prci_register_clocks(struct device *dev, struct __prci_data *pd, pic->pd = pd; if (pic->pwd) - __prci_wrpll_read_cfg(pd, pic->pwd); + __prci_wrpll_read_cfg0(pd, pic->pwd); r = devm_clk_hw_register(dev, &pic->hw); if (r) { diff --git a/drivers/clk/sifive/sifive-prci.h b/drivers/clk/sifive/sifive-prci.h index 88493f3b9edf..dbdbd1722688 100644 --- a/drivers/clk/sifive/sifive-prci.h +++ b/drivers/clk/sifive/sifive-prci.h @@ -40,6 +40,11 @@ #define PRCI_COREPLLCFG0_LOCK_SHIFT 31 #define PRCI_COREPLLCFG0_LOCK_MASK (0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT) +/* COREPLLCFG1 */ +#define PRCI_COREPLLCFG1_OFFSET 0x8 +#define PRCI_COREPLLCFG1_CKE_SHIFT 31 +#define PRCI_COREPLLCFG1_CKE_MASK (0x1 << PRCI_COREPLLCFG1_CKE_SHIFT) + /* DDRPLLCFG0 */ #define PRCI_DDRPLLCFG0_OFFSET 0xc #define PRCI_DDRPLLCFG0_DIVR_SHIFT 0 @@ -220,6 +225,7 @@ struct __prci_data { * @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL) * @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL) * @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address + * @cfg1_offs: WRPLL CFG1 register offset (in bytes) from the PRCI base address * * @enable_bypass and @disable_bypass are used for WRPLL instances * that contain a separate external glitchless clock mux downstream @@ -230,6 +236,7 @@ struct __prci_wrpll_data { void (*enable_bypass)(struct __prci_data *pd); void (*disable_bypass)(struct __prci_data *pd); u8 cfg0_offs; + u8 cfg1_offs; }; /** @@ -279,6 +286,9 @@ long sifive_prci_wrpll_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate); int sifive_prci_wrpll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate); +int sifive_clk_is_enabled(struct clk_hw *hw); +int sifive_prci_clock_enable(struct clk_hw *hw); +void sifive_prci_clock_disable(struct clk_hw *hw); unsigned long sifive_prci_wrpll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate); unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw, From 2aeff9d8c8e69edd268e06a79771d71d5f46b4a3 Mon Sep 17 00:00:00 2001 From: Weiyi Lu Date: Fri, 13 Nov 2020 16:29:52 +0800 Subject: [PATCH 105/134] clk: mediatek: Make mtk_clk_register_mux() a static function mtk_clk_register_mux() should be a static function Fixes: a3ae549917f16 ("clk: mediatek: Add new clkmux register API") Signed-off-by: Weiyi Lu Link: https://lore.kernel.org/r/1605256192-31307-1-git-send-email-weiyi.lu@mediatek.com Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mux.c | 2 +- drivers/clk/mediatek/clk-mux.h | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/clk/mediatek/clk-mux.c b/drivers/clk/mediatek/clk-mux.c index 14e127e9a740..dcc1352bf13c 100644 --- a/drivers/clk/mediatek/clk-mux.c +++ b/drivers/clk/mediatek/clk-mux.c @@ -155,7 +155,7 @@ const struct clk_ops mtk_mux_gate_clr_set_upd_ops = { .set_parent = mtk_clk_mux_set_parent_setclr_lock, }; -struct clk *mtk_clk_register_mux(const struct mtk_mux *mux, +static struct clk *mtk_clk_register_mux(const struct mtk_mux *mux, struct regmap *regmap, spinlock_t *lock) { diff --git a/drivers/clk/mediatek/clk-mux.h b/drivers/clk/mediatek/clk-mux.h index f5625f4d9e6c..8e2f927dd2ff 100644 --- a/drivers/clk/mediatek/clk-mux.h +++ b/drivers/clk/mediatek/clk-mux.h @@ -77,10 +77,6 @@ extern const struct clk_ops mtk_mux_gate_clr_set_upd_ops; _width, _gate, _upd_ofs, _upd, \ CLK_SET_RATE_PARENT) -struct clk *mtk_clk_register_mux(const struct mtk_mux *mux, - struct regmap *regmap, - spinlock_t *lock); - int mtk_clk_register_muxes(const struct mtk_mux *muxes, int num, struct device_node *node, spinlock_t *lock, From bf6d43d7232511d4aadb634ec97fcbe5d49ee120 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 15 Nov 2020 23:34:32 +0300 Subject: [PATCH 106/134] clk: Add hardware-enable column to clk summary Add "hardware enable" column to the clk summary in order to show actual hardware enable-state of all clocks. The possible states are "Y/N/?", where question mark means that state is unknown, i.e. clock isn't a mux and clk-driver doesn't support is_enabled() callback for this clock. In conjunction with clk_ignore_unused, this tells us what unused clocks are left enabled after bootloader. This is also a useful aid for debugging interactions with firmware which changes clock states without notifying kernel. Signed-off-by: Dmitry Osipenko Link: https://lore.kernel.org/r/20201115203432.13934-1-digetx@gmail.com Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index f83dac54ed85..c2cbf3618680 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2931,7 +2931,14 @@ static void clk_summary_show_one(struct seq_file *s, struct clk_core *c, else seq_puts(s, "-----"); - seq_printf(s, " %6d\n", clk_core_get_scaled_duty_cycle(c, 100000)); + seq_printf(s, " %6d", clk_core_get_scaled_duty_cycle(c, 100000)); + + if (c->ops->is_enabled) + seq_printf(s, " %9c\n", clk_core_is_enabled(c) ? 'Y' : 'N'); + else if (!c->ops->enable) + seq_printf(s, " %9c\n", 'Y'); + else + seq_printf(s, " %9c\n", '?'); } static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c, @@ -2950,9 +2957,9 @@ static int clk_summary_show(struct seq_file *s, void *data) struct clk_core *c; struct hlist_head **lists = (struct hlist_head **)s->private; - seq_puts(s, " enable prepare protect duty\n"); - seq_puts(s, " clock count count count rate accuracy phase cycle\n"); - seq_puts(s, "---------------------------------------------------------------------------------------------\n"); + seq_puts(s, " enable prepare protect duty hardware\n"); + seq_puts(s, " clock count count count rate accuracy phase cycle enable\n"); + seq_puts(s, "-------------------------------------------------------------------------------------------------------\n"); clk_prepare_lock(); From 8c6239f6e95f583bb763d0228e02d4dd0fb3d492 Mon Sep 17 00:00:00 2001 From: Zhang Qilong Date: Fri, 13 Nov 2020 21:16:23 +0800 Subject: [PATCH 107/134] clk: ti: Fix memleak in ti_fapll_synth_setup If clk_register fails, we should goto free branch before function returns to prevent memleak. Fixes: 163152cbbe321 ("clk: ti: Add support for FAPLL on dm816x") Reported-by: Hulk Robot Signed-off-by: Zhang Qilong Link: https://lore.kernel.org/r/20201113131623.2098222-1-zhangqilong3@huawei.com Acked-by: Tony Lindgren Signed-off-by: Stephen Boyd --- drivers/clk/ti/fapll.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/clk/ti/fapll.c b/drivers/clk/ti/fapll.c index 95e36ba64acc..8024c6d2b9e9 100644 --- a/drivers/clk/ti/fapll.c +++ b/drivers/clk/ti/fapll.c @@ -498,6 +498,7 @@ static struct clk * __init ti_fapll_synth_setup(struct fapll_data *fd, { struct clk_init_data *init; struct fapll_synth *synth; + struct clk *clk = ERR_PTR(-ENOMEM); init = kzalloc(sizeof(*init), GFP_KERNEL); if (!init) @@ -520,13 +521,19 @@ static struct clk * __init ti_fapll_synth_setup(struct fapll_data *fd, synth->hw.init = init; synth->clk_pll = pll_clk; - return clk_register(NULL, &synth->hw); + clk = clk_register(NULL, &synth->hw); + if (IS_ERR(clk)) { + pr_err("failed to register clock\n"); + goto free; + } + + return clk; free: kfree(synth); kfree(init); - return ERR_PTR(-ENOMEM); + return clk; } static void __init ti_fapll_setup(struct device_node *node) From 66cc7af38149fefd2d8c9a47a456884bd2105c9d Mon Sep 17 00:00:00 2001 From: David Shah Date: Sun, 6 Dec 2020 12:18:51 +0100 Subject: [PATCH 108/134] clk: ti: omap5: Fix reboot DPLL lock failure when using ABE TIMERs Having the ABE DPLL ref and bypass muxes set to different inputs was causing the DPLL not to lock when TIMER8 was used, as it is in the Pyra for the backlight. This patch fixes this by setting abe_dpll_bypass_clk_mux to sys_32k_ck in omap5xxx_dt_clk_init. A similar patch may also be needed for OMAP44xx which has similar code in omap4xxx_dt_clk_init, but I have not added this as I have no hardware to test on. Signed-off-by: David Shah Signed-off-by: H. Nikolaus Schaller Link: https://lore.kernel.org/r/1d3abe2512054866cc2ea7b2592238f4fa06502a.1607253531.git.hns@goldelico.com Acked-by: Tony Lindgren Signed-off-by: Stephen Boyd --- drivers/clk/ti/clk-54xx.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/clk/ti/clk-54xx.c b/drivers/clk/ti/clk-54xx.c index 8694bc9f5fc7..f0542391ca4b 100644 --- a/drivers/clk/ti/clk-54xx.c +++ b/drivers/clk/ti/clk-54xx.c @@ -605,7 +605,7 @@ static struct ti_dt_clk omap54xx_clks[] = { int __init omap5xxx_dt_clk_init(void) { int rc; - struct clk *abe_dpll_ref, *abe_dpll, *sys_32k_ck, *usb_dpll; + struct clk *abe_dpll_ref, *abe_dpll, *abe_dpll_byp, *sys_32k_ck, *usb_dpll; ti_dt_clocks_register(omap54xx_clks); @@ -616,6 +616,16 @@ int __init omap5xxx_dt_clk_init(void) abe_dpll_ref = clk_get_sys(NULL, "abe_dpll_clk_mux"); sys_32k_ck = clk_get_sys(NULL, "sys_32k_ck"); rc = clk_set_parent(abe_dpll_ref, sys_32k_ck); + + /* + * This must also be set to sys_32k_ck to match or + * the ABE DPLL will not lock on a warm reboot when + * ABE timers are used. + */ + abe_dpll_byp = clk_get_sys(NULL, "abe_dpll_bypass_clk_mux"); + if (!rc) + rc = clk_set_parent(abe_dpll_byp, sys_32k_ck); + abe_dpll = clk_get_sys(NULL, "dpll_abe_ck"); if (!rc) rc = clk_set_rate(abe_dpll, OMAP5_DPLL_ABE_DEFFREQ); From bd91abb218e0ac4a7402d6c25d383e2a706bb511 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Tue, 13 Oct 2020 17:34:20 +0300 Subject: [PATCH 109/134] dt-bindings: clock: adi,axi-clkgen: convert old binding to yaml format This change converts the old binding for the AXI clkgen driver to a yaml format. As maintainers, added: - Lars-Peter Clausen - as original author of driver & binding - Michael Hennerich - as supporter of Analog Devices drivers Acked-by: Michael Hennerich Acked-by: Lars-Peter Clausen Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20201013143421.84188-1-alexandru.ardelean@analog.com Reviewed-by: Rob Herring Signed-off-by: Stephen Boyd --- .../bindings/clock/adi,axi-clkgen.yaml | 53 +++++++++++++++++++ .../devicetree/bindings/clock/axi-clkgen.txt | 25 --------- 2 files changed, 53 insertions(+), 25 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/adi,axi-clkgen.yaml delete mode 100644 Documentation/devicetree/bindings/clock/axi-clkgen.txt diff --git a/Documentation/devicetree/bindings/clock/adi,axi-clkgen.yaml b/Documentation/devicetree/bindings/clock/adi,axi-clkgen.yaml new file mode 100644 index 000000000000..0d06387184d6 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/adi,axi-clkgen.yaml @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/adi,axi-clkgen.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Binding for Analog Devices AXI clkgen pcore clock generator + +maintainers: + - Lars-Peter Clausen + - Michael Hennerich + +description: | + The axi_clkgen IP core is a software programmable clock generator, + that can be synthesized on various FPGA platforms. + + Link: https://wiki.analog.com/resources/fpga/docs/axi_clkgen + +properties: + compatible: + enum: + - adi,axi-clkgen-2.00.a + + clocks: + description: + Specifies the reference clock(s) from which the output frequency is + derived. This must either reference one clock if only the first clock + input is connected or two if both clock inputs are connected. + minItems: 1 + maxItems: 2 + + '#clock-cells': + const: 0 + + reg: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - '#clock-cells' + +additionalProperties: false + +examples: + - | + clock-controller@ff000000 { + compatible = "adi,axi-clkgen-2.00.a"; + #clock-cells = <0>; + reg = <0xff000000 0x1000>; + clocks = <&osc 1>; + }; diff --git a/Documentation/devicetree/bindings/clock/axi-clkgen.txt b/Documentation/devicetree/bindings/clock/axi-clkgen.txt deleted file mode 100644 index aca94fe9416f..000000000000 --- a/Documentation/devicetree/bindings/clock/axi-clkgen.txt +++ /dev/null @@ -1,25 +0,0 @@ -Binding for the axi-clkgen clock generator - -This binding uses the common clock binding[1]. - -[1] Documentation/devicetree/bindings/clock/clock-bindings.txt - -Required properties: -- compatible : shall be "adi,axi-clkgen-1.00.a" or "adi,axi-clkgen-2.00.a". -- #clock-cells : from common clock binding; Should always be set to 0. -- reg : Address and length of the axi-clkgen register set. -- clocks : Phandle and clock specifier for the parent clock(s). This must - either reference one clock if only the first clock input is connected or two - if both clock inputs are connected. For the later case the clock connected - to the first input must be specified first. - -Optional properties: -- clock-output-names : From common clock binding. - -Example: - clock@ff000000 { - compatible = "adi,axi-clkgen"; - #clock-cells = <0>; - reg = <0xff000000 0x1000>; - clocks = <&osc 1>; - }; From ac1ee86a9cdb002b0c130cfbad668dd992a0596a Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 3 Dec 2020 09:40:36 +0200 Subject: [PATCH 110/134] clk: axi-clkgen: wrap limits in a struct and keep copy on the state object Up until the these limits were global/hard-coded, since they are typically limits of the fabric. However, since this is an FPGA generated clock, this may run on setups where one clock is on a fabric, and another one synthesized on another fabric connected via PCIe (or some other inter-connect, and then these limits need to be adjusted for each instance of the AXI CLKGEN. This change wraps the current constants in 'axi_clkgen_limits' struct and the 'axi_clkgen' instance keeps a copy of these limits, which is initialized at probe from the default limits. The limits are stored on the device-tree OF table, so that we can adjust them via the compatible string. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20201203074037.26940-1-alexandru.ardelean@analog.com Signed-off-by: Stephen Boyd --- drivers/clk/clk-axi-clkgen.c | 48 +++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/drivers/clk/clk-axi-clkgen.c b/drivers/clk/clk-axi-clkgen.c index 14d803e6af62..963a62e9c728 100644 --- a/drivers/clk/clk-axi-clkgen.c +++ b/drivers/clk/clk-axi-clkgen.c @@ -46,9 +46,17 @@ #define MMCM_CLK_DIV_DIVIDE BIT(11) #define MMCM_CLK_DIV_NOCOUNT BIT(12) +struct axi_clkgen_limits { + unsigned int fpfd_min; + unsigned int fpfd_max; + unsigned int fvco_min; + unsigned int fvco_max; +}; + struct axi_clkgen { void __iomem *base; struct clk_hw clk_hw; + struct axi_clkgen_limits limits; }; static uint32_t axi_clkgen_lookup_filter(unsigned int m) @@ -100,12 +108,15 @@ static uint32_t axi_clkgen_lookup_lock(unsigned int m) return 0x1f1f00fa; } -static const unsigned int fpfd_min = 10000; -static const unsigned int fpfd_max = 300000; -static const unsigned int fvco_min = 600000; -static const unsigned int fvco_max = 1200000; +static const struct axi_clkgen_limits axi_clkgen_zynq_default_limits = { + .fpfd_min = 10000, + .fpfd_max = 300000, + .fvco_min = 600000, + .fvco_max = 1200000, +}; -static void axi_clkgen_calc_params(unsigned long fin, unsigned long fout, +static void axi_clkgen_calc_params(const struct axi_clkgen_limits *limits, + unsigned long fin, unsigned long fout, unsigned int *best_d, unsigned int *best_m, unsigned int *best_dout) { unsigned long d, d_min, d_max, _d_min, _d_max; @@ -122,12 +133,12 @@ static void axi_clkgen_calc_params(unsigned long fin, unsigned long fout, *best_m = 0; *best_dout = 0; - d_min = max_t(unsigned long, DIV_ROUND_UP(fin, fpfd_max), 1); - d_max = min_t(unsigned long, fin / fpfd_min, 80); + d_min = max_t(unsigned long, DIV_ROUND_UP(fin, limits->fpfd_max), 1); + d_max = min_t(unsigned long, fin / limits->fpfd_min, 80); again: - fvco_min_fract = fvco_min << fract_shift; - fvco_max_fract = fvco_max << fract_shift; + fvco_min_fract = limits->fvco_min << fract_shift; + fvco_max_fract = limits->fvco_max << fract_shift; m_min = max_t(unsigned long, DIV_ROUND_UP(fvco_min_fract, fin) * d_min, 1); m_max = min_t(unsigned long, fvco_max_fract * d_max / fin, 64 << fract_shift); @@ -319,6 +330,7 @@ static int axi_clkgen_set_rate(struct clk_hw *clk_hw, unsigned long rate, unsigned long parent_rate) { struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw); + const struct axi_clkgen_limits *limits = &axi_clkgen->limits; unsigned int d, m, dout; struct axi_clkgen_div_params params; uint32_t power = 0; @@ -328,7 +340,7 @@ static int axi_clkgen_set_rate(struct clk_hw *clk_hw, if (parent_rate == 0 || rate == 0) return -EINVAL; - axi_clkgen_calc_params(parent_rate, rate, &d, &m, &dout); + axi_clkgen_calc_params(limits, parent_rate, rate, &d, &m, &dout); if (d == 0 || dout == 0 || m == 0) return -EINVAL; @@ -368,10 +380,12 @@ static int axi_clkgen_set_rate(struct clk_hw *clk_hw, static long axi_clkgen_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { + struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(hw); + const struct axi_clkgen_limits *limits = &axi_clkgen->limits; unsigned int d, m, dout; unsigned long long tmp; - axi_clkgen_calc_params(*parent_rate, rate, &d, &m, &dout); + axi_clkgen_calc_params(limits, *parent_rate, rate, &d, &m, &dout); if (d == 0 || dout == 0 || m == 0) return -EINVAL; @@ -485,6 +499,7 @@ static const struct clk_ops axi_clkgen_ops = { static const struct of_device_id axi_clkgen_ids[] = { { .compatible = "adi,axi-clkgen-2.00.a", + .data = &axi_clkgen_zynq_default_limits, }, { }, }; @@ -492,7 +507,7 @@ MODULE_DEVICE_TABLE(of, axi_clkgen_ids); static int axi_clkgen_probe(struct platform_device *pdev) { - const struct of_device_id *id; + const struct axi_clkgen_limits *dflt_limits; struct axi_clkgen *axi_clkgen; struct clk_init_data init; const char *parent_names[2]; @@ -501,11 +516,8 @@ static int axi_clkgen_probe(struct platform_device *pdev) unsigned int i; int ret; - if (!pdev->dev.of_node) - return -ENODEV; - - id = of_match_node(axi_clkgen_ids, pdev->dev.of_node); - if (!id) + dflt_limits = device_get_match_data(&pdev->dev); + if (!dflt_limits) return -ENODEV; axi_clkgen = devm_kzalloc(&pdev->dev, sizeof(*axi_clkgen), GFP_KERNEL); @@ -527,6 +539,8 @@ static int axi_clkgen_probe(struct platform_device *pdev) return -EINVAL; } + memcpy(&axi_clkgen->limits, dflt_limits, sizeof(axi_clkgen->limits)); + clk_name = pdev->dev.of_node->name; of_property_read_string(pdev->dev.of_node, "clock-output-names", &clk_name); From 16214f97f44321a48985ef37f5ca2d5b2479b8f2 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 3 Dec 2020 09:40:37 +0200 Subject: [PATCH 111/134] clk: axi-clkgen: move the OF table at the bottom of the file The change is mostly cosmetic. No functional changes. Since the driver now uses of_device_get_match_data() to obtain some driver specific info, there is no need to define the OF table before the probe function. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20201203074037.26940-2-alexandru.ardelean@analog.com Signed-off-by: Stephen Boyd --- drivers/clk/clk-axi-clkgen.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/clk/clk-axi-clkgen.c b/drivers/clk/clk-axi-clkgen.c index 963a62e9c728..ad86e031ba3e 100644 --- a/drivers/clk/clk-axi-clkgen.c +++ b/drivers/clk/clk-axi-clkgen.c @@ -496,15 +496,6 @@ static const struct clk_ops axi_clkgen_ops = { .get_parent = axi_clkgen_get_parent, }; -static const struct of_device_id axi_clkgen_ids[] = { - { - .compatible = "adi,axi-clkgen-2.00.a", - .data = &axi_clkgen_zynq_default_limits, - }, - { }, -}; -MODULE_DEVICE_TABLE(of, axi_clkgen_ids); - static int axi_clkgen_probe(struct platform_device *pdev) { const struct axi_clkgen_limits *dflt_limits; @@ -568,6 +559,15 @@ static int axi_clkgen_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id axi_clkgen_ids[] = { + { + .compatible = "adi,axi-clkgen-2.00.a", + .data = &axi_clkgen_zynq_default_limits, + }, + { } +}; +MODULE_DEVICE_TABLE(of, axi_clkgen_ids); + static struct platform_driver axi_clkgen_driver = { .driver = { .name = "adi-axi-clkgen", From 03813d9b7d4368d4a8c9bb8f5a2a1e23dac8f1b5 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 7 Dec 2020 11:50:50 +0100 Subject: [PATCH 112/134] clk: Trace clk_set_rate() "range" functions The clk_set_rate "range" functions don't have any tracepoints even though it might be useful. Add some. Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20201207105050.2096917-1-maxime@cerno.tech [sboyd@kernel.org: Reword commit text] Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 6 ++++++ include/trace/events/clk.h | 44 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index f83dac54ed85..b98415d280c8 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2314,6 +2314,8 @@ int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max) if (!clk) return 0; + trace_clk_set_rate_range(clk->core, min, max); + if (min > max) { pr_err("%s: clk %s dev %s con %s: invalid range [%lu, %lu]\n", __func__, clk->core->name, clk->dev_id, clk->con_id, @@ -2381,6 +2383,8 @@ int clk_set_min_rate(struct clk *clk, unsigned long rate) if (!clk) return 0; + trace_clk_set_min_rate(clk->core, rate); + return clk_set_rate_range(clk, rate, clk->max_rate); } EXPORT_SYMBOL_GPL(clk_set_min_rate); @@ -2397,6 +2401,8 @@ int clk_set_max_rate(struct clk *clk, unsigned long rate) if (!clk) return 0; + trace_clk_set_max_rate(clk->core, rate); + return clk_set_rate_range(clk, clk->min_rate, rate); } EXPORT_SYMBOL_GPL(clk_set_max_rate); diff --git a/include/trace/events/clk.h b/include/trace/events/clk.h index cb1aea25c199..e19edc63ee95 100644 --- a/include/trace/events/clk.h +++ b/include/trace/events/clk.h @@ -118,6 +118,50 @@ DEFINE_EVENT(clk_rate, clk_set_rate_complete, TP_ARGS(core, rate) ); +DEFINE_EVENT(clk_rate, clk_set_min_rate, + + TP_PROTO(struct clk_core *core, unsigned long rate), + + TP_ARGS(core, rate) +); + +DEFINE_EVENT(clk_rate, clk_set_max_rate, + + TP_PROTO(struct clk_core *core, unsigned long rate), + + TP_ARGS(core, rate) +); + +DECLARE_EVENT_CLASS(clk_rate_range, + + TP_PROTO(struct clk_core *core, unsigned long min, unsigned long max), + + TP_ARGS(core, min, max), + + TP_STRUCT__entry( + __string( name, core->name ) + __field(unsigned long, min ) + __field(unsigned long, max ) + ), + + TP_fast_assign( + __assign_str(name, core->name); + __entry->min = min; + __entry->max = max; + ), + + TP_printk("%s min %lu max %lu", __get_str(name), + (unsigned long)__entry->min, + (unsigned long)__entry->max) +); + +DEFINE_EVENT(clk_rate_range, clk_set_rate_range, + + TP_PROTO(struct clk_core *core, unsigned long min, unsigned long max), + + TP_ARGS(core, min, max) +); + DECLARE_EVENT_CLASS(clk_parent, TP_PROTO(struct clk_core *core, struct clk_core *parent), From c82cf05190d482bb3546dffd6a337f38e105daf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 20 Nov 2020 14:21:21 +0100 Subject: [PATCH 113/134] clk: bcm: dvp: drop a variable that is assigned to only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The third parameter to devm_platform_get_and_ioremap_resource() is used only to provide the used resource. As this variable isn't used afterwards, switch to the function devm_platform_ioremap_resource() which doesn't provide this output parameter. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20201120132121.2678997-1-u.kleine-koenig@pengutronix.de Reviewed-by: Nicolas Saenz Julienne Signed-off-by: Stephen Boyd --- drivers/clk/bcm/clk-bcm2711-dvp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/clk/bcm/clk-bcm2711-dvp.c b/drivers/clk/bcm/clk-bcm2711-dvp.c index 8333e20dc9d2..6696200ecf7e 100644 --- a/drivers/clk/bcm/clk-bcm2711-dvp.c +++ b/drivers/clk/bcm/clk-bcm2711-dvp.c @@ -25,7 +25,6 @@ static const struct clk_parent_data clk_dvp_parent = { static int clk_dvp_probe(struct platform_device *pdev) { struct clk_hw_onecell_data *data; - struct resource *res; struct clk_dvp *dvp; void __iomem *base; int ret; @@ -42,7 +41,7 @@ static int clk_dvp_probe(struct platform_device *pdev) return -ENOMEM; data = dvp->data; - base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); From be439cc4c404f646a8ba090fa786d53c10926b12 Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Wed, 2 Dec 2020 11:35:18 +0100 Subject: [PATCH 114/134] clk: bcm: dvp: Add MODULE_DEVICE_TABLE() Add MODULE_DEVICE_TABLE() so as to be able to use the driver as a module. More precisely, for the driver to be loaded automatically at boot. Fixes: 1bc95972715a ("clk: bcm: Add BCM2711 DVP driver") Signed-off-by: Nicolas Saenz Julienne Link: https://lore.kernel.org/r/20201202103518.21889-1-nsaenzjulienne@suse.de Reviewed-by: Maxime Ripard Signed-off-by: Stephen Boyd --- drivers/clk/bcm/clk-bcm2711-dvp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/bcm/clk-bcm2711-dvp.c b/drivers/clk/bcm/clk-bcm2711-dvp.c index 6696200ecf7e..e63a42618ac2 100644 --- a/drivers/clk/bcm/clk-bcm2711-dvp.c +++ b/drivers/clk/bcm/clk-bcm2711-dvp.c @@ -107,6 +107,7 @@ static const struct of_device_id clk_dvp_dt_ids[] = { { .compatible = "brcm,brcm2711-dvp", }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, clk_dvp_dt_ids); static struct platform_driver clk_dvp_driver = { .probe = clk_dvp_probe, From 91274497c79170aaadc491d4ffe4de35495a060d Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 19 Nov 2020 17:43:07 +0200 Subject: [PATCH 115/134] clk: at91: sama7g5: fix compilation error pmc_data_allocate() has been changed. pmc_data_free() was removed. Adapt the code taking this into consideration. With this the programmable clocks were also saved in sama7g5_pmc so that they could be later referenced. Fixes: cb783bbbcf54 ("clk: at91: sama7g5: add clock support for sama7g5") Signed-off-by: Claudiu Beznea Reviewed-by: Tudor Ambarus Tested-by: Tudor Ambarus Link: https://lore.kernel.org/r/1605800597-16720-2-git-send-email-claudiu.beznea@microchip.com Signed-off-by: Stephen Boyd --- drivers/clk/at91/sama7g5.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c index 0db2ab3eca14..a092a940baa4 100644 --- a/drivers/clk/at91/sama7g5.c +++ b/drivers/clk/at91/sama7g5.c @@ -838,7 +838,7 @@ static void __init sama7g5_pmc_setup(struct device_node *np) sama7g5_pmc = pmc_data_allocate(PMC_I2S1_MUX + 1, nck(sama7g5_systemck), nck(sama7g5_periphck), - nck(sama7g5_gck)); + nck(sama7g5_gck), 8); if (!sama7g5_pmc) return; @@ -980,6 +980,8 @@ static void __init sama7g5_pmc_setup(struct device_node *np) sama7g5_prog_mux_table); if (IS_ERR(hw)) goto err_free; + + sama7g5_pmc->pchws[i] = hw; } for (i = 0; i < ARRAY_SIZE(sama7g5_systemck); i++) { @@ -1052,7 +1054,7 @@ err_free: kfree(alloc_mem); } - pmc_data_free(sama7g5_pmc); + kfree(sama7g5_pmc); } /* Some clks are used for a clocksource */ From 3d86ee17d4670406d07f92da6fa4f2aa82cdc5a2 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Thu, 19 Nov 2020 17:43:08 +0200 Subject: [PATCH 116/134] dt-bindings: clock: at91: add sama7g5 pll defines Add SAMA7G5 specific PLL defines to be referenced in a phandle as a PMC_TYPE_CORE clock. Suggested-by: Claudiu Beznea Signed-off-by: Eugen Hristev [claudiu.beznea@microchip.com: adapt comit message, adapt sama7g5.c] Signed-off-by: Claudiu Beznea Link: https://lore.kernel.org/r/1605800597-16720-3-git-send-email-claudiu.beznea@microchip.com Signed-off-by: Stephen Boyd --- drivers/clk/at91/sama7g5.c | 6 +++--- include/dt-bindings/clock/at91.h | 10 ++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c index a092a940baa4..7ef7963126b6 100644 --- a/drivers/clk/at91/sama7g5.c +++ b/drivers/clk/at91/sama7g5.c @@ -182,13 +182,13 @@ static const struct { .p = "audiopll_fracck", .l = &pll_layout_divpmc, .t = PLL_TYPE_DIV, - .eid = PMC_I2S0_MUX, }, + .eid = PMC_AUDIOPMCPLL, }, { .n = "audiopll_diviock", .p = "audiopll_fracck", .l = &pll_layout_divio, .t = PLL_TYPE_DIV, - .eid = PMC_I2S1_MUX, }, + .eid = PMC_AUDIOIOPLL, }, }, [PLL_ID_ETH] = { @@ -835,7 +835,7 @@ static void __init sama7g5_pmc_setup(struct device_node *np) if (IS_ERR(regmap)) return; - sama7g5_pmc = pmc_data_allocate(PMC_I2S1_MUX + 1, + sama7g5_pmc = pmc_data_allocate(PMC_ETHPLL + 1, nck(sama7g5_systemck), nck(sama7g5_periphck), nck(sama7g5_gck), 8); diff --git a/include/dt-bindings/clock/at91.h b/include/dt-bindings/clock/at91.h index eba17106608b..fab313f62e8f 100644 --- a/include/dt-bindings/clock/at91.h +++ b/include/dt-bindings/clock/at91.h @@ -25,6 +25,16 @@ #define PMC_PLLBCK 8 #define PMC_AUDIOPLLCK 9 +/* SAMA7G5 */ +#define PMC_CPUPLL (PMC_MAIN + 1) +#define PMC_SYSPLL (PMC_MAIN + 2) +#define PMC_DDRPLL (PMC_MAIN + 3) +#define PMC_IMGPLL (PMC_MAIN + 4) +#define PMC_BAUDPLL (PMC_MAIN + 5) +#define PMC_AUDIOPMCPLL (PMC_MAIN + 6) +#define PMC_AUDIOIOPLL (PMC_MAIN + 7) +#define PMC_ETHPLL (PMC_MAIN + 8) + #ifndef AT91_PMC_MOSCS #define AT91_PMC_MOSCS 0 /* MOSCS Flag */ #define AT91_PMC_LOCKA 1 /* PLLA Lock */ From 83d002877365afac2cb65ef4ad36b445652ebda3 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Thu, 19 Nov 2020 17:43:09 +0200 Subject: [PATCH 117/134] clk: at91: sama7g5: allow SYS and CPU PLLs to be exported and referenced in DT Allow SYSPLL and CPUPLL to be referenced as a PMC_TYPE_CORE clock from phandle in DT. Suggested-by: Claudiu Beznea Signed-off-by: Eugen Hristev [claudiu.beznea@microchip.com: adapt commit message, add CPU PLL] Signed-off-by: Claudiu Beznea Link: https://lore.kernel.org/r/1605800597-16720-4-git-send-email-claudiu.beznea@microchip.com Signed-off-by: Stephen Boyd --- drivers/clk/at91/sama7g5.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c index 7ef7963126b6..d3c3469d47d9 100644 --- a/drivers/clk/at91/sama7g5.c +++ b/drivers/clk/at91/sama7g5.c @@ -117,7 +117,8 @@ static const struct { .p = "cpupll_fracck", .l = &pll_layout_divpmc, .t = PLL_TYPE_DIV, - .c = 1, }, + .c = 1, + .eid = PMC_CPUPLL, }, }, [PLL_ID_SYS] = { @@ -131,7 +132,8 @@ static const struct { .p = "syspll_fracck", .l = &pll_layout_divpmc, .t = PLL_TYPE_DIV, - .c = 1, }, + .c = 1, + .eid = PMC_SYSPLL, }, }, [PLL_ID_DDR] = { From e26b3006ff07020e509fb9e0e560e462ff4077c9 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Thu, 19 Nov 2020 17:43:10 +0200 Subject: [PATCH 118/134] clk: at91: clk-master: add 5th divisor for mck master clk-master can have 5 divisors with a field width of 3 bits on some products. Change the mask and number of divisors accordingly. Reported-by: Mihai Sain Signed-off-by: Eugen Hristev Signed-off-by: Claudiu Beznea Link: https://lore.kernel.org/r/1605800597-16720-5-git-send-email-claudiu.beznea@microchip.com Signed-off-by: Stephen Boyd --- drivers/clk/at91/clk-master.c | 2 +- drivers/clk/at91/pmc.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c index bd0d8a69a2cf..aafd003b30cf 100644 --- a/drivers/clk/at91/clk-master.c +++ b/drivers/clk/at91/clk-master.c @@ -15,7 +15,7 @@ #define MASTER_PRES_MASK 0x7 #define MASTER_PRES_MAX MASTER_PRES_MASK #define MASTER_DIV_SHIFT 8 -#define MASTER_DIV_MASK 0x3 +#define MASTER_DIV_MASK 0x7 #define PMC_MCR 0x30 #define PMC_MCR_ID_MSK GENMASK(3, 0) diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 7b86affc6d7c..0a9364bde339 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -48,7 +48,7 @@ extern const struct clk_master_layout at91sam9x5_master_layout; struct clk_master_characteristics { struct clk_range output; - u32 divisors[4]; + u32 divisors[5]; u8 have_div3_pres; }; From 0bb4623f13d46b2ea054777accff0c41af8036be Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Thu, 19 Nov 2020 17:43:11 +0200 Subject: [PATCH 119/134] clk: at91: sama7g5: add 5th divisor for mck0 layout and characteristics This SoC has the 5th divisor for the mck0 master clock. Adapt the characteristics accordingly. Reported-by: Mihai Sain Signed-off-by: Eugen Hristev Signed-off-by: Claudiu Beznea Link: https://lore.kernel.org/r/1605800597-16720-6-git-send-email-claudiu.beznea@microchip.com Signed-off-by: Stephen Boyd --- drivers/clk/at91/sama7g5.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c index d3c3469d47d9..d685e22b2014 100644 --- a/drivers/clk/at91/sama7g5.c +++ b/drivers/clk/at91/sama7g5.c @@ -775,13 +775,13 @@ static const struct clk_pll_characteristics pll_characteristics = { /* MCK0 characteristics. */ static const struct clk_master_characteristics mck0_characteristics = { .output = { .min = 140000000, .max = 200000000 }, - .divisors = { 1, 2, 4, 3 }, + .divisors = { 1, 2, 4, 3, 5 }, .have_div3_pres = 1, }; /* MCK0 layout. */ static const struct clk_master_layout mck0_layout = { - .mask = 0x373, + .mask = 0x773, .pres_shift = 4, .offset = 0x28, }; From 8dc4af8bef127425271e06d09370a2479dae69c3 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 19 Nov 2020 17:43:12 +0200 Subject: [PATCH 120/134] clk: at91: clk-sam9x60-pll: allow runtime changes for pll Allow runtime frequency changes for PLLs registered with proper flags. This is necessary for CPU PLL on SAMA7G5 which is used by DVFS. Signed-off-by: Claudiu Beznea Link: https://lore.kernel.org/r/1605800597-16720-7-git-send-email-claudiu.beznea@microchip.com Signed-off-by: Stephen Boyd --- drivers/clk/at91/clk-sam9x60-pll.c | 145 +++++++++++++++++++++++++---- drivers/clk/at91/pmc.h | 4 +- drivers/clk/at91/sam9x60.c | 22 ++++- drivers/clk/at91/sama7g5.c | 67 +++++++++---- 4 files changed, 197 insertions(+), 41 deletions(-) diff --git a/drivers/clk/at91/clk-sam9x60-pll.c b/drivers/clk/at91/clk-sam9x60-pll.c index 78f458a7b2ef..34e3ab13741a 100644 --- a/drivers/clk/at91/clk-sam9x60-pll.c +++ b/drivers/clk/at91/clk-sam9x60-pll.c @@ -229,6 +229,57 @@ static int sam9x60_frac_pll_set_rate(struct clk_hw *hw, unsigned long rate, return sam9x60_frac_pll_compute_mul_frac(core, rate, parent_rate, true); } +static int sam9x60_frac_pll_set_rate_chg(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw); + struct sam9x60_frac *frac = to_sam9x60_frac(core); + struct regmap *regmap = core->regmap; + unsigned long irqflags; + unsigned int val, cfrac, cmul; + long ret; + + ret = sam9x60_frac_pll_compute_mul_frac(core, rate, parent_rate, true); + if (ret <= 0) + return ret; + + spin_lock_irqsave(core->lock, irqflags); + + regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK, + core->id); + regmap_read(regmap, AT91_PMC_PLL_CTRL1, &val); + cmul = (val & core->layout->mul_mask) >> core->layout->mul_shift; + cfrac = (val & core->layout->frac_mask) >> core->layout->frac_shift; + + if (cmul == frac->mul && cfrac == frac->frac) + goto unlock; + + regmap_write(regmap, AT91_PMC_PLL_CTRL1, + (frac->mul << core->layout->mul_shift) | + (frac->frac << core->layout->frac_shift)); + + regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, + AT91_PMC_PLL_UPDT_UPDATE | core->id); + + regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0, + AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL, + AT91_PMC_PLL_CTRL0_ENLOCK | + AT91_PMC_PLL_CTRL0_ENPLL); + + regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, + AT91_PMC_PLL_UPDT_UPDATE | core->id); + + while (!sam9x60_pll_ready(regmap, core->id)) + cpu_relax(); + +unlock: + spin_unlock_irqrestore(core->lock, irqflags); + + return ret; +} + static const struct clk_ops sam9x60_frac_pll_ops = { .prepare = sam9x60_frac_pll_prepare, .unprepare = sam9x60_frac_pll_unprepare, @@ -238,6 +289,15 @@ static const struct clk_ops sam9x60_frac_pll_ops = { .set_rate = sam9x60_frac_pll_set_rate, }; +static const struct clk_ops sam9x60_frac_pll_ops_chg = { + .prepare = sam9x60_frac_pll_prepare, + .unprepare = sam9x60_frac_pll_unprepare, + .is_prepared = sam9x60_frac_pll_is_prepared, + .recalc_rate = sam9x60_frac_pll_recalc_rate, + .round_rate = sam9x60_frac_pll_round_rate, + .set_rate = sam9x60_frac_pll_set_rate_chg, +}; + static int sam9x60_div_pll_prepare(struct clk_hw *hw) { struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw); @@ -384,6 +444,44 @@ static int sam9x60_div_pll_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } +static int sam9x60_div_pll_set_rate_chg(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw); + struct sam9x60_div *div = to_sam9x60_div(core); + struct regmap *regmap = core->regmap; + unsigned long irqflags; + unsigned int val, cdiv; + + div->div = DIV_ROUND_CLOSEST(parent_rate, rate) - 1; + + spin_lock_irqsave(core->lock, irqflags); + regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK, + core->id); + regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val); + cdiv = (val & core->layout->div_mask) >> core->layout->div_shift; + + /* Stop if nothing changed. */ + if (cdiv == div->div) + goto unlock; + + regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0, + core->layout->div_mask, + (div->div << core->layout->div_shift)); + + regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, + AT91_PMC_PLL_UPDT_UPDATE | core->id); + + while (!sam9x60_pll_ready(regmap, core->id)) + cpu_relax(); + +unlock: + spin_unlock_irqrestore(core->lock, irqflags); + + return 0; +} + static const struct clk_ops sam9x60_div_pll_ops = { .prepare = sam9x60_div_pll_prepare, .unprepare = sam9x60_div_pll_unprepare, @@ -393,17 +491,26 @@ static const struct clk_ops sam9x60_div_pll_ops = { .set_rate = sam9x60_div_pll_set_rate, }; +static const struct clk_ops sam9x60_div_pll_ops_chg = { + .prepare = sam9x60_div_pll_prepare, + .unprepare = sam9x60_div_pll_unprepare, + .is_prepared = sam9x60_div_pll_is_prepared, + .recalc_rate = sam9x60_div_pll_recalc_rate, + .round_rate = sam9x60_div_pll_round_rate, + .set_rate = sam9x60_div_pll_set_rate_chg, +}; + struct clk_hw * __init sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock, const char *name, const char *parent_name, struct clk_hw *parent_hw, u8 id, const struct clk_pll_characteristics *characteristics, - const struct clk_pll_layout *layout, bool critical) + const struct clk_pll_layout *layout, u32 flags) { struct sam9x60_frac *frac; struct clk_hw *hw; struct clk_init_data init; - unsigned long parent_rate, flags; + unsigned long parent_rate, irqflags; unsigned int val; int ret; @@ -417,10 +524,12 @@ sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock, init.name = name; init.parent_names = &parent_name; init.num_parents = 1; - init.ops = &sam9x60_frac_pll_ops; - init.flags = CLK_SET_RATE_GATE; - if (critical) - init.flags |= CLK_IS_CRITICAL; + if (flags & CLK_SET_RATE_GATE) + init.ops = &sam9x60_frac_pll_ops; + else + init.ops = &sam9x60_frac_pll_ops_chg; + + init.flags = flags; frac->core.id = id; frac->core.hw.init = &init; @@ -429,7 +538,7 @@ sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock, frac->core.regmap = regmap; frac->core.lock = lock; - spin_lock_irqsave(frac->core.lock, flags); + spin_lock_irqsave(frac->core.lock, irqflags); if (sam9x60_pll_ready(regmap, id)) { regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK, id); @@ -457,7 +566,7 @@ sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock, goto free; } } - spin_unlock_irqrestore(frac->core.lock, flags); + spin_unlock_irqrestore(frac->core.lock, irqflags); hw = &frac->core.hw; ret = clk_hw_register(NULL, hw); @@ -469,7 +578,7 @@ sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock, return hw; free: - spin_unlock_irqrestore(frac->core.lock, flags); + spin_unlock_irqrestore(frac->core.lock, irqflags); kfree(frac); return hw; } @@ -478,12 +587,12 @@ struct clk_hw * __init sam9x60_clk_register_div_pll(struct regmap *regmap, spinlock_t *lock, const char *name, const char *parent_name, u8 id, const struct clk_pll_characteristics *characteristics, - const struct clk_pll_layout *layout, bool critical) + const struct clk_pll_layout *layout, u32 flags) { struct sam9x60_div *div; struct clk_hw *hw; struct clk_init_data init; - unsigned long flags; + unsigned long irqflags; unsigned int val; int ret; @@ -497,11 +606,11 @@ sam9x60_clk_register_div_pll(struct regmap *regmap, spinlock_t *lock, init.name = name; init.parent_names = &parent_name; init.num_parents = 1; - init.ops = &sam9x60_div_pll_ops; - init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | - CLK_SET_RATE_PARENT; - if (critical) - init.flags |= CLK_IS_CRITICAL; + if (flags & CLK_SET_RATE_GATE) + init.ops = &sam9x60_div_pll_ops; + else + init.ops = &sam9x60_div_pll_ops_chg; + init.flags = flags; div->core.id = id; div->core.hw.init = &init; @@ -510,14 +619,14 @@ sam9x60_clk_register_div_pll(struct regmap *regmap, spinlock_t *lock, div->core.regmap = regmap; div->core.lock = lock; - spin_lock_irqsave(div->core.lock, flags); + spin_lock_irqsave(div->core.lock, irqflags); regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK, id); regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val); div->div = FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, val); - spin_unlock_irqrestore(div->core.lock, flags); + spin_unlock_irqrestore(div->core.lock, irqflags); hw = &div->core.hw; ret = clk_hw_register(NULL, hw); diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 0a9364bde339..bedcd85ad750 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -190,14 +190,14 @@ struct clk_hw * __init sam9x60_clk_register_div_pll(struct regmap *regmap, spinlock_t *lock, const char *name, const char *parent_name, u8 id, const struct clk_pll_characteristics *characteristics, - const struct clk_pll_layout *layout, bool critical); + const struct clk_pll_layout *layout, u32 flags); struct clk_hw * __init sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock, const char *name, const char *parent_name, struct clk_hw *parent_hw, u8 id, const struct clk_pll_characteristics *characteristics, - const struct clk_pll_layout *layout, bool critical); + const struct clk_pll_layout *layout, u32 flags); struct clk_hw * __init at91_clk_register_programmable(struct regmap *regmap, const char *name, diff --git a/drivers/clk/at91/sam9x60.c b/drivers/clk/at91/sam9x60.c index 3c4c95603595..dd62bb2880cf 100644 --- a/drivers/clk/at91/sam9x60.c +++ b/drivers/clk/at91/sam9x60.c @@ -228,13 +228,24 @@ static void __init sam9x60_pmc_setup(struct device_node *np) hw = sam9x60_clk_register_frac_pll(regmap, &pmc_pll_lock, "pllack_fracck", "mainck", sam9x60_pmc->chws[PMC_MAIN], 0, &plla_characteristics, - &pll_frac_layout, true); + &pll_frac_layout, + /* + * This feeds pllack_divck which + * feeds CPU. It should not be + * disabled. + */ + CLK_IS_CRITICAL | CLK_SET_RATE_GATE); if (IS_ERR(hw)) goto err_free; hw = sam9x60_clk_register_div_pll(regmap, &pmc_pll_lock, "pllack_divck", "pllack_fracck", 0, &plla_characteristics, - &pll_div_layout, true); + &pll_div_layout, + /* + * This feeds CPU. It should not + * be disabled. + */ + CLK_IS_CRITICAL | CLK_SET_RATE_GATE); if (IS_ERR(hw)) goto err_free; @@ -243,13 +254,16 @@ static void __init sam9x60_pmc_setup(struct device_node *np) hw = sam9x60_clk_register_frac_pll(regmap, &pmc_pll_lock, "upllck_fracck", "main_osc", main_osc_hw, 1, &upll_characteristics, - &pll_frac_layout, false); + &pll_frac_layout, CLK_SET_RATE_GATE); if (IS_ERR(hw)) goto err_free; hw = sam9x60_clk_register_div_pll(regmap, &pmc_pll_lock, "upllck_divck", "upllck_fracck", 1, &upll_characteristics, - &pll_div_layout, false); + &pll_div_layout, + CLK_SET_RATE_GATE | + CLK_SET_PARENT_GATE | + CLK_SET_RATE_PARENT); if (IS_ERR(hw)) goto err_free; diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c index d685e22b2014..d7c2b731ad20 100644 --- a/drivers/clk/at91/sama7g5.c +++ b/drivers/clk/at91/sama7g5.c @@ -95,15 +95,15 @@ static const struct clk_pll_layout pll_layout_divio = { * @p: clock parent * @l: clock layout * @t: clock type - * @f: true if clock is critical and cannot be disabled + * @f: clock flags * @eid: export index in sama7g5->chws[] array */ static const struct { const char *n; const char *p; const struct clk_pll_layout *l; + unsigned long f; u8 t; - u8 c; u8 eid; } sama7g5_plls[][PLL_ID_MAX] = { [PLL_ID_CPU] = { @@ -111,13 +111,18 @@ static const struct { .p = "mainck", .l = &pll_layout_frac, .t = PLL_TYPE_FRAC, - .c = 1, }, + /* + * This feeds cpupll_divpmcck which feeds CPU. It should + * not be disabled. + */ + .f = CLK_IS_CRITICAL, }, { .n = "cpupll_divpmcck", .p = "cpupll_fracck", .l = &pll_layout_divpmc, .t = PLL_TYPE_DIV, - .c = 1, + /* This feeds CPU. It should not be disabled. */ + .f = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT, .eid = PMC_CPUPLL, }, }, @@ -126,13 +131,22 @@ static const struct { .p = "mainck", .l = &pll_layout_frac, .t = PLL_TYPE_FRAC, - .c = 1, }, + /* + * This feeds syspll_divpmcck which may feed critial parts + * of the systems like timers. Therefore it should not be + * disabled. + */ + .f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE, }, { .n = "syspll_divpmcck", .p = "syspll_fracck", .l = &pll_layout_divpmc, .t = PLL_TYPE_DIV, - .c = 1, + /* + * This may feed critial parts of the systems like timers. + * Therefore it should not be disabled. + */ + .f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE, .eid = PMC_SYSPLL, }, }, @@ -141,55 +155,71 @@ static const struct { .p = "mainck", .l = &pll_layout_frac, .t = PLL_TYPE_FRAC, - .c = 1, }, + /* + * This feeds ddrpll_divpmcck which feeds DDR. It should not + * be disabled. + */ + .f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE, }, { .n = "ddrpll_divpmcck", .p = "ddrpll_fracck", .l = &pll_layout_divpmc, .t = PLL_TYPE_DIV, - .c = 1, }, + /* This feeds DDR. It should not be disabled. */ + .f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE, }, }, [PLL_ID_IMG] = { { .n = "imgpll_fracck", .p = "mainck", .l = &pll_layout_frac, - .t = PLL_TYPE_FRAC, }, + .t = PLL_TYPE_FRAC, + .f = CLK_SET_RATE_GATE, }, { .n = "imgpll_divpmcck", .p = "imgpll_fracck", .l = &pll_layout_divpmc, - .t = PLL_TYPE_DIV, }, + .t = PLL_TYPE_DIV, + .f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | + CLK_SET_RATE_PARENT, }, }, [PLL_ID_BAUD] = { { .n = "baudpll_fracck", .p = "mainck", .l = &pll_layout_frac, - .t = PLL_TYPE_FRAC, }, + .t = PLL_TYPE_FRAC, + .f = CLK_SET_RATE_GATE, }, { .n = "baudpll_divpmcck", .p = "baudpll_fracck", .l = &pll_layout_divpmc, - .t = PLL_TYPE_DIV, }, + .t = PLL_TYPE_DIV, + .f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | + CLK_SET_RATE_PARENT, }, }, [PLL_ID_AUDIO] = { { .n = "audiopll_fracck", .p = "main_xtal", .l = &pll_layout_frac, - .t = PLL_TYPE_FRAC, }, + .t = PLL_TYPE_FRAC, + .f = CLK_SET_RATE_GATE, }, { .n = "audiopll_divpmcck", .p = "audiopll_fracck", .l = &pll_layout_divpmc, .t = PLL_TYPE_DIV, + .f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | + CLK_SET_RATE_PARENT, .eid = PMC_AUDIOPMCPLL, }, { .n = "audiopll_diviock", .p = "audiopll_fracck", .l = &pll_layout_divio, .t = PLL_TYPE_DIV, + .f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | + CLK_SET_RATE_PARENT, .eid = PMC_AUDIOIOPLL, }, }, @@ -197,12 +227,15 @@ static const struct { { .n = "ethpll_fracck", .p = "main_xtal", .l = &pll_layout_frac, - .t = PLL_TYPE_FRAC, }, + .t = PLL_TYPE_FRAC, + .f = CLK_SET_RATE_GATE, }, { .n = "ethpll_divpmcck", .p = "ethpll_fracck", .l = &pll_layout_divpmc, - .t = PLL_TYPE_DIV, }, + .t = PLL_TYPE_DIV, + .f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | + CLK_SET_RATE_PARENT, }, }, }; @@ -890,7 +923,7 @@ static void __init sama7g5_pmc_setup(struct device_node *np) sama7g5_plls[i][j].p, parent_hw, i, &pll_characteristics, sama7g5_plls[i][j].l, - sama7g5_plls[i][j].c); + sama7g5_plls[i][j].f); break; case PLL_TYPE_DIV: @@ -899,7 +932,7 @@ static void __init sama7g5_pmc_setup(struct device_node *np) sama7g5_plls[i][j].p, i, &pll_characteristics, sama7g5_plls[i][j].l, - sama7g5_plls[i][j].c); + sama7g5_plls[i][j].f); break; default: From 4011f03ee4756df3091ad0c2cfb0593bee8ecdf1 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 19 Nov 2020 17:43:13 +0200 Subject: [PATCH 121/134] clk: at91: sama7g5: remove mck0 from parent list of other clocks MCK0 is changed at runtime by DVFS. Due to this, since not all IPs are glitch free aware at MCK0 changes, remove MCK0 from parent list of other clocks (e.g. generic clock, programmable/system clock, MCKX). Signed-off-by: Claudiu Beznea Link: https://lore.kernel.org/r/1605800597-16720-8-git-send-email-claudiu.beznea@microchip.com Signed-off-by: Stephen Boyd --- drivers/clk/at91/sama7g5.c | 55 ++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c index d7c2b731ad20..335e9c943c65 100644 --- a/drivers/clk/at91/sama7g5.c +++ b/drivers/clk/at91/sama7g5.c @@ -280,7 +280,7 @@ static const struct { .ep = { "syspll_divpmcck", "ddrpll_divpmcck", "imgpll_divpmcck", }, .ep_mux_table = { 5, 6, 7, }, .ep_count = 3, - .ep_chg_id = 6, }, + .ep_chg_id = 5, }, { .n = "mck4", .id = 4, @@ -313,7 +313,7 @@ static const struct { }; /* Mux table for programmable clocks. */ -static u32 sama7g5_prog_mux_table[] = { 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, }; +static u32 sama7g5_prog_mux_table[] = { 0, 1, 2, 5, 6, 7, 8, 9, 10, }; /** * Peripheral clock description @@ -436,7 +436,7 @@ static const struct { .pp = { "audiopll_divpmcck", }, .pp_mux_table = { 9, }, .pp_count = 1, - .pp_chg_id = 4, }, + .pp_chg_id = 3, }, { .n = "csi_gclk", .id = 33, @@ -548,7 +548,7 @@ static const struct { .pp = { "ethpll_divpmcck", }, .pp_mux_table = { 10, }, .pp_count = 1, - .pp_chg_id = 4, }, + .pp_chg_id = 3, }, { .n = "gmac1_gclk", .id = 52, @@ -580,7 +580,7 @@ static const struct { .pp = { "syspll_divpmcck", "audiopll_divpmcck", }, .pp_mux_table = { 5, 9, }, .pp_count = 2, - .pp_chg_id = 5, }, + .pp_chg_id = 4, }, { .n = "i2smcc1_gclk", .id = 58, @@ -588,7 +588,7 @@ static const struct { .pp = { "syspll_divpmcck", "audiopll_divpmcck", }, .pp_mux_table = { 5, 9, }, .pp_count = 2, - .pp_chg_id = 5, }, + .pp_chg_id = 4, }, { .n = "mcan0_gclk", .id = 61, @@ -730,7 +730,7 @@ static const struct { .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, .pp_mux_table = { 5, 8, }, .pp_count = 2, - .pp_chg_id = 5, }, + .pp_chg_id = 4, }, { .n = "sdmmc1_gclk", .id = 81, @@ -738,7 +738,7 @@ static const struct { .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, .pp_mux_table = { 5, 8, }, .pp_count = 2, - .pp_chg_id = 5, }, + .pp_chg_id = 4, }, { .n = "sdmmc2_gclk", .id = 82, @@ -746,7 +746,7 @@ static const struct { .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, .pp_mux_table = { 5, 8, }, .pp_count = 2, - .pp_chg_id = 5, }, + .pp_chg_id = 4, }, { .n = "spdifrx_gclk", .id = 84, @@ -754,7 +754,7 @@ static const struct { .pp = { "syspll_divpmcck", "audiopll_divpmcck", }, .pp_mux_table = { 5, 9, }, .pp_count = 2, - .pp_chg_id = 5, }, + .pp_chg_id = 4, }, { .n = "spdiftx_gclk", .id = 85, @@ -762,7 +762,7 @@ static const struct { .pp = { "syspll_divpmcck", "audiopll_divpmcck", }, .pp_mux_table = { 5, 9, }, .pp_count = 2, - .pp_chg_id = 5, }, + .pp_chg_id = 4, }, { .n = "tcb0_ch0_gclk", .id = 88, @@ -961,9 +961,8 @@ static void __init sama7g5_pmc_setup(struct device_node *np) parent_names[0] = md_slck_name; parent_names[1] = td_slck_name; parent_names[2] = "mainck"; - parent_names[3] = "mck0"; for (i = 0; i < ARRAY_SIZE(sama7g5_mckx); i++) { - u8 num_parents = 4 + sama7g5_mckx[i].ep_count; + u8 num_parents = 3 + sama7g5_mckx[i].ep_count; u32 *mux_table; mux_table = kmalloc_array(num_parents, sizeof(*mux_table), @@ -971,10 +970,10 @@ static void __init sama7g5_pmc_setup(struct device_node *np) if (!mux_table) goto err_free; - SAMA7G5_INIT_TABLE(mux_table, 4); - SAMA7G5_FILL_TABLE(&mux_table[4], sama7g5_mckx[i].ep_mux_table, + SAMA7G5_INIT_TABLE(mux_table, 3); + SAMA7G5_FILL_TABLE(&mux_table[3], sama7g5_mckx[i].ep_mux_table, sama7g5_mckx[i].ep_count); - SAMA7G5_FILL_TABLE(&parent_names[4], sama7g5_mckx[i].ep, + SAMA7G5_FILL_TABLE(&parent_names[3], sama7g5_mckx[i].ep, sama7g5_mckx[i].ep_count); hw = at91_clk_sama7g5_register_master(regmap, sama7g5_mckx[i].n, @@ -997,20 +996,19 @@ static void __init sama7g5_pmc_setup(struct device_node *np) parent_names[0] = md_slck_name; parent_names[1] = td_slck_name; parent_names[2] = "mainck"; - parent_names[3] = "mck0"; - parent_names[4] = "syspll_divpmcck"; - parent_names[5] = "ddrpll_divpmcck"; - parent_names[6] = "imgpll_divpmcck"; - parent_names[7] = "baudpll_divpmcck"; - parent_names[8] = "audiopll_divpmcck"; - parent_names[9] = "ethpll_divpmcck"; + parent_names[3] = "syspll_divpmcck"; + parent_names[4] = "ddrpll_divpmcck"; + parent_names[5] = "imgpll_divpmcck"; + parent_names[6] = "baudpll_divpmcck"; + parent_names[7] = "audiopll_divpmcck"; + parent_names[8] = "ethpll_divpmcck"; for (i = 0; i < 8; i++) { char name[6]; snprintf(name, sizeof(name), "prog%d", i); hw = at91_clk_register_programmable(regmap, name, parent_names, - 10, i, + 9, i, &programmable_layout, sama7g5_prog_mux_table); if (IS_ERR(hw)) @@ -1047,9 +1045,8 @@ static void __init sama7g5_pmc_setup(struct device_node *np) parent_names[0] = md_slck_name; parent_names[1] = td_slck_name; parent_names[2] = "mainck"; - parent_names[3] = "mck0"; for (i = 0; i < ARRAY_SIZE(sama7g5_gck); i++) { - u8 num_parents = 4 + sama7g5_gck[i].pp_count; + u8 num_parents = 3 + sama7g5_gck[i].pp_count; u32 *mux_table; mux_table = kmalloc_array(num_parents, sizeof(*mux_table), @@ -1057,10 +1054,10 @@ static void __init sama7g5_pmc_setup(struct device_node *np) if (!mux_table) goto err_free; - SAMA7G5_INIT_TABLE(mux_table, 4); - SAMA7G5_FILL_TABLE(&mux_table[4], sama7g5_gck[i].pp_mux_table, + SAMA7G5_INIT_TABLE(mux_table, 3); + SAMA7G5_FILL_TABLE(&mux_table[3], sama7g5_gck[i].pp_mux_table, sama7g5_gck[i].pp_count); - SAMA7G5_FILL_TABLE(&parent_names[4], sama7g5_gck[i].pp, + SAMA7G5_FILL_TABLE(&parent_names[3], sama7g5_gck[i].pp, sama7g5_gck[i].pp_count); hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, From f803858af84e1e6916edfbc5ae0fac403c02ee46 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 19 Nov 2020 17:43:14 +0200 Subject: [PATCH 122/134] clk: at91: sama7g5: decrease lower limit for MCK0 rate On SAMA7G5 CPU clock is changed at run-time by DVFS. Since MCK0 and CPU clock shares the same parent clock (CPUPLL clock) the MCK0 is also changed by DVFS to avoid over/under clocking of MCK0 consumers. The lower limit is changed to be able to set MCK0 accordingly by DVFS. Signed-off-by: Claudiu Beznea Link: https://lore.kernel.org/r/1605800597-16720-9-git-send-email-claudiu.beznea@microchip.com Signed-off-by: Stephen Boyd --- drivers/clk/at91/sama7g5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c index 335e9c943c65..29d9781e6712 100644 --- a/drivers/clk/at91/sama7g5.c +++ b/drivers/clk/at91/sama7g5.c @@ -807,7 +807,7 @@ static const struct clk_pll_characteristics pll_characteristics = { /* MCK0 characteristics. */ static const struct clk_master_characteristics mck0_characteristics = { - .output = { .min = 140000000, .max = 200000000 }, + .output = { .min = 50000000, .max = 200000000 }, .divisors = { 1, 2, 4, 3, 5 }, .have_div3_pres = 1, }; From 120d5d8b4614ee26c576b29377a968093948473f Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 19 Nov 2020 17:43:15 +0200 Subject: [PATCH 123/134] clk: at91: sama7g5: do not allow cpu pll to go higher than 1GHz Since CPU PLL feeds both CPU clock and MCK0, MCK0 cannot go higher than 200MHz and MCK0 maximum prescaller is 5 limit the CPU PLL at 1GHz to avoid MCK0 overclocking while CPU PLL is changed by DVFS. Signed-off-by: Claudiu Beznea Link: https://lore.kernel.org/r/1605800597-16720-10-git-send-email-claudiu.beznea@microchip.com Signed-off-by: Stephen Boyd --- drivers/clk/at91/sama7g5.c | 61 +++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c index 29d9781e6712..e0c4d2eb9f59 100644 --- a/drivers/clk/at91/sama7g5.c +++ b/drivers/clk/at91/sama7g5.c @@ -89,11 +89,40 @@ static const struct clk_pll_layout pll_layout_divio = { .endiv_shift = 30, }; +/* + * CPU PLL output range. + * Notice: The upper limit has been setup to 1000000002 due to hardware + * block which cannot output exactly 1GHz. + */ +static const struct clk_range cpu_pll_outputs[] = { + { .min = 2343750, .max = 1000000002 }, +}; + +/* PLL output range. */ +static const struct clk_range pll_outputs[] = { + { .min = 2343750, .max = 1200000000 }, +}; + +/* CPU PLL characteristics. */ +static const struct clk_pll_characteristics cpu_pll_characteristics = { + .input = { .min = 12000000, .max = 50000000 }, + .num_output = ARRAY_SIZE(cpu_pll_outputs), + .output = cpu_pll_outputs, +}; + +/* PLL characteristics. */ +static const struct clk_pll_characteristics pll_characteristics = { + .input = { .min = 12000000, .max = 50000000 }, + .num_output = ARRAY_SIZE(pll_outputs), + .output = pll_outputs, +}; + /** * PLL clocks description * @n: clock name * @p: clock parent * @l: clock layout + * @c: clock characteristics * @t: clock type * @f: clock flags * @eid: export index in sama7g5->chws[] array @@ -102,6 +131,7 @@ static const struct { const char *n; const char *p; const struct clk_pll_layout *l; + const struct clk_pll_characteristics *c; unsigned long f; u8 t; u8 eid; @@ -110,6 +140,7 @@ static const struct { { .n = "cpupll_fracck", .p = "mainck", .l = &pll_layout_frac, + .c = &cpu_pll_characteristics, .t = PLL_TYPE_FRAC, /* * This feeds cpupll_divpmcck which feeds CPU. It should @@ -120,6 +151,7 @@ static const struct { { .n = "cpupll_divpmcck", .p = "cpupll_fracck", .l = &pll_layout_divpmc, + .c = &cpu_pll_characteristics, .t = PLL_TYPE_DIV, /* This feeds CPU. It should not be disabled. */ .f = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT, @@ -130,6 +162,7 @@ static const struct { { .n = "syspll_fracck", .p = "mainck", .l = &pll_layout_frac, + .c = &pll_characteristics, .t = PLL_TYPE_FRAC, /* * This feeds syspll_divpmcck which may feed critial parts @@ -141,6 +174,7 @@ static const struct { { .n = "syspll_divpmcck", .p = "syspll_fracck", .l = &pll_layout_divpmc, + .c = &pll_characteristics, .t = PLL_TYPE_DIV, /* * This may feed critial parts of the systems like timers. @@ -154,6 +188,7 @@ static const struct { { .n = "ddrpll_fracck", .p = "mainck", .l = &pll_layout_frac, + .c = &pll_characteristics, .t = PLL_TYPE_FRAC, /* * This feeds ddrpll_divpmcck which feeds DDR. It should not @@ -164,6 +199,7 @@ static const struct { { .n = "ddrpll_divpmcck", .p = "ddrpll_fracck", .l = &pll_layout_divpmc, + .c = &pll_characteristics, .t = PLL_TYPE_DIV, /* This feeds DDR. It should not be disabled. */ .f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE, }, @@ -173,12 +209,14 @@ static const struct { { .n = "imgpll_fracck", .p = "mainck", .l = &pll_layout_frac, + .c = &pll_characteristics, .t = PLL_TYPE_FRAC, .f = CLK_SET_RATE_GATE, }, { .n = "imgpll_divpmcck", .p = "imgpll_fracck", .l = &pll_layout_divpmc, + .c = &pll_characteristics, .t = PLL_TYPE_DIV, .f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | CLK_SET_RATE_PARENT, }, @@ -188,12 +226,14 @@ static const struct { { .n = "baudpll_fracck", .p = "mainck", .l = &pll_layout_frac, + .c = &pll_characteristics, .t = PLL_TYPE_FRAC, .f = CLK_SET_RATE_GATE, }, { .n = "baudpll_divpmcck", .p = "baudpll_fracck", .l = &pll_layout_divpmc, + .c = &pll_characteristics, .t = PLL_TYPE_DIV, .f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | CLK_SET_RATE_PARENT, }, @@ -203,12 +243,14 @@ static const struct { { .n = "audiopll_fracck", .p = "main_xtal", .l = &pll_layout_frac, + .c = &pll_characteristics, .t = PLL_TYPE_FRAC, .f = CLK_SET_RATE_GATE, }, { .n = "audiopll_divpmcck", .p = "audiopll_fracck", .l = &pll_layout_divpmc, + .c = &pll_characteristics, .t = PLL_TYPE_DIV, .f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | CLK_SET_RATE_PARENT, @@ -217,6 +259,7 @@ static const struct { { .n = "audiopll_diviock", .p = "audiopll_fracck", .l = &pll_layout_divio, + .c = &pll_characteristics, .t = PLL_TYPE_DIV, .f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | CLK_SET_RATE_PARENT, @@ -227,12 +270,14 @@ static const struct { { .n = "ethpll_fracck", .p = "main_xtal", .l = &pll_layout_frac, + .c = &pll_characteristics, .t = PLL_TYPE_FRAC, .f = CLK_SET_RATE_GATE, }, { .n = "ethpll_divpmcck", .p = "ethpll_fracck", .l = &pll_layout_divpmc, + .c = &pll_characteristics, .t = PLL_TYPE_DIV, .f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | CLK_SET_RATE_PARENT, }, @@ -793,18 +838,6 @@ static const struct { .pp_chg_id = INT_MIN, }, }; -/* PLL output range. */ -static const struct clk_range pll_outputs[] = { - { .min = 2343750, .max = 1200000000 }, -}; - -/* PLL characteristics. */ -static const struct clk_pll_characteristics pll_characteristics = { - .input = { .min = 12000000, .max = 50000000 }, - .num_output = ARRAY_SIZE(pll_outputs), - .output = pll_outputs, -}; - /* MCK0 characteristics. */ static const struct clk_master_characteristics mck0_characteristics = { .output = { .min = 50000000, .max = 200000000 }, @@ -921,7 +954,7 @@ static void __init sama7g5_pmc_setup(struct device_node *np) hw = sam9x60_clk_register_frac_pll(regmap, &pmc_pll_lock, sama7g5_plls[i][j].n, sama7g5_plls[i][j].p, parent_hw, i, - &pll_characteristics, + sama7g5_plls[i][j].c, sama7g5_plls[i][j].l, sama7g5_plls[i][j].f); break; @@ -930,7 +963,7 @@ static void __init sama7g5_pmc_setup(struct device_node *np) hw = sam9x60_clk_register_div_pll(regmap, &pmc_pll_lock, sama7g5_plls[i][j].n, sama7g5_plls[i][j].p, i, - &pll_characteristics, + sama7g5_plls[i][j].c, sama7g5_plls[i][j].l, sama7g5_plls[i][j].f); break; From 7a110b9107ed8fe27277988cdb4d18e7043b7252 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 19 Nov 2020 17:43:16 +0200 Subject: [PATCH 124/134] clk: at91: clk-master: re-factor master clock Re-factor master clock driver by splitting it into 2 clocks: prescaller and divider clocks. Based on registered clock flags the prescaler's rate could be changed at runtime. This is necessary for platforms supporting DVFS (e.g. SAMA7G5) where master clock could be changed at run-time. Signed-off-by: Claudiu Beznea Link: https://lore.kernel.org/r/1605800597-16720-11-git-send-email-claudiu.beznea@microchip.com Signed-off-by: Stephen Boyd --- drivers/clk/at91/at91rm9200.c | 21 +- drivers/clk/at91/at91sam9260.c | 26 ++- drivers/clk/at91/at91sam9g45.c | 32 ++- drivers/clk/at91/at91sam9n12.c | 36 ++- drivers/clk/at91/at91sam9rl.c | 23 +- drivers/clk/at91/at91sam9x5.c | 28 ++- drivers/clk/at91/clk-master.c | 385 +++++++++++++++++++++++++++------ drivers/clk/at91/dt-compat.c | 15 +- drivers/clk/at91/pmc.h | 16 +- drivers/clk/at91/sam9x60.c | 23 +- drivers/clk/at91/sama5d2.c | 42 ++-- drivers/clk/at91/sama5d3.c | 38 ++-- drivers/clk/at91/sama5d4.c | 40 ++-- drivers/clk/at91/sama7g5.c | 13 +- 14 files changed, 567 insertions(+), 171 deletions(-) diff --git a/drivers/clk/at91/at91rm9200.c b/drivers/clk/at91/at91rm9200.c index 2c3d8e6ca63c..0fad1009f315 100644 --- a/drivers/clk/at91/at91rm9200.c +++ b/drivers/clk/at91/at91rm9200.c @@ -7,6 +7,8 @@ #include "pmc.h" +static DEFINE_SPINLOCK(rm9200_mck_lock); + struct sck { char *n; char *p; @@ -137,9 +139,20 @@ static void __init at91rm9200_pmc_setup(struct device_node *np) parent_names[1] = "mainck"; parent_names[2] = "pllack"; parent_names[3] = "pllbck"; - hw = at91_clk_register_master(regmap, "masterck", 4, parent_names, - &at91rm9200_master_layout, - &rm9200_mck_characteristics); + hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4, + parent_names, + &at91rm9200_master_layout, + &rm9200_mck_characteristics, + &rm9200_mck_lock, CLK_SET_RATE_GATE, + INT_MIN); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_master_div(regmap, "masterck_div", + "masterck_pres", + &at91rm9200_master_layout, + &rm9200_mck_characteristics, + &rm9200_mck_lock, CLK_SET_RATE_GATE); if (IS_ERR(hw)) goto err_free; @@ -181,7 +194,7 @@ static void __init at91rm9200_pmc_setup(struct device_node *np) for (i = 0; i < ARRAY_SIZE(at91rm9200_periphck); i++) { hw = at91_clk_register_peripheral(regmap, at91rm9200_periphck[i].n, - "masterck", + "masterck_div", at91rm9200_periphck[i].id); if (IS_ERR(hw)) goto err_free; diff --git a/drivers/clk/at91/at91sam9260.c b/drivers/clk/at91/at91sam9260.c index bb81ff731ad8..ceb5495f723a 100644 --- a/drivers/clk/at91/at91sam9260.c +++ b/drivers/clk/at91/at91sam9260.c @@ -32,6 +32,8 @@ struct at91sam926x_data { bool has_slck; }; +static DEFINE_SPINLOCK(at91sam9260_mck_lock); + static const struct clk_master_characteristics sam9260_mck_characteristics = { .output = { .min = 0, .max = 105000000 }, .divisors = { 1, 2, 4, 0 }, @@ -218,8 +220,8 @@ static const struct sck at91sam9261_systemck[] = { { .n = "pck1", .p = "prog1", .id = 9 }, { .n = "pck2", .p = "prog2", .id = 10 }, { .n = "pck3", .p = "prog3", .id = 11 }, - { .n = "hclk0", .p = "masterck", .id = 16 }, - { .n = "hclk1", .p = "masterck", .id = 17 }, + { .n = "hclk0", .p = "masterck_div", .id = 16 }, + { .n = "hclk1", .p = "masterck_div", .id = 17 }, }; static const struct pck at91sam9261_periphck[] = { @@ -413,9 +415,21 @@ static void __init at91sam926x_pmc_setup(struct device_node *np, parent_names[1] = "mainck"; parent_names[2] = "pllack"; parent_names[3] = "pllbck"; - hw = at91_clk_register_master(regmap, "masterck", 4, parent_names, - &at91rm9200_master_layout, - data->mck_characteristics); + hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4, + parent_names, + &at91rm9200_master_layout, + data->mck_characteristics, + &at91sam9260_mck_lock, + CLK_SET_RATE_GATE, INT_MIN); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_master_div(regmap, "masterck_div", + "masterck_pres", + &at91rm9200_master_layout, + data->mck_characteristics, + &at91sam9260_mck_lock, + CLK_SET_RATE_GATE); if (IS_ERR(hw)) goto err_free; @@ -457,7 +471,7 @@ static void __init at91sam926x_pmc_setup(struct device_node *np, for (i = 0; i < data->num_pck; i++) { hw = at91_clk_register_peripheral(regmap, data->pck[i].n, - "masterck", + "masterck_div", data->pck[i].id); if (IS_ERR(hw)) goto err_free; diff --git a/drivers/clk/at91/at91sam9g45.c b/drivers/clk/at91/at91sam9g45.c index cb4a406ed15d..0214333dedd3 100644 --- a/drivers/clk/at91/at91sam9g45.c +++ b/drivers/clk/at91/at91sam9g45.c @@ -7,6 +7,8 @@ #include "pmc.h" +static DEFINE_SPINLOCK(at91sam9g45_mck_lock); + static const struct clk_master_characteristics mck_characteristics = { .output = { .min = 0, .max = 133333333 }, .divisors = { 1, 2, 4, 3 }, @@ -40,10 +42,10 @@ static const struct { char *p; u8 id; } at91sam9g45_systemck[] = { - { .n = "ddrck", .p = "masterck", .id = 2 }, - { .n = "uhpck", .p = "usbck", .id = 6 }, - { .n = "pck0", .p = "prog0", .id = 8 }, - { .n = "pck1", .p = "prog1", .id = 9 }, + { .n = "ddrck", .p = "masterck_div", .id = 2 }, + { .n = "uhpck", .p = "usbck", .id = 6 }, + { .n = "pck0", .p = "prog0", .id = 8 }, + { .n = "pck1", .p = "prog1", .id = 9 }, }; struct pck { @@ -148,9 +150,21 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np) parent_names[1] = "mainck"; parent_names[2] = "plladivck"; parent_names[3] = "utmick"; - hw = at91_clk_register_master(regmap, "masterck", 4, parent_names, - &at91rm9200_master_layout, - &mck_characteristics); + hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4, + parent_names, + &at91rm9200_master_layout, + &mck_characteristics, + &at91sam9g45_mck_lock, + CLK_SET_RATE_GATE, INT_MIN); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_master_div(regmap, "masterck_div", + "masterck_pres", + &at91rm9200_master_layout, + &mck_characteristics, + &at91sam9g45_mck_lock, + CLK_SET_RATE_GATE); if (IS_ERR(hw)) goto err_free; @@ -166,7 +180,7 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np) parent_names[1] = "mainck"; parent_names[2] = "plladivck"; parent_names[3] = "utmick"; - parent_names[4] = "masterck"; + parent_names[4] = "masterck_div"; for (i = 0; i < 2; i++) { char name[6]; @@ -195,7 +209,7 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np) for (i = 0; i < ARRAY_SIZE(at91sam9g45_periphck); i++) { hw = at91_clk_register_peripheral(regmap, at91sam9g45_periphck[i].n, - "masterck", + "masterck_div", at91sam9g45_periphck[i].id); if (IS_ERR(hw)) goto err_free; diff --git a/drivers/clk/at91/at91sam9n12.c b/drivers/clk/at91/at91sam9n12.c index 93f7eb216122..f9db5316a7f1 100644 --- a/drivers/clk/at91/at91sam9n12.c +++ b/drivers/clk/at91/at91sam9n12.c @@ -7,6 +7,8 @@ #include "pmc.h" +static DEFINE_SPINLOCK(at91sam9n12_mck_lock); + static const struct clk_master_characteristics mck_characteristics = { .output = { .min = 0, .max = 133333333 }, .divisors = { 1, 2, 4, 3 }, @@ -54,12 +56,12 @@ static const struct { char *p; u8 id; } at91sam9n12_systemck[] = { - { .n = "ddrck", .p = "masterck", .id = 2 }, - { .n = "lcdck", .p = "masterck", .id = 3 }, - { .n = "uhpck", .p = "usbck", .id = 6 }, - { .n = "udpck", .p = "usbck", .id = 7 }, - { .n = "pck0", .p = "prog0", .id = 8 }, - { .n = "pck1", .p = "prog1", .id = 9 }, + { .n = "ddrck", .p = "masterck_div", .id = 2 }, + { .n = "lcdck", .p = "masterck_div", .id = 3 }, + { .n = "uhpck", .p = "usbck", .id = 6 }, + { .n = "udpck", .p = "usbck", .id = 7 }, + { .n = "pck0", .p = "prog0", .id = 8 }, + { .n = "pck1", .p = "prog1", .id = 9 }, }; static const struct clk_pcr_layout at91sam9n12_pcr_layout = { @@ -175,9 +177,21 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np) parent_names[1] = "mainck"; parent_names[2] = "plladivck"; parent_names[3] = "pllbck"; - hw = at91_clk_register_master(regmap, "masterck", 4, parent_names, - &at91sam9x5_master_layout, - &mck_characteristics); + hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4, + parent_names, + &at91sam9x5_master_layout, + &mck_characteristics, + &at91sam9n12_mck_lock, + CLK_SET_RATE_GATE, INT_MIN); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_master_div(regmap, "masterck_div", + "masterck_pres", + &at91sam9x5_master_layout, + &mck_characteristics, + &at91sam9n12_mck_lock, + CLK_SET_RATE_GATE); if (IS_ERR(hw)) goto err_free; @@ -191,7 +205,7 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np) parent_names[1] = "mainck"; parent_names[2] = "plladivck"; parent_names[3] = "pllbck"; - parent_names[4] = "masterck"; + parent_names[4] = "masterck_div"; for (i = 0; i < 2; i++) { char name[6]; @@ -221,7 +235,7 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np) hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, &at91sam9n12_pcr_layout, at91sam9n12_periphck[i].n, - "masterck", + "masterck_div", at91sam9n12_periphck[i].id, &range, INT_MIN); if (IS_ERR(hw)) diff --git a/drivers/clk/at91/at91sam9rl.c b/drivers/clk/at91/at91sam9rl.c index a343eb69bb35..66736e03cfef 100644 --- a/drivers/clk/at91/at91sam9rl.c +++ b/drivers/clk/at91/at91sam9rl.c @@ -7,6 +7,8 @@ #include "pmc.h" +static DEFINE_SPINLOCK(sam9rl_mck_lock); + static const struct clk_master_characteristics sam9rl_mck_characteristics = { .output = { .min = 0, .max = 94000000 }, .divisors = { 1, 2, 4, 0 }, @@ -117,9 +119,20 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np) parent_names[1] = "mainck"; parent_names[2] = "pllack"; parent_names[3] = "utmick"; - hw = at91_clk_register_master(regmap, "masterck", 4, parent_names, - &at91rm9200_master_layout, - &sam9rl_mck_characteristics); + hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4, + parent_names, + &at91rm9200_master_layout, + &sam9rl_mck_characteristics, + &sam9rl_mck_lock, CLK_SET_RATE_GATE, + INT_MIN); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_master_div(regmap, "masterck_div", + "masterck_pres", + &at91rm9200_master_layout, + &sam9rl_mck_characteristics, + &sam9rl_mck_lock, CLK_SET_RATE_GATE); if (IS_ERR(hw)) goto err_free; @@ -129,7 +142,7 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np) parent_names[1] = "mainck"; parent_names[2] = "pllack"; parent_names[3] = "utmick"; - parent_names[4] = "masterck"; + parent_names[4] = "masterck_div"; for (i = 0; i < 2; i++) { char name[6]; @@ -158,7 +171,7 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np) for (i = 0; i < ARRAY_SIZE(at91sam9rl_periphck); i++) { hw = at91_clk_register_peripheral(regmap, at91sam9rl_periphck[i].n, - "masterck", + "masterck_div", at91sam9rl_periphck[i].id); if (IS_ERR(hw)) goto err_free; diff --git a/drivers/clk/at91/at91sam9x5.c b/drivers/clk/at91/at91sam9x5.c index 22b9aad9efb8..79b9d3667228 100644 --- a/drivers/clk/at91/at91sam9x5.c +++ b/drivers/clk/at91/at91sam9x5.c @@ -7,6 +7,8 @@ #include "pmc.h" +static DEFINE_SPINLOCK(mck_lock); + static const struct clk_master_characteristics mck_characteristics = { .output = { .min = 0, .max = 133333333 }, .divisors = { 1, 2, 4, 3 }, @@ -41,7 +43,7 @@ static const struct { char *p; u8 id; } at91sam9x5_systemck[] = { - { .n = "ddrck", .p = "masterck", .id = 2 }, + { .n = "ddrck", .p = "masterck_div", .id = 2 }, { .n = "smdck", .p = "smdclk", .id = 4 }, { .n = "uhpck", .p = "usbck", .id = 6 }, { .n = "udpck", .p = "usbck", .id = 7 }, @@ -196,9 +198,19 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np, parent_names[1] = "mainck"; parent_names[2] = "plladivck"; parent_names[3] = "utmick"; - hw = at91_clk_register_master(regmap, "masterck", 4, parent_names, - &at91sam9x5_master_layout, - &mck_characteristics); + hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4, + parent_names, + &at91sam9x5_master_layout, + &mck_characteristics, &mck_lock, + CLK_SET_RATE_GATE, INT_MIN); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_master_div(regmap, "masterck_div", + "masterck_pres", + &at91sam9x5_master_layout, + &mck_characteristics, &mck_lock, + CLK_SET_RATE_GATE); if (IS_ERR(hw)) goto err_free; @@ -218,7 +230,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np, parent_names[1] = "mainck"; parent_names[2] = "plladivck"; parent_names[3] = "utmick"; - parent_names[4] = "masterck"; + parent_names[4] = "masterck_div"; for (i = 0; i < 2; i++) { char name[6]; @@ -245,7 +257,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np, } if (has_lcdck) { - hw = at91_clk_register_system(regmap, "lcdck", "masterck", 3); + hw = at91_clk_register_system(regmap, "lcdck", "masterck_div", 3); if (IS_ERR(hw)) goto err_free; @@ -256,7 +268,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np, hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, &at91sam9x5_pcr_layout, at91sam9x5_periphck[i].n, - "masterck", + "masterck_div", at91sam9x5_periphck[i].id, &range, INT_MIN); if (IS_ERR(hw)) @@ -269,7 +281,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np, hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, &at91sam9x5_pcr_layout, extra_pcks[i].n, - "masterck", + "masterck_div", extra_pcks[i].id, &range, INT_MIN); if (IS_ERR(hw)) diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c index aafd003b30cf..a80427980bf7 100644 --- a/drivers/clk/at91/clk-master.c +++ b/drivers/clk/at91/clk-master.c @@ -58,119 +58,153 @@ static inline bool clk_master_ready(struct clk_master *master) static int clk_master_prepare(struct clk_hw *hw) { struct clk_master *master = to_clk_master(hw); + unsigned long flags; + + spin_lock_irqsave(master->lock, flags); while (!clk_master_ready(master)) cpu_relax(); + spin_unlock_irqrestore(master->lock, flags); + return 0; } static int clk_master_is_prepared(struct clk_hw *hw) { struct clk_master *master = to_clk_master(hw); + unsigned long flags; + bool status; - return clk_master_ready(master); + spin_lock_irqsave(master->lock, flags); + status = clk_master_ready(master); + spin_unlock_irqrestore(master->lock, flags); + + return status; } -static unsigned long clk_master_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) +static unsigned long clk_master_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) { - u8 pres; u8 div; - unsigned long rate = parent_rate; + unsigned long flags, rate = parent_rate; struct clk_master *master = to_clk_master(hw); const struct clk_master_layout *layout = master->layout; const struct clk_master_characteristics *characteristics = master->characteristics; unsigned int mckr; + spin_lock_irqsave(master->lock, flags); regmap_read(master->regmap, master->layout->offset, &mckr); + spin_unlock_irqrestore(master->lock, flags); + mckr &= layout->mask; - pres = (mckr >> layout->pres_shift) & MASTER_PRES_MASK; div = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK; - if (characteristics->have_div3_pres && pres == MASTER_PRES_MAX) - rate /= 3; - else - rate >>= pres; - rate /= characteristics->divisors[div]; if (rate < characteristics->output.min) - pr_warn("master clk is underclocked"); + pr_warn("master clk div is underclocked"); else if (rate > characteristics->output.max) - pr_warn("master clk is overclocked"); + pr_warn("master clk div is overclocked"); return rate; } -static u8 clk_master_get_parent(struct clk_hw *hw) -{ - struct clk_master *master = to_clk_master(hw); - unsigned int mckr; - - regmap_read(master->regmap, master->layout->offset, &mckr); - - return mckr & AT91_PMC_CSS; -} - -static const struct clk_ops master_ops = { +static const struct clk_ops master_div_ops = { .prepare = clk_master_prepare, .is_prepared = clk_master_is_prepared, - .recalc_rate = clk_master_recalc_rate, - .get_parent = clk_master_get_parent, + .recalc_rate = clk_master_div_recalc_rate, }; -struct clk_hw * __init -at91_clk_register_master(struct regmap *regmap, - const char *name, int num_parents, - const char **parent_names, - const struct clk_master_layout *layout, - const struct clk_master_characteristics *characteristics) -{ - struct clk_master *master; - struct clk_init_data init; - struct clk_hw *hw; - int ret; - - if (!name || !num_parents || !parent_names) - return ERR_PTR(-EINVAL); - - master = kzalloc(sizeof(*master), GFP_KERNEL); - if (!master) - return ERR_PTR(-ENOMEM); - - init.name = name; - init.ops = &master_ops; - init.parent_names = parent_names; - init.num_parents = num_parents; - init.flags = 0; - - master->hw.init = &init; - master->layout = layout; - master->characteristics = characteristics; - master->regmap = regmap; - - hw = &master->hw; - ret = clk_hw_register(NULL, &master->hw); - if (ret) { - kfree(master); - hw = ERR_PTR(ret); - } - - return hw; -} - -static unsigned long -clk_sama7g5_master_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) +static int clk_master_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) { struct clk_master *master = to_clk_master(hw); + const struct clk_master_characteristics *characteristics = + master->characteristics; + unsigned long flags; + int div, i; - return DIV_ROUND_CLOSEST_ULL(parent_rate, (1 << master->div)); + div = DIV_ROUND_CLOSEST(parent_rate, rate); + if (div > ARRAY_SIZE(characteristics->divisors)) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(characteristics->divisors); i++) { + if (!characteristics->divisors[i]) + break; + + if (div == characteristics->divisors[i]) { + div = i; + break; + } + } + + if (i == ARRAY_SIZE(characteristics->divisors)) + return -EINVAL; + + spin_lock_irqsave(master->lock, flags); + regmap_update_bits(master->regmap, master->layout->offset, + (MASTER_DIV_MASK << MASTER_DIV_SHIFT), + (div << MASTER_DIV_SHIFT)); + while (!clk_master_ready(master)) + cpu_relax(); + spin_unlock_irqrestore(master->lock, flags); + + return 0; } +static int clk_master_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_master *master = to_clk_master(hw); + const struct clk_master_characteristics *characteristics = + master->characteristics; + struct clk_hw *parent; + unsigned long parent_rate, tmp_rate, best_rate = 0; + int i, best_diff = INT_MIN, tmp_diff; + + parent = clk_hw_get_parent(hw); + if (!parent) + return -EINVAL; + + parent_rate = clk_hw_get_rate(parent); + if (!parent_rate) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(characteristics->divisors); i++) { + if (!characteristics->divisors[i]) + break; + + tmp_rate = DIV_ROUND_CLOSEST_ULL(parent_rate, + characteristics->divisors[i]); + tmp_diff = abs(tmp_rate - req->rate); + + if (!best_rate || best_diff > tmp_diff) { + best_diff = tmp_diff; + best_rate = tmp_rate; + } + + if (!best_diff) + break; + } + + req->best_parent_rate = best_rate; + req->best_parent_hw = parent; + req->rate = best_rate; + + return 0; +} + +static const struct clk_ops master_div_ops_chg = { + .prepare = clk_master_prepare, + .is_prepared = clk_master_is_prepared, + .recalc_rate = clk_master_div_recalc_rate, + .determine_rate = clk_master_div_determine_rate, + .set_rate = clk_master_div_set_rate, +}; + static void clk_sama7g5_master_best_diff(struct clk_rate_request *req, struct clk_hw *parent, unsigned long parent_rate, @@ -195,6 +229,217 @@ static void clk_sama7g5_master_best_diff(struct clk_rate_request *req, } } +static int clk_master_pres_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_master *master = to_clk_master(hw); + struct clk_rate_request req_parent = *req; + const struct clk_master_characteristics *characteristics = + master->characteristics; + struct clk_hw *parent; + long best_rate = LONG_MIN, best_diff = LONG_MIN; + u32 pres; + int i; + + if (master->chg_pid < 0) + return -EOPNOTSUPP; + + parent = clk_hw_get_parent_by_index(hw, master->chg_pid); + if (!parent) + return -EOPNOTSUPP; + + for (i = 0; i <= MASTER_PRES_MAX; i++) { + if (characteristics->have_div3_pres && i == MASTER_PRES_MAX) + pres = 3; + else + pres = 1 << i; + + req_parent.rate = req->rate * pres; + if (__clk_determine_rate(parent, &req_parent)) + continue; + + clk_sama7g5_master_best_diff(req, parent, req_parent.rate, + &best_diff, &best_rate, pres); + if (!best_diff) + break; + } + + return 0; +} + +static int clk_master_pres_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_master *master = to_clk_master(hw); + unsigned long flags; + unsigned int pres; + + pres = DIV_ROUND_CLOSEST(parent_rate, rate); + if (pres > MASTER_PRES_MAX) + return -EINVAL; + + else if (pres == 3) + pres = MASTER_PRES_MAX; + else + pres = ffs(pres) - 1; + + spin_lock_irqsave(master->lock, flags); + regmap_update_bits(master->regmap, master->layout->offset, + (MASTER_PRES_MASK << master->layout->pres_shift), + (pres << master->layout->pres_shift)); + + while (!clk_master_ready(master)) + cpu_relax(); + spin_unlock_irqrestore(master->lock, flags); + + return 0; +} + +static unsigned long clk_master_pres_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_master *master = to_clk_master(hw); + const struct clk_master_characteristics *characteristics = + master->characteristics; + unsigned long flags; + unsigned int val, pres; + + spin_lock_irqsave(master->lock, flags); + regmap_read(master->regmap, master->layout->offset, &val); + spin_unlock_irqrestore(master->lock, flags); + + pres = (val >> master->layout->pres_shift) & MASTER_PRES_MASK; + if (pres == 3 && characteristics->have_div3_pres) + pres = 3; + else + pres = (1 << pres); + + return DIV_ROUND_CLOSEST_ULL(parent_rate, pres); +} + +static u8 clk_master_pres_get_parent(struct clk_hw *hw) +{ + struct clk_master *master = to_clk_master(hw); + unsigned long flags; + unsigned int mckr; + + spin_lock_irqsave(master->lock, flags); + regmap_read(master->regmap, master->layout->offset, &mckr); + spin_unlock_irqrestore(master->lock, flags); + + return mckr & AT91_PMC_CSS; +} + +static const struct clk_ops master_pres_ops = { + .prepare = clk_master_prepare, + .is_prepared = clk_master_is_prepared, + .recalc_rate = clk_master_pres_recalc_rate, + .get_parent = clk_master_pres_get_parent, +}; + +static const struct clk_ops master_pres_ops_chg = { + .prepare = clk_master_prepare, + .is_prepared = clk_master_is_prepared, + .determine_rate = clk_master_pres_determine_rate, + .recalc_rate = clk_master_pres_recalc_rate, + .get_parent = clk_master_pres_get_parent, + .set_rate = clk_master_pres_set_rate, +}; + +static struct clk_hw * __init +at91_clk_register_master_internal(struct regmap *regmap, + const char *name, int num_parents, + const char **parent_names, + const struct clk_master_layout *layout, + const struct clk_master_characteristics *characteristics, + const struct clk_ops *ops, spinlock_t *lock, u32 flags, + int chg_pid) +{ + struct clk_master *master; + struct clk_init_data init; + struct clk_hw *hw; + int ret; + + if (!name || !num_parents || !parent_names || !lock) + return ERR_PTR(-EINVAL); + + master = kzalloc(sizeof(*master), GFP_KERNEL); + if (!master) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = ops; + init.parent_names = parent_names; + init.num_parents = num_parents; + init.flags = flags; + + master->hw.init = &init; + master->layout = layout; + master->characteristics = characteristics; + master->regmap = regmap; + master->chg_pid = chg_pid; + master->lock = lock; + + hw = &master->hw; + ret = clk_hw_register(NULL, &master->hw); + if (ret) { + kfree(master); + hw = ERR_PTR(ret); + } + + return hw; +} + +struct clk_hw * __init +at91_clk_register_master_pres(struct regmap *regmap, + const char *name, int num_parents, + const char **parent_names, + const struct clk_master_layout *layout, + const struct clk_master_characteristics *characteristics, + spinlock_t *lock, u32 flags, int chg_pid) +{ + const struct clk_ops *ops; + + if (flags & CLK_SET_RATE_GATE) + ops = &master_pres_ops; + else + ops = &master_pres_ops_chg; + + return at91_clk_register_master_internal(regmap, name, num_parents, + parent_names, layout, + characteristics, ops, + lock, flags, chg_pid); +} + +struct clk_hw * __init +at91_clk_register_master_div(struct regmap *regmap, + const char *name, const char *parent_name, + const struct clk_master_layout *layout, + const struct clk_master_characteristics *characteristics, + spinlock_t *lock, u32 flags) +{ + const struct clk_ops *ops; + + if (flags & CLK_SET_RATE_GATE) + ops = &master_div_ops; + else + ops = &master_div_ops_chg; + + return at91_clk_register_master_internal(regmap, name, 1, + &parent_name, layout, + characteristics, ops, + lock, flags, -EINVAL); +} + +static unsigned long +clk_sama7g5_master_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_master *master = to_clk_master(hw); + + return DIV_ROUND_CLOSEST_ULL(parent_rate, (1 << master->div)); +} + static int clk_sama7g5_master_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { diff --git a/drivers/clk/at91/dt-compat.c b/drivers/clk/at91/dt-compat.c index a50084de97d4..a97b99c2dc12 100644 --- a/drivers/clk/at91/dt-compat.c +++ b/drivers/clk/at91/dt-compat.c @@ -24,6 +24,8 @@ #define GCK_INDEX_DT_AUDIO_PLL 5 +static DEFINE_SPINLOCK(mck_lock); + #ifdef CONFIG_HAVE_AT91_AUDIO_PLL static void __init of_sama5d2_clk_audio_pll_frac_setup(struct device_node *np) { @@ -388,9 +390,16 @@ of_at91_clk_master_setup(struct device_node *np, if (IS_ERR(regmap)) return; - hw = at91_clk_register_master(regmap, name, num_parents, - parent_names, layout, - characteristics); + hw = at91_clk_register_master_pres(regmap, "masterck_pres", num_parents, + parent_names, layout, + characteristics, &mck_lock, + CLK_SET_RATE_GATE, INT_MIN); + if (IS_ERR(hw)) + goto out_free_characteristics; + + hw = at91_clk_register_master_div(regmap, name, "masterck_pres", + layout, characteristics, + &mck_lock, CLK_SET_RATE_GATE); if (IS_ERR(hw)) goto out_free_characteristics; diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index bedcd85ad750..a49076c804a9 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -155,10 +155,18 @@ at91_clk_register_sam9x5_main(struct regmap *regmap, const char *name, const char **parent_names, int num_parents); struct clk_hw * __init -at91_clk_register_master(struct regmap *regmap, const char *name, - int num_parents, const char **parent_names, - const struct clk_master_layout *layout, - const struct clk_master_characteristics *characteristics); +at91_clk_register_master_pres(struct regmap *regmap, const char *name, + int num_parents, const char **parent_names, + const struct clk_master_layout *layout, + const struct clk_master_characteristics *characteristics, + spinlock_t *lock, u32 flags, int chg_pid); + +struct clk_hw * __init +at91_clk_register_master_div(struct regmap *regmap, const char *name, + const char *parent_names, + const struct clk_master_layout *layout, + const struct clk_master_characteristics *characteristics, + spinlock_t *lock, u32 flags); struct clk_hw * __init at91_clk_sama7g5_register_master(struct regmap *regmap, diff --git a/drivers/clk/at91/sam9x60.c b/drivers/clk/at91/sam9x60.c index dd62bb2880cf..240e48149bcd 100644 --- a/drivers/clk/at91/sam9x60.c +++ b/drivers/clk/at91/sam9x60.c @@ -8,6 +8,7 @@ #include "pmc.h" static DEFINE_SPINLOCK(pmc_pll_lock); +static DEFINE_SPINLOCK(mck_lock); static const struct clk_master_characteristics mck_characteristics = { .output = { .min = 140000000, .max = 200000000 }, @@ -76,11 +77,11 @@ static const struct { char *p; u8 id; } sam9x60_systemck[] = { - { .n = "ddrck", .p = "masterck", .id = 2 }, + { .n = "ddrck", .p = "masterck_div", .id = 2 }, { .n = "uhpck", .p = "usbck", .id = 6 }, { .n = "pck0", .p = "prog0", .id = 8 }, { .n = "pck1", .p = "prog1", .id = 9 }, - { .n = "qspick", .p = "masterck", .id = 19 }, + { .n = "qspick", .p = "masterck_div", .id = 19 }, }; static const struct { @@ -272,9 +273,17 @@ static void __init sam9x60_pmc_setup(struct device_node *np) parent_names[0] = md_slck_name; parent_names[1] = "mainck"; parent_names[2] = "pllack_divck"; - hw = at91_clk_register_master(regmap, "masterck", 3, parent_names, - &sam9x60_master_layout, - &mck_characteristics); + hw = at91_clk_register_master_pres(regmap, "masterck_pres", 3, + parent_names, &sam9x60_master_layout, + &mck_characteristics, &mck_lock, + CLK_SET_RATE_GATE, INT_MIN); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_master_div(regmap, "masterck_div", + "masterck_pres", &sam9x60_master_layout, + &mck_characteristics, &mck_lock, + CLK_SET_RATE_GATE); if (IS_ERR(hw)) goto err_free; @@ -290,7 +299,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np) parent_names[0] = md_slck_name; parent_names[1] = td_slck_name; parent_names[2] = "mainck"; - parent_names[3] = "masterck"; + parent_names[3] = "masterck_div"; parent_names[4] = "pllack_divck"; parent_names[5] = "upllck_divck"; for (i = 0; i < 2; i++) { @@ -322,7 +331,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np) hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, &sam9x60_pcr_layout, sam9x60_periphck[i].n, - "masterck", + "masterck_div", sam9x60_periphck[i].id, &range, INT_MIN); if (IS_ERR(hw)) diff --git a/drivers/clk/at91/sama5d2.c b/drivers/clk/at91/sama5d2.c index 8b220762941a..9a5cbc7cd55a 100644 --- a/drivers/clk/at91/sama5d2.c +++ b/drivers/clk/at91/sama5d2.c @@ -7,6 +7,8 @@ #include "pmc.h" +static DEFINE_SPINLOCK(mck_lock); + static const struct clk_master_characteristics mck_characteristics = { .output = { .min = 124000000, .max = 166000000 }, .divisors = { 1, 2, 4, 3 }, @@ -40,14 +42,14 @@ static const struct { char *p; u8 id; } sama5d2_systemck[] = { - { .n = "ddrck", .p = "masterck", .id = 2 }, - { .n = "lcdck", .p = "masterck", .id = 3 }, - { .n = "uhpck", .p = "usbck", .id = 6 }, - { .n = "udpck", .p = "usbck", .id = 7 }, - { .n = "pck0", .p = "prog0", .id = 8 }, - { .n = "pck1", .p = "prog1", .id = 9 }, - { .n = "pck2", .p = "prog2", .id = 10 }, - { .n = "iscck", .p = "masterck", .id = 18 }, + { .n = "ddrck", .p = "masterck_div", .id = 2 }, + { .n = "lcdck", .p = "masterck_div", .id = 3 }, + { .n = "uhpck", .p = "usbck", .id = 6 }, + { .n = "udpck", .p = "usbck", .id = 7 }, + { .n = "pck0", .p = "prog0", .id = 8 }, + { .n = "pck1", .p = "prog1", .id = 9 }, + { .n = "pck2", .p = "prog2", .id = 10 }, + { .n = "iscck", .p = "masterck_div", .id = 18 }, }; static const struct { @@ -235,15 +237,25 @@ static void __init sama5d2_pmc_setup(struct device_node *np) parent_names[1] = "mainck"; parent_names[2] = "plladivck"; parent_names[3] = "utmick"; - hw = at91_clk_register_master(regmap, "masterck", 4, parent_names, - &at91sam9x5_master_layout, - &mck_characteristics); + hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4, + parent_names, + &at91sam9x5_master_layout, + &mck_characteristics, &mck_lock, + CLK_SET_RATE_GATE, INT_MIN); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_master_div(regmap, "masterck_div", + "masterck_pres", + &at91sam9x5_master_layout, + &mck_characteristics, &mck_lock, + CLK_SET_RATE_GATE); if (IS_ERR(hw)) goto err_free; sama5d2_pmc->chws[PMC_MCK] = hw; - hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck"); + hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck_div"); if (IS_ERR(hw)) goto err_free; @@ -259,7 +271,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np) parent_names[1] = "mainck"; parent_names[2] = "plladivck"; parent_names[3] = "utmick"; - parent_names[4] = "masterck"; + parent_names[4] = "masterck_div"; parent_names[5] = "audiopll_pmcck"; for (i = 0; i < 3; i++) { char name[6]; @@ -290,7 +302,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np) hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, &sama5d2_pcr_layout, sama5d2_periphck[i].n, - "masterck", + "masterck_div", sama5d2_periphck[i].id, &range, INT_MIN); if (IS_ERR(hw)) @@ -317,7 +329,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np) parent_names[1] = "mainck"; parent_names[2] = "plladivck"; parent_names[3] = "utmick"; - parent_names[4] = "masterck"; + parent_names[4] = "masterck_div"; parent_names[5] = "audiopll_pmcck"; for (i = 0; i < ARRAY_SIZE(sama5d2_gck); i++) { hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, diff --git a/drivers/clk/at91/sama5d3.c b/drivers/clk/at91/sama5d3.c index 7c6e0a5b9dc8..87009ee8effc 100644 --- a/drivers/clk/at91/sama5d3.c +++ b/drivers/clk/at91/sama5d3.c @@ -7,6 +7,8 @@ #include "pmc.h" +static DEFINE_SPINLOCK(mck_lock); + static const struct clk_master_characteristics mck_characteristics = { .output = { .min = 0, .max = 166000000 }, .divisors = { 1, 2, 4, 3 }, @@ -40,14 +42,14 @@ static const struct { char *p; u8 id; } sama5d3_systemck[] = { - { .n = "ddrck", .p = "masterck", .id = 2 }, - { .n = "lcdck", .p = "masterck", .id = 3 }, - { .n = "smdck", .p = "smdclk", .id = 4 }, - { .n = "uhpck", .p = "usbck", .id = 6 }, - { .n = "udpck", .p = "usbck", .id = 7 }, - { .n = "pck0", .p = "prog0", .id = 8 }, - { .n = "pck1", .p = "prog1", .id = 9 }, - { .n = "pck2", .p = "prog2", .id = 10 }, + { .n = "ddrck", .p = "masterck_div", .id = 2 }, + { .n = "lcdck", .p = "masterck_div", .id = 3 }, + { .n = "smdck", .p = "smdclk", .id = 4 }, + { .n = "uhpck", .p = "usbck", .id = 6 }, + { .n = "udpck", .p = "usbck", .id = 7 }, + { .n = "pck0", .p = "prog0", .id = 8 }, + { .n = "pck1", .p = "prog1", .id = 9 }, + { .n = "pck2", .p = "prog2", .id = 10 }, }; static const struct { @@ -170,9 +172,19 @@ static void __init sama5d3_pmc_setup(struct device_node *np) parent_names[1] = "mainck"; parent_names[2] = "plladivck"; parent_names[3] = "utmick"; - hw = at91_clk_register_master(regmap, "masterck", 4, parent_names, - &at91sam9x5_master_layout, - &mck_characteristics); + hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4, + parent_names, + &at91sam9x5_master_layout, + &mck_characteristics, &mck_lock, + CLK_SET_RATE_GATE, INT_MIN); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_master_div(regmap, "masterck_div", + "masterck_pres", + &at91sam9x5_master_layout, + &mck_characteristics, &mck_lock, + CLK_SET_RATE_GATE); if (IS_ERR(hw)) goto err_free; @@ -192,7 +204,7 @@ static void __init sama5d3_pmc_setup(struct device_node *np) parent_names[1] = "mainck"; parent_names[2] = "plladivck"; parent_names[3] = "utmick"; - parent_names[4] = "masterck"; + parent_names[4] = "masterck_div"; for (i = 0; i < 3; i++) { char name[6]; @@ -222,7 +234,7 @@ static void __init sama5d3_pmc_setup(struct device_node *np) hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, &sama5d3_pcr_layout, sama5d3_periphck[i].n, - "masterck", + "masterck_div", sama5d3_periphck[i].id, &sama5d3_periphck[i].r, INT_MIN); diff --git a/drivers/clk/at91/sama5d4.c b/drivers/clk/at91/sama5d4.c index 92d8d4141b43..57fff790188b 100644 --- a/drivers/clk/at91/sama5d4.c +++ b/drivers/clk/at91/sama5d4.c @@ -7,6 +7,8 @@ #include "pmc.h" +static DEFINE_SPINLOCK(mck_lock); + static const struct clk_master_characteristics mck_characteristics = { .output = { .min = 125000000, .max = 200000000 }, .divisors = { 1, 2, 4, 3 }, @@ -39,14 +41,14 @@ static const struct { char *p; u8 id; } sama5d4_systemck[] = { - { .n = "ddrck", .p = "masterck", .id = 2 }, - { .n = "lcdck", .p = "masterck", .id = 3 }, - { .n = "smdck", .p = "smdclk", .id = 4 }, - { .n = "uhpck", .p = "usbck", .id = 6 }, - { .n = "udpck", .p = "usbck", .id = 7 }, - { .n = "pck0", .p = "prog0", .id = 8 }, - { .n = "pck1", .p = "prog1", .id = 9 }, - { .n = "pck2", .p = "prog2", .id = 10 }, + { .n = "ddrck", .p = "masterck_div", .id = 2 }, + { .n = "lcdck", .p = "masterck_div", .id = 3 }, + { .n = "smdck", .p = "smdclk", .id = 4 }, + { .n = "uhpck", .p = "usbck", .id = 6 }, + { .n = "udpck", .p = "usbck", .id = 7 }, + { .n = "pck0", .p = "prog0", .id = 8 }, + { .n = "pck1", .p = "prog1", .id = 9 }, + { .n = "pck2", .p = "prog2", .id = 10 }, }; static const struct { @@ -185,15 +187,25 @@ static void __init sama5d4_pmc_setup(struct device_node *np) parent_names[1] = "mainck"; parent_names[2] = "plladivck"; parent_names[3] = "utmick"; - hw = at91_clk_register_master(regmap, "masterck", 4, parent_names, - &at91sam9x5_master_layout, - &mck_characteristics); + hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4, + parent_names, + &at91sam9x5_master_layout, + &mck_characteristics, &mck_lock, + CLK_SET_RATE_GATE, INT_MIN); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_master_div(regmap, "masterck_div", + "masterck_pres", + &at91sam9x5_master_layout, + &mck_characteristics, &mck_lock, + CLK_SET_RATE_GATE); if (IS_ERR(hw)) goto err_free; sama5d4_pmc->chws[PMC_MCK] = hw; - hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck"); + hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck_div"); if (IS_ERR(hw)) goto err_free; @@ -215,7 +227,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np) parent_names[1] = "mainck"; parent_names[2] = "plladivck"; parent_names[3] = "utmick"; - parent_names[4] = "masterck"; + parent_names[4] = "masterck_div"; for (i = 0; i < 3; i++) { char name[6]; @@ -245,7 +257,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np) hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, &sama5d4_pcr_layout, sama5d4_periphck[i].n, - "masterck", + "masterck_div", sama5d4_periphck[i].id, &range, INT_MIN); if (IS_ERR(hw)) diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c index e0c4d2eb9f59..927eb3b2b126 100644 --- a/drivers/clk/at91/sama7g5.c +++ b/drivers/clk/at91/sama7g5.c @@ -32,6 +32,7 @@ } while (0) static DEFINE_SPINLOCK(pmc_pll_lock); +static DEFINE_SPINLOCK(pmc_mck0_lock); static DEFINE_SPINLOCK(pmc_mckX_lock); /** @@ -984,8 +985,16 @@ static void __init sama7g5_pmc_setup(struct device_node *np) parent_names[1] = "mainck"; parent_names[2] = "cpupll_divpmcck"; parent_names[3] = "syspll_divpmcck"; - hw = at91_clk_register_master(regmap, "mck0", 4, parent_names, - &mck0_layout, &mck0_characteristics); + hw = at91_clk_register_master_pres(regmap, "mck0_pres", 4, parent_names, + &mck0_layout, &mck0_characteristics, + &pmc_mck0_lock, + CLK_SET_RATE_PARENT, 0); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_master_div(regmap, "mck0_div", "mck0_pres", + &mck0_layout, &mck0_characteristics, + &pmc_mck0_lock, 0); if (IS_ERR(hw)) goto err_free; From 91f3bf0d5315ea3f139ae440f2b7772ecdcd67ec Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 19 Nov 2020 17:43:17 +0200 Subject: [PATCH 125/134] clk: at91: sama7g5: register cpu clock Register CPU clock as being the master clock prescaler. This would be used by DVFS. The block schema of SAMA7G5's PMC contains also a divider between master clock prescaler and CPU (PMC_CPU_RATIO.RATIO) but the frequencies supported by SAMA7G5 could be directly received from CPUPLL + master clock prescaler and the extra divider would do no work in case it would be enabled. Signed-off-by: Claudiu Beznea Link: https://lore.kernel.org/r/1605800597-16720-12-git-send-email-claudiu.beznea@microchip.com Signed-off-by: Stephen Boyd --- drivers/clk/at91/sama7g5.c | 13 ++++++------- include/dt-bindings/clock/at91.h | 1 + 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c index 927eb3b2b126..a6e20b35960e 100644 --- a/drivers/clk/at91/sama7g5.c +++ b/drivers/clk/at91/sama7g5.c @@ -904,7 +904,7 @@ static void __init sama7g5_pmc_setup(struct device_node *np) if (IS_ERR(regmap)) return; - sama7g5_pmc = pmc_data_allocate(PMC_ETHPLL + 1, + sama7g5_pmc = pmc_data_allocate(PMC_CPU + 1, nck(sama7g5_systemck), nck(sama7g5_periphck), nck(sama7g5_gck), 8); @@ -981,18 +981,17 @@ static void __init sama7g5_pmc_setup(struct device_node *np) } } - parent_names[0] = md_slck_name; - parent_names[1] = "mainck"; - parent_names[2] = "cpupll_divpmcck"; - parent_names[3] = "syspll_divpmcck"; - hw = at91_clk_register_master_pres(regmap, "mck0_pres", 4, parent_names, + parent_names[0] = "cpupll_divpmcck"; + hw = at91_clk_register_master_pres(regmap, "cpuck", 1, parent_names, &mck0_layout, &mck0_characteristics, &pmc_mck0_lock, CLK_SET_RATE_PARENT, 0); if (IS_ERR(hw)) goto err_free; - hw = at91_clk_register_master_div(regmap, "mck0_div", "mck0_pres", + sama7g5_pmc->chws[PMC_CPU] = hw; + + hw = at91_clk_register_master_div(regmap, "mck0", "cpuck", &mck0_layout, &mck0_characteristics, &pmc_mck0_lock, 0); if (IS_ERR(hw)) diff --git a/include/dt-bindings/clock/at91.h b/include/dt-bindings/clock/at91.h index fab313f62e8f..98e1b2ab6403 100644 --- a/include/dt-bindings/clock/at91.h +++ b/include/dt-bindings/clock/at91.h @@ -34,6 +34,7 @@ #define PMC_AUDIOPMCPLL (PMC_MAIN + 6) #define PMC_AUDIOIOPLL (PMC_MAIN + 7) #define PMC_ETHPLL (PMC_MAIN + 8) +#define PMC_CPU (PMC_MAIN + 9) #ifndef AT91_PMC_MOSCS #define AT91_PMC_MOSCS 0 /* MOSCS Flag */ From 01324f9e88b5cfc1f4c26eef66bdcb52596c9af8 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 2 Dec 2020 13:58:15 +0100 Subject: [PATCH 126/134] clk: at91: sam9x60: remove atmel,osc-bypass support The sam9x60 doesn't have the MOSCXTBY bit to enable the crystal oscillator bypass. Fixes: 01e2113de9a5 ("clk: at91: add sam9x60 pmc driver") Reported-by: Claudiu Beznea Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20201202125816.168618-1-alexandre.belloni@bootlin.com Reviewed-by: Claudiu Beznea Tested-by: Claudiu Beznea Signed-off-by: Stephen Boyd --- drivers/clk/at91/sam9x60.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/clk/at91/sam9x60.c b/drivers/clk/at91/sam9x60.c index 240e48149bcd..5f6fa89571b7 100644 --- a/drivers/clk/at91/sam9x60.c +++ b/drivers/clk/at91/sam9x60.c @@ -175,7 +175,6 @@ static void __init sam9x60_pmc_setup(struct device_node *np) struct regmap *regmap; struct clk_hw *hw; int i; - bool bypass; i = of_property_match_string(np, "clock-names", "td_slck"); if (i < 0) @@ -210,10 +209,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np) if (IS_ERR(hw)) goto err_free; - bypass = of_property_read_bool(np, "atmel,osc-bypass"); - - hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name, - bypass); + hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name, 0); if (IS_ERR(hw)) goto err_free; main_osc_hw = hw; From 5142cbcea324909be03b176540c0c2f3975922b4 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 30 Nov 2020 10:10:33 +0100 Subject: [PATCH 127/134] clk: si5351: Wait for bit clear after PLL reset Documentation states that SI5351_PLL_RESET_B and SI5351_PLL_RESET_A bits are self clearing bits, so wait until they are cleared before continuing. This fixes a case when the clock doesn't come up properly after a PLL reset. It worked properly when the frequency was below 900MHz, but with 900MHz it only works when we are waiting for the bit to clear. Signed-off-by: Sascha Hauer Link: https://lore.kernel.org/r/20201130091033.1687-1-s.hauer@pengutronix.de Signed-off-by: Stephen Boyd --- drivers/clk/clk-si5351.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c index 1e1702e609cb..57e4597cdf4c 100644 --- a/drivers/clk/clk-si5351.c +++ b/drivers/clk/clk-si5351.c @@ -902,6 +902,10 @@ static int _si5351_clkout_set_disable_state( static void _si5351_clkout_reset_pll(struct si5351_driver_data *drvdata, int num) { u8 val = si5351_reg_read(drvdata, SI5351_CLK0_CTRL + num); + u8 mask = val & SI5351_CLK_PLL_SELECT ? SI5351_PLL_RESET_B : + SI5351_PLL_RESET_A; + unsigned int v; + int err; switch (val & SI5351_CLK_INPUT_MASK) { case SI5351_CLK_INPUT_XTAL: @@ -909,9 +913,12 @@ static void _si5351_clkout_reset_pll(struct si5351_driver_data *drvdata, int num return; /* pll not used, no need to reset */ } - si5351_reg_write(drvdata, SI5351_PLL_RESET, - val & SI5351_CLK_PLL_SELECT ? SI5351_PLL_RESET_B : - SI5351_PLL_RESET_A); + si5351_reg_write(drvdata, SI5351_PLL_RESET, mask); + + err = regmap_read_poll_timeout(drvdata->regmap, SI5351_PLL_RESET, v, + !(v & mask), 0, 20000); + if (err < 0) + dev_err(&drvdata->client->dev, "Reset bit didn't clear\n"); dev_dbg(&drvdata->client->dev, "%s - %s: pll = %d\n", __func__, clk_hw_get_name(&drvdata->clkout[num].hw), From 6f37689cf6b38fff96de52e7f0d3e78f22803ba0 Mon Sep 17 00:00:00 2001 From: Terry Zhou Date: Fri, 6 Nov 2020 11:00:39 +0100 Subject: [PATCH 128/134] clk: mvebu: a3700: fix the XTAL MODE pin to MPP1_9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is an error in the current code that the XTAL MODE pin was set to NB MPP1_31 which should be NB MPP1_9. The latch register of NB MPP1_9 has different offset of 0x8. Signed-off-by: Terry Zhou [pali: Fix pin name in commit message] Signed-off-by: Pali Rohár Fixes: 7ea8250406a6 ("clk: mvebu: Add the xtal clock for Armada 3700 SoC") Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20201106100039.11385-1-pali@kernel.org Reviewed-by: Marek Behún Signed-off-by: Stephen Boyd --- drivers/clk/mvebu/armada-37xx-xtal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/mvebu/armada-37xx-xtal.c b/drivers/clk/mvebu/armada-37xx-xtal.c index e9e306d4e9af..41271351cf1f 100644 --- a/drivers/clk/mvebu/armada-37xx-xtal.c +++ b/drivers/clk/mvebu/armada-37xx-xtal.c @@ -13,8 +13,8 @@ #include #include -#define NB_GPIO1_LATCH 0xC -#define XTAL_MODE BIT(31) +#define NB_GPIO1_LATCH 0x8 +#define XTAL_MODE BIT(9) static int armada_3700_xtal_clock_probe(struct platform_device *pdev) { From d2d94fc567624f96187e8b52083795620f93e69f Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 12 Dec 2020 13:28:18 +0100 Subject: [PATCH 129/134] clk: s2mps11: Fix a resource leak in error handling paths in the probe function Some resource should be released in the error handling path of the probe function, as already done in the remove function. The remove function was fixed in commit bf416bd45738 ("clk: s2mps11: Add missing of_node_put and of_clk_del_provider") Fixes: 7cc560dea415 ("clk: s2mps11: Add support for s2mps11") Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/20201212122818.86195-1-christophe.jaillet@wanadoo.fr Reviewed-by: Krzysztof Kozlowski Signed-off-by: Stephen Boyd --- drivers/clk/clk-s2mps11.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c index aa21371f9104..a3e883a9f406 100644 --- a/drivers/clk/clk-s2mps11.c +++ b/drivers/clk/clk-s2mps11.c @@ -195,6 +195,7 @@ static int s2mps11_clk_probe(struct platform_device *pdev) return ret; err_reg: + of_node_put(s2mps11_clks[0].clk_np); while (--i >= 0) clkdev_drop(s2mps11_clks[i].lookup); From 48f68de00c1405351fa0e7bc44bca067c49cd0a3 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Wed, 2 Dec 2020 21:38:17 +0100 Subject: [PATCH 130/134] clk: sunxi-ng: Make sure divider tables have sentinel Two clock divider tables are missing sentinel at the end. Effect of that is that clock framework reads past the last entry. Fix that with adding sentinel at the end. Issue was discovered with KASan. Fixes: 0577e4853bfb ("clk: sunxi-ng: Add H3 clocks") Fixes: c6a0637460c2 ("clk: sunxi-ng: Add A64 clocks") Signed-off-by: Jernej Skrabec Link: https://lore.kernel.org/r/20201202203817.438713-1-jernej.skrabec@siol.net Acked-by: Maxime Ripard Signed-off-by: Stephen Boyd --- drivers/clk/sunxi-ng/ccu-sun50i-a64.c | 1 + drivers/clk/sunxi-ng/ccu-sun8i-h3.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c index 5f66bf879772..149cfde817cb 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c @@ -389,6 +389,7 @@ static struct clk_div_table ths_div_table[] = { { .val = 1, .div = 2 }, { .val = 2, .div = 4 }, { .val = 3, .div = 6 }, + { /* Sentinel */ }, }; static const char * const ths_parents[] = { "osc24M" }; static struct ccu_div ths_clk = { diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c index 6b636362379e..7e629a4493af 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c @@ -322,6 +322,7 @@ static struct clk_div_table ths_div_table[] = { { .val = 1, .div = 2 }, { .val = 2, .div = 4 }, { .val = 3, .div = 6 }, + { /* Sentinel */ }, }; static SUNXI_CCU_DIV_TABLE_WITH_GATE(ths_clk, "ths", "osc24M", 0x074, 0, 2, ths_div_table, BIT(31), 0); From 11a163f2c7d6a9f27ce144cd7e367a81c851621a Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 12 Dec 2020 13:57:33 +0000 Subject: [PATCH 131/134] clk: ingenic: Fix divider calculation with div tables The previous code assumed that a higher hardware value always resulted in a bigger divider, which is correct for the regular clocks, but is an invalid assumption when a divider table is provided for the clock. Perfect example of this is the PLL0_HALF clock, which applies a /2 divider with the hardware value 0, and a /1 divider otherwise. Fixes: a9fa2893fcc6 ("clk: ingenic: Add support for divider tables") Cc: # 5.2 Signed-off-by: Paul Cercueil Link: https://lore.kernel.org/r/20201212135733.38050-1-paul@crapouillou.net Signed-off-by: Stephen Boyd --- drivers/clk/ingenic/cgu.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c index dac6edc670cc..c8e9cb6c8e39 100644 --- a/drivers/clk/ingenic/cgu.c +++ b/drivers/clk/ingenic/cgu.c @@ -392,15 +392,21 @@ static unsigned int ingenic_clk_calc_hw_div(const struct ingenic_cgu_clk_info *clk_info, unsigned int div) { - unsigned int i; + unsigned int i, best_i = 0, best = (unsigned int)-1; for (i = 0; i < (1 << clk_info->div.bits) && clk_info->div.div_table[i]; i++) { - if (clk_info->div.div_table[i] >= div) - return i; + if (clk_info->div.div_table[i] >= div && + clk_info->div.div_table[i] < best) { + best = clk_info->div.div_table[i]; + best_i = i; + + if (div == best) + break; + } } - return i - 1; + return best_i; } static unsigned From 4b003f5fcadfa2d0e087e907b0c65d023f6e29fb Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 18 Dec 2020 13:52:53 +0100 Subject: [PATCH 132/134] clk: vc5: Use "idt,voltage-microvolt" instead of "idt,voltage-microvolts" Commit 45c940184b501fc6 ("dt-bindings: clk: versaclock5: convert to yaml") accidentally changed "idt,voltage-microvolts" to "idt,voltage-microvolt" in the DT bindings, while the driver still used the former. Update the driver to match the bindings, as Documentation/devicetree/bindings/property-units.txt actually recommends using "microvolt". Fixes: 260249f929e81d3d ("clk: vc5: Enable addition output configurations of the Versaclock") Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20201218125253.3815567-1-geert+renesas@glider.be Reviewed-by: Luca Ceresoli Signed-off-by: Stephen Boyd --- drivers/clk/clk-versaclock5.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk-versaclock5.c b/drivers/clk/clk-versaclock5.c index c90460e7ef21..43db67337bc0 100644 --- a/drivers/clk/clk-versaclock5.c +++ b/drivers/clk/clk-versaclock5.c @@ -739,8 +739,8 @@ static int vc5_update_power(struct device_node *np_output, { u32 value; - if (!of_property_read_u32(np_output, - "idt,voltage-microvolts", &value)) { + if (!of_property_read_u32(np_output, "idt,voltage-microvolt", + &value)) { clk_out->clk_output_cfg0_mask |= VC5_CLK_OUTPUT_CFG0_PWR_MASK; switch (value) { case 1800000: From 6c5c16007a11676eb8d4aeeb090a940b20976747 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Sun, 20 Dec 2020 17:57:24 +0900 Subject: [PATCH 133/134] dt-bindings: Add Canaan vendor prefix Update Documentation/devicetree/bindings/vendor-prefixes.yaml to include "canaan" as a vendor prefix for "Canaan Inc.". Canaan is the vendor of the Kendryte K210 RISC-V SoC. Signed-off-by: Damien Le Moal Acked-by: Rob Herring Link: https://lore.kernel.org/r/20201220085725.19545-2-damien.lemoal@wdc.com Signed-off-by: Stephen Boyd --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 2735be1a8470..a07231aaf3e7 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -179,6 +179,8 @@ patternProperties: description: CALAO Systems SAS "^calxeda,.*": description: Calxeda + "^canaan,.*": + description: Canaan, Inc. "^caninos,.*": description: Caninos Loucos Program "^capella,.*": From 0c797d2c7e82bfec69e8fceb0d03b1e016eed03b Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Sun, 20 Dec 2020 17:57:25 +0900 Subject: [PATCH 134/134] dt-binding: clock: Document canaan,k210-clk bindings Document the device tree bindings of the Canaan Kendryte K210 SoC clock driver in Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml. The header file include/dt-bindings/clock/k210-clk.h is modified to include the complete list of IDs for all clocks of the SoC. Signed-off-by: Damien Le Moal Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20201220085725.19545-3-damien.lemoal@wdc.com Signed-off-by: Stephen Boyd --- .../bindings/clock/canaan,k210-clk.yaml | 54 ++++++++++++++++++ include/dt-bindings/clock/k210-clk.h | 56 +++++++++++++++---- 2 files changed, 99 insertions(+), 11 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml diff --git a/Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml b/Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml new file mode 100644 index 000000000000..565ca468cb44 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/canaan,k210-clk.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Canaan Kendryte K210 Clock Device Tree Bindings + +maintainers: + - Damien Le Moal + +description: | + Canaan Kendryte K210 SoC clocks driver bindings. The clock + controller node must be defined as a child node of the K210 + system controller node. + + See also: + - dt-bindings/clock/k210-clk.h + +properties: + compatible: + const: canaan,k210-clk + + clocks: + description: + Phandle of the SoC 26MHz fixed-rate oscillator clock. + + '#clock-cells': + const: 1 + +required: + - compatible + - '#clock-cells' + - clocks + +additionalProperties: false + +examples: + - | + #include + clocks { + in0: oscillator { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <26000000>; + }; + }; + + /* ... */ + sysclk: clock-controller { + #clock-cells = <1>; + compatible = "canaan,k210-clk"; + clocks = <&in0>; + }; diff --git a/include/dt-bindings/clock/k210-clk.h b/include/dt-bindings/clock/k210-clk.h index 5a2fd64d1a49..a48176ad3c23 100644 --- a/include/dt-bindings/clock/k210-clk.h +++ b/include/dt-bindings/clock/k210-clk.h @@ -3,18 +3,52 @@ * Copyright (C) 2019-20 Sean Anderson * Copyright (c) 2020 Western Digital Corporation or its affiliates. */ -#ifndef K210_CLK_H -#define K210_CLK_H +#ifndef CLOCK_K210_CLK_H +#define CLOCK_K210_CLK_H /* - * Arbitrary identifiers for clocks. - * The structure is: in0 -> pll0 -> aclk -> cpu - * - * Since we use the hardware defaults for now, set all these to the same clock. + * Kendryte K210 SoC clock identifiers (arbitrary values). */ -#define K210_CLK_PLL0 0 -#define K210_CLK_PLL1 0 -#define K210_CLK_ACLK 0 -#define K210_CLK_CPU 0 +#define K210_CLK_ACLK 0 +#define K210_CLK_CPU 0 +#define K210_CLK_SRAM0 1 +#define K210_CLK_SRAM1 2 +#define K210_CLK_AI 3 +#define K210_CLK_DMA 4 +#define K210_CLK_FFT 5 +#define K210_CLK_ROM 6 +#define K210_CLK_DVP 7 +#define K210_CLK_APB0 8 +#define K210_CLK_APB1 9 +#define K210_CLK_APB2 10 +#define K210_CLK_I2S0 11 +#define K210_CLK_I2S1 12 +#define K210_CLK_I2S2 13 +#define K210_CLK_I2S0_M 14 +#define K210_CLK_I2S1_M 15 +#define K210_CLK_I2S2_M 16 +#define K210_CLK_WDT0 17 +#define K210_CLK_WDT1 18 +#define K210_CLK_SPI0 19 +#define K210_CLK_SPI1 20 +#define K210_CLK_SPI2 21 +#define K210_CLK_I2C0 22 +#define K210_CLK_I2C1 23 +#define K210_CLK_I2C2 24 +#define K210_CLK_SPI3 25 +#define K210_CLK_TIMER0 26 +#define K210_CLK_TIMER1 27 +#define K210_CLK_TIMER2 28 +#define K210_CLK_GPIO 29 +#define K210_CLK_UART1 30 +#define K210_CLK_UART2 31 +#define K210_CLK_UART3 32 +#define K210_CLK_FPIOA 33 +#define K210_CLK_SHA 34 +#define K210_CLK_AES 35 +#define K210_CLK_OTP 36 +#define K210_CLK_RTC 37 -#endif /* K210_CLK_H */ +#define K210_NUM_CLKS 38 + +#endif /* CLOCK_K210_CLK_H */