From patchwork Sat Jan 13 06:02:36 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Wu X-Patchwork-Id: 860290 X-Patchwork-Delegate: philipp.tomsich@theobroma-systems.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 3zJTZD619hz9t5Q for ; Sat, 13 Jan 2018 17:03:32 +1100 (AEDT) Received: by lists.denx.de (Postfix, from userid 105) id 4E9B0C21F22; Sat, 13 Jan 2018 06:03:24 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.6 required=5.0 tests=RCVD_IN_MSPIKE_H2, RCVD_IN_SORBS_WEB autolearn=no autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 58DDAC21EFF; Sat, 13 Jan 2018 06:03:21 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 157D1C21F0A; Sat, 13 Jan 2018 06:02:56 +0000 (UTC) Received: from regular1.263xmail.com (regular1.263xmail.com [211.150.99.140]) by lists.denx.de (Postfix) with ESMTPS id 81652C21F42 for ; Sat, 13 Jan 2018 06:02:54 +0000 (UTC) Received: from david.wu?rock-chips.com (unknown [192.168.167.73]) by regular1.263xmail.com (Postfix) with ESMTP id 3967E4AA5; Sat, 13 Jan 2018 14:02:50 +0800 (CST) X-263anti-spam: KSV:0; X-MAIL-GRAY: 0 X-MAIL-DELIVERY: 1 X-KSVirus-check: 0 X-ABS-CHECKED: 4 Received: from localhost.localdomain (localhost [127.0.0.1]) by smtp.263.net (Postfix) with ESMTPA id 6960A389; Sat, 13 Jan 2018 14:02:50 +0800 (CST) X-RL-SENDER: david.wu@rock-chips.com X-FST-TO: philipp.tomsich@theobroma-systems.com X-SENDER-IP: 58.22.7.114 X-LOGIN-NAME: david.wu@rock-chips.com X-UNIQUE-TAG: X-ATTACHMENT-NUM: 0 X-SENDER: wdc@rock-chips.com X-DNS-TYPE: 0 Received: from localhost.localdomain (unknown [58.22.7.114]) by smtp.263.net (Postfix) whith ESMTP id 18680XGUVT2; Sat, 13 Jan 2018 14:02:51 +0800 (CST) From: David Wu To: philipp.tomsich@theobroma-systems.com, sjg@chromium.org Date: Sat, 13 Jan 2018 14:02:36 +0800 Message-Id: <1515823356-52452-1-git-send-email-david.wu@rock-chips.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1515822853-52036-1-git-send-email-david.wu@rock-chips.com> References: <1515822853-52036-1-git-send-email-david.wu@rock-chips.com> Cc: huangtao@rock-chips.com, joe.hershberger@ni.com, u-boot@lists.denx.de, David Wu , andy.yan@rock-chips.com Subject: [U-Boot] [PATCH v3 08/20] clk: rockchip: Add rk3328 gamc clock support X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" The rk3328 soc has two gmac controllers, one is gmac2io, the other is gmac2phy. We use the gmac2io rgmii interface for 1000M phy here. Signed-off-by: David Wu Acked-by: Philipp Tomsich Reviewed-by: Philipp Tomsich --- Changes in v3: - Add "set parent" for gmac2io - Add internal mac clk div_sel for gmac2io Changes in v2: - New patch drivers/clk/rockchip/clk_rk3328.c | 178 +++++++++++++++++++++++++++++++++ include/dt-bindings/clock/rk3328-cru.h | 6 +- 2 files changed, 181 insertions(+), 3 deletions(-) diff --git a/drivers/clk/rockchip/clk_rk3328.c b/drivers/clk/rockchip/clk_rk3328.c index fa0c777..2ccc798 100644 --- a/drivers/clk/rockchip/clk_rk3328.c +++ b/drivers/clk/rockchip/clk_rk3328.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -94,6 +95,14 @@ enum { PCLK_DBG_DIV_SHIFT = 0, PCLK_DBG_DIV_MASK = 0xF << PCLK_DBG_DIV_SHIFT, + /* CLKSEL_CON27 */ + GMAC2IO_PLL_SEL_SHIFT = 7, + GMAC2IO_PLL_SEL_MASK = 1 << GMAC2IO_PLL_SEL_SHIFT, + GMAC2IO_PLL_SEL_CPLL = 0, + GMAC2IO_PLL_SEL_GPLL = 1, + GMAC2IO_CLK_DIV_MASK = 0x1f, + GMAC2IO_CLK_DIV_SHIFT = 0, + /* CLKSEL_CON28 */ ACLK_PERIHP_PLL_SEL_CPLL = 0, ACLK_PERIHP_PLL_SEL_GPLL, @@ -393,6 +402,44 @@ static ulong rk3328_i2c_set_clk(struct rk3328_cru *cru, ulong clk_id, uint hz) return DIV_TO_RATE(GPLL_HZ, src_clk_div); } +static ulong rk3328_gmac2io_set_clk(struct rk3328_cru *cru, ulong rate) +{ + struct rk3328_grf_regs *grf; + ulong ret; + + grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + + /* + * The RGMII CLK can be derived either from an external "clkin" + * or can be generated from internally by a divider from SCLK_MAC. + */ + if (readl(&grf->mac_con[1]) & BIT(10) && + readl(&grf->soc_con[4]) & BIT(14)) { + /* An external clock will always generate the right rate... */ + ret = rate; + } else { + u32 con = readl(&cru->clksel_con[27]); + ulong pll_rate; + u8 div; + + if ((con >> GMAC2IO_PLL_SEL_SHIFT) & GMAC2IO_PLL_SEL_GPLL) + pll_rate = GPLL_HZ; + else + pll_rate = CPLL_HZ; + + div = DIV_ROUND_UP(pll_rate, rate) - 1; + if (div <= 0x1f) + rk_clrsetreg(&cru->clksel_con[27], GMAC2IO_CLK_DIV_MASK, + div << GMAC2IO_CLK_DIV_SHIFT); + else + debug("Unsupported div for gmac:%d\n", div); + + return DIV_TO_RATE(pll_rate, div); + } + + return ret; +} + static ulong rk3328_mmc_get_clk(struct rk3328_cru *cru, uint clk_id) { u32 div, con, con_id; @@ -558,12 +605,48 @@ static ulong rk3328_clk_set_rate(struct clk *clk, ulong rate) case SCLK_I2C3: ret = rk3328_i2c_set_clk(priv->cru, clk->id, rate); break; + case SCLK_MAC2IO: + ret = rk3328_gmac2io_set_clk(priv->cru, rate); + break; case SCLK_PWM: ret = rk3328_pwm_set_clk(priv->cru, rate); break; case SCLK_SARADC: ret = rk3328_saradc_set_clk(priv->cru, rate); break; + case DCLK_LCDC: + case SCLK_PDM: + case SCLK_RTC32K: + case SCLK_UART0: + case SCLK_UART1: + case SCLK_UART2: + case SCLK_SDIO: + case SCLK_TSP: + case SCLK_WIFI: + case ACLK_BUS_PRE: + case HCLK_BUS_PRE: + case PCLK_BUS_PRE: + case ACLK_PERI_PRE: + case HCLK_PERI: + case PCLK_PERI: + case ACLK_VIO_PRE: + case HCLK_VIO_PRE: + case ACLK_RGA_PRE: + case SCLK_RGA: + case ACLK_VOP_PRE: + case ACLK_RKVDEC_PRE: + case ACLK_RKVENC: + case ACLK_VPU_PRE: + case SCLK_VDEC_CABAC: + case SCLK_VDEC_CORE: + case SCLK_VENC_CORE: + case SCLK_VENC_DSP: + case SCLK_EFUSE: + case PCLK_DDR: + case ACLK_GMAC: + case PCLK_GMAC: + case SCLK_USB3OTG_SUSPEND: + return 0; default: return -ENOENT; } @@ -571,9 +654,104 @@ static ulong rk3328_clk_set_rate(struct clk *clk, ulong rate) return ret; } +static int rk3328_gmac2io_set_parent(struct clk *clk, struct clk *parent) +{ + struct rk3328_grf_regs *grf; + const char *clock_output_name; + int ret; + + grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + + /* + * If the requested parent is in the same clock-controller and the id + * is SCLK_MAC2IO_SRC ("clk_mac2io_src"), switch to the internal clock. + */ + if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC2IO_SRC)) { + debug("%s: switching RGMII to SCLK_MAC2IO_SRC\n", __func__); + rk_clrreg(&grf->mac_con[1], BIT(10)); + return 0; + } + + /* + * Otherwise, we need to check the clock-output-names of the + * requested parent to see if the requested id is "gmac_clkin". + */ + ret = dev_read_string_index(parent->dev, "clock-output-names", + parent->id, &clock_output_name); + if (ret < 0) + return -ENODATA; + + /* If this is "gmac_clkin", switch to the external clock input */ + if (!strcmp(clock_output_name, "gmac_clkin")) { + debug("%s: switching RGMII to CLKIN\n", __func__); + rk_setreg(&grf->mac_con[1], BIT(10)); + return 0; + } + + return -EINVAL; +} + +static int rk3328_gmac2io_ext_set_parent(struct clk *clk, struct clk *parent) +{ + struct rk3328_grf_regs *grf; + const char *clock_output_name; + int ret; + + grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + + /* + * If the requested parent is in the same clock-controller and the id + * is SCLK_MAC2IO ("clk_mac2io"), switch to the internal clock. + */ + if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC2IO)) { + debug("%s: switching RGMII to SCLK_MAC2IO\n", __func__); + rk_clrreg(&grf->soc_con[4], BIT(14)); + return 0; + } + + /* + * Otherwise, we need to check the clock-output-names of the + * requested parent to see if the requested id is "gmac_clkin". + */ + ret = dev_read_string_index(parent->dev, "clock-output-names", + parent->id, &clock_output_name); + if (ret < 0) + return -ENODATA; + + /* If this is "gmac_clkin", switch to the external clock input */ + if (!strcmp(clock_output_name, "gmac_clkin")) { + debug("%s: switching RGMII to CLKIN\n", __func__); + rk_setreg(&grf->soc_con[4], BIT(14)); + return 0; + } + + return -EINVAL; +} + +static int rk3328_clk_set_parent(struct clk *clk, struct clk *parent) +{ + switch (clk->id) { + case SCLK_MAC2IO: + return rk3328_gmac2io_set_parent(clk, parent); + case SCLK_MAC2IO_EXT: + return rk3328_gmac2io_ext_set_parent(clk, parent); + case DCLK_LCDC: + case SCLK_PDM: + case SCLK_RTC32K: + case SCLK_UART0: + case SCLK_UART1: + case SCLK_UART2: + return 0; + } + + debug("%s: unsupported clk %ld\n", __func__, clk->id); + return -ENOENT; +} + static struct clk_ops rk3328_clk_ops = { .get_rate = rk3328_clk_get_rate, .set_rate = rk3328_clk_set_rate, + .set_parent = rk3328_clk_set_parent, }; static int rk3328_clk_probe(struct udevice *dev) diff --git a/include/dt-bindings/clock/rk3328-cru.h b/include/dt-bindings/clock/rk3328-cru.h index 6d8bf13..cdc0b33 100644 --- a/include/dt-bindings/clock/rk3328-cru.h +++ b/include/dt-bindings/clock/rk3328-cru.h @@ -86,6 +86,9 @@ #define SCLK_USB3OTG_SUSPEND 97 #define SCLK_REF_USB3OTG_SRC 98 #define SCLK_MAC2IO_SRC 99 +#define SCLK_MAC2IO 100 +#define SCLK_MAC2PHY 101 +#define SCLK_MAC2IO_EXT 102 /* dclk gates */ #define DCLK_LCDC 180 @@ -199,9 +202,6 @@ #define CLK_NR_CLKS (HCLK_HDCP + 1) -#define SCLK_MAC2IO 0 -#define SCLK_MAC2PHY 1 - #define CLKGRF_NR_CLKS (SCLK_MAC2PHY + 1) /* soft-reset indices */