From a2c08df3813b6b1ab6fd016a9f5b264c634e6813 Mon Sep 17 00:00:00 2001 From: Kever Yang Date: Tue, 16 Aug 2016 17:58:11 +0800 Subject: pinctrl: add driver for rk3399 This patch add pinctrl driver for rk3399. Signed-off-by: Kever Yang Acked-by: Simon Glass --- drivers/pinctrl/Kconfig | 9 + drivers/pinctrl/rockchip/Makefile | 1 + drivers/pinctrl/rockchip/pinctrl_rk3399.c | 439 ++++++++++++++++++++++++++++++ 3 files changed, 449 insertions(+) create mode 100644 drivers/pinctrl/rockchip/pinctrl_rk3399.c (limited to 'drivers') diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index f8cfd4bb245..12be3cfe0b8 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -148,6 +148,15 @@ config PINCTRL_AT91PIO4 This option is to enable the AT91 pinctrl driver for AT91 PIO4 controller which is available on SAMA5D2 SoC. +config ROCKCHIP_RK3399_PINCTRL + bool "Rockchip pin control driver" + depends on DM + help + Support pin multiplexing control on Rockchip rk3399 SoCs. The driver + is controlled by a device tree node which contains both the GPIO + definitions and pin control functions for each available multiplex + function. + config PINCTRL_SANDBOX bool "Sandbox pinctrl driver" depends on SANDBOX diff --git a/drivers/pinctrl/rockchip/Makefile b/drivers/pinctrl/rockchip/Makefile index 64e9587cce4..805c833ec9d 100644 --- a/drivers/pinctrl/rockchip/Makefile +++ b/drivers/pinctrl/rockchip/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_ROCKCHIP_RK3036_PINCTRL) += pinctrl_rk3036.o obj-$(CONFIG_ROCKCHIP_RK3288_PINCTRL) += pinctrl_rk3288.o +obj-$(CONFIG_ROCKCHIP_RK3399_PINCTRL) += pinctrl_rk3399.o diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3399.c b/drivers/pinctrl/rockchip/pinctrl_rk3399.c new file mode 100644 index 00000000000..17ea165edaf --- /dev/null +++ b/drivers/pinctrl/rockchip/pinctrl_rk3399.c @@ -0,0 +1,439 @@ +/* + * (C) Copyright 2016 Rockchip Electronics Co., Ltd + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +struct rk3399_pinctrl_priv { + struct rk3399_grf_regs *grf; + struct rk3399_pmugrf_regs *pmugrf; +}; + +enum { + /* GRF_GPIO2B_IOMUX */ + GRF_GPIO2B1_SEL_SHIFT = 0, + GRF_GPIO2B1_SEL_MASK = 3 << GRF_GPIO2B1_SEL_SHIFT, + GRF_SPI2TPM_RXD = 1, + GRF_GPIO2B2_SEL_SHIFT = 2, + GRF_GPIO2B2_SEL_MASK = 3 << GRF_GPIO2B2_SEL_SHIFT, + GRF_SPI2TPM_TXD = 1, + GRF_GPIO2B3_SEL_SHIFT = 6, + GRF_GPIO2B3_SEL_MASK = 3 << GRF_GPIO2B3_SEL_SHIFT, + GRF_SPI2TPM_CLK = 1, + GRF_GPIO2B4_SEL_SHIFT = 8, + GRF_GPIO2B4_SEL_MASK = 3 << GRF_GPIO2B4_SEL_SHIFT, + GRF_SPI2TPM_CSN0 = 1, + + /* GRF_GPIO3A_IOMUX */ + GRF_GPIO3A4_SEL_SHIFT = 8, + GRF_GPIO3A4_SEL_MASK = 3 << GRF_GPIO3A4_SEL_SHIFT, + GRF_SPI0NORCODEC_RXD = 2, + GRF_GPIO3A5_SEL_SHIFT = 10, + GRF_GPIO3A5_SEL_MASK = 3 << GRF_GPIO3A5_SEL_SHIFT, + GRF_SPI0NORCODEC_TXD = 2, + GRF_GPIO3A6_SEL_SHIFT = 12, + GRF_GPIO3A6_SEL_MASK = 3 << GRF_GPIO3A6_SEL_SHIFT, + GRF_SPI0NORCODEC_CLK = 2, + GRF_GPIO3A7_SEL_SHIFT = 14, + GRF_GPIO3A7_SEL_MASK = 3 << GRF_GPIO3A7_SEL_SHIFT, + GRF_SPI0NORCODEC_CSN0 = 2, + + /* GRF_GPIO3B_IOMUX */ + GRF_GPIO3B0_SEL_SHIFT = 0, + GRF_GPIO3B0_SEL_MASK = 3 << GRF_GPIO3B0_SEL_SHIFT, + GRF_SPI0NORCODEC_CSN1 = 2, + + /* GRF_GPIO4B_IOMUX */ + GRF_GPIO4B0_SEL_SHIFT = 0, + GRF_GPIO4B0_SEL_MASK = 3 << GRF_GPIO4B0_SEL_SHIFT, + GRF_SDMMC_DATA0 = 1, + GRF_UART2DBGA_SIN = 2, + GRF_GPIO4B1_SEL_SHIFT = 2, + GRF_GPIO4B1_SEL_MASK = 3 << GRF_GPIO4B1_SEL_SHIFT, + GRF_SDMMC_DATA1 = 1, + GRF_UART2DBGA_SOUT = 2, + GRF_GPIO4B2_SEL_SHIFT = 4, + GRF_GPIO4B2_SEL_MASK = 3 << GRF_GPIO4B2_SEL_SHIFT, + GRF_SDMMC_DATA2 = 1, + GRF_GPIO4B3_SEL_SHIFT = 6, + GRF_GPIO4B3_SEL_MASK = 3 << GRF_GPIO4B3_SEL_SHIFT, + GRF_SDMMC_DATA3 = 1, + GRF_GPIO4B4_SEL_SHIFT = 8, + GRF_GPIO4B4_SEL_MASK = 3 << GRF_GPIO4B4_SEL_SHIFT, + GRF_SDMMC_CLKOUT = 1, + GRF_GPIO4B5_SEL_SHIFT = 10, + GRF_GPIO4B5_SEL_MASK = 3 << GRF_GPIO4B5_SEL_SHIFT, + GRF_SDMMC_CMD = 1, + + /* GRF_GPIO4C_IOMUX */ + GRF_GPIO4C2_SEL_SHIFT = 4, + GRF_GPIO4C2_SEL_MASK = 3 << GRF_GPIO4C2_SEL_SHIFT, + GRF_PWM_0 = 1, + GRF_GPIO4C3_SEL_SHIFT = 6, + GRF_GPIO4C3_SEL_MASK = 3 << GRF_GPIO4C3_SEL_SHIFT, + GRF_UART2DGBC_SIN = 1, + GRF_GPIO4C4_SEL_SHIFT = 8, + GRF_GPIO4C4_SEL_MASK = 3 << GRF_GPIO4C4_SEL_SHIFT, + GRF_UART2DBGC_SOUT = 1, + GRF_GPIO4C6_SEL_SHIFT = 12, + GRF_GPIO4C6_SEL_MASK = 3 << GRF_GPIO4C6_SEL_SHIFT, + GRF_PWM_1 = 1, + + /* PMUGRF_GPIO0A_IOMUX */ + PMUGRF_GPIO0A6_SEL_SHIFT = 12, + PMUGRF_GPIO0A6_SEL_MASK = 3 << PMUGRF_GPIO0A6_SEL_SHIFT, + PMUGRF_PWM_3A = 1, + + /* PMUGRF_GPIO1A_IOMUX */ + PMUGRF_GPIO1A7_SEL_SHIFT = 14, + PMUGRF_GPIO1A7_SEL_MASK = 3 << PMUGRF_GPIO1A7_SEL_SHIFT, + PMUGRF_SPI1EC_RXD = 2, + + /* PMUGRF_GPIO1B_IOMUX */ + PMUGRF_GPIO1B0_SEL_SHIFT = 0, + PMUGRF_GPIO1B0_SEL_MASK = 3 << PMUGRF_GPIO1B0_SEL_SHIFT, + PMUGRF_SPI1EC_TXD = 2, + PMUGRF_GPIO1B1_SEL_SHIFT = 2, + PMUGRF_GPIO1B1_SEL_MASK = 3 << PMUGRF_GPIO1B1_SEL_SHIFT, + PMUGRF_SPI1EC_CLK = 2, + PMUGRF_GPIO1B2_SEL_SHIFT = 4, + PMUGRF_GPIO1B2_SEL_MASK = 3 << PMUGRF_GPIO1B2_SEL_SHIFT, + PMUGRF_SPI1EC_CSN0 = 2, + PMUGRF_GPIO1B6_SEL_SHIFT = 12, + PMUGRF_GPIO1B6_SEL_MASK = 3 << PMUGRF_GPIO1B6_SEL_SHIFT, + PMUGRF_PWM_3B = 1, + PMUGRF_GPIO1B7_SEL_SHIFT = 14, + PMUGRF_GPIO1B7_SEL_MASK = 3 << PMUGRF_GPIO1B7_SEL_SHIFT, + PMUGRF_I2C0PMU_SDA = 2, + + /* PMUGRF_GPIO1C_IOMUX */ + PMUGRF_GPIO1C0_SEL_SHIFT = 0, + PMUGRF_GPIO1C0_SEL_MASK = 3 << PMUGRF_GPIO1C0_SEL_SHIFT, + PMUGRF_I2C0PMU_SCL = 2, + PMUGRF_GPIO1C3_SEL_SHIFT = 6, + PMUGRF_GPIO1C3_SEL_MASK = 3 << PMUGRF_GPIO1C3_SEL_SHIFT, + PMUGRF_PWM_2 = 1, + +}; +static void pinctrl_rk3399_pwm_config(struct rk3399_grf_regs *grf, + struct rk3399_pmugrf_regs *pmugrf, int pwm_id) +{ + switch (pwm_id) { + case PERIPH_ID_PWM0: + rk_clrsetreg(&grf->gpio4c_iomux, + GRF_GPIO4C2_SEL_MASK, + GRF_PWM_0 << GRF_GPIO4C2_SEL_SHIFT); + break; + case PERIPH_ID_PWM1: + rk_clrsetreg(&grf->gpio4c_iomux, + GRF_GPIO4C6_SEL_MASK, + GRF_PWM_1 << GRF_GPIO4C6_SEL_SHIFT); + break; + case PERIPH_ID_PWM2: + rk_clrsetreg(&pmugrf->gpio1c_iomux, + PMUGRF_GPIO1C3_SEL_MASK, + PMUGRF_PWM_2 << PMUGRF_GPIO1C3_SEL_SHIFT); + break; + case PERIPH_ID_PWM3: + if (readl(&pmugrf->soc_con0) & (1 << 5)) + rk_clrsetreg(&pmugrf->gpio1b_iomux, + PMUGRF_GPIO1B6_SEL_MASK, + PMUGRF_PWM_3B << PMUGRF_GPIO1B6_SEL_SHIFT); + else + rk_clrsetreg(&pmugrf->gpio0a_iomux, + PMUGRF_GPIO0A6_SEL_MASK, + PMUGRF_PWM_3A << PMUGRF_GPIO0A6_SEL_SHIFT); + break; + default: + debug("pwm id = %d iomux error!\n", pwm_id); + break; + } +} + +static void pinctrl_rk3399_i2c_config(struct rk3399_grf_regs *grf, + struct rk3399_pmugrf_regs *pmugrf, + int i2c_id) +{ + switch (i2c_id) { + case PERIPH_ID_I2C0: + rk_clrsetreg(&pmugrf->gpio1b_iomux, + PMUGRF_GPIO1B7_SEL_MASK, + PMUGRF_I2C0PMU_SDA << PMUGRF_GPIO1B7_SEL_SHIFT); + rk_clrsetreg(&pmugrf->gpio1c_iomux, + PMUGRF_GPIO1C0_SEL_MASK, + PMUGRF_I2C0PMU_SCL << PMUGRF_GPIO1C0_SEL_SHIFT); + break; + case PERIPH_ID_I2C1: + case PERIPH_ID_I2C2: + case PERIPH_ID_I2C3: + case PERIPH_ID_I2C4: + case PERIPH_ID_I2C5: + default: + debug("i2c id = %d iomux error!\n", i2c_id); + break; + } +} + +static void pinctrl_rk3399_lcdc_config(struct rk3399_grf_regs *grf, int lcd_id) +{ + switch (lcd_id) { + case PERIPH_ID_LCDC0: + break; + default: + debug("lcdc id = %d iomux error!\n", lcd_id); + break; + } +} + +static int pinctrl_rk3399_spi_config(struct rk3399_grf_regs *grf, + struct rk3399_pmugrf_regs *pmugrf, + enum periph_id spi_id, int cs) +{ + switch (spi_id) { + case PERIPH_ID_SPI0: + switch (cs) { + case 0: + rk_clrsetreg(&grf->gpio3a_iomux, + GRF_GPIO3A7_SEL_MASK, + GRF_SPI0NORCODEC_CSN0 + << GRF_GPIO3A7_SEL_SHIFT); + break; + case 1: + rk_clrsetreg(&grf->gpio3b_iomux, + GRF_GPIO3B0_SEL_MASK, + GRF_SPI0NORCODEC_CSN1 + << GRF_GPIO3B0_SEL_SHIFT); + break; + default: + goto err; + } + rk_clrsetreg(&grf->gpio3a_iomux, + GRF_GPIO3A4_SEL_MASK | GRF_GPIO3A5_SEL_SHIFT + | GRF_GPIO3A6_SEL_SHIFT, + GRF_SPI0NORCODEC_RXD << GRF_GPIO3A4_SEL_SHIFT + | GRF_SPI0NORCODEC_RXD << GRF_GPIO3A5_SEL_SHIFT + | GRF_SPI0NORCODEC_RXD << GRF_GPIO3A6_SEL_SHIFT); + break; + case PERIPH_ID_SPI1: + if (cs != 0) + goto err; + rk_clrsetreg(&pmugrf->gpio1a_iomux, + PMUGRF_GPIO1A7_SEL_MASK, + PMUGRF_SPI1EC_RXD << PMUGRF_GPIO1A7_SEL_SHIFT); + rk_clrsetreg(&pmugrf->gpio1b_iomux, + PMUGRF_GPIO1B0_SEL_MASK | PMUGRF_GPIO1B1_SEL_MASK + | PMUGRF_GPIO1B2_SEL_MASK, + PMUGRF_SPI1EC_TXD << PMUGRF_GPIO1B0_SEL_SHIFT + | PMUGRF_SPI1EC_CLK << PMUGRF_GPIO1B1_SEL_SHIFT + | PMUGRF_SPI1EC_CSN0 << PMUGRF_GPIO1B2_SEL_SHIFT); + break; + case PERIPH_ID_SPI2: + if (cs != 0) + goto err; + rk_clrsetreg(&grf->gpio2b_iomux, + GRF_GPIO2B1_SEL_MASK | GRF_GPIO2B2_SEL_MASK + | GRF_GPIO2B3_SEL_MASK | GRF_GPIO2B4_SEL_MASK, + GRF_SPI2TPM_RXD << GRF_GPIO2B1_SEL_SHIFT + | GRF_SPI2TPM_TXD << GRF_GPIO2B2_SEL_SHIFT + | GRF_SPI2TPM_CLK << GRF_GPIO2B3_SEL_SHIFT + | GRF_SPI2TPM_CSN0 << GRF_GPIO2B4_SEL_SHIFT); + break; + default: + goto err; + } + + return 0; +err: + debug("rkspi: periph%d cs=%d not supported", spi_id, cs); + return -ENOENT; +} + +static void pinctrl_rk3399_uart_config(struct rk3399_grf_regs *grf, + struct rk3399_pmugrf_regs *pmugrf, + int uart_id) +{ + switch (uart_id) { + case PERIPH_ID_UART2: + /* Using channel-C by default */ + rk_clrsetreg(&grf->gpio4c_iomux, + GRF_GPIO4C3_SEL_MASK, + GRF_UART2DGBC_SIN << GRF_GPIO4C3_SEL_SHIFT); + rk_clrsetreg(&grf->gpio4c_iomux, + GRF_GPIO4C4_SEL_MASK, + GRF_UART2DBGC_SOUT << GRF_GPIO4C4_SEL_SHIFT); + break; + case PERIPH_ID_UART0: + case PERIPH_ID_UART1: + case PERIPH_ID_UART3: + case PERIPH_ID_UART4: + default: + debug("uart id = %d iomux error!\n", uart_id); + break; + } +} + +static void pinctrl_rk3399_sdmmc_config(struct rk3399_grf_regs *grf, int mmc_id) +{ + switch (mmc_id) { + case PERIPH_ID_EMMC: + break; + case PERIPH_ID_SDCARD: + rk_clrsetreg(&grf->gpio4b_iomux, + GRF_GPIO4B0_SEL_MASK | GRF_GPIO4B1_SEL_MASK + | GRF_GPIO4B2_SEL_MASK | GRF_GPIO4B3_SEL_MASK + | GRF_GPIO4B4_SEL_MASK | GRF_GPIO4B5_SEL_MASK, + GRF_SDMMC_DATA0 << GRF_GPIO4B0_SEL_SHIFT + | GRF_SDMMC_DATA1 << GRF_GPIO4B1_SEL_SHIFT + | GRF_SDMMC_DATA2 << GRF_GPIO4B2_SEL_SHIFT + | GRF_SDMMC_DATA3 << GRF_GPIO4B3_SEL_SHIFT + | GRF_SDMMC_CLKOUT << GRF_GPIO4B4_SEL_SHIFT + | GRF_SDMMC_CMD << GRF_GPIO4B5_SEL_SHIFT); + break; + default: + debug("mmc id = %d iomux error!\n", mmc_id); + break; + } +} + +static int rk3399_pinctrl_request(struct udevice *dev, int func, int flags) +{ + struct rk3399_pinctrl_priv *priv = dev_get_priv(dev); + + debug("%s: func=%x, flags=%x\n", __func__, func, flags); + switch (func) { + case PERIPH_ID_PWM0: + case PERIPH_ID_PWM1: + case PERIPH_ID_PWM2: + case PERIPH_ID_PWM3: + case PERIPH_ID_PWM4: + pinctrl_rk3399_pwm_config(priv->grf, priv->pmugrf, func); + break; + case PERIPH_ID_I2C0: + case PERIPH_ID_I2C1: + case PERIPH_ID_I2C2: + case PERIPH_ID_I2C3: + case PERIPH_ID_I2C4: + case PERIPH_ID_I2C5: + pinctrl_rk3399_i2c_config(priv->grf, priv->pmugrf, func); + break; + case PERIPH_ID_SPI0: + case PERIPH_ID_SPI1: + case PERIPH_ID_SPI2: + pinctrl_rk3399_spi_config(priv->grf, priv->pmugrf, func, flags); + break; + case PERIPH_ID_UART0: + case PERIPH_ID_UART1: + case PERIPH_ID_UART2: + case PERIPH_ID_UART3: + case PERIPH_ID_UART4: + pinctrl_rk3399_uart_config(priv->grf, priv->pmugrf, func); + break; + case PERIPH_ID_LCDC0: + case PERIPH_ID_LCDC1: + pinctrl_rk3399_lcdc_config(priv->grf, func); + break; + case PERIPH_ID_SDMMC0: + case PERIPH_ID_SDMMC1: + pinctrl_rk3399_sdmmc_config(priv->grf, func); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rk3399_pinctrl_get_periph_id(struct udevice *dev, + struct udevice *periph) +{ + u32 cell[3]; + int ret; + + ret = fdtdec_get_int_array(gd->fdt_blob, periph->of_offset, + "interrupts", cell, ARRAY_SIZE(cell)); + if (ret < 0) + return -EINVAL; + + switch (cell[1]) { + case 68: + return PERIPH_ID_SPI0; + case 53: + return PERIPH_ID_SPI1; + case 52: + return PERIPH_ID_SPI2; + case 57: + return PERIPH_ID_I2C0; + case 59: /* Note strange order */ + return PERIPH_ID_I2C1; + case 35: + return PERIPH_ID_I2C2; + case 34: + return PERIPH_ID_I2C3; + case 56: + return PERIPH_ID_I2C4; + case 38: + return PERIPH_ID_I2C5; + case 65: + return PERIPH_ID_SDMMC1; + } + + return -ENOENT; +} + +static int rk3399_pinctrl_set_state_simple(struct udevice *dev, + struct udevice *periph) +{ + int func; + + func = rk3399_pinctrl_get_periph_id(dev, periph); + if (func < 0) + return func; + + return rk3399_pinctrl_request(dev, func, 0); +} + +static struct pinctrl_ops rk3399_pinctrl_ops = { + .set_state_simple = rk3399_pinctrl_set_state_simple, + .request = rk3399_pinctrl_request, + .get_periph_id = rk3399_pinctrl_get_periph_id, +}; + +static int rk3399_pinctrl_probe(struct udevice *dev) +{ + struct rk3399_pinctrl_priv *priv = dev_get_priv(dev); + int ret = 0; + + priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + priv->pmugrf = syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF); + debug("%s: grf=%p, pmugrf=%p\n", __func__, priv->grf, priv->pmugrf); + + return ret; +} + +static const struct udevice_id rk3399_pinctrl_ids[] = { + { .compatible = "rockchip,rk3399-pinctrl" }, + { } +}; + +U_BOOT_DRIVER(pinctrl_rk3399) = { + .name = "rockchip_rk3399_pinctrl", + .id = UCLASS_PINCTRL, + .of_match = rk3399_pinctrl_ids, + .priv_auto_alloc_size = sizeof(struct rk3399_pinctrl_priv), + .ops = &rk3399_pinctrl_ops, + .bind = dm_scan_fdt_dev, + .probe = rk3399_pinctrl_probe, +}; -- cgit v1.3.1 From 12406ae247736bb6dfd4a92431caec33ab2a54d7 Mon Sep 17 00:00:00 2001 From: Kever Yang Date: Fri, 12 Aug 2016 17:57:48 +0800 Subject: rk_pwm: use clock framework API to get module clock This patch use clock API instead of hardcode for get pwm clock. Signed-off-by: Kever Yang Acked-by: Simon Glass Fix printf() to debug() nit: Signed-off-by: Simon Glass --- drivers/pwm/rk_pwm.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/rk_pwm.c b/drivers/pwm/rk_pwm.c index 2d289a4c07f..d60d55d71f8 100644 --- a/drivers/pwm/rk_pwm.c +++ b/drivers/pwm/rk_pwm.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -13,9 +14,9 @@ #include #include #include -#include #include #include +#include #include DECLARE_GLOBAL_DATA_PTR; @@ -23,6 +24,7 @@ DECLARE_GLOBAL_DATA_PTR; struct rk_pwm_priv { struct rk3288_pwm *regs; struct rk3288_grf *grf; + ulong freq; }; static int rk_pwm_set_config(struct udevice *dev, uint channel, uint period_ns, @@ -38,8 +40,8 @@ static int rk_pwm_set_config(struct udevice *dev, uint channel, uint period_ns, RK_PWM_DISABLE, ®s->ctrl); - period = lldiv((uint64_t)(PD_BUS_PCLK_HZ / 1000) * period_ns, 1000000); - duty = lldiv((uint64_t)(PD_BUS_PCLK_HZ / 1000) * duty_ns, 1000000); + period = lldiv((uint64_t)(priv->freq / 1000) * period_ns, 1000000); + duty = lldiv((uint64_t)(priv->freq / 1000) * duty_ns, 1000000); writel(period, ®s->period_hpr); writel(duty, ®s->duty_lpr); @@ -76,9 +78,18 @@ static int rk_pwm_ofdata_to_platdata(struct udevice *dev) static int rk_pwm_probe(struct udevice *dev) { struct rk_pwm_priv *priv = dev_get_priv(dev); + struct clk clk; + int ret = 0; rk_setreg(&priv->grf->soc_con2, 1 << 0); + ret = clk_get_by_index(dev, 0, &clk); + if (ret < 0) { + debug("%s get clock fail!\n", __func__); + return -EINVAL; + } + priv->freq = clk_get_rate(&clk); + return 0; } -- cgit v1.3.1 From e2e4e1453680a0a5e87f3976bf48ebfe02c9e192 Mon Sep 17 00:00:00 2001 From: Kever Yang Date: Fri, 12 Aug 2016 17:58:02 +0800 Subject: rk_pwm: remove grf setting code from driver We consider the grf setting for pwm controller select as the system operation instead of driver operation, move it to soc init, let's remove it from pwm driver first. Signed-off-by: Kever Yang Acked-by: Simon Glass --- drivers/pwm/rk_pwm.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/rk_pwm.c b/drivers/pwm/rk_pwm.c index d60d55d71f8..9254f5bc397 100644 --- a/drivers/pwm/rk_pwm.c +++ b/drivers/pwm/rk_pwm.c @@ -13,17 +13,13 @@ #include #include #include -#include -#include #include -#include #include DECLARE_GLOBAL_DATA_PTR; struct rk_pwm_priv { struct rk3288_pwm *regs; - struct rk3288_grf *grf; ulong freq; }; @@ -64,13 +60,8 @@ static int rk_pwm_set_enable(struct udevice *dev, uint channel, bool enable) static int rk_pwm_ofdata_to_platdata(struct udevice *dev) { struct rk_pwm_priv *priv = dev_get_priv(dev); - struct regmap *map; priv->regs = (struct rk3288_pwm *)dev_get_addr(dev); - map = syscon_get_regmap_by_driver_data(ROCKCHIP_SYSCON_GRF); - if (IS_ERR(map)) - return PTR_ERR(map); - priv->grf = regmap_get_range(map, 0); return 0; } @@ -81,8 +72,6 @@ static int rk_pwm_probe(struct udevice *dev) struct clk clk; int ret = 0; - rk_setreg(&priv->grf->soc_con2, 1 << 0); - ret = clk_get_by_index(dev, 0, &clk); if (ret < 0) { debug("%s get clock fail!\n", __func__); -- cgit v1.3.1 From b44566c4ce5ca95264860f78a6ba1d26a5edb5ea Mon Sep 17 00:00:00 2001 From: MengDongyang Date: Wed, 24 Aug 2016 12:02:17 +0800 Subject: usb: xhci-rockchip: add rockchip dwc3 controller driver This patch add support for rockchip dwc3 controller, which corresponding to the two type-C port on rk3399 evb. Only support usb2.0 currently for we have not enable the usb3.0 phy driver and PD(fusb302) driver. Signed-off-by: MengDongyang Signed-off-by: Kever Yang Reviewed-by: Marek Vasut Reviewed-by: Simon Glass --- drivers/usb/host/Makefile | 1 + drivers/usb/host/xhci-rockchip.c | 211 +++++++++++++++++++++++++++++++++++++++ include/linux/usb/dwc3.h | 14 +++ 3 files changed, 226 insertions(+) create mode 100644 drivers/usb/host/xhci-rockchip.c (limited to 'drivers') diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 55190bb667f..de253284fba 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_USB_EHCI_ZYNQ) += ehci-zynq.o # xhci obj-$(CONFIG_USB_XHCI_HCD) += xhci.o xhci-mem.o xhci-ring.o obj-$(CONFIG_USB_XHCI_DWC3) += xhci-dwc3.o +obj-$(CONFIG_USB_XHCI_ROCKCHIP) += xhci-rockchip.o obj-$(CONFIG_USB_XHCI_ZYNQMP) += xhci-zynqmp.o obj-$(CONFIG_USB_XHCI_KEYSTONE) += xhci-keystone.o obj-$(CONFIG_USB_XHCI_EXYNOS) += xhci-exynos5.o diff --git a/drivers/usb/host/xhci-rockchip.c b/drivers/usb/host/xhci-rockchip.c new file mode 100644 index 00000000000..561bf867026 --- /dev/null +++ b/drivers/usb/host/xhci-rockchip.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2016 Rockchip, Inc. + * Authors: Daniel Meng + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xhci.h" + +DECLARE_GLOBAL_DATA_PTR; + +struct rockchip_xhci_platdata { + fdt_addr_t hcd_base; + fdt_addr_t phy_base; + struct gpio_desc vbus_gpio; +}; + +/* + * Contains pointers to register base addresses + * for the usb controller. + */ +struct rockchip_xhci { + struct usb_platdata usb_plat; + struct xhci_ctrl ctrl; + struct xhci_hccr *hcd; + struct dwc3 *dwc3_reg; +}; + +static int xhci_usb_ofdata_to_platdata(struct udevice *dev) +{ + struct rockchip_xhci_platdata *plat = dev_get_platdata(dev); + struct udevice *child; + int ret = 0; + + /* + * Get the base address for XHCI controller from the device node + */ + plat->hcd_base = dev_get_addr(dev); + if (plat->hcd_base == FDT_ADDR_T_NONE) { + debug("Can't get the XHCI register base address\n"); + return -ENXIO; + } + + /* Get the base address for usbphy from the device node */ + for (device_find_first_child(dev, &child); child; + device_find_next_child(&child)) { + if (!of_device_is_compatible(child, "rockchip,rk3399-usb3-phy")) + continue; + plat->phy_base = dev_get_addr(child); + break; + } + + if (plat->phy_base == FDT_ADDR_T_NONE) { + debug("Can't get the usbphy register address\n"); + return -ENXIO; + } + + /* Vbus gpio */ + ret = gpio_request_by_name(dev, "rockchip,vbus-gpio", 0, + &plat->vbus_gpio, GPIOD_IS_OUT); + if (ret) + debug("rockchip,vbus-gpio node missing!"); + + return 0; +} + +/* + * rockchip_dwc3_phy_setup() - Configure USB PHY Interface of DWC3 Core + * @dwc: Pointer to our controller context structure + * @dev: Pointer to ulcass device + */ +static void rockchip_dwc3_phy_setup(struct dwc3 *dwc3_reg, + struct udevice *dev) +{ + u32 reg; + const void *blob = gd->fdt_blob; + u32 utmi_bits; + + /* Set dwc3 usb2 phy config */ + reg = readl(&dwc3_reg->g_usb2phycfg[0]); + + if (fdtdec_get_bool(blob, dev->of_offset, + "snps,dis-enblslpm-quirk")) + reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; + + utmi_bits = fdtdec_get_int(blob, dev->of_offset, + "snps,phyif-utmi-bits", -1); + if (utmi_bits == 16) { + reg |= DWC3_GUSB2PHYCFG_PHYIF; + reg &= ~DWC3_GUSB2PHYCFG_USBTRDTIM_MASK; + reg |= DWC3_GUSB2PHYCFG_USBTRDTIM_16BIT; + } else if (utmi_bits == 8) { + reg &= ~DWC3_GUSB2PHYCFG_PHYIF; + reg &= ~DWC3_GUSB2PHYCFG_USBTRDTIM_MASK; + reg |= DWC3_GUSB2PHYCFG_USBTRDTIM_8BIT; + } + + if (fdtdec_get_bool(blob, dev->of_offset, + "snps,dis-u2-freeclk-exists-quirk")) + reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS; + + if (fdtdec_get_bool(blob, dev->of_offset, + "snps,dis-u2-susphy-quirk")) + reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; + + writel(reg, &dwc3_reg->g_usb2phycfg[0]); +} + +static int rockchip_xhci_core_init(struct rockchip_xhci *rkxhci, + struct udevice *dev) +{ + int ret; + + ret = dwc3_core_init(rkxhci->dwc3_reg); + if (ret) { + debug("failed to initialize core\n"); + return ret; + } + + rockchip_dwc3_phy_setup(rkxhci->dwc3_reg, dev); + + /* We are hard-coding DWC3 core to Host Mode */ + dwc3_set_mode(rkxhci->dwc3_reg, DWC3_GCTL_PRTCAP_HOST); + + return 0; +} + +static int rockchip_xhci_core_exit(struct rockchip_xhci *rkxhci) +{ + return 0; +} + +static int xhci_usb_probe(struct udevice *dev) +{ + struct rockchip_xhci_platdata *plat = dev_get_platdata(dev); + struct rockchip_xhci *ctx = dev_get_priv(dev); + struct xhci_hcor *hcor; + int ret; + + ctx->hcd = (struct xhci_hccr *)plat->hcd_base; + ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET); + hcor = (struct xhci_hcor *)((uint64_t)ctx->hcd + + HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase))); + + /* setup the Vbus gpio here */ + if (dm_gpio_is_valid(&plat->vbus_gpio)) + dm_gpio_set_value(&plat->vbus_gpio, 1); + + ret = rockchip_xhci_core_init(ctx, dev); + if (ret) { + debug("XHCI: failed to initialize controller\n"); + return ret; + } + + return xhci_register(dev, ctx->hcd, hcor); +} + +static int xhci_usb_remove(struct udevice *dev) +{ + struct rockchip_xhci *ctx = dev_get_priv(dev); + int ret; + + ret = xhci_deregister(dev); + if (ret) + return ret; + ret = rockchip_xhci_core_exit(ctx); + if (ret) + return ret; + + return 0; +} + +static const struct udevice_id xhci_usb_ids[] = { + { .compatible = "rockchip,rk3399-xhci" }, + { } +}; + +U_BOOT_DRIVER(usb_xhci) = { + .name = "xhci_rockchip", + .id = UCLASS_USB, + .of_match = xhci_usb_ids, + .ofdata_to_platdata = xhci_usb_ofdata_to_platdata, + .probe = xhci_usb_probe, + .remove = xhci_usb_remove, + .ops = &xhci_usb_ops, + .bind = dm_scan_fdt_dev, + .platdata_auto_alloc_size = sizeof(struct rockchip_xhci_platdata), + .priv_auto_alloc_size = sizeof(struct rockchip_xhci), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; + +static const struct udevice_id usb_phy_ids[] = { + { .compatible = "rockchip,rk3399-usb3-phy" }, + { } +}; + +U_BOOT_DRIVER(usb_phy) = { + .name = "usb_phy_rockchip", + .of_match = usb_phy_ids, +}; diff --git a/include/linux/usb/dwc3.h b/include/linux/usb/dwc3.h index 6d1e36505d8..a0274461cc1 100644 --- a/include/linux/usb/dwc3.h +++ b/include/linux/usb/dwc3.h @@ -180,7 +180,21 @@ struct dwc3 { /* offset: 0xC100 */ /* Global USB2 PHY Configuration Register */ #define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31) +#define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS (1 << 30) +#define DWC3_GUSB2PHYCFG_ENBLSLPM (1 << 8) #define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6) +#define DWC3_GUSB2PHYCFG_PHYIF (1 << 3) + +/* Global USB2 PHY Configuration Mask */ +#define DWC3_GUSB2PHYCFG_USBTRDTIM_MASK (0xf << 10) + +/* Global USB2 PHY Configuration Offset */ +#define DWC3_GUSB2PHYCFG_USBTRDTIM_OFFSET 10 + +#define DWC3_GUSB2PHYCFG_USBTRDTIM_16BIT (0x5 << \ + DWC3_GUSB2PHYCFG_USBTRDTIM_OFFSET) +#define DWC3_GUSB2PHYCFG_USBTRDTIM_8BIT (0x9 << \ + DWC3_GUSB2PHYCFG_USBTRDTIM_OFFSET) /* Global USB3 PIPE Control Register */ #define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31) -- cgit v1.3.1 From f7bb27a577405914d747605f885d839a9c523773 Mon Sep 17 00:00:00 2001 From: Kever Yang Date: Wed, 21 Sep 2016 11:35:42 +0800 Subject: usb: host: add Kconfig for USB_XHCI_ROCKCHIP Add a Kconfig for Rockchip xhci controller. Signed-off-by: Kever Yang Acked-by: Marek Vasut --- drivers/usb/host/Kconfig | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 42e8a9f934f..61e13d76e65 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -21,6 +21,13 @@ config USB_XHCI_DWC3 Say Y or if your system has a Dual Role SuperSpeed USB controller based on the DesignWare USB3 IP Core. +config USB_XHCI_ROCKCHIP + bool "Support for Rockchip on-chip xHCI USB controller" + depends on ARCH_ROCKCHIP + default y + help + Enables support for the on-chip xHCI controller on Rockchip SoCs. + endif # USB_XHCI_HCD config USB_EHCI_HCD -- cgit v1.3.1 From 5e79f443550a0aac1a4a118d956a48177972aa51 Mon Sep 17 00:00:00 2001 From: Kever Yang Date: Fri, 12 Aug 2016 17:47:15 +0800 Subject: clk: rk3399: add pmucru controller support pmucru is a module like cru which is a clock controller manage some PLL and module clocks. Signed-off-by: Kever Yang Acked-by: Simon Glass --- drivers/clk/rockchip/clk_rk3399.c | 177 +++++++++++++++++++++++++++++++++++++- 1 file changed, 173 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c index 0b4ea828f60..ea0ce2aab10 100644 --- a/drivers/clk/rockchip/clk_rk3399.c +++ b/drivers/clk/rockchip/clk_rk3399.c @@ -23,6 +23,10 @@ struct rk3399_clk_priv { ulong rate; }; +struct rk3399_pmuclk_priv { + struct rk3399_pmucru *pmucru; +}; + struct pll_div { u32 refdiv; u32 fbdiv; @@ -95,11 +99,11 @@ enum { /* PMUCRU_CLKSEL_CON2 */ I2C_DIV_CON_MASK = 0x7f, - I2C8_DIV_CON_SHIFT = 8, - I2C0_DIV_CON_SHIFT = 0, + CLK_I2C8_DIV_CON_SHIFT = 8, + CLK_I2C0_DIV_CON_SHIFT = 0, /* PMUCRU_CLKSEL_CON3 */ - I2C4_DIV_CON_SHIFT = 0, + CLK_I2C4_DIV_CON_SHIFT = 0, /* CLKSEL_CON0 */ ACLKM_CORE_L_DIV_CON_SHIFT = 8, @@ -507,6 +511,14 @@ void rk3399_configure_cpu(struct rk3399_cru *cru, (con >> CLK_I2C ##bus## _DIV_CON_SHIFT) & \ I2C_DIV_CON_MASK; +#define I2C_PMUCLK_REG_MASK(bus) \ + (I2C_DIV_CON_MASK << \ + CLK_I2C ##bus## _DIV_CON_SHIFT) + +#define I2C_PMUCLK_REG_VALUE(bus, clk_div) \ + ((clk_div - 1) << \ + CLK_I2C ##bus## _DIV_CON_SHIFT) + static ulong rk3399_i2c_get_clk(struct rk3399_cru *cru, ulong clk_id) { u32 div, con; @@ -754,7 +766,7 @@ static ulong rk3399_clk_set_rate(struct clk *clk, ulong rate) break; case DCLK_VOP0: case DCLK_VOP1: - rate = rk3399_vop_set_clk(priv->cru, clk->id, rate); + ret = rk3399_vop_set_clk(priv->cru, clk->id, rate); break; default: return -ENOENT; @@ -830,3 +842,160 @@ U_BOOT_DRIVER(clk_rk3399) = { .bind = rk3399_clk_bind, .probe = rk3399_clk_probe, }; + +static ulong rk3399_i2c_get_pmuclk(struct rk3399_pmucru *pmucru, ulong clk_id) +{ + u32 div, con; + + switch (clk_id) { + case SCLK_I2C0_PMU: + con = readl(&pmucru->pmucru_clksel[2]); + div = I2C_CLK_DIV_VALUE(con, 0); + break; + case SCLK_I2C4_PMU: + con = readl(&pmucru->pmucru_clksel[3]); + div = I2C_CLK_DIV_VALUE(con, 4); + break; + case SCLK_I2C8_PMU: + con = readl(&pmucru->pmucru_clksel[2]); + div = I2C_CLK_DIV_VALUE(con, 8); + break; + default: + printf("do not support this i2c bus\n"); + return -EINVAL; + } + + return DIV_TO_RATE(PPLL_HZ, div); +} + +static ulong rk3399_i2c_set_pmuclk(struct rk3399_pmucru *pmucru, ulong clk_id, + uint hz) +{ + int src_clk_div; + + src_clk_div = PPLL_HZ / hz; + assert(src_clk_div - 1 < 127); + + switch (clk_id) { + case SCLK_I2C0_PMU: + rk_clrsetreg(&pmucru->pmucru_clksel[2], I2C_PMUCLK_REG_MASK(0), + I2C_PMUCLK_REG_VALUE(0, src_clk_div)); + break; + case SCLK_I2C4_PMU: + rk_clrsetreg(&pmucru->pmucru_clksel[3], I2C_PMUCLK_REG_MASK(4), + I2C_PMUCLK_REG_VALUE(4, src_clk_div)); + break; + case SCLK_I2C8_PMU: + rk_clrsetreg(&pmucru->pmucru_clksel[2], I2C_PMUCLK_REG_MASK(8), + I2C_PMUCLK_REG_VALUE(8, src_clk_div)); + break; + default: + printf("do not support this i2c bus\n"); + return -EINVAL; + } + + return DIV_TO_RATE(PPLL_HZ, src_clk_div); +} + +static ulong rk3399_pwm_get_clk(struct rk3399_pmucru *pmucru) +{ + u32 div, con; + + /* PWM closk rate is same as pclk_pmu */ + con = readl(&pmucru->pmucru_clksel[0]); + div = con & PMU_PCLK_DIV_CON_MASK; + + return DIV_TO_RATE(PPLL_HZ, div); +} + +static ulong rk3399_pmuclk_get_rate(struct clk *clk) +{ + struct rk3399_pmuclk_priv *priv = dev_get_priv(clk->dev); + ulong rate = 0; + + switch (clk->id) { + case PCLK_RKPWM_PMU: + rate = rk3399_pwm_get_clk(priv->pmucru); + break; + case SCLK_I2C0_PMU: + case SCLK_I2C4_PMU: + case SCLK_I2C8_PMU: + rate = rk3399_i2c_get_pmuclk(priv->pmucru, clk->id); + break; + default: + return -ENOENT; + } + + return rate; +} + +static ulong rk3399_pmuclk_set_rate(struct clk *clk, ulong rate) +{ + struct rk3399_pmuclk_priv *priv = dev_get_priv(clk->dev); + ulong ret = 0; + + switch (clk->id) { + case SCLK_I2C0_PMU: + case SCLK_I2C4_PMU: + case SCLK_I2C8_PMU: + ret = rk3399_i2c_set_pmuclk(priv->pmucru, clk->id, rate); + break; + default: + return -ENOENT; + } + + return ret; +} + +static struct clk_ops rk3399_pmuclk_ops = { + .get_rate = rk3399_pmuclk_get_rate, + .set_rate = rk3399_pmuclk_set_rate, +}; + +static void pmuclk_init(struct rk3399_pmucru *pmucru) +{ + u32 pclk_div; + + /* configure pmu pll(ppll) */ + rkclk_set_pll(&pmucru->ppll_con[0], &ppll_init_cfg); + + /* configure pmu pclk */ + pclk_div = PPLL_HZ / PMU_PCLK_HZ - 1; + assert((pclk_div + 1) * PMU_PCLK_HZ == PPLL_HZ && pclk_div < 0x1f); + rk_clrsetreg(&pmucru->pmucru_clksel[0], + PMU_PCLK_DIV_CON_MASK, + pclk_div << PMU_PCLK_DIV_CON_SHIFT); +} + +static int rk3399_pmuclk_probe(struct udevice *dev) +{ + struct rk3399_pmuclk_priv *priv = dev_get_priv(dev); + + pmuclk_init(priv->pmucru); + + return 0; +} + +static int rk3399_pmuclk_ofdata_to_platdata(struct udevice *dev) +{ + struct rk3399_pmuclk_priv *priv = dev_get_priv(dev); + + priv->pmucru = (struct rk3399_pmucru *)dev_get_addr(dev); + + return 0; +} + +static const struct udevice_id rk3399_pmuclk_ids[] = { + { .compatible = "rockchip,rk3399-pmucru" }, + { } +}; + +U_BOOT_DRIVER(pmuclk_rk3399) = { + .name = "pmuclk_rk3399", + .id = UCLASS_CLK, + .of_match = rk3399_pmuclk_ids, + .priv_auto_alloc_size = sizeof(struct rk3399_pmuclk_priv), + .ofdata_to_platdata = rk3399_pmuclk_ofdata_to_platdata, + .ops = &rk3399_pmuclk_ops, + .probe = rk3399_pmuclk_probe, +}; -- cgit v1.3.1 From 4f0b8efa50a543efd407fb8b2e9ad0de49467a15 Mon Sep 17 00:00:00 2001 From: Kever Yang Date: Fri, 12 Aug 2016 17:57:05 +0800 Subject: clk: rk3288: add PWM clock get rate This patch add clk_get_rate for PWM device. Signed-off-by: Kever Yang Acked-by: Simon Glass --- drivers/clk/rockchip/clk_rk3288.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/rockchip/clk_rk3288.c b/drivers/clk/rockchip/clk_rk3288.c index c07203d84b9..bd71a969278 100644 --- a/drivers/clk/rockchip/clk_rk3288.c +++ b/drivers/clk/rockchip/clk_rk3288.c @@ -695,6 +695,8 @@ static ulong rk3288_clk_get_rate(struct clk *clk) case PCLK_I2C4: case PCLK_I2C5: return gclk_rate; + case PCLK_PWM: + return PD_BUS_PCLK_HZ; default: return -ENOENT; } -- cgit v1.3.1