summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2019-11-18 05:15:57 +0300
committerTom Rini <trini@konsulko.com>2019-11-18 05:15:57 +0300
commitd64efd920e429f1c5dc085e2e8614c5d139ec37d (patch)
treefb1b00b875c2efd1a3d5310227c0d214cd48cf45 /drivers
parentfd8adc33b8f999cb09c3ba8ea8860ded28e8d6ca (diff)
parent59b01eb7a17a7c0915fd8aff8f818699b4624137 (diff)
downloadu-boot-d64efd920e429f1c5dc085e2e8614c5d139ec37d.tar.xz
Merge tag 'u-boot-rockchip-20191118' of https://gitlab.denx.de/u-boot/custodians/u-boot-rockchip
- Add support for rockchip SoC: PX30, RK3308 - Add and migrate to use common dram driver: PX30, RK3328, RK3399 - Add rk3399 board Tinker-s support - Board config update for Rock960, Rockpro64
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/rockchip/Makefile3
-rw-r--r--drivers/clk/rockchip/clk_pll.c360
-rw-r--r--drivers/clk/rockchip/clk_px30.c1630
-rw-r--r--drivers/clk/rockchip/clk_rk3036.c2
-rw-r--r--drivers/clk/rockchip/clk_rk3188.c2
-rw-r--r--drivers/clk/rockchip/clk_rk322x.c2
-rw-r--r--drivers/clk/rockchip/clk_rk3288.c2
-rw-r--r--drivers/clk/rockchip/clk_rk3308.c1072
-rw-r--r--drivers/clk/rockchip/clk_rk3328.c2
-rw-r--r--drivers/clk/rockchip/clk_rk3368.c2
-rw-r--r--drivers/clk/rockchip/clk_rk3399.c2
-rw-r--r--drivers/clk/rockchip/clk_rv1108.c18
-rw-r--r--drivers/misc/Kconfig9
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/rockchip-otp.c176
-rw-r--r--drivers/net/gmac_rockchip.c69
-rw-r--r--drivers/pinctrl/rockchip/Makefile1
-rw-r--r--drivers/pinctrl/rockchip/pinctrl-px30.c368
-rw-r--r--drivers/ram/Kconfig2
-rw-r--r--drivers/ram/rockchip/Kconfig17
-rw-r--r--drivers/ram/rockchip/Makefile8
-rw-r--r--drivers/ram/rockchip/dmc-rk3368.c2
-rw-r--r--drivers/ram/rockchip/sdram-px30-ddr3-detect-333.inc72
-rw-r--r--drivers/ram/rockchip/sdram-px30-ddr4-detect-333.inc75
-rw-r--r--drivers/ram/rockchip/sdram-px30-ddr_skew.inc121
-rw-r--r--drivers/ram/rockchip/sdram-px30-lpddr2-detect-333.inc73
-rw-r--r--drivers/ram/rockchip/sdram-px30-lpddr3-detect-333.inc74
-rw-r--r--drivers/ram/rockchip/sdram-rk3399-lpddr4-400.inc28
-rw-r--r--drivers/ram/rockchip/sdram-rk3399-lpddr4-800.inc28
-rw-r--r--drivers/ram/rockchip/sdram_common.c429
-rw-r--r--drivers/ram/rockchip/sdram_debug.c147
-rw-r--r--drivers/ram/rockchip/sdram_pctl_px30.c205
-rw-r--r--drivers/ram/rockchip/sdram_phy_px30.c205
-rw-r--r--drivers/ram/rockchip/sdram_px30.c751
-rw-r--r--drivers/ram/rockchip/sdram_rk3128.c2
-rw-r--r--drivers/ram/rockchip/sdram_rk3188.c2
-rw-r--r--drivers/ram/rockchip/sdram_rk322x.c2
-rw-r--r--drivers/ram/rockchip/sdram_rk3288.c2
-rw-r--r--drivers/ram/rockchip/sdram_rk3308.c55
-rw-r--r--drivers/ram/rockchip/sdram_rk3328.c765
-rw-r--r--drivers/ram/rockchip/sdram_rk3399.c1201
-rw-r--r--drivers/usb/phy/rockchip_usb2_phy.c5
42 files changed, 6793 insertions, 1199 deletions
diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
index 41cfb7ad3f..4cfcf83309 100644
--- a/drivers/clk/rockchip/Makefile
+++ b/drivers/clk/rockchip/Makefile
@@ -3,11 +3,14 @@
# Copyright (c) 2017 Rockchip Electronics Co., Ltd
#
+obj-y += clk_pll.o
+obj-$(CONFIG_ROCKCHIP_PX30) += clk_px30.o
obj-$(CONFIG_ROCKCHIP_RK3036) += clk_rk3036.o
obj-$(CONFIG_ROCKCHIP_RK3128) += clk_rk3128.o
obj-$(CONFIG_ROCKCHIP_RK3188) += clk_rk3188.o
obj-$(CONFIG_ROCKCHIP_RK322X) += clk_rk322x.o
obj-$(CONFIG_ROCKCHIP_RK3288) += clk_rk3288.o
+obj-$(CONFIG_ROCKCHIP_RK3308) += clk_rk3308.o
obj-$(CONFIG_ROCKCHIP_RK3328) += clk_rk3328.o
obj-$(CONFIG_ROCKCHIP_RK3368) += clk_rk3368.o
obj-$(CONFIG_ROCKCHIP_RK3399) += clk_rk3399.o
diff --git a/drivers/clk/rockchip/clk_pll.c b/drivers/clk/rockchip/clk_pll.c
new file mode 100644
index 0000000000..c4b45314ec
--- /dev/null
+++ b/drivers/clk/rockchip/clk_pll.c
@@ -0,0 +1,360 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2018-2019 Rockchip Electronics Co., Ltd
+ */
+ #include <common.h>
+#include <bitfield.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/hardware.h>
+#include <div64.h>
+
+static struct rockchip_pll_rate_table rockchip_auto_table;
+
+#define PLL_MODE_MASK 0x3
+#define PLL_RK3328_MODE_MASK 0x1
+
+#define RK3036_PLLCON0_FBDIV_MASK 0xfff
+#define RK3036_PLLCON0_FBDIV_SHIFT 0
+#define RK3036_PLLCON0_POSTDIV1_MASK 0x7 << 12
+#define RK3036_PLLCON0_POSTDIV1_SHIFT 12
+#define RK3036_PLLCON1_REFDIV_MASK 0x3f
+#define RK3036_PLLCON1_REFDIV_SHIFT 0
+#define RK3036_PLLCON1_POSTDIV2_MASK 0x7 << 6
+#define RK3036_PLLCON1_POSTDIV2_SHIFT 6
+#define RK3036_PLLCON1_DSMPD_MASK 0x1 << 12
+#define RK3036_PLLCON1_DSMPD_SHIFT 12
+#define RK3036_PLLCON2_FRAC_MASK 0xffffff
+#define RK3036_PLLCON2_FRAC_SHIFT 0
+#define RK3036_PLLCON1_PWRDOWN_SHIT 13
+
+#define MHZ 1000000
+#define KHZ 1000
+enum {
+ OSC_HZ = 24 * 1000000,
+ VCO_MAX_HZ = 3200U * 1000000,
+ VCO_MIN_HZ = 800 * 1000000,
+ OUTPUT_MAX_HZ = 3200U * 1000000,
+ OUTPUT_MIN_HZ = 24 * 1000000,
+};
+
+#define MIN_FOUTVCO_FREQ (800 * MHZ)
+#define MAX_FOUTVCO_FREQ (2000 * MHZ)
+
+int gcd(int m, int n)
+{
+ int t;
+
+ while (m > 0) {
+ if (n > m) {
+ t = m;
+ m = n;
+ n = t;
+ } /* swap */
+ m -= n;
+ }
+ return n;
+}
+
+/*
+ * How to calculate the PLL(from TRM V0.3 Part 1 Page 63):
+ * Formulas also embedded within the Fractional PLL Verilog model:
+ * If DSMPD = 1 (DSM is disabled, "integer mode")
+ * FOUTVCO = FREF / REFDIV * FBDIV
+ * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
+ * Where:
+ * FOUTVCO = Fractional PLL non-divided output frequency
+ * FOUTPOSTDIV = Fractional PLL divided output frequency
+ * (output of second post divider)
+ * FREF = Fractional PLL input reference frequency, (the OSC_HZ 24MHz input)
+ * REFDIV = Fractional PLL input reference clock divider
+ * FBDIV = Integer value programmed into feedback divide
+ *
+ */
+
+static int rockchip_pll_clk_set_postdiv(ulong fout_hz,
+ u32 *postdiv1,
+ u32 *postdiv2,
+ u32 *foutvco)
+{
+ ulong freq;
+
+ if (fout_hz < MIN_FOUTVCO_FREQ) {
+ for (*postdiv1 = 1; *postdiv1 <= 7; (*postdiv1)++) {
+ for (*postdiv2 = 1; *postdiv2 <= 7; (*postdiv2)++) {
+ freq = fout_hz * (*postdiv1) * (*postdiv2);
+ if (freq >= MIN_FOUTVCO_FREQ &&
+ freq <= MAX_FOUTVCO_FREQ) {
+ *foutvco = freq;
+ return 0;
+ }
+ }
+ }
+ printf("Can't FIND postdiv1/2 to make fout=%lu in 800~2000M.\n",
+ fout_hz);
+ } else {
+ *postdiv1 = 1;
+ *postdiv2 = 1;
+ }
+ return 0;
+}
+
+static struct rockchip_pll_rate_table *
+rockchip_pll_clk_set_by_auto(ulong fin_hz,
+ ulong fout_hz)
+{
+ struct rockchip_pll_rate_table *rate_table = &rockchip_auto_table;
+ /* FIXME set postdiv1/2 always 1*/
+ u32 foutvco = fout_hz;
+ ulong fin_64, frac_64;
+ u32 f_frac, postdiv1, postdiv2;
+ ulong clk_gcd = 0;
+
+ if (fin_hz == 0 || fout_hz == 0 || fout_hz == fin_hz)
+ return NULL;
+
+ rockchip_pll_clk_set_postdiv(fout_hz, &postdiv1, &postdiv2, &foutvco);
+ rate_table->postdiv1 = postdiv1;
+ rate_table->postdiv2 = postdiv2;
+ rate_table->dsmpd = 1;
+
+ if (fin_hz / MHZ * MHZ == fin_hz && fout_hz / MHZ * MHZ == fout_hz) {
+ fin_hz /= MHZ;
+ foutvco /= MHZ;
+ clk_gcd = gcd(fin_hz, foutvco);
+ rate_table->refdiv = fin_hz / clk_gcd;
+ rate_table->fbdiv = foutvco / clk_gcd;
+
+ rate_table->frac = 0;
+
+ debug("fin = %ld, fout = %ld, clk_gcd = %ld,\n",
+ fin_hz, fout_hz, clk_gcd);
+ debug("refdiv= %d,fbdiv= %d,postdiv1= %d,postdiv2= %d\n",
+ rate_table->refdiv,
+ rate_table->fbdiv, rate_table->postdiv1,
+ rate_table->postdiv2);
+ } else {
+ debug("frac div,fin_hz = %ld,fout_hz = %ld\n",
+ fin_hz, fout_hz);
+ debug("frac get postdiv1 = %d, postdiv2 = %d, foutvco = %d\n",
+ rate_table->postdiv1, rate_table->postdiv2, foutvco);
+ clk_gcd = gcd(fin_hz / MHZ, foutvco / MHZ);
+ rate_table->refdiv = fin_hz / MHZ / clk_gcd;
+ rate_table->fbdiv = foutvco / MHZ / clk_gcd;
+ debug("frac get refdiv = %d, fbdiv = %d\n",
+ rate_table->refdiv, rate_table->fbdiv);
+
+ rate_table->frac = 0;
+
+ f_frac = (foutvco % MHZ);
+ fin_64 = fin_hz;
+ fin_64 = fin_64 / rate_table->refdiv;
+ frac_64 = f_frac << 24;
+ frac_64 = frac_64 / fin_64;
+ rate_table->frac = frac_64;
+ if (rate_table->frac > 0)
+ rate_table->dsmpd = 0;
+ debug("frac = %x\n", rate_table->frac);
+ }
+ return rate_table;
+}
+
+static const struct rockchip_pll_rate_table *
+rockchip_get_pll_settings(struct rockchip_pll_clock *pll, ulong rate)
+{
+ struct rockchip_pll_rate_table *rate_table = pll->rate_table;
+
+ while (rate_table->rate) {
+ if (rate_table->rate == rate)
+ break;
+ rate_table++;
+ }
+ if (rate_table->rate != rate)
+ return rockchip_pll_clk_set_by_auto(24 * MHZ, rate);
+ else
+ return rate_table;
+}
+
+static int rk3036_pll_set_rate(struct rockchip_pll_clock *pll,
+ void __iomem *base, ulong pll_id,
+ ulong drate)
+{
+ const struct rockchip_pll_rate_table *rate;
+
+ rate = rockchip_get_pll_settings(pll, drate);
+ if (!rate) {
+ printf("%s unsupport rate\n", __func__);
+ return -EINVAL;
+ }
+
+ debug("%s: rate settings for %lu fbdiv: %d, postdiv1: %d, refdiv: %d\n",
+ __func__, rate->rate, rate->fbdiv, rate->postdiv1, rate->refdiv);
+ debug("%s: rate settings for %lu postdiv2: %d, dsmpd: %d, frac: %d\n",
+ __func__, rate->rate, rate->postdiv2, rate->dsmpd, rate->frac);
+
+ /*
+ * When power on or changing PLL setting,
+ * we must force PLL into slow mode to ensure output stable clock.
+ */
+ rk_clrsetreg(base + pll->mode_offset,
+ pll->mode_mask << pll->mode_shift,
+ RKCLK_PLL_MODE_SLOW << pll->mode_shift);
+
+ /* Power down */
+ rk_setreg(base + pll->con_offset + 0x4,
+ 1 << RK3036_PLLCON1_PWRDOWN_SHIT);
+
+ rk_clrsetreg(base + pll->con_offset,
+ (RK3036_PLLCON0_POSTDIV1_MASK |
+ RK3036_PLLCON0_FBDIV_MASK),
+ (rate->postdiv1 << RK3036_PLLCON0_POSTDIV1_SHIFT) |
+ rate->fbdiv);
+ rk_clrsetreg(base + pll->con_offset + 0x4,
+ (RK3036_PLLCON1_POSTDIV2_MASK |
+ RK3036_PLLCON1_REFDIV_MASK),
+ (rate->postdiv2 << RK3036_PLLCON1_POSTDIV2_SHIFT |
+ rate->refdiv << RK3036_PLLCON1_REFDIV_SHIFT));
+ if (!rate->dsmpd) {
+ rk_clrsetreg(base + pll->con_offset + 0x4,
+ RK3036_PLLCON1_DSMPD_MASK,
+ rate->dsmpd << RK3036_PLLCON1_DSMPD_SHIFT);
+ writel((readl(base + pll->con_offset + 0x8) &
+ (~RK3036_PLLCON2_FRAC_MASK)) |
+ (rate->frac << RK3036_PLLCON2_FRAC_SHIFT),
+ base + pll->con_offset + 0x8);
+ }
+
+ /* Power Up */
+ rk_clrreg(base + pll->con_offset + 0x4,
+ 1 << RK3036_PLLCON1_PWRDOWN_SHIT);
+
+ /* waiting for pll lock */
+ while (!(readl(base + pll->con_offset + 0x4) & (1 << pll->lock_shift)))
+ udelay(1);
+
+ rk_clrsetreg(base + pll->mode_offset, pll->mode_mask << pll->mode_shift,
+ RKCLK_PLL_MODE_NORMAL << pll->mode_shift);
+ debug("PLL at %p: con0=%x con1= %x con2= %x mode= %x\n",
+ pll, readl(base + pll->con_offset),
+ readl(base + pll->con_offset + 0x4),
+ readl(base + pll->con_offset + 0x8),
+ readl(base + pll->mode_offset));
+
+ return 0;
+}
+
+static ulong rk3036_pll_get_rate(struct rockchip_pll_clock *pll,
+ void __iomem *base, ulong pll_id)
+{
+ u32 refdiv, fbdiv, postdiv1, postdiv2, dsmpd, frac;
+ u32 con = 0, shift, mask;
+ ulong rate;
+
+ con = readl(base + pll->mode_offset);
+ shift = pll->mode_shift;
+ mask = pll->mode_mask << shift;
+
+ switch ((con & mask) >> shift) {
+ case RKCLK_PLL_MODE_SLOW:
+ return OSC_HZ;
+ case RKCLK_PLL_MODE_NORMAL:
+ /* normal mode */
+ con = readl(base + pll->con_offset);
+ postdiv1 = (con & RK3036_PLLCON0_POSTDIV1_MASK) >>
+ RK3036_PLLCON0_POSTDIV1_SHIFT;
+ fbdiv = (con & RK3036_PLLCON0_FBDIV_MASK) >>
+ RK3036_PLLCON0_FBDIV_SHIFT;
+ con = readl(base + pll->con_offset + 0x4);
+ postdiv2 = (con & RK3036_PLLCON1_POSTDIV2_MASK) >>
+ RK3036_PLLCON1_POSTDIV2_SHIFT;
+ refdiv = (con & RK3036_PLLCON1_REFDIV_MASK) >>
+ RK3036_PLLCON1_REFDIV_SHIFT;
+ dsmpd = (con & RK3036_PLLCON1_DSMPD_MASK) >>
+ RK3036_PLLCON1_DSMPD_SHIFT;
+ con = readl(base + pll->con_offset + 0x8);
+ frac = (con & RK3036_PLLCON2_FRAC_MASK) >>
+ RK3036_PLLCON2_FRAC_SHIFT;
+ rate = (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000;
+ if (dsmpd == 0) {
+ u64 frac_rate = OSC_HZ * (u64)frac;
+
+ do_div(frac_rate, refdiv);
+ frac_rate >>= 24;
+ do_div(frac_rate, postdiv1);
+ do_div(frac_rate, postdiv1);
+ rate += frac_rate;
+ }
+ return rate;
+ case RKCLK_PLL_MODE_DEEP:
+ default:
+ return 32768;
+ }
+}
+
+ulong rockchip_pll_get_rate(struct rockchip_pll_clock *pll,
+ void __iomem *base,
+ ulong pll_id)
+{
+ ulong rate = 0;
+
+ switch (pll->type) {
+ case pll_rk3036:
+ pll->mode_mask = PLL_MODE_MASK;
+ rate = rk3036_pll_get_rate(pll, base, pll_id);
+ break;
+ case pll_rk3328:
+ pll->mode_mask = PLL_RK3328_MODE_MASK;
+ rate = rk3036_pll_get_rate(pll, base, pll_id);
+ break;
+ default:
+ printf("%s: Unknown pll type for pll clk %ld\n",
+ __func__, pll_id);
+ }
+ return rate;
+}
+
+int rockchip_pll_set_rate(struct rockchip_pll_clock *pll,
+ void __iomem *base, ulong pll_id,
+ ulong drate)
+{
+ int ret = 0;
+
+ if (rockchip_pll_get_rate(pll, base, pll_id) == drate)
+ return 0;
+
+ switch (pll->type) {
+ case pll_rk3036:
+ pll->mode_mask = PLL_MODE_MASK;
+ ret = rk3036_pll_set_rate(pll, base, pll_id, drate);
+ break;
+ case pll_rk3328:
+ pll->mode_mask = PLL_RK3328_MODE_MASK;
+ ret = rk3036_pll_set_rate(pll, base, pll_id, drate);
+ break;
+ default:
+ printf("%s: Unknown pll type for pll clk %ld\n",
+ __func__, pll_id);
+ }
+ return ret;
+}
+
+const struct rockchip_cpu_rate_table *
+rockchip_get_cpu_settings(struct rockchip_cpu_rate_table *cpu_table,
+ ulong rate)
+{
+ struct rockchip_cpu_rate_table *ps = cpu_table;
+
+ while (ps->rate) {
+ if (ps->rate == rate)
+ break;
+ ps++;
+ }
+ if (ps->rate != rate)
+ return NULL;
+ else
+ return ps;
+}
+
diff --git a/drivers/clk/rockchip/clk_px30.c b/drivers/clk/rockchip/clk_px30.c
new file mode 100644
index 0000000000..36764c128b
--- /dev/null
+++ b/drivers/clk/rockchip/clk_px30.c
@@ -0,0 +1,1630 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2017 Rockchip Electronics Co., Ltd
+ */
+
+#include <common.h>
+#include <bitfield.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <syscon.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_px30.h>
+#include <asm/arch-rockchip/hardware.h>
+#include <asm/io.h>
+#include <dm/lists.h>
+#include <dt-bindings/clock/px30-cru.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum {
+ VCO_MAX_HZ = 3200U * 1000000,
+ VCO_MIN_HZ = 800 * 1000000,
+ OUTPUT_MAX_HZ = 3200U * 1000000,
+ OUTPUT_MIN_HZ = 24 * 1000000,
+};
+
+#define PX30_VOP_PLL_LIMIT 600000000
+
+#define PX30_PLL_RATE(_rate, _refdiv, _fbdiv, _postdiv1, \
+ _postdiv2, _dsmpd, _frac) \
+{ \
+ .rate = _rate##U, \
+ .fbdiv = _fbdiv, \
+ .postdiv1 = _postdiv1, \
+ .refdiv = _refdiv, \
+ .postdiv2 = _postdiv2, \
+ .dsmpd = _dsmpd, \
+ .frac = _frac, \
+}
+
+#define PX30_CPUCLK_RATE(_rate, _aclk_div, _pclk_div) \
+{ \
+ .rate = _rate##U, \
+ .aclk_div = _aclk_div, \
+ .pclk_div = _pclk_div, \
+}
+
+#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
+
+#define PX30_CLK_DUMP(_id, _name, _iscru) \
+{ \
+ .id = _id, \
+ .name = _name, \
+ .is_cru = _iscru, \
+}
+
+static struct pll_rate_table px30_pll_rates[] = {
+ /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
+ PX30_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
+ PX30_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0),
+ PX30_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0),
+ PX30_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
+ PX30_PLL_RATE(1000000000, 6, 500, 2, 1, 1, 0),
+ PX30_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
+ PX30_PLL_RATE(600000000, 1, 75, 3, 1, 1, 0),
+};
+
+static struct cpu_rate_table px30_cpu_rates[] = {
+ PX30_CPUCLK_RATE(1200000000, 1, 5),
+ PX30_CPUCLK_RATE(1008000000, 1, 5),
+ PX30_CPUCLK_RATE(816000000, 1, 3),
+ PX30_CPUCLK_RATE(600000000, 1, 3),
+ PX30_CPUCLK_RATE(408000000, 1, 1),
+};
+
+static u8 pll_mode_shift[PLL_COUNT] = {
+ APLL_MODE_SHIFT, DPLL_MODE_SHIFT, CPLL_MODE_SHIFT,
+ NPLL_MODE_SHIFT, GPLL_MODE_SHIFT
+};
+
+static u32 pll_mode_mask[PLL_COUNT] = {
+ APLL_MODE_MASK, DPLL_MODE_MASK, CPLL_MODE_MASK,
+ NPLL_MODE_MASK, GPLL_MODE_MASK
+};
+
+static struct pll_rate_table auto_table;
+
+static ulong px30_clk_get_pll_rate(struct px30_clk_priv *priv,
+ enum px30_pll_id pll_id);
+
+static struct pll_rate_table *pll_clk_set_by_auto(u32 drate)
+{
+ struct pll_rate_table *rate = &auto_table;
+ u32 ref_khz = OSC_HZ / KHz, refdiv, fbdiv = 0;
+ u32 postdiv1, postdiv2 = 1;
+ u32 fref_khz;
+ u32 diff_khz, best_diff_khz;
+ const u32 max_refdiv = 63, max_fbdiv = 3200, min_fbdiv = 16;
+ const u32 max_postdiv1 = 7, max_postdiv2 = 7;
+ u32 vco_khz;
+ u32 rate_khz = drate / KHz;
+
+ if (!drate) {
+ printf("%s: the frequency can't be 0 Hz\n", __func__);
+ return NULL;
+ }
+
+ postdiv1 = DIV_ROUND_UP(VCO_MIN_HZ / 1000, rate_khz);
+ if (postdiv1 > max_postdiv1) {
+ postdiv2 = DIV_ROUND_UP(postdiv1, max_postdiv1);
+ postdiv1 = DIV_ROUND_UP(postdiv1, postdiv2);
+ }
+
+ vco_khz = rate_khz * postdiv1 * postdiv2;
+
+ if (vco_khz < (VCO_MIN_HZ / KHz) || vco_khz > (VCO_MAX_HZ / KHz) ||
+ postdiv2 > max_postdiv2) {
+ printf("%s: Cannot find out a supported VCO for Freq (%uHz)\n",
+ __func__, rate_khz);
+ return NULL;
+ }
+
+ rate->postdiv1 = postdiv1;
+ rate->postdiv2 = postdiv2;
+
+ best_diff_khz = vco_khz;
+ for (refdiv = 1; refdiv < max_refdiv && best_diff_khz; refdiv++) {
+ fref_khz = ref_khz / refdiv;
+
+ fbdiv = vco_khz / fref_khz;
+ if (fbdiv >= max_fbdiv || fbdiv <= min_fbdiv)
+ continue;
+
+ diff_khz = vco_khz - fbdiv * fref_khz;
+ if (fbdiv + 1 < max_fbdiv && diff_khz > fref_khz / 2) {
+ fbdiv++;
+ diff_khz = fref_khz - diff_khz;
+ }
+
+ if (diff_khz >= best_diff_khz)
+ continue;
+
+ best_diff_khz = diff_khz;
+ rate->refdiv = refdiv;
+ rate->fbdiv = fbdiv;
+ }
+
+ if (best_diff_khz > 4 * (MHz / KHz)) {
+ printf("%s: Failed to match output frequency %u bestis %u Hz\n",
+ __func__, rate_khz,
+ best_diff_khz * KHz);
+ return NULL;
+ }
+
+ return rate;
+}
+
+static const struct pll_rate_table *get_pll_settings(unsigned long rate)
+{
+ unsigned int rate_count = ARRAY_SIZE(px30_pll_rates);
+ int i;
+
+ for (i = 0; i < rate_count; i++) {
+ if (rate == px30_pll_rates[i].rate)
+ return &px30_pll_rates[i];
+ }
+
+ return pll_clk_set_by_auto(rate);
+}
+
+static const struct cpu_rate_table *get_cpu_settings(unsigned long rate)
+{
+ unsigned int rate_count = ARRAY_SIZE(px30_cpu_rates);
+ int i;
+
+ for (i = 0; i < rate_count; i++) {
+ if (rate == px30_cpu_rates[i].rate)
+ return &px30_cpu_rates[i];
+ }
+
+ return NULL;
+}
+
+/*
+ * How to calculate the PLL(from TRM V0.3 Part 1 Page 63):
+ * Formulas also embedded within the Fractional PLL Verilog model:
+ * If DSMPD = 1 (DSM is disabled, "integer mode")
+ * FOUTVCO = FREF / REFDIV * FBDIV
+ * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
+ * Where:
+ * FOUTVCO = Fractional PLL non-divided output frequency
+ * FOUTPOSTDIV = Fractional PLL divided output frequency
+ * (output of second post divider)
+ * FREF = Fractional PLL input reference frequency, (the OSC_HZ 24MHz input)
+ * REFDIV = Fractional PLL input reference clock divider
+ * FBDIV = Integer value programmed into feedback divide
+ *
+ */
+static int rkclk_set_pll(struct px30_pll *pll, unsigned int *mode,
+ enum px30_pll_id pll_id,
+ unsigned long drate)
+{
+ const struct pll_rate_table *rate;
+ uint vco_hz, output_hz;
+
+ rate = get_pll_settings(drate);
+ if (!rate) {
+ printf("%s unsupport rate\n", __func__);
+ return -EINVAL;
+ }
+
+ /* All PLLs have same VCO and output frequency range restrictions. */
+ vco_hz = OSC_HZ / 1000 * rate->fbdiv / rate->refdiv * 1000;
+ output_hz = vco_hz / rate->postdiv1 / rate->postdiv2;
+
+ debug("PLL at %p: fb=%d, ref=%d, pst1=%d, pst2=%d, vco=%u Hz, output=%u Hz\n",
+ pll, rate->fbdiv, rate->refdiv, rate->postdiv1,
+ rate->postdiv2, vco_hz, output_hz);
+ assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ &&
+ output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ);
+
+ /*
+ * When power on or changing PLL setting,
+ * we must force PLL into slow mode to ensure output stable clock.
+ */
+ rk_clrsetreg(mode, pll_mode_mask[pll_id],
+ PLLMUX_FROM_XIN24M << pll_mode_shift[pll_id]);
+
+ /* use integer mode */
+ rk_setreg(&pll->con1, 1 << PLL_DSMPD_SHIFT);
+ /* Power down */
+ rk_setreg(&pll->con1, 1 << PLL_PD_SHIFT);
+
+ rk_clrsetreg(&pll->con0,
+ PLL_POSTDIV1_MASK | PLL_FBDIV_MASK,
+ (rate->postdiv1 << PLL_POSTDIV1_SHIFT) | rate->fbdiv);
+ rk_clrsetreg(&pll->con1, PLL_POSTDIV2_MASK | PLL_REFDIV_MASK,
+ (rate->postdiv2 << PLL_POSTDIV2_SHIFT |
+ rate->refdiv << PLL_REFDIV_SHIFT));
+
+ /* Power Up */
+ rk_clrreg(&pll->con1, 1 << PLL_PD_SHIFT);
+
+ /* waiting for pll lock */
+ while (!(readl(&pll->con1) & (1 << PLL_LOCK_STATUS_SHIFT)))
+ udelay(1);
+
+ rk_clrsetreg(mode, pll_mode_mask[pll_id],
+ PLLMUX_FROM_PLL << pll_mode_shift[pll_id]);
+
+ return 0;
+}
+
+static uint32_t rkclk_pll_get_rate(struct px30_pll *pll, unsigned int *mode,
+ enum px30_pll_id pll_id)
+{
+ u32 refdiv, fbdiv, postdiv1, postdiv2;
+ u32 con, shift, mask;
+
+ con = readl(mode);
+ shift = pll_mode_shift[pll_id];
+ mask = pll_mode_mask[pll_id];
+
+ switch ((con & mask) >> shift) {
+ case PLLMUX_FROM_XIN24M:
+ return OSC_HZ;
+ case PLLMUX_FROM_PLL:
+ /* normal mode */
+ con = readl(&pll->con0);
+ postdiv1 = (con & PLL_POSTDIV1_MASK) >> PLL_POSTDIV1_SHIFT;
+ fbdiv = (con & PLL_FBDIV_MASK) >> PLL_FBDIV_SHIFT;
+ con = readl(&pll->con1);
+ postdiv2 = (con & PLL_POSTDIV2_MASK) >> PLL_POSTDIV2_SHIFT;
+ refdiv = (con & PLL_REFDIV_MASK) >> PLL_REFDIV_SHIFT;
+ return (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000;
+ case PLLMUX_FROM_RTC32K:
+ default:
+ return 32768;
+ }
+}
+
+static ulong px30_i2c_get_clk(struct px30_clk_priv *priv, ulong clk_id)
+{
+ struct px30_cru *cru = priv->cru;
+ u32 div, con;
+
+ switch (clk_id) {
+ case SCLK_I2C0:
+ con = readl(&cru->clksel_con[49]);
+ div = con >> CLK_I2C0_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
+ break;
+ case SCLK_I2C1:
+ con = readl(&cru->clksel_con[49]);
+ div = con >> CLK_I2C1_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
+ break;
+ case SCLK_I2C2:
+ con = readl(&cru->clksel_con[50]);
+ div = con >> CLK_I2C2_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
+ break;
+ case SCLK_I2C3:
+ con = readl(&cru->clksel_con[50]);
+ div = con >> CLK_I2C3_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
+ break;
+ default:
+ printf("do not support this i2c bus\n");
+ return -EINVAL;
+ }
+
+ return DIV_TO_RATE(priv->gpll_hz, div);
+}
+
+static ulong px30_i2c_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz)
+{
+ struct px30_cru *cru = priv->cru;
+ int src_clk_div;
+
+ src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
+ assert(src_clk_div - 1 <= 127);
+
+ switch (clk_id) {
+ case SCLK_I2C0:
+ rk_clrsetreg(&cru->clksel_con[49],
+ CLK_I2C_DIV_CON_MASK << CLK_I2C0_DIV_CON_SHIFT |
+ CLK_I2C_PLL_SEL_MASK << CLK_I2C0_PLL_SEL_SHIFT,
+ (src_clk_div - 1) << CLK_I2C0_DIV_CON_SHIFT |
+ CLK_I2C_PLL_SEL_GPLL << CLK_I2C0_PLL_SEL_SHIFT);
+ break;
+ case SCLK_I2C1:
+ rk_clrsetreg(&cru->clksel_con[49],
+ CLK_I2C_DIV_CON_MASK << CLK_I2C1_DIV_CON_SHIFT |
+ CLK_I2C_PLL_SEL_MASK << CLK_I2C1_PLL_SEL_SHIFT,
+ (src_clk_div - 1) << CLK_I2C1_DIV_CON_SHIFT |
+ CLK_I2C_PLL_SEL_GPLL << CLK_I2C1_PLL_SEL_SHIFT);
+ break;
+ case SCLK_I2C2:
+ rk_clrsetreg(&cru->clksel_con[50],
+ CLK_I2C_DIV_CON_MASK << CLK_I2C2_DIV_CON_SHIFT |
+ CLK_I2C_PLL_SEL_MASK << CLK_I2C2_PLL_SEL_SHIFT,
+ (src_clk_div - 1) << CLK_I2C2_DIV_CON_SHIFT |
+ CLK_I2C_PLL_SEL_GPLL << CLK_I2C2_PLL_SEL_SHIFT);
+ break;
+ case SCLK_I2C3:
+ rk_clrsetreg(&cru->clksel_con[50],
+ CLK_I2C_DIV_CON_MASK << CLK_I2C3_DIV_CON_SHIFT |
+ CLK_I2C_PLL_SEL_MASK << CLK_I2C3_PLL_SEL_SHIFT,
+ (src_clk_div - 1) << CLK_I2C3_DIV_CON_SHIFT |
+ CLK_I2C_PLL_SEL_GPLL << CLK_I2C3_PLL_SEL_SHIFT);
+ break;
+ default:
+ printf("do not support this i2c bus\n");
+ return -EINVAL;
+ }
+
+ return px30_i2c_get_clk(priv, clk_id);
+}
+
+/*
+ * calculate best rational approximation for a given fraction
+ * taking into account restricted register size, e.g. to find
+ * appropriate values for a pll with 5 bit denominator and
+ * 8 bit numerator register fields, trying to set up with a
+ * frequency ratio of 3.1415, one would say:
+ *
+ * rational_best_approximation(31415, 10000,
+ * (1 << 8) - 1, (1 << 5) - 1, &n, &d);
+ *
+ * you may look at given_numerator as a fixed point number,
+ * with the fractional part size described in given_denominator.
+ *
+ * for theoretical background, see:
+ * http://en.wikipedia.org/wiki/Continued_fraction
+ */
+static void rational_best_approximation(unsigned long given_numerator,
+ unsigned long given_denominator,
+ unsigned long max_numerator,
+ unsigned long max_denominator,
+ unsigned long *best_numerator,
+ unsigned long *best_denominator)
+{
+ unsigned long n, d, n0, d0, n1, d1;
+
+ n = given_numerator;
+ d = given_denominator;
+ n0 = 0;
+ d1 = 0;
+ n1 = 1;
+ d0 = 1;
+ for (;;) {
+ unsigned long t, a;
+
+ if (n1 > max_numerator || d1 > max_denominator) {
+ n1 = n0;
+ d1 = d0;
+ break;
+ }
+ if (d == 0)
+ break;
+ t = d;
+ a = n / d;
+ d = n % d;
+ n = t;
+ t = n0 + a * n1;
+ n0 = n1;
+ n1 = t;
+ t = d0 + a * d1;
+ d0 = d1;
+ d1 = t;
+ }
+ *best_numerator = n1;
+ *best_denominator = d1;
+}
+
+static ulong px30_i2s_get_clk(struct px30_clk_priv *priv, ulong clk_id)
+{
+ u32 con, fracdiv, gate;
+ u32 clk_src = priv->gpll_hz / 2;
+ unsigned long m, n;
+ struct px30_cru *cru = priv->cru;
+
+ switch (clk_id) {
+ case SCLK_I2S1:
+ con = readl(&cru->clksel_con[30]);
+ fracdiv = readl(&cru->clksel_con[31]);
+ gate = readl(&cru->clkgate_con[10]);
+ m = fracdiv & CLK_I2S1_FRAC_NUMERATOR_MASK;
+ m >>= CLK_I2S1_FRAC_NUMERATOR_SHIFT;
+ n = fracdiv & CLK_I2S1_FRAC_DENOMINATOR_MASK;
+ n >>= CLK_I2S1_FRAC_DENOMINATOR_SHIFT;
+ debug("con30: 0x%x, gate: 0x%x, frac: 0x%x\n",
+ con, gate, fracdiv);
+ break;
+ default:
+ printf("do not support this i2s bus\n");
+ return -EINVAL;
+ }
+
+ return clk_src * n / m;
+}
+
+static ulong px30_i2s_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz)
+{
+ u32 clk_src;
+ unsigned long m, n, val;
+ struct px30_cru *cru = priv->cru;
+
+ clk_src = priv->gpll_hz / 2;
+ rational_best_approximation(hz, clk_src,
+ GENMASK(16 - 1, 0),
+ GENMASK(16 - 1, 0),
+ &m, &n);
+ switch (clk_id) {
+ case SCLK_I2S1:
+ rk_clrsetreg(&cru->clksel_con[30],
+ CLK_I2S1_PLL_SEL_MASK, CLK_I2S1_PLL_SEL_GPLL);
+ rk_clrsetreg(&cru->clksel_con[30],
+ CLK_I2S1_DIV_CON_MASK, 0x1);
+ rk_clrsetreg(&cru->clksel_con[30],
+ CLK_I2S1_SEL_MASK, CLK_I2S1_SEL_FRAC);
+ val = m << CLK_I2S1_FRAC_NUMERATOR_SHIFT | n;
+ writel(val, &cru->clksel_con[31]);
+ rk_clrsetreg(&cru->clkgate_con[10],
+ CLK_I2S1_OUT_MCLK_PAD_MASK,
+ CLK_I2S1_OUT_MCLK_PAD_ENABLE);
+ break;
+ default:
+ printf("do not support this i2s bus\n");
+ return -EINVAL;
+ }
+
+ return px30_i2s_get_clk(priv, clk_id);
+}
+
+static ulong px30_nandc_get_clk(struct px30_clk_priv *priv)
+{
+ struct px30_cru *cru = priv->cru;
+ u32 div, con;
+
+ con = readl(&cru->clksel_con[15]);
+ div = (con & NANDC_DIV_MASK) >> NANDC_DIV_SHIFT;
+
+ return DIV_TO_RATE(priv->gpll_hz, div);
+}
+
+static ulong px30_nandc_set_clk(struct px30_clk_priv *priv,
+ ulong set_rate)
+{
+ struct px30_cru *cru = priv->cru;
+ int src_clk_div;
+
+ /* Select nandc source from GPLL by default */
+ /* nandc clock defaulg div 2 internal, need provide double in cru */
+ src_clk_div = DIV_ROUND_UP(priv->gpll_hz, set_rate);
+ assert(src_clk_div - 1 <= 31);
+
+ rk_clrsetreg(&cru->clksel_con[15],
+ NANDC_CLK_SEL_MASK | NANDC_PLL_MASK |
+ NANDC_DIV_MASK,
+ NANDC_CLK_SEL_NANDC << NANDC_CLK_SEL_SHIFT |
+ NANDC_SEL_GPLL << NANDC_PLL_SHIFT |
+ (src_clk_div - 1) << NANDC_DIV_SHIFT);
+
+ return px30_nandc_get_clk(priv);
+}
+
+static ulong px30_mmc_get_clk(struct px30_clk_priv *priv, uint clk_id)
+{
+ struct px30_cru *cru = priv->cru;
+ u32 div, con, con_id;
+
+ switch (clk_id) {
+ case HCLK_SDMMC:
+ case SCLK_SDMMC:
+ con_id = 16;
+ break;
+ case HCLK_EMMC:
+ case SCLK_EMMC:
+ case SCLK_EMMC_SAMPLE:
+ con_id = 20;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ con = readl(&cru->clksel_con[con_id]);
+ div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT;
+
+ if ((con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT
+ == EMMC_SEL_24M)
+ return DIV_TO_RATE(OSC_HZ, div) / 2;
+ else
+ return DIV_TO_RATE(priv->gpll_hz, div) / 2;
+}
+
+static ulong px30_mmc_set_clk(struct px30_clk_priv *priv,
+ ulong clk_id, ulong set_rate)
+{
+ struct px30_cru *cru = priv->cru;
+ int src_clk_div;
+ u32 con_id;
+
+ switch (clk_id) {
+ case HCLK_SDMMC:
+ case SCLK_SDMMC:
+ con_id = 16;
+ break;
+ case HCLK_EMMC:
+ case SCLK_EMMC:
+ con_id = 20;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Select clk_sdmmc/emmc source from GPLL by default */
+ /* mmc clock defaulg div 2 internal, need provide double in cru */
+ src_clk_div = DIV_ROUND_UP(priv->gpll_hz / 2, set_rate);
+
+ if (src_clk_div > 127) {
+ /* use 24MHz source for 400KHz clock */
+ src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, set_rate);
+ rk_clrsetreg(&cru->clksel_con[con_id],
+ EMMC_PLL_MASK | EMMC_DIV_MASK,
+ EMMC_SEL_24M << EMMC_PLL_SHIFT |
+ (src_clk_div - 1) << EMMC_DIV_SHIFT);
+ } else {
+ rk_clrsetreg(&cru->clksel_con[con_id],
+ EMMC_PLL_MASK | EMMC_DIV_MASK,
+ EMMC_SEL_GPLL << EMMC_PLL_SHIFT |
+ (src_clk_div - 1) << EMMC_DIV_SHIFT);
+ }
+ rk_clrsetreg(&cru->clksel_con[con_id + 1], EMMC_CLK_SEL_MASK,
+ EMMC_CLK_SEL_EMMC);
+
+ return px30_mmc_get_clk(priv, clk_id);
+}
+
+static ulong px30_pwm_get_clk(struct px30_clk_priv *priv, ulong clk_id)
+{
+ struct px30_cru *cru = priv->cru;
+ u32 div, con;
+
+ switch (clk_id) {
+ case SCLK_PWM0:
+ con = readl(&cru->clksel_con[52]);
+ div = con >> CLK_PWM0_DIV_CON_SHIFT & CLK_PWM_DIV_CON_MASK;
+ break;
+ case SCLK_PWM1:
+ con = readl(&cru->clksel_con[52]);
+ div = con >> CLK_PWM1_DIV_CON_SHIFT & CLK_PWM_DIV_CON_MASK;
+ break;
+ default:
+ printf("do not support this pwm bus\n");
+ return -EINVAL;
+ }
+
+ return DIV_TO_RATE(priv->gpll_hz, div);
+}
+
+static ulong px30_pwm_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz)
+{
+ struct px30_cru *cru = priv->cru;
+ int src_clk_div;
+
+ src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
+ assert(src_clk_div - 1 <= 127);
+
+ switch (clk_id) {
+ case SCLK_PWM0:
+ rk_clrsetreg(&cru->clksel_con[52],
+ CLK_PWM_DIV_CON_MASK << CLK_PWM0_DIV_CON_SHIFT |
+ CLK_PWM_PLL_SEL_MASK << CLK_PWM0_PLL_SEL_SHIFT,
+ (src_clk_div - 1) << CLK_PWM0_DIV_CON_SHIFT |
+ CLK_PWM_PLL_SEL_GPLL << CLK_PWM0_PLL_SEL_SHIFT);
+ break;
+ case SCLK_PWM1:
+ rk_clrsetreg(&cru->clksel_con[52],
+ CLK_PWM_DIV_CON_MASK << CLK_PWM1_DIV_CON_SHIFT |
+ CLK_PWM_PLL_SEL_MASK << CLK_PWM1_PLL_SEL_SHIFT,
+ (src_clk_div - 1) << CLK_PWM1_DIV_CON_SHIFT |
+ CLK_PWM_PLL_SEL_GPLL << CLK_PWM1_PLL_SEL_SHIFT);
+ break;
+ default:
+ printf("do not support this pwm bus\n");
+ return -EINVAL;
+ }
+
+ return px30_pwm_get_clk(priv, clk_id);
+}
+
+static ulong px30_saradc_get_clk(struct px30_clk_priv *priv)
+{
+ struct px30_cru *cru = priv->cru;
+ u32 div, con;
+
+ con = readl(&cru->clksel_con[55]);
+ div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK;
+
+ return DIV_TO_RATE(OSC_HZ, div);
+}
+
+static ulong px30_saradc_set_clk(struct px30_clk_priv *priv, uint hz)
+{
+ struct px30_cru *cru = priv->cru;
+ int src_clk_div;
+
+ src_clk_div = DIV_ROUND_UP(OSC_HZ, hz);
+ assert(src_clk_div - 1 <= 2047);
+
+ rk_clrsetreg(&cru->clksel_con[55],
+ CLK_SARADC_DIV_CON_MASK,
+ (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT);
+
+ return px30_saradc_get_clk(priv);
+}
+
+static ulong px30_tsadc_get_clk(struct px30_clk_priv *priv)
+{
+ struct px30_cru *cru = priv->cru;
+ u32 div, con;
+
+ con = readl(&cru->clksel_con[54]);
+ div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK;
+
+ return DIV_TO_RATE(OSC_HZ, div);
+}
+
+static ulong px30_tsadc_set_clk(struct px30_clk_priv *priv, uint hz)
+{
+ struct px30_cru *cru = priv->cru;
+ int src_clk_div;
+
+ src_clk_div = DIV_ROUND_UP(OSC_HZ, hz);
+ assert(src_clk_div - 1 <= 2047);
+
+ rk_clrsetreg(&cru->clksel_con[54],
+ CLK_SARADC_DIV_CON_MASK,
+ (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT);
+
+ return px30_tsadc_get_clk(priv);
+}
+
+static ulong px30_spi_get_clk(struct px30_clk_priv *priv, ulong clk_id)
+{
+ struct px30_cru *cru = priv->cru;
+ u32 div, con;
+
+ switch (clk_id) {
+ case SCLK_SPI0:
+ con = readl(&cru->clksel_con[53]);
+ div = con >> CLK_SPI0_DIV_CON_SHIFT & CLK_SPI_DIV_CON_MASK;
+ break;
+ case SCLK_SPI1:
+ con = readl(&cru->clksel_con[53]);
+ div = con >> CLK_SPI1_DIV_CON_SHIFT & CLK_SPI_DIV_CON_MASK;
+ break;
+ default:
+ printf("do not support this pwm bus\n");
+ return -EINVAL;
+ }
+
+ return DIV_TO_RATE(priv->gpll_hz, div);
+}
+
+static ulong px30_spi_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz)
+{
+ struct px30_cru *cru = priv->cru;
+ int src_clk_div;
+
+ src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
+ assert(src_clk_div - 1 <= 127);
+
+ switch (clk_id) {
+ case SCLK_SPI0:
+ rk_clrsetreg(&cru->clksel_con[53],
+ CLK_SPI_DIV_CON_MASK << CLK_SPI0_DIV_CON_SHIFT |
+ CLK_SPI_PLL_SEL_MASK << CLK_SPI0_PLL_SEL_SHIFT,
+ (src_clk_div - 1) << CLK_SPI0_DIV_CON_SHIFT |
+ CLK_SPI_PLL_SEL_GPLL << CLK_SPI0_PLL_SEL_SHIFT);
+ break;
+ case SCLK_SPI1:
+ rk_clrsetreg(&cru->clksel_con[53],
+ CLK_SPI_DIV_CON_MASK << CLK_SPI1_DIV_CON_SHIFT |
+ CLK_SPI_PLL_SEL_MASK << CLK_SPI1_PLL_SEL_SHIFT,
+ (src_clk_div - 1) << CLK_SPI1_DIV_CON_SHIFT |
+ CLK_SPI_PLL_SEL_GPLL << CLK_SPI1_PLL_SEL_SHIFT);
+ break;
+ default:
+ printf("do not support this pwm bus\n");
+ return -EINVAL;
+ }
+
+ return px30_spi_get_clk(priv, clk_id);
+}
+
+static ulong px30_vop_get_clk(struct px30_clk_priv *priv, ulong clk_id)
+{
+ struct px30_cru *cru = priv->cru;
+ u32 div, con, parent;
+
+ switch (clk_id) {
+ case ACLK_VOPB:
+ case ACLK_VOPL:
+ con = readl(&cru->clksel_con[3]);
+ div = con & ACLK_VO_DIV_MASK;
+ parent = priv->gpll_hz;
+ break;
+ case DCLK_VOPB:
+ con = readl(&cru->clksel_con[5]);
+ div = con & DCLK_VOPB_DIV_MASK;
+ parent = rkclk_pll_get_rate(&cru->pll[CPLL], &cru->mode, CPLL);
+ break;
+ case DCLK_VOPL:
+ con = readl(&cru->clksel_con[8]);
+ div = con & DCLK_VOPL_DIV_MASK;
+ parent = rkclk_pll_get_rate(&cru->pll[NPLL], &cru->mode, NPLL);
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return DIV_TO_RATE(parent, div);
+}
+
+static ulong px30_vop_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz)
+{
+ struct px30_cru *cru = priv->cru;
+ ulong npll_hz;
+ int src_clk_div;
+
+ switch (clk_id) {
+ case ACLK_VOPB:
+ case ACLK_VOPL:
+ src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
+ assert(src_clk_div - 1 <= 31);
+ rk_clrsetreg(&cru->clksel_con[3],
+ ACLK_VO_PLL_MASK | ACLK_VO_DIV_MASK,
+ ACLK_VO_SEL_GPLL << ACLK_VO_PLL_SHIFT |
+ (src_clk_div - 1) << ACLK_VO_DIV_SHIFT);
+ break;
+ case DCLK_VOPB:
+ if (hz < PX30_VOP_PLL_LIMIT) {
+ src_clk_div = DIV_ROUND_UP(PX30_VOP_PLL_LIMIT, hz);
+ if (src_clk_div % 2)
+ src_clk_div = src_clk_div - 1;
+ } else {
+ src_clk_div = 1;
+ }
+ assert(src_clk_div - 1 <= 255);
+ rkclk_set_pll(&cru->pll[CPLL], &cru->mode,
+ CPLL, hz * src_clk_div);
+ rk_clrsetreg(&cru->clksel_con[5],
+ DCLK_VOPB_SEL_MASK | DCLK_VOPB_PLL_SEL_MASK |
+ DCLK_VOPB_DIV_MASK,
+ DCLK_VOPB_SEL_DIVOUT << DCLK_VOPB_SEL_SHIFT |
+ DCLK_VOPB_PLL_SEL_CPLL << DCLK_VOPB_PLL_SEL_SHIFT |
+ (src_clk_div - 1) << DCLK_VOPB_DIV_SHIFT);
+ break;
+ case DCLK_VOPL:
+ npll_hz = px30_clk_get_pll_rate(priv, NPLL);
+ if (npll_hz >= PX30_VOP_PLL_LIMIT && npll_hz >= hz &&
+ npll_hz % hz == 0) {
+ src_clk_div = npll_hz / hz;
+ assert(src_clk_div - 1 <= 255);
+ } else {
+ if (hz < PX30_VOP_PLL_LIMIT) {
+ src_clk_div = DIV_ROUND_UP(PX30_VOP_PLL_LIMIT,
+ hz);
+ if (src_clk_div % 2)
+ src_clk_div = src_clk_div - 1;
+ } else {
+ src_clk_div = 1;
+ }
+ assert(src_clk_div - 1 <= 255);
+ rkclk_set_pll(&cru->pll[NPLL], &cru->mode, NPLL,
+ hz * src_clk_div);
+ }
+ rk_clrsetreg(&cru->clksel_con[8],
+ DCLK_VOPL_SEL_MASK | DCLK_VOPL_PLL_SEL_MASK |
+ DCLK_VOPL_DIV_MASK,
+ DCLK_VOPL_SEL_DIVOUT << DCLK_VOPL_SEL_SHIFT |
+ DCLK_VOPL_PLL_SEL_NPLL << DCLK_VOPL_PLL_SEL_SHIFT |
+ (src_clk_div - 1) << DCLK_VOPL_DIV_SHIFT);
+ break;
+ default:
+ printf("do not support this vop freq\n");
+ return -EINVAL;
+ }
+
+ return px30_vop_get_clk(priv, clk_id);
+}
+
+static ulong px30_bus_get_clk(struct px30_clk_priv *priv, ulong clk_id)
+{
+ struct px30_cru *cru = priv->cru;
+ u32 div, con, parent;
+
+ switch (clk_id) {
+ case ACLK_BUS_PRE:
+ con = readl(&cru->clksel_con[23]);
+ div = (con & BUS_ACLK_DIV_MASK) >> BUS_ACLK_DIV_SHIFT;
+ parent = priv->gpll_hz;
+ break;
+ case HCLK_BUS_PRE:
+ con = readl(&cru->clksel_con[24]);
+ div = (con & BUS_HCLK_DIV_MASK) >> BUS_HCLK_DIV_SHIFT;
+ parent = priv->gpll_hz;
+ break;
+ case PCLK_BUS_PRE:
+ case PCLK_WDT_NS:
+ parent = px30_bus_get_clk(priv, ACLK_BUS_PRE);
+ con = readl(&cru->clksel_con[24]);
+ div = (con & BUS_PCLK_DIV_MASK) >> BUS_PCLK_DIV_SHIFT;
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return DIV_TO_RATE(parent, div);
+}
+
+static ulong px30_bus_set_clk(struct px30_clk_priv *priv, ulong clk_id,
+ ulong hz)
+{
+ struct px30_cru *cru = priv->cru;
+ int src_clk_div;
+
+ /*
+ * select gpll as pd_bus bus clock source and
+ * set up dependent divisors for PCLK/HCLK and ACLK clocks.
+ */
+ switch (clk_id) {
+ case ACLK_BUS_PRE:
+ src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
+ assert(src_clk_div - 1 <= 31);
+ rk_clrsetreg(&cru->clksel_con[23],
+ BUS_PLL_SEL_MASK | BUS_ACLK_DIV_MASK,
+ BUS_PLL_SEL_GPLL << BUS_PLL_SEL_SHIFT |
+ (src_clk_div - 1) << BUS_ACLK_DIV_SHIFT);
+ break;
+ case HCLK_BUS_PRE:
+ src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
+ assert(src_clk_div - 1 <= 31);
+ rk_clrsetreg(&cru->clksel_con[24],
+ BUS_PLL_SEL_MASK | BUS_HCLK_DIV_MASK,
+ BUS_PLL_SEL_GPLL << BUS_PLL_SEL_SHIFT |
+ (src_clk_div - 1) << BUS_HCLK_DIV_SHIFT);
+ break;
+ case PCLK_BUS_PRE:
+ src_clk_div =
+ DIV_ROUND_UP(px30_bus_get_clk(priv, ACLK_BUS_PRE), hz);
+ assert(src_clk_div - 1 <= 3);
+ rk_clrsetreg(&cru->clksel_con[24],
+ BUS_PCLK_DIV_MASK,
+ (src_clk_div - 1) << BUS_PCLK_DIV_SHIFT);
+ break;
+ default:
+ printf("do not support this bus freq\n");
+ return -EINVAL;
+ }
+
+ return px30_bus_get_clk(priv, clk_id);
+}
+
+static ulong px30_peri_get_clk(struct px30_clk_priv *priv, ulong clk_id)
+{
+ struct px30_cru *cru = priv->cru;
+ u32 div, con, parent;
+
+ switch (clk_id) {
+ case ACLK_PERI_PRE:
+ con = readl(&cru->clksel_con[14]);
+ div = (con & PERI_ACLK_DIV_MASK) >> PERI_ACLK_DIV_SHIFT;
+ parent = priv->gpll_hz;
+ break;
+ case HCLK_PERI_PRE:
+ con = readl(&cru->clksel_con[14]);
+ div = (con & PERI_HCLK_DIV_MASK) >> PERI_HCLK_DIV_SHIFT;
+ parent = priv->gpll_hz;
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return DIV_TO_RATE(parent, div);
+}
+
+static ulong px30_peri_set_clk(struct px30_clk_priv *priv, ulong clk_id,
+ ulong hz)
+{
+ struct px30_cru *cru = priv->cru;
+ int src_clk_div;
+
+ src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
+ assert(src_clk_div - 1 <= 31);
+
+ /*
+ * select gpll as pd_peri bus clock source and
+ * set up dependent divisors for HCLK and ACLK clocks.
+ */
+ switch (clk_id) {
+ case ACLK_PERI_PRE:
+ rk_clrsetreg(&cru->clksel_con[14],
+ PERI_PLL_SEL_MASK | PERI_ACLK_DIV_MASK,
+ PERI_PLL_GPLL << PERI_PLL_SEL_SHIFT |
+ (src_clk_div - 1) << PERI_ACLK_DIV_SHIFT);
+ break;
+ case HCLK_PERI_PRE:
+ rk_clrsetreg(&cru->clksel_con[14],
+ PERI_PLL_SEL_MASK | PERI_HCLK_DIV_MASK,
+ PERI_PLL_GPLL << PERI_PLL_SEL_SHIFT |
+ (src_clk_div - 1) << PERI_HCLK_DIV_SHIFT);
+ break;
+ default:
+ printf("do not support this peri freq\n");
+ return -EINVAL;
+ }
+
+ return px30_peri_get_clk(priv, clk_id);
+}
+
+#ifndef CONFIG_SPL_BUILD
+static ulong px30_crypto_get_clk(struct px30_clk_priv *priv, ulong clk_id)
+{
+ struct px30_cru *cru = priv->cru;
+ u32 div, con, parent;
+
+ switch (clk_id) {
+ case SCLK_CRYPTO:
+ con = readl(&cru->clksel_con[25]);
+ div = (con & CRYPTO_DIV_MASK) >> CRYPTO_DIV_SHIFT;
+ parent = priv->gpll_hz;
+ break;
+ case SCLK_CRYPTO_APK:
+ con = readl(&cru->clksel_con[25]);
+ div = (con & CRYPTO_APK_DIV_MASK) >> CRYPTO_APK_DIV_SHIFT;
+ parent = priv->gpll_hz;
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return DIV_TO_RATE(parent, div);
+}
+
+static ulong px30_crypto_set_clk(struct px30_clk_priv *priv, ulong clk_id,
+ ulong hz)
+{
+ struct px30_cru *cru = priv->cru;
+ int src_clk_div;
+
+ src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
+ assert(src_clk_div - 1 <= 31);
+
+ /*
+ * select gpll as crypto clock source and
+ * set up dependent divisors for crypto clocks.
+ */
+ switch (clk_id) {
+ case SCLK_CRYPTO:
+ rk_clrsetreg(&cru->clksel_con[25],
+ CRYPTO_PLL_SEL_MASK | CRYPTO_DIV_MASK,
+ CRYPTO_PLL_SEL_GPLL << CRYPTO_PLL_SEL_SHIFT |
+ (src_clk_div - 1) << CRYPTO_DIV_SHIFT);
+ break;
+ case SCLK_CRYPTO_APK:
+ rk_clrsetreg(&cru->clksel_con[25],
+ CRYPTO_APK_PLL_SEL_MASK | CRYPTO_APK_DIV_MASK,
+ CRYPTO_PLL_SEL_GPLL << CRYPTO_APK_SEL_SHIFT |
+ (src_clk_div - 1) << CRYPTO_APK_DIV_SHIFT);
+ break;
+ default:
+ printf("do not support this peri freq\n");
+ return -EINVAL;
+ }
+
+ return px30_crypto_get_clk(priv, clk_id);
+}
+
+static ulong px30_i2s1_mclk_get_clk(struct px30_clk_priv *priv, ulong clk_id)
+{
+ struct px30_cru *cru = priv->cru;
+ u32 con;
+
+ con = readl(&cru->clksel_con[30]);
+
+ if (!(con & CLK_I2S1_OUT_SEL_MASK))
+ return -ENOENT;
+
+ return 12000000;
+}
+
+static ulong px30_i2s1_mclk_set_clk(struct px30_clk_priv *priv, ulong clk_id,
+ ulong hz)
+{
+ struct px30_cru *cru = priv->cru;
+
+ if (hz != 12000000) {
+ printf("do not support this i2s1_mclk freq\n");
+ return -EINVAL;
+ }
+
+ rk_clrsetreg(&cru->clksel_con[30], CLK_I2S1_OUT_SEL_MASK,
+ CLK_I2S1_OUT_SEL_OSC);
+ rk_clrsetreg(&cru->clkgate_con[10], CLK_I2S1_OUT_MCLK_PAD_MASK,
+ CLK_I2S1_OUT_MCLK_PAD_ENABLE);
+
+ return px30_i2s1_mclk_get_clk(priv, clk_id);
+}
+
+static ulong px30_mac_set_clk(struct px30_clk_priv *priv, uint hz)
+{
+ struct px30_cru *cru = priv->cru;
+ u32 con = readl(&cru->clksel_con[22]);
+ ulong pll_rate;
+ u8 div;
+
+ if ((con >> GMAC_PLL_SEL_SHIFT) & GMAC_PLL_SEL_CPLL)
+ pll_rate = px30_clk_get_pll_rate(priv, CPLL);
+ else if ((con >> GMAC_PLL_SEL_SHIFT) & GMAC_PLL_SEL_NPLL)
+ pll_rate = px30_clk_get_pll_rate(priv, NPLL);
+ else
+ pll_rate = priv->gpll_hz;
+
+ /*default set 50MHZ for gmac*/
+ if (!hz)
+ hz = 50000000;
+
+ div = DIV_ROUND_UP(pll_rate, hz) - 1;
+ assert(div < 32);
+ rk_clrsetreg(&cru->clksel_con[22], CLK_GMAC_DIV_MASK,
+ div << CLK_GMAC_DIV_SHIFT);
+
+ return DIV_TO_RATE(pll_rate, div);
+}
+
+static int px30_mac_set_speed_clk(struct px30_clk_priv *priv, uint hz)
+{
+ struct px30_cru *cru = priv->cru;
+
+ if (hz != 2500000 && hz != 25000000) {
+ debug("Unsupported mac speed:%d\n", hz);
+ return -EINVAL;
+ }
+
+ rk_clrsetreg(&cru->clksel_con[23], RMII_CLK_SEL_MASK,
+ ((hz == 2500000) ? 0 : 1) << RMII_CLK_SEL_SHIFT);
+
+ return 0;
+}
+
+#endif
+
+static ulong px30_clk_get_pll_rate(struct px30_clk_priv *priv,
+ enum px30_pll_id pll_id)
+{
+ struct px30_cru *cru = priv->cru;
+
+ return rkclk_pll_get_rate(&cru->pll[pll_id], &cru->mode, pll_id);
+}
+
+static ulong px30_clk_set_pll_rate(struct px30_clk_priv *priv,
+ enum px30_pll_id pll_id, ulong hz)
+{
+ struct px30_cru *cru = priv->cru;
+
+ if (rkclk_set_pll(&cru->pll[pll_id], &cru->mode, pll_id, hz))
+ return -EINVAL;
+ return rkclk_pll_get_rate(&cru->pll[pll_id], &cru->mode, pll_id);
+}
+
+static ulong px30_armclk_set_clk(struct px30_clk_priv *priv, ulong hz)
+{
+ struct px30_cru *cru = priv->cru;
+ const struct cpu_rate_table *rate;
+ ulong old_rate;
+
+ rate = get_cpu_settings(hz);
+ if (!rate) {
+ printf("%s unsupport rate\n", __func__);
+ return -EINVAL;
+ }
+
+ /*
+ * select apll as cpu/core clock pll source and
+ * set up dependent divisors for PERI and ACLK clocks.
+ * core hz : apll = 1:1
+ */
+ old_rate = px30_clk_get_pll_rate(priv, APLL);
+ if (old_rate > hz) {
+ if (rkclk_set_pll(&cru->pll[APLL], &cru->mode, APLL, hz))
+ return -EINVAL;
+ rk_clrsetreg(&cru->clksel_con[0],
+ CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK |
+ CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
+ rate->aclk_div << CORE_ACLK_DIV_SHIFT |
+ rate->pclk_div << CORE_DBG_DIV_SHIFT |
+ CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
+ 0 << CORE_DIV_CON_SHIFT);
+ } else if (old_rate < hz) {
+ rk_clrsetreg(&cru->clksel_con[0],
+ CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK |
+ CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
+ rate->aclk_div << CORE_ACLK_DIV_SHIFT |
+ rate->pclk_div << CORE_DBG_DIV_SHIFT |
+ CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
+ 0 << CORE_DIV_CON_SHIFT);
+ if (rkclk_set_pll(&cru->pll[APLL], &cru->mode, APLL, hz))
+ return -EINVAL;
+ }
+
+ return px30_clk_get_pll_rate(priv, APLL);
+}
+
+static ulong px30_clk_get_rate(struct clk *clk)
+{
+ struct px30_clk_priv *priv = dev_get_priv(clk->dev);
+ ulong rate = 0;
+
+ if (!priv->gpll_hz && clk->id > ARMCLK) {
+ printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
+ return -ENOENT;
+ }
+
+ debug("%s %ld\n", __func__, clk->id);
+ switch (clk->id) {
+ case PLL_APLL:
+ rate = px30_clk_get_pll_rate(priv, APLL);
+ break;
+ case PLL_DPLL:
+ rate = px30_clk_get_pll_rate(priv, DPLL);
+ break;
+ case PLL_CPLL:
+ rate = px30_clk_get_pll_rate(priv, CPLL);
+ break;
+ case PLL_NPLL:
+ rate = px30_clk_get_pll_rate(priv, NPLL);
+ break;
+ case ARMCLK:
+ rate = px30_clk_get_pll_rate(priv, APLL);
+ break;
+ case HCLK_SDMMC:
+ case HCLK_EMMC:
+ case SCLK_SDMMC:
+ case SCLK_EMMC:
+ case SCLK_EMMC_SAMPLE:
+ rate = px30_mmc_get_clk(priv, clk->id);
+ break;
+ case SCLK_I2C0:
+ case SCLK_I2C1:
+ case SCLK_I2C2:
+ case SCLK_I2C3:
+ rate = px30_i2c_get_clk(priv, clk->id);
+ break;
+ case SCLK_I2S1:
+ rate = px30_i2s_get_clk(priv, clk->id);
+ break;
+ case SCLK_NANDC:
+ rate = px30_nandc_get_clk(priv);
+ break;
+ case SCLK_PWM0:
+ case SCLK_PWM1:
+ rate = px30_pwm_get_clk(priv, clk->id);
+ break;
+ case SCLK_SARADC:
+ rate = px30_saradc_get_clk(priv);
+ break;
+ case SCLK_TSADC:
+ rate = px30_tsadc_get_clk(priv);
+ break;
+ case SCLK_SPI0:
+ case SCLK_SPI1:
+ rate = px30_spi_get_clk(priv, clk->id);
+ break;
+ case ACLK_VOPB:
+ case ACLK_VOPL:
+ case DCLK_VOPB:
+ case DCLK_VOPL:
+ rate = px30_vop_get_clk(priv, clk->id);
+ break;
+ case ACLK_BUS_PRE:
+ case HCLK_BUS_PRE:
+ case PCLK_BUS_PRE:
+ case PCLK_WDT_NS:
+ rate = px30_bus_get_clk(priv, clk->id);
+ break;
+ case ACLK_PERI_PRE:
+ case HCLK_PERI_PRE:
+ rate = px30_peri_get_clk(priv, clk->id);
+ break;
+#ifndef CONFIG_SPL_BUILD
+ case SCLK_CRYPTO:
+ case SCLK_CRYPTO_APK:
+ rate = px30_crypto_get_clk(priv, clk->id);
+ break;
+#endif
+ default:
+ return -ENOENT;
+ }
+
+ return rate;
+}
+
+static ulong px30_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct px30_clk_priv *priv = dev_get_priv(clk->dev);
+ ulong ret = 0;
+
+ if (!priv->gpll_hz && clk->id > ARMCLK) {
+ printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
+ return -ENOENT;
+ }
+
+ debug("%s %ld %ld\n", __func__, clk->id, rate);
+ switch (clk->id) {
+ case PLL_NPLL:
+ ret = px30_clk_set_pll_rate(priv, NPLL, rate);
+ break;
+ case ARMCLK:
+ ret = px30_armclk_set_clk(priv, rate);
+ break;
+ case HCLK_SDMMC:
+ case HCLK_EMMC:
+ case SCLK_SDMMC:
+ case SCLK_EMMC:
+ ret = px30_mmc_set_clk(priv, clk->id, rate);
+ break;
+ case SCLK_I2C0:
+ case SCLK_I2C1:
+ case SCLK_I2C2:
+ case SCLK_I2C3:
+ ret = px30_i2c_set_clk(priv, clk->id, rate);
+ break;
+ case SCLK_I2S1:
+ ret = px30_i2s_set_clk(priv, clk->id, rate);
+ break;
+ case SCLK_NANDC:
+ ret = px30_nandc_set_clk(priv, rate);
+ break;
+ case SCLK_PWM0:
+ case SCLK_PWM1:
+ ret = px30_pwm_set_clk(priv, clk->id, rate);
+ break;
+ case SCLK_SARADC:
+ ret = px30_saradc_set_clk(priv, rate);
+ break;
+ case SCLK_TSADC:
+ ret = px30_tsadc_set_clk(priv, rate);
+ break;
+ case SCLK_SPI0:
+ case SCLK_SPI1:
+ ret = px30_spi_set_clk(priv, clk->id, rate);
+ break;
+ case ACLK_VOPB:
+ case ACLK_VOPL:
+ case DCLK_VOPB:
+ case DCLK_VOPL:
+ ret = px30_vop_set_clk(priv, clk->id, rate);
+ break;
+ case ACLK_BUS_PRE:
+ case HCLK_BUS_PRE:
+ case PCLK_BUS_PRE:
+ ret = px30_bus_set_clk(priv, clk->id, rate);
+ break;
+ case ACLK_PERI_PRE:
+ case HCLK_PERI_PRE:
+ ret = px30_peri_set_clk(priv, clk->id, rate);
+ break;
+#ifndef CONFIG_SPL_BUILD
+ case SCLK_CRYPTO:
+ case SCLK_CRYPTO_APK:
+ ret = px30_crypto_set_clk(priv, clk->id, rate);
+ break;
+ case SCLK_I2S1_OUT:
+ ret = px30_i2s1_mclk_set_clk(priv, clk->id, rate);
+ break;
+ case SCLK_GMAC:
+ case SCLK_GMAC_SRC:
+ ret = px30_mac_set_clk(priv, rate);
+ break;
+ case SCLK_GMAC_RMII:
+ ret = px30_mac_set_speed_clk(priv, rate);
+ break;
+#endif
+ default:
+ return -ENOENT;
+ }
+
+ return ret;
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+static int px30_gmac_set_parent(struct clk *clk, struct clk *parent)
+{
+ struct px30_clk_priv *priv = dev_get_priv(clk->dev);
+ struct px30_cru *cru = priv->cru;
+
+ if (parent->id == SCLK_GMAC_SRC) {
+ debug("%s: switching GAMC to SCLK_GMAC_SRC\n", __func__);
+ rk_clrsetreg(&cru->clksel_con[23], RMII_EXTCLK_SEL_MASK,
+ RMII_EXTCLK_SEL_INT << RMII_EXTCLK_SEL_SHIFT);
+ } else {
+ debug("%s: switching GMAC to external clock\n", __func__);
+ rk_clrsetreg(&cru->clksel_con[23], RMII_EXTCLK_SEL_MASK,
+ RMII_EXTCLK_SEL_EXT << RMII_EXTCLK_SEL_SHIFT);
+ }
+ return 0;
+}
+
+static int px30_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ switch (clk->id) {
+ case SCLK_GMAC:
+ return px30_gmac_set_parent(clk, parent);
+ default:
+ return -ENOENT;
+ }
+}
+#endif
+
+static int px30_clk_enable(struct clk *clk)
+{
+ switch (clk->id) {
+ case HCLK_HOST:
+ case SCLK_GMAC:
+ case SCLK_GMAC_RX_TX:
+ case SCLK_MAC_REF:
+ case SCLK_MAC_REFOUT:
+ case ACLK_GMAC:
+ case PCLK_GMAC:
+ case SCLK_GMAC_RMII:
+ /* Required to successfully probe the Designware GMAC driver */
+ return 0;
+ }
+
+ debug("%s: unsupported clk %ld\n", __func__, clk->id);
+ return -ENOENT;
+}
+
+static struct clk_ops px30_clk_ops = {
+ .get_rate = px30_clk_get_rate,
+ .set_rate = px30_clk_set_rate,
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+ .set_parent = px30_clk_set_parent,
+#endif
+ .enable = px30_clk_enable,
+};
+
+static void px30_clk_init(struct px30_clk_priv *priv)
+{
+ ulong npll_hz;
+ int ret;
+
+ npll_hz = px30_clk_get_pll_rate(priv, NPLL);
+ if (npll_hz != NPLL_HZ) {
+ ret = px30_clk_set_pll_rate(priv, NPLL, NPLL_HZ);
+ if (ret < 0)
+ printf("%s failed to set npll rate\n", __func__);
+ }
+
+ px30_bus_set_clk(priv, ACLK_BUS_PRE, ACLK_BUS_HZ);
+ px30_bus_set_clk(priv, HCLK_BUS_PRE, HCLK_BUS_HZ);
+ px30_bus_set_clk(priv, PCLK_BUS_PRE, PCLK_BUS_HZ);
+ px30_peri_set_clk(priv, ACLK_PERI_PRE, ACLK_PERI_HZ);
+ px30_peri_set_clk(priv, HCLK_PERI_PRE, HCLK_PERI_HZ);
+}
+
+static int px30_clk_probe(struct udevice *dev)
+{
+ struct px30_clk_priv *priv = dev_get_priv(dev);
+ struct clk clk_gpll;
+ int ret;
+
+ if (px30_clk_get_pll_rate(priv, APLL) != APLL_HZ)
+ px30_armclk_set_clk(priv, APLL_HZ);
+
+ /* get the GPLL rate from the pmucru */
+ ret = clk_get_by_name(dev, "gpll", &clk_gpll);
+ if (ret) {
+ printf("%s: failed to get gpll clk from pmucru\n", __func__);
+ return ret;
+ }
+
+ priv->gpll_hz = clk_get_rate(&clk_gpll);
+
+ px30_clk_init(priv);
+
+ return 0;
+}
+
+static int px30_clk_ofdata_to_platdata(struct udevice *dev)
+{
+ struct px30_clk_priv *priv = dev_get_priv(dev);
+
+ priv->cru = dev_read_addr_ptr(dev);
+
+ return 0;
+}
+
+static int px30_clk_bind(struct udevice *dev)
+{
+ int ret;
+ struct udevice *sys_child;
+ struct sysreset_reg *priv;
+
+ /* The reset driver does not have a device node, so bind it here */
+ ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
+ &sys_child);
+ if (ret) {
+ debug("Warning: No sysreset driver: ret=%d\n", ret);
+ } else {
+ priv = malloc(sizeof(struct sysreset_reg));
+ priv->glb_srst_fst_value = offsetof(struct px30_cru,
+ glb_srst_fst);
+ priv->glb_srst_snd_value = offsetof(struct px30_cru,
+ glb_srst_snd);
+ sys_child->priv = priv;
+ }
+
+#if CONFIG_IS_ENABLED(RESET_ROCKCHIP)
+ ret = offsetof(struct px30_cru, softrst_con[0]);
+ ret = rockchip_reset_bind(dev, ret, 12);
+ if (ret)
+ debug("Warning: software reset driver bind faile\n");
+#endif
+
+ return 0;
+}
+
+static const struct udevice_id px30_clk_ids[] = {
+ { .compatible = "rockchip,px30-cru" },
+ { }
+};
+
+U_BOOT_DRIVER(rockchip_px30_cru) = {
+ .name = "rockchip_px30_cru",
+ .id = UCLASS_CLK,
+ .of_match = px30_clk_ids,
+ .priv_auto_alloc_size = sizeof(struct px30_clk_priv),
+ .ofdata_to_platdata = px30_clk_ofdata_to_platdata,
+ .ops = &px30_clk_ops,
+ .bind = px30_clk_bind,
+ .probe = px30_clk_probe,
+};
+
+static ulong px30_pclk_pmu_get_pmuclk(struct px30_pmuclk_priv *priv)
+{
+ struct px30_pmucru *pmucru = priv->pmucru;
+ u32 div, con;
+
+ con = readl(&pmucru->pmu_clksel_con[0]);
+ div = (con & CLK_PMU_PCLK_DIV_MASK) >> CLK_PMU_PCLK_DIV_SHIFT;
+
+ return DIV_TO_RATE(priv->gpll_hz, div);
+}
+
+static ulong px30_pclk_pmu_set_pmuclk(struct px30_pmuclk_priv *priv, ulong hz)
+{
+ struct px30_pmucru *pmucru = priv->pmucru;
+ int src_clk_div;
+
+ src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
+ assert(src_clk_div - 1 <= 31);
+
+ rk_clrsetreg(&pmucru->pmu_clksel_con[0],
+ CLK_PMU_PCLK_DIV_MASK,
+ (src_clk_div - 1) << CLK_PMU_PCLK_DIV_SHIFT);
+
+ return px30_pclk_pmu_get_pmuclk(priv);
+}
+
+static ulong px30_pmuclk_get_gpll_rate(struct px30_pmuclk_priv *priv)
+{
+ struct px30_pmucru *pmucru = priv->pmucru;
+
+ return rkclk_pll_get_rate(&pmucru->pll, &pmucru->pmu_mode, GPLL);
+}
+
+static ulong px30_pmuclk_set_gpll_rate(struct px30_pmuclk_priv *priv, ulong hz)
+{
+ struct px30_pmucru *pmucru = priv->pmucru;
+ ulong pclk_pmu_rate;
+ u32 div;
+
+ if (priv->gpll_hz == hz)
+ return priv->gpll_hz;
+
+ div = DIV_ROUND_UP(hz, priv->gpll_hz);
+
+ /* save clock rate */
+ pclk_pmu_rate = px30_pclk_pmu_get_pmuclk(priv);
+
+ /* avoid rate too large, reduce rate first */
+ px30_pclk_pmu_set_pmuclk(priv, pclk_pmu_rate / div);
+
+ /* change gpll rate */
+ rkclk_set_pll(&pmucru->pll, &pmucru->pmu_mode, GPLL, hz);
+ priv->gpll_hz = px30_pmuclk_get_gpll_rate(priv);
+
+ /* restore clock rate */
+ px30_pclk_pmu_set_pmuclk(priv, pclk_pmu_rate);
+
+ return priv->gpll_hz;
+}
+
+static ulong px30_pmuclk_get_rate(struct clk *clk)
+{
+ struct px30_pmuclk_priv *priv = dev_get_priv(clk->dev);
+ ulong rate = 0;
+
+ debug("%s %ld\n", __func__, clk->id);
+ switch (clk->id) {
+ case PLL_GPLL:
+ rate = px30_pmuclk_get_gpll_rate(priv);
+ break;
+ case PCLK_PMU_PRE:
+ rate = px30_pclk_pmu_get_pmuclk(priv);
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return rate;
+}
+
+static ulong px30_pmuclk_set_rate(struct clk *clk, ulong rate)
+{
+ struct px30_pmuclk_priv *priv = dev_get_priv(clk->dev);
+ ulong ret = 0;
+
+ debug("%s %ld %ld\n", __func__, clk->id, rate);
+ switch (clk->id) {
+ case PLL_GPLL:
+ ret = px30_pmuclk_set_gpll_rate(priv, rate);
+ break;
+ case PCLK_PMU_PRE:
+ ret = px30_pclk_pmu_set_pmuclk(priv, rate);
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return ret;
+}
+
+static struct clk_ops px30_pmuclk_ops = {
+ .get_rate = px30_pmuclk_get_rate,
+ .set_rate = px30_pmuclk_set_rate,
+};
+
+static void px30_pmuclk_init(struct px30_pmuclk_priv *priv)
+{
+ priv->gpll_hz = px30_pmuclk_get_gpll_rate(priv);
+ px30_pmuclk_set_gpll_rate(priv, GPLL_HZ);
+
+ px30_pclk_pmu_set_pmuclk(priv, PCLK_PMU_HZ);
+}
+
+static int px30_pmuclk_probe(struct udevice *dev)
+{
+ struct px30_pmuclk_priv *priv = dev_get_priv(dev);
+
+ px30_pmuclk_init(priv);
+
+ return 0;
+}
+
+static int px30_pmuclk_ofdata_to_platdata(struct udevice *dev)
+{
+ struct px30_pmuclk_priv *priv = dev_get_priv(dev);
+
+ priv->pmucru = dev_read_addr_ptr(dev);
+
+ return 0;
+}
+
+static const struct udevice_id px30_pmuclk_ids[] = {
+ { .compatible = "rockchip,px30-pmucru" },
+ { }
+};
+
+U_BOOT_DRIVER(rockchip_px30_pmucru) = {
+ .name = "rockchip_px30_pmucru",
+ .id = UCLASS_CLK,
+ .of_match = px30_pmuclk_ids,
+ .priv_auto_alloc_size = sizeof(struct px30_pmuclk_priv),
+ .ofdata_to_platdata = px30_pmuclk_ofdata_to_platdata,
+ .ops = &px30_pmuclk_ops,
+ .probe = px30_pmuclk_probe,
+};
diff --git a/drivers/clk/rockchip/clk_rk3036.c b/drivers/clk/rockchip/clk_rk3036.c
index 9bf9cedaf8..6d5ae3d003 100644
--- a/drivers/clk/rockchip/clk_rk3036.c
+++ b/drivers/clk/rockchip/clk_rk3036.c
@@ -352,7 +352,7 @@ static int rk3036_clk_bind(struct udevice *dev)
sys_child->priv = priv;
}
-#if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP)
+#if CONFIG_IS_ENABLED(RESET_ROCKCHIP)
ret = offsetof(struct rk3036_cru, cru_softrst_con[0]);
ret = rockchip_reset_bind(dev, ret, 9);
if (ret)
diff --git a/drivers/clk/rockchip/clk_rk3188.c b/drivers/clk/rockchip/clk_rk3188.c
index dda686cfb3..3ea9a81b32 100644
--- a/drivers/clk/rockchip/clk_rk3188.c
+++ b/drivers/clk/rockchip/clk_rk3188.c
@@ -590,7 +590,7 @@ static int rk3188_clk_bind(struct udevice *dev)
sys_child->priv = priv;
}
-#if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP)
+#if CONFIG_IS_ENABLED(RESET_ROCKCHIP)
ret = offsetof(struct rk3188_cru, cru_softrst_con[0]);
ret = rockchip_reset_bind(dev, ret, 9);
if (ret)
diff --git a/drivers/clk/rockchip/clk_rk322x.c b/drivers/clk/rockchip/clk_rk322x.c
index f09730c91b..6e8a164d62 100644
--- a/drivers/clk/rockchip/clk_rk322x.c
+++ b/drivers/clk/rockchip/clk_rk322x.c
@@ -508,7 +508,7 @@ static int rk322x_clk_bind(struct udevice *dev)
sys_child->priv = priv;
}
-#if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP)
+#if CONFIG_IS_ENABLED(RESET_ROCKCHIP)
ret = offsetof(struct rk322x_cru, cru_softrst_con[0]);
ret = rockchip_reset_bind(dev, ret, 9);
if (ret)
diff --git a/drivers/clk/rockchip/clk_rk3288.c b/drivers/clk/rockchip/clk_rk3288.c
index 0122381633..85d1b67e43 100644
--- a/drivers/clk/rockchip/clk_rk3288.c
+++ b/drivers/clk/rockchip/clk_rk3288.c
@@ -1015,7 +1015,7 @@ static int rk3288_clk_bind(struct udevice *dev)
sys_child->priv = priv;
}
-#if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP)
+#if CONFIG_IS_ENABLED(RESET_ROCKCHIP)
ret = offsetof(struct rk3288_cru, cru_softrst_con[0]);
ret = rockchip_reset_bind(dev, ret, 12);
if (ret)
diff --git a/drivers/clk/rockchip/clk_rk3308.c b/drivers/clk/rockchip/clk_rk3308.c
new file mode 100644
index 0000000000..f212c5ffc2
--- /dev/null
+++ b/drivers/clk/rockchip/clk_rk3308.c
@@ -0,0 +1,1072 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2017-2019 Rockchip Electronics Co., Ltd
+ */
+#include <common.h>
+#include <bitfield.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <div64.h>
+#include <errno.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <asm/arch/cru_rk3308.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/hardware.h>
+#include <dm/lists.h>
+#include <dt-bindings/clock/rk3308-cru.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum {
+ VCO_MAX_HZ = 3200U * 1000000,
+ VCO_MIN_HZ = 800 * 1000000,
+ OUTPUT_MAX_HZ = 3200U * 1000000,
+ OUTPUT_MIN_HZ = 24 * 1000000,
+};
+
+#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
+
+#define RK3308_CPUCLK_RATE(_rate, _aclk_div, _pclk_div) \
+{ \
+ .rate = _rate##U, \
+ .aclk_div = _aclk_div, \
+ .pclk_div = _pclk_div, \
+}
+
+static struct rockchip_pll_rate_table rk3308_pll_rates[] = {
+ /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
+ RK3036_PLL_RATE(1300000000, 6, 325, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
+ RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
+ RK3036_PLL_RATE(748000000, 2, 187, 3, 1, 1, 0),
+};
+
+static struct rockchip_cpu_rate_table rk3308_cpu_rates[] = {
+ RK3308_CPUCLK_RATE(1200000000, 1, 5),
+ RK3308_CPUCLK_RATE(1008000000, 1, 5),
+ RK3308_CPUCLK_RATE(816000000, 1, 3),
+ RK3308_CPUCLK_RATE(600000000, 1, 3),
+ RK3308_CPUCLK_RATE(408000000, 1, 1),
+};
+
+static struct rockchip_pll_clock rk3308_pll_clks[] = {
+ [APLL] = PLL(pll_rk3328, PLL_APLL, RK3308_PLL_CON(0),
+ RK3308_MODE_CON, 0, 10, 0, rk3308_pll_rates),
+ [DPLL] = PLL(pll_rk3328, PLL_DPLL, RK3308_PLL_CON(8),
+ RK3308_MODE_CON, 2, 10, 0, NULL),
+ [VPLL0] = PLL(pll_rk3328, PLL_VPLL0, RK3308_PLL_CON(16),
+ RK3308_MODE_CON, 4, 10, 0, NULL),
+ [VPLL1] = PLL(pll_rk3328, PLL_VPLL1, RK3308_PLL_CON(24),
+ RK3308_MODE_CON, 6, 10, 0, NULL),
+};
+
+static ulong rk3308_armclk_set_clk(struct rk3308_clk_priv *priv, ulong hz)
+{
+ struct rk3308_cru *cru = priv->cru;
+ const struct rockchip_cpu_rate_table *rate;
+ ulong old_rate;
+
+ rate = rockchip_get_cpu_settings(rk3308_cpu_rates, hz);
+ if (!rate) {
+ printf("%s unsupport rate\n", __func__);
+ return -EINVAL;
+ }
+
+ /*
+ * select apll as cpu/core clock pll source and
+ * set up dependent divisors for PERI and ACLK clocks.
+ * core hz : apll = 1:1
+ */
+ old_rate = rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
+ priv->cru, APLL);
+ if (old_rate > hz) {
+ if (rockchip_pll_set_rate(&rk3308_pll_clks[APLL],
+ priv->cru, APLL, hz))
+ return -EINVAL;
+ rk_clrsetreg(&cru->clksel_con[0],
+ CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK |
+ CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
+ rate->aclk_div << CORE_ACLK_DIV_SHIFT |
+ rate->pclk_div << CORE_DBG_DIV_SHIFT |
+ CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
+ 0 << CORE_DIV_CON_SHIFT);
+ } else if (old_rate < hz) {
+ rk_clrsetreg(&cru->clksel_con[0],
+ CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK |
+ CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
+ rate->aclk_div << CORE_ACLK_DIV_SHIFT |
+ rate->pclk_div << CORE_DBG_DIV_SHIFT |
+ CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
+ 0 << CORE_DIV_CON_SHIFT);
+ if (rockchip_pll_set_rate(&rk3308_pll_clks[APLL],
+ priv->cru, APLL, hz))
+ return -EINVAL;
+ }
+
+ return rockchip_pll_get_rate(&rk3308_pll_clks[APLL], priv->cru, APLL);
+}
+
+static void rk3308_clk_get_pll_rate(struct rk3308_clk_priv *priv)
+{
+ if (!priv->dpll_hz)
+ priv->dpll_hz = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL],
+ priv->cru, DPLL);
+ if (!priv->vpll0_hz)
+ priv->vpll0_hz = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL0],
+ priv->cru, VPLL0);
+ if (!priv->vpll1_hz)
+ priv->vpll1_hz = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL1],
+ priv->cru, VPLL1);
+}
+
+static ulong rk3308_i2c_get_clk(struct clk *clk)
+{
+ struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
+ struct rk3308_cru *cru = priv->cru;
+ u32 div, con, con_id;
+
+ switch (clk->id) {
+ case SCLK_I2C0:
+ con_id = 25;
+ break;
+ case SCLK_I2C1:
+ con_id = 26;
+ break;
+ case SCLK_I2C2:
+ con_id = 27;
+ break;
+ case SCLK_I2C3:
+ con_id = 28;
+ break;
+ default:
+ printf("do not support this i2c bus\n");
+ return -EINVAL;
+ }
+
+ con = readl(&cru->clksel_con[con_id]);
+ div = con >> CLK_I2C_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
+
+ return DIV_TO_RATE(priv->dpll_hz, div);
+}
+
+static ulong rk3308_i2c_set_clk(struct clk *clk, uint hz)
+{
+ struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
+ struct rk3308_cru *cru = priv->cru;
+ u32 src_clk_div, con_id;
+
+ src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
+ assert(src_clk_div - 1 <= 127);
+
+ switch (clk->id) {
+ case SCLK_I2C0:
+ con_id = 25;
+ break;
+ case SCLK_I2C1:
+ con_id = 26;
+ break;
+ case SCLK_I2C2:
+ con_id = 27;
+ break;
+ case SCLK_I2C3:
+ con_id = 28;
+ break;
+ default:
+ printf("do not support this i2c bus\n");
+ return -EINVAL;
+ }
+ rk_clrsetreg(&cru->clksel_con[con_id],
+ CLK_I2C_PLL_SEL_MASK | CLK_I2C_DIV_CON_MASK,
+ CLK_I2C_PLL_SEL_DPLL << CLK_I2C_PLL_SEL_SHIFT |
+ (src_clk_div - 1) << CLK_I2C_DIV_CON_SHIFT);
+
+ return rk3308_i2c_get_clk(clk);
+}
+
+static ulong rk3308_mac_set_clk(struct clk *clk, uint hz)
+{
+ struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
+ struct rk3308_cru *cru = priv->cru;
+ u32 con = readl(&cru->clksel_con[43]);
+ ulong pll_rate;
+ u8 div;
+
+ if ((con >> MAC_PLL_SHIFT) & MAC_SEL_VPLL0)
+ pll_rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL0],
+ priv->cru, VPLL0);
+ else if ((con >> MAC_PLL_SHIFT) & MAC_SEL_VPLL1)
+ pll_rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL1],
+ priv->cru, VPLL1);
+ else
+ pll_rate = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL],
+ priv->cru, DPLL);
+
+ /*default set 50MHZ for gmac*/
+ if (!hz)
+ hz = 50000000;
+
+ div = DIV_ROUND_UP(pll_rate, hz) - 1;
+ assert(div < 32);
+ rk_clrsetreg(&cru->clksel_con[43], MAC_DIV_MASK,
+ div << MAC_DIV_SHIFT);
+
+ return DIV_TO_RATE(pll_rate, div);
+}
+
+static int rk3308_mac_set_speed_clk(struct clk *clk, uint hz)
+{
+ struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
+ struct rk3308_cru *cru = priv->cru;
+
+ if (hz != 2500000 && hz != 25000000) {
+ debug("Unsupported mac speed:%d\n", hz);
+ return -EINVAL;
+ }
+
+ rk_clrsetreg(&cru->clksel_con[43], MAC_CLK_SPEED_SEL_MASK,
+ ((hz == 2500000) ? 0 : 1) << MAC_CLK_SPEED_SEL_SHIFT);
+
+ return 0;
+}
+
+static ulong rk3308_mmc_get_clk(struct clk *clk)
+{
+ struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
+ struct rk3308_cru *cru = priv->cru;
+ u32 div, con, con_id;
+
+ switch (clk->id) {
+ case HCLK_SDMMC:
+ case SCLK_SDMMC:
+ con_id = 39;
+ break;
+ case HCLK_EMMC:
+ case SCLK_EMMC:
+ case SCLK_EMMC_SAMPLE:
+ con_id = 41;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ con = readl(&cru->clksel_con[con_id]);
+ div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT;
+
+ if ((con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT
+ == EMMC_SEL_24M)
+ return DIV_TO_RATE(OSC_HZ, div) / 2;
+ else
+ return DIV_TO_RATE(priv->vpll0_hz, div) / 2;
+}
+
+static ulong rk3308_mmc_set_clk(struct clk *clk, ulong set_rate)
+{
+ struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
+ struct rk3308_cru *cru = priv->cru;
+ int src_clk_div;
+ u32 con_id;
+
+ switch (clk->id) {
+ case HCLK_SDMMC:
+ case SCLK_SDMMC:
+ con_id = 39;
+ break;
+ case HCLK_EMMC:
+ case SCLK_EMMC:
+ con_id = 41;
+ break;
+ default:
+ return -EINVAL;
+ }
+ /* Select clk_sdmmc/emmc source from VPLL0 by default */
+ /* mmc clock defaulg div 2 internal, need provide double in cru */
+ src_clk_div = DIV_ROUND_UP(priv->vpll0_hz / 2, set_rate);
+
+ if (src_clk_div > 127) {
+ /* use 24MHz source for 400KHz clock */
+ src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, set_rate);
+ rk_clrsetreg(&cru->clksel_con[con_id],
+ EMMC_PLL_MASK | EMMC_DIV_MASK | EMMC_CLK_SEL_MASK,
+ EMMC_CLK_SEL_EMMC << EMMC_CLK_SEL_SHIFT |
+ EMMC_SEL_24M << EMMC_PLL_SHIFT |
+ (src_clk_div - 1) << EMMC_DIV_SHIFT);
+ } else {
+ rk_clrsetreg(&cru->clksel_con[con_id],
+ EMMC_PLL_MASK | EMMC_DIV_MASK | EMMC_CLK_SEL_MASK,
+ EMMC_CLK_SEL_EMMC << EMMC_CLK_SEL_SHIFT |
+ EMMC_SEL_VPLL0 << EMMC_PLL_SHIFT |
+ (src_clk_div - 1) << EMMC_DIV_SHIFT);
+ }
+
+ return rk3308_mmc_get_clk(clk);
+}
+
+static ulong rk3308_saradc_get_clk(struct clk *clk)
+{
+ struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
+ struct rk3308_cru *cru = priv->cru;
+ u32 div, con;
+
+ con = readl(&cru->clksel_con[34]);
+ div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK;
+
+ return DIV_TO_RATE(OSC_HZ, div);
+}
+
+static ulong rk3308_saradc_set_clk(struct clk *clk, uint hz)
+{
+ struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
+ struct rk3308_cru *cru = priv->cru;
+ int src_clk_div;
+
+ src_clk_div = DIV_ROUND_UP(OSC_HZ, hz);
+ assert(src_clk_div - 1 <= 2047);
+
+ rk_clrsetreg(&cru->clksel_con[34],
+ CLK_SARADC_DIV_CON_MASK,
+ (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT);
+
+ return rk3308_saradc_get_clk(clk);
+}
+
+static ulong rk3308_tsadc_get_clk(struct clk *clk)
+{
+ struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
+ struct rk3308_cru *cru = priv->cru;
+ u32 div, con;
+
+ con = readl(&cru->clksel_con[33]);
+ div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK;
+
+ return DIV_TO_RATE(OSC_HZ, div);
+}
+
+static ulong rk3308_tsadc_set_clk(struct clk *clk, uint hz)
+{
+ struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
+ struct rk3308_cru *cru = priv->cru;
+ int src_clk_div;
+
+ src_clk_div = DIV_ROUND_UP(OSC_HZ, hz);
+ assert(src_clk_div - 1 <= 2047);
+
+ rk_clrsetreg(&cru->clksel_con[33],
+ CLK_SARADC_DIV_CON_MASK,
+ (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT);
+
+ return rk3308_tsadc_get_clk(clk);
+}
+
+static ulong rk3308_spi_get_clk(struct clk *clk)
+{
+ struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
+ struct rk3308_cru *cru = priv->cru;
+ u32 div, con, con_id;
+
+ switch (clk->id) {
+ case SCLK_SPI0:
+ con_id = 30;
+ break;
+ case SCLK_SPI1:
+ con_id = 31;
+ break;
+ case SCLK_SPI2:
+ con_id = 32;
+ break;
+ default:
+ printf("do not support this spi bus\n");
+ return -EINVAL;
+ }
+
+ con = readl(&cru->clksel_con[con_id]);
+ div = con >> CLK_SPI_DIV_CON_SHIFT & CLK_SPI_DIV_CON_MASK;
+
+ return DIV_TO_RATE(priv->dpll_hz, div);
+}
+
+static ulong rk3308_spi_set_clk(struct clk *clk, uint hz)
+{
+ struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
+ struct rk3308_cru *cru = priv->cru;
+ u32 src_clk_div, con_id;
+
+ src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
+ assert(src_clk_div - 1 <= 127);
+
+ switch (clk->id) {
+ case SCLK_SPI0:
+ con_id = 30;
+ break;
+ case SCLK_SPI1:
+ con_id = 31;
+ break;
+ case SCLK_SPI2:
+ con_id = 32;
+ break;
+ default:
+ printf("do not support this spi bus\n");
+ return -EINVAL;
+ }
+
+ rk_clrsetreg(&cru->clksel_con[con_id],
+ CLK_SPI_PLL_SEL_MASK | CLK_SPI_DIV_CON_MASK,
+ CLK_SPI_PLL_SEL_DPLL << CLK_SPI_PLL_SEL_SHIFT |
+ (src_clk_div - 1) << CLK_SPI_DIV_CON_SHIFT);
+
+ return rk3308_spi_get_clk(clk);
+}
+
+static ulong rk3308_pwm_get_clk(struct clk *clk)
+{
+ struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
+ struct rk3308_cru *cru = priv->cru;
+ u32 div, con;
+
+ con = readl(&cru->clksel_con[29]);
+ div = con >> CLK_PWM_DIV_CON_SHIFT & CLK_PWM_DIV_CON_MASK;
+
+ return DIV_TO_RATE(priv->dpll_hz, div);
+}
+
+static ulong rk3308_pwm_set_clk(struct clk *clk, uint hz)
+{
+ struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
+ struct rk3308_cru *cru = priv->cru;
+ int src_clk_div;
+
+ src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
+ assert(src_clk_div - 1 <= 127);
+
+ rk_clrsetreg(&cru->clksel_con[29],
+ CLK_PWM_PLL_SEL_MASK | CLK_PWM_DIV_CON_MASK,
+ CLK_PWM_PLL_SEL_DPLL << CLK_PWM_PLL_SEL_SHIFT |
+ (src_clk_div - 1) << CLK_PWM_DIV_CON_SHIFT);
+
+ return rk3308_pwm_get_clk(clk);
+}
+
+static ulong rk3308_vop_get_clk(struct clk *clk)
+{
+ struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
+ struct rk3308_cru *cru = priv->cru;
+ u32 div, pll_sel, vol_sel, con, parent;
+
+ con = readl(&cru->clksel_con[8]);
+ vol_sel = (con & DCLK_VOP_SEL_MASK) >> DCLK_VOP_SEL_SHIFT;
+ pll_sel = (con & DCLK_VOP_PLL_SEL_MASK) >> DCLK_VOP_PLL_SEL_SHIFT;
+ div = con & DCLK_VOP_DIV_MASK;
+
+ if (vol_sel == DCLK_VOP_SEL_24M) {
+ parent = OSC_HZ;
+ } else if (vol_sel == DCLK_VOP_SEL_DIVOUT) {
+ switch (pll_sel) {
+ case DCLK_VOP_PLL_SEL_DPLL:
+ parent = priv->dpll_hz;
+ break;
+ case DCLK_VOP_PLL_SEL_VPLL0:
+ parent = priv->vpll0_hz;
+ break;
+ case DCLK_VOP_PLL_SEL_VPLL1:
+ parent = priv->vpll0_hz;
+ break;
+ default:
+ printf("do not support this vop pll sel\n");
+ return -EINVAL;
+ }
+ } else {
+ printf("do not support this vop sel\n");
+ return -EINVAL;
+ }
+
+ return DIV_TO_RATE(parent, div);
+}
+
+static ulong rk3308_vop_set_clk(struct clk *clk, ulong hz)
+{
+ struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
+ struct rk3308_cru *cru = priv->cru;
+ ulong pll_rate, now, best_rate = 0;
+ u32 i, div, best_div = 0, best_sel = 0;
+
+ for (i = 0; i <= DCLK_VOP_PLL_SEL_VPLL1; i++) {
+ switch (i) {
+ case DCLK_VOP_PLL_SEL_DPLL:
+ pll_rate = priv->dpll_hz;
+ break;
+ case DCLK_VOP_PLL_SEL_VPLL0:
+ pll_rate = priv->vpll0_hz;
+ break;
+ case DCLK_VOP_PLL_SEL_VPLL1:
+ pll_rate = priv->vpll1_hz;
+ break;
+ default:
+ printf("do not support this vop pll sel\n");
+ return -EINVAL;
+ }
+
+ div = DIV_ROUND_UP(pll_rate, hz);
+ if (div > 255)
+ continue;
+ now = pll_rate / div;
+ if (abs(hz - now) < abs(hz - best_rate)) {
+ best_rate = now;
+ best_div = div;
+ best_sel = i;
+ }
+ debug("pll_rate=%lu, best_rate=%lu, best_div=%u, best_sel=%u\n",
+ pll_rate, best_rate, best_div, best_sel);
+ }
+
+ if (best_rate != hz && hz == OSC_HZ) {
+ rk_clrsetreg(&cru->clksel_con[8],
+ DCLK_VOP_SEL_MASK,
+ DCLK_VOP_SEL_24M << DCLK_VOP_SEL_SHIFT);
+ } else if (best_rate) {
+ rk_clrsetreg(&cru->clksel_con[8],
+ DCLK_VOP_SEL_MASK | DCLK_VOP_PLL_SEL_MASK |
+ DCLK_VOP_DIV_MASK,
+ DCLK_VOP_SEL_DIVOUT << DCLK_VOP_SEL_SHIFT |
+ best_sel << DCLK_VOP_PLL_SEL_SHIFT |
+ (best_div - 1) << DCLK_VOP_DIV_SHIFT);
+ } else {
+ printf("do not support this vop freq\n");
+ return -EINVAL;
+ }
+
+ return rk3308_vop_get_clk(clk);
+}
+
+static ulong rk3308_bus_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
+{
+ struct rk3308_cru *cru = priv->cru;
+ u32 div, con, parent = priv->dpll_hz;
+
+ switch (clk_id) {
+ case ACLK_BUS:
+ con = readl(&cru->clksel_con[5]);
+ div = (con & BUS_ACLK_DIV_MASK) >> BUS_ACLK_DIV_SHIFT;
+ break;
+ case HCLK_BUS:
+ con = readl(&cru->clksel_con[6]);
+ div = (con & BUS_HCLK_DIV_MASK) >> BUS_HCLK_DIV_SHIFT;
+ break;
+ case PCLK_BUS:
+ case PCLK_WDT:
+ con = readl(&cru->clksel_con[6]);
+ div = (con & BUS_PCLK_DIV_MASK) >> BUS_PCLK_DIV_SHIFT;
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return DIV_TO_RATE(parent, div);
+}
+
+static ulong rk3308_bus_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
+ ulong hz)
+{
+ struct rk3308_cru *cru = priv->cru;
+ int src_clk_div;
+
+ src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
+ assert(src_clk_div - 1 <= 31);
+
+ /*
+ * select dpll as pd_bus bus clock source and
+ * set up dependent divisors for PCLK/HCLK and ACLK clocks.
+ */
+ switch (clk_id) {
+ case ACLK_BUS:
+ rk_clrsetreg(&cru->clksel_con[5],
+ BUS_PLL_SEL_MASK | BUS_ACLK_DIV_MASK,
+ BUS_PLL_SEL_DPLL << BUS_PLL_SEL_SHIFT |
+ (src_clk_div - 1) << BUS_ACLK_DIV_SHIFT);
+ break;
+ case HCLK_BUS:
+ rk_clrsetreg(&cru->clksel_con[6],
+ BUS_HCLK_DIV_MASK,
+ (src_clk_div - 1) << BUS_HCLK_DIV_SHIFT);
+ break;
+ case PCLK_BUS:
+ rk_clrsetreg(&cru->clksel_con[6],
+ BUS_PCLK_DIV_MASK,
+ (src_clk_div - 1) << BUS_PCLK_DIV_SHIFT);
+ break;
+ default:
+ printf("do not support this bus freq\n");
+ return -EINVAL;
+ }
+
+ return rk3308_bus_get_clk(priv, clk_id);
+}
+
+static ulong rk3308_peri_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
+{
+ struct rk3308_cru *cru = priv->cru;
+ u32 div, con, parent = priv->dpll_hz;
+
+ switch (clk_id) {
+ case ACLK_PERI:
+ con = readl(&cru->clksel_con[36]);
+ div = (con & PERI_ACLK_DIV_MASK) >> PERI_ACLK_DIV_SHIFT;
+ break;
+ case HCLK_PERI:
+ con = readl(&cru->clksel_con[37]);
+ div = (con & PERI_HCLK_DIV_MASK) >> PERI_HCLK_DIV_SHIFT;
+ break;
+ case PCLK_PERI:
+ con = readl(&cru->clksel_con[37]);
+ div = (con & PERI_PCLK_DIV_MASK) >> PERI_PCLK_DIV_SHIFT;
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return DIV_TO_RATE(parent, div);
+}
+
+static ulong rk3308_peri_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
+ ulong hz)
+{
+ struct rk3308_cru *cru = priv->cru;
+ int src_clk_div;
+
+ src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
+ assert(src_clk_div - 1 <= 31);
+
+ /*
+ * select dpll as pd_peri bus clock source and
+ * set up dependent divisors for PCLK/HCLK and ACLK clocks.
+ */
+ switch (clk_id) {
+ case ACLK_PERI:
+ rk_clrsetreg(&cru->clksel_con[36],
+ PERI_PLL_SEL_MASK | PERI_ACLK_DIV_MASK,
+ PERI_PLL_DPLL << PERI_PLL_SEL_SHIFT |
+ (src_clk_div - 1) << PERI_ACLK_DIV_SHIFT);
+ break;
+ case HCLK_PERI:
+ rk_clrsetreg(&cru->clksel_con[37],
+ PERI_HCLK_DIV_MASK,
+ (src_clk_div - 1) << PERI_HCLK_DIV_SHIFT);
+ break;
+ case PCLK_PERI:
+ rk_clrsetreg(&cru->clksel_con[37],
+ PERI_PCLK_DIV_MASK,
+ (src_clk_div - 1) << PERI_PCLK_DIV_SHIFT);
+ break;
+ default:
+ printf("do not support this peri freq\n");
+ return -EINVAL;
+ }
+
+ return rk3308_peri_get_clk(priv, clk_id);
+}
+
+static ulong rk3308_audio_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
+{
+ struct rk3308_cru *cru = priv->cru;
+ u32 div, con, parent = priv->vpll0_hz;
+
+ switch (clk_id) {
+ case HCLK_AUDIO:
+ con = readl(&cru->clksel_con[45]);
+ div = (con & AUDIO_HCLK_DIV_MASK) >> AUDIO_HCLK_DIV_SHIFT;
+ break;
+ case PCLK_AUDIO:
+ con = readl(&cru->clksel_con[45]);
+ div = (con & AUDIO_PCLK_DIV_MASK) >> AUDIO_PCLK_DIV_SHIFT;
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return DIV_TO_RATE(parent, div);
+}
+
+static ulong rk3308_audio_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
+ ulong hz)
+{
+ struct rk3308_cru *cru = priv->cru;
+ int src_clk_div;
+
+ src_clk_div = DIV_ROUND_UP(priv->vpll0_hz, hz);
+ assert(src_clk_div - 1 <= 31);
+
+ /*
+ * select vpll0 as audio bus clock source and
+ * set up dependent divisors for HCLK and PCLK clocks.
+ */
+ switch (clk_id) {
+ case HCLK_AUDIO:
+ rk_clrsetreg(&cru->clksel_con[45],
+ AUDIO_PLL_SEL_MASK | AUDIO_HCLK_DIV_MASK,
+ AUDIO_PLL_VPLL0 << AUDIO_PLL_SEL_SHIFT |
+ (src_clk_div - 1) << AUDIO_HCLK_DIV_SHIFT);
+ break;
+ case PCLK_AUDIO:
+ rk_clrsetreg(&cru->clksel_con[45],
+ AUDIO_PLL_SEL_MASK | AUDIO_PCLK_DIV_MASK,
+ AUDIO_PLL_VPLL0 << AUDIO_PLL_SEL_SHIFT |
+ (src_clk_div - 1) << AUDIO_PCLK_DIV_SHIFT);
+ break;
+ default:
+ printf("do not support this audio freq\n");
+ return -EINVAL;
+ }
+
+ return rk3308_peri_get_clk(priv, clk_id);
+}
+
+static ulong rk3308_crypto_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
+{
+ struct rk3308_cru *cru = priv->cru;
+ u32 div, con, parent;
+
+ switch (clk_id) {
+ case SCLK_CRYPTO:
+ con = readl(&cru->clksel_con[7]);
+ div = (con & CRYPTO_DIV_MASK) >> CRYPTO_DIV_SHIFT;
+ parent = priv->vpll0_hz;
+ break;
+ case SCLK_CRYPTO_APK:
+ con = readl(&cru->clksel_con[7]);
+ div = (con & CRYPTO_APK_DIV_MASK) >> CRYPTO_APK_DIV_SHIFT;
+ parent = priv->vpll0_hz;
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return DIV_TO_RATE(parent, div);
+}
+
+static ulong rk3308_crypto_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
+ ulong hz)
+{
+ struct rk3308_cru *cru = priv->cru;
+ int src_clk_div;
+
+ src_clk_div = DIV_ROUND_UP(priv->vpll0_hz, hz);
+ assert(src_clk_div - 1 <= 31);
+
+ /*
+ * select gpll as crypto clock source and
+ * set up dependent divisors for crypto clocks.
+ */
+ switch (clk_id) {
+ case SCLK_CRYPTO:
+ rk_clrsetreg(&cru->clksel_con[7],
+ CRYPTO_PLL_SEL_MASK | CRYPTO_DIV_MASK,
+ CRYPTO_PLL_SEL_VPLL0 << CRYPTO_PLL_SEL_SHIFT |
+ (src_clk_div - 1) << CRYPTO_DIV_SHIFT);
+ break;
+ case SCLK_CRYPTO_APK:
+ rk_clrsetreg(&cru->clksel_con[7],
+ CRYPTO_APK_PLL_SEL_MASK | CRYPTO_APK_DIV_MASK,
+ CRYPTO_PLL_SEL_VPLL0 << CRYPTO_APK_SEL_SHIFT |
+ (src_clk_div - 1) << CRYPTO_APK_DIV_SHIFT);
+ break;
+ default:
+ printf("do not support this peri freq\n");
+ return -EINVAL;
+ }
+
+ return rk3308_crypto_get_clk(priv, clk_id);
+}
+
+static ulong rk3308_clk_get_rate(struct clk *clk)
+{
+ struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
+ ulong rate = 0;
+
+ debug("%s id:%ld\n", __func__, clk->id);
+
+ switch (clk->id) {
+ case PLL_APLL:
+ case ARMCLK:
+ rate = rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
+ priv->cru, APLL);
+ break;
+ case PLL_DPLL:
+ rate = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL],
+ priv->cru, DPLL);
+ break;
+ case PLL_VPLL0:
+ rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL0],
+ priv->cru, VPLL0);
+ break;
+ case PLL_VPLL1:
+ rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL1],
+ priv->cru, VPLL1);
+ break;
+ case HCLK_SDMMC:
+ case HCLK_EMMC:
+ case SCLK_SDMMC:
+ case SCLK_EMMC:
+ case SCLK_EMMC_SAMPLE:
+ rate = rk3308_mmc_get_clk(clk);
+ break;
+ case SCLK_I2C0:
+ case SCLK_I2C1:
+ case SCLK_I2C2:
+ case SCLK_I2C3:
+ rate = rk3308_i2c_get_clk(clk);
+ break;
+ case SCLK_SARADC:
+ rate = rk3308_saradc_get_clk(clk);
+ break;
+ case SCLK_TSADC:
+ rate = rk3308_tsadc_get_clk(clk);
+ break;
+ case SCLK_SPI0:
+ case SCLK_SPI1:
+ rate = rk3308_spi_get_clk(clk);
+ break;
+ case SCLK_PWM0:
+ rate = rk3308_pwm_get_clk(clk);
+ break;
+ case DCLK_VOP:
+ rate = rk3308_vop_get_clk(clk);
+ break;
+ case ACLK_BUS:
+ case HCLK_BUS:
+ case PCLK_BUS:
+ case PCLK_WDT:
+ rate = rk3308_bus_get_clk(priv, clk->id);
+ break;
+ case ACLK_PERI:
+ case HCLK_PERI:
+ case PCLK_PERI:
+ rate = rk3308_peri_get_clk(priv, clk->id);
+ break;
+ case HCLK_AUDIO:
+ case PCLK_AUDIO:
+ rate = rk3308_audio_get_clk(priv, clk->id);
+ break;
+ case SCLK_CRYPTO:
+ case SCLK_CRYPTO_APK:
+ rate = rk3308_crypto_get_clk(priv, clk->id);
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return rate;
+}
+
+static ulong rk3308_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
+ ulong ret = 0;
+
+ debug("%s %ld %ld\n", __func__, clk->id, rate);
+
+ switch (clk->id) {
+ case PLL_DPLL:
+ ret = rockchip_pll_set_rate(&rk3308_pll_clks[DPLL], priv->cru,
+ DPLL, rate);
+ priv->dpll_hz = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL],
+ priv->cru, DPLL);
+ break;
+ case ARMCLK:
+ if (priv->armclk_hz)
+ rk3308_armclk_set_clk(priv, rate);
+ priv->armclk_hz = rate;
+ break;
+ case HCLK_SDMMC:
+ case HCLK_EMMC:
+ case SCLK_SDMMC:
+ case SCLK_EMMC:
+ ret = rk3308_mmc_set_clk(clk, rate);
+ break;
+ case SCLK_I2C0:
+ case SCLK_I2C1:
+ case SCLK_I2C2:
+ case SCLK_I2C3:
+ ret = rk3308_i2c_set_clk(clk, rate);
+ break;
+ case SCLK_MAC:
+ ret = rk3308_mac_set_clk(clk, rate);
+ break;
+ case SCLK_MAC_RMII:
+ ret = rk3308_mac_set_speed_clk(clk, rate);
+ break;
+ case SCLK_SARADC:
+ ret = rk3308_saradc_set_clk(clk, rate);
+ break;
+ case SCLK_TSADC:
+ ret = rk3308_tsadc_set_clk(clk, rate);
+ break;
+ case SCLK_SPI0:
+ case SCLK_SPI1:
+ ret = rk3308_spi_set_clk(clk, rate);
+ break;
+ case SCLK_PWM0:
+ ret = rk3308_pwm_set_clk(clk, rate);
+ break;
+ case DCLK_VOP:
+ ret = rk3308_vop_set_clk(clk, rate);
+ break;
+ case ACLK_BUS:
+ case HCLK_BUS:
+ case PCLK_BUS:
+ rate = rk3308_bus_set_clk(priv, clk->id, rate);
+ break;
+ case ACLK_PERI:
+ case HCLK_PERI:
+ case PCLK_PERI:
+ rate = rk3308_peri_set_clk(priv, clk->id, rate);
+ break;
+ case HCLK_AUDIO:
+ case PCLK_AUDIO:
+ rate = rk3308_audio_set_clk(priv, clk->id, rate);
+ break;
+ case SCLK_CRYPTO:
+ case SCLK_CRYPTO_APK:
+ ret = rk3308_crypto_set_clk(priv, clk->id, rate);
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return ret;
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+static int __maybe_unused rk3308_mac_set_parent(struct clk *clk, struct clk *parent)
+{
+ struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
+
+ /*
+ * If the requested parent is in the same clock-controller and
+ * the id is SCLK_MAC_SRC, switch to the internal clock.
+ */
+ if (parent->id == SCLK_MAC_SRC) {
+ debug("%s: switching RMII to SCLK_MAC\n", __func__);
+ rk_clrreg(&priv->cru->clksel_con[43], BIT(14));
+ } else {
+ debug("%s: switching RMII to CLKIN\n", __func__);
+ rk_setreg(&priv->cru->clksel_con[43], BIT(14));
+ }
+
+ return 0;
+}
+
+static int __maybe_unused rk3308_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ switch (clk->id) {
+ case SCLK_MAC:
+ return rk3308_mac_set_parent(clk, parent);
+ default:
+ break;
+ }
+
+ debug("%s: unsupported clk %ld\n", __func__, clk->id);
+ return -ENOENT;
+}
+#endif
+
+static struct clk_ops rk3308_clk_ops = {
+ .get_rate = rk3308_clk_get_rate,
+ .set_rate = rk3308_clk_set_rate,
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+ .set_parent = rk3308_clk_set_parent,
+#endif
+};
+
+static void rk3308_clk_init(struct udevice *dev)
+{
+ struct rk3308_clk_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ if (rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
+ priv->cru, APLL) != APLL_HZ) {
+ ret = rk3308_armclk_set_clk(priv, APLL_HZ);
+ if (ret < 0)
+ printf("%s failed to set armclk rate\n", __func__);
+ }
+
+ rk3308_clk_get_pll_rate(priv);
+
+ rk3308_bus_set_clk(priv, ACLK_BUS, BUS_ACLK_HZ);
+ rk3308_bus_set_clk(priv, HCLK_BUS, BUS_HCLK_HZ);
+ rk3308_bus_set_clk(priv, PCLK_BUS, BUS_PCLK_HZ);
+
+ rk3308_peri_set_clk(priv, ACLK_PERI, PERI_ACLK_HZ);
+ rk3308_peri_set_clk(priv, HCLK_PERI, PERI_HCLK_HZ);
+ rk3308_peri_set_clk(priv, PCLK_PERI, PERI_PCLK_HZ);
+
+ rk3308_audio_set_clk(priv, HCLK_AUDIO, AUDIO_HCLK_HZ);
+ rk3308_audio_set_clk(priv, PCLK_AUDIO, AUDIO_PCLK_HZ);
+}
+
+static int rk3308_clk_probe(struct udevice *dev)
+{
+ int ret;
+
+ rk3308_clk_init(dev);
+
+ /* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
+ ret = clk_set_defaults(dev, 1);
+ if (ret)
+ debug("%s clk_set_defaults failed %d\n", __func__, ret);
+
+ return ret;
+}
+
+static int rk3308_clk_ofdata_to_platdata(struct udevice *dev)
+{
+ struct rk3308_clk_priv *priv = dev_get_priv(dev);
+
+ priv->cru = dev_read_addr_ptr(dev);
+
+ return 0;
+}
+
+static int rk3308_clk_bind(struct udevice *dev)
+{
+ int ret;
+ struct udevice *sys_child;
+ struct sysreset_reg *priv;
+
+ /* The reset driver does not have a device node, so bind it here */
+ ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
+ &sys_child);
+ if (ret) {
+ debug("Warning: No sysreset driver: ret=%d\n", ret);
+ } else {
+ priv = malloc(sizeof(struct sysreset_reg));
+ priv->glb_srst_fst_value = offsetof(struct rk3308_cru,
+ glb_srst_fst);
+ priv->glb_srst_snd_value = offsetof(struct rk3308_cru,
+ glb_srst_snd);
+ sys_child->priv = priv;
+ }
+
+#if CONFIG_IS_ENABLED(RESET_ROCKCHIP)
+ ret = offsetof(struct rk3308_cru, softrst_con[0]);
+ ret = rockchip_reset_bind(dev, ret, 12);
+ if (ret)
+ debug("Warning: software reset driver bind faile\n");
+#endif
+
+ return 0;
+}
+
+static const struct udevice_id rk3308_clk_ids[] = {
+ { .compatible = "rockchip,rk3308-cru" },
+ { }
+};
+
+U_BOOT_DRIVER(rockchip_rk3308_cru) = {
+ .name = "rockchip_rk3308_cru",
+ .id = UCLASS_CLK,
+ .of_match = rk3308_clk_ids,
+ .priv_auto_alloc_size = sizeof(struct rk3308_clk_priv),
+ .ofdata_to_platdata = rk3308_clk_ofdata_to_platdata,
+ .ops = &rk3308_clk_ops,
+ .bind = rk3308_clk_bind,
+ .probe = rk3308_clk_probe,
+};
diff --git a/drivers/clk/rockchip/clk_rk3328.c b/drivers/clk/rockchip/clk_rk3328.c
index 4331048a87..e700a1bc25 100644
--- a/drivers/clk/rockchip/clk_rk3328.c
+++ b/drivers/clk/rockchip/clk_rk3328.c
@@ -791,7 +791,7 @@ static int rk3328_clk_bind(struct udevice *dev)
sys_child->priv = priv;
}
-#if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP)
+#if CONFIG_IS_ENABLED(RESET_ROCKCHIP)
ret = offsetof(struct rk3328_cru, softrst_con[0]);
ret = rockchip_reset_bind(dev, ret, 12);
if (ret)
diff --git a/drivers/clk/rockchip/clk_rk3368.c b/drivers/clk/rockchip/clk_rk3368.c
index c1a867b2ed..b51d529ade 100644
--- a/drivers/clk/rockchip/clk_rk3368.c
+++ b/drivers/clk/rockchip/clk_rk3368.c
@@ -620,7 +620,7 @@ static int rk3368_clk_bind(struct udevice *dev)
sys_child->priv = priv;
}
-#if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP)
+#if CONFIG_IS_ENABLED(RESET_ROCKCHIP)
ret = offsetof(struct rk3368_cru, softrst_con[0]);
ret = rockchip_reset_bind(dev, ret, 15);
if (ret)
diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c
index a273bd1beb..9020a9f202 100644
--- a/drivers/clk/rockchip/clk_rk3399.c
+++ b/drivers/clk/rockchip/clk_rk3399.c
@@ -1195,7 +1195,7 @@ static int rk3399_clk_bind(struct udevice *dev)
sys_child->priv = priv;
}
-#if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP)
+#if CONFIG_IS_ENABLED(RESET_ROCKCHIP)
ret = offsetof(struct rk3399_cru, softrst_con[0]);
ret = rockchip_reset_bind(dev, ret, 21);
if (ret)
diff --git a/drivers/clk/rockchip/clk_rv1108.c b/drivers/clk/rockchip/clk_rv1108.c
index 3ebb007fab..97fdd099ef 100644
--- a/drivers/clk/rockchip/clk_rv1108.c
+++ b/drivers/clk/rockchip/clk_rv1108.c
@@ -679,9 +679,8 @@ static int rv1108_clk_probe(struct udevice *dev)
static int rv1108_clk_bind(struct udevice *dev)
{
int ret;
- struct udevice *sys_child, *sf_child;
+ struct udevice *sys_child;
struct sysreset_reg *priv;
- struct softreset_reg *sf_priv;
/* The reset driver does not have a device node, so bind it here */
ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
@@ -697,23 +696,12 @@ static int rv1108_clk_bind(struct udevice *dev)
sys_child->priv = priv;
}
-#if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP)
- ret = offsetof(struct rk3368_cru, softrst_con[0]);
+#if CONFIG_IS_ENABLED(RESET_ROCKCHIP)
+ ret = offsetof(struct rv1108_cru, softrst_con[0]);
ret = rockchip_reset_bind(dev, ret, 13);
if (ret)
debug("Warning: software reset driver bind faile\n");
#endif
- ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
- dev_ofnode(dev), &sf_child);
- if (ret) {
- debug("Warning: No rockchip reset driver: ret=%d\n", ret);
- } else {
- sf_priv = malloc(sizeof(struct softreset_reg));
- sf_priv->sf_reset_offset = offsetof(struct rv1108_cru,
- softrst_con[0]);
- sf_priv->sf_reset_num = 13;
- sf_child->priv = sf_priv;
- }
return 0;
}
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 7a8ba587da..82bb093c56 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -59,6 +59,15 @@ config ROCKCHIP_EFUSE
extended (by porting the read function from the Linux kernel sources)
to support other recent Rockchip devices.
+config ROCKCHIP_OTP
+ bool "Rockchip OTP Support"
+ depends on MISC
+ help
+ Enable (read-only) access for the one-time-programmable memory block
+ found in Rockchip SoCs: accesses can either be made using byte
+ addressing and a length or through child-nodes that are generated
+ based on the e-fuse map retrieved from the DTS.
+
config VEXPRESS_CONFIG
bool "Enable support for Arm Versatile Express config bus"
depends on MISC
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 870655e802..55976d6be5 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_PCA9551_LED) += pca9551_led.o
obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o
obj-$(CONFIG_QFW) += qfw.o
obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o
+obj-$(CONFIG_ROCKCHIP_OTP) += rockchip-otp.o
obj-$(CONFIG_SANDBOX) += syscon_sandbox.o misc_sandbox.o
obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o
obj-$(CONFIG_SMSC_SIO1007) += smsc_sio1007.o
diff --git a/drivers/misc/rockchip-otp.c b/drivers/misc/rockchip-otp.c
new file mode 100644
index 0000000000..bdd443b3db
--- /dev/null
+++ b/drivers/misc/rockchip-otp.c
@@ -0,0 +1,176 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <command.h>
+#include <dm.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <misc.h>
+
+/* OTP Register Offsets */
+#define OTPC_SBPI_CTRL 0x0020
+#define OTPC_SBPI_CMD_VALID_PRE 0x0024
+#define OTPC_SBPI_CS_VALID_PRE 0x0028
+#define OTPC_SBPI_STATUS 0x002C
+#define OTPC_USER_CTRL 0x0100
+#define OTPC_USER_ADDR 0x0104
+#define OTPC_USER_ENABLE 0x0108
+#define OTPC_USER_QP 0x0120
+#define OTPC_USER_Q 0x0124
+#define OTPC_INT_STATUS 0x0304
+#define OTPC_SBPI_CMD0_OFFSET 0x1000
+#define OTPC_SBPI_CMD1_OFFSET 0x1004
+
+/* OTP Register bits and masks */
+#define OTPC_USER_ADDR_MASK GENMASK(31, 16)
+#define OTPC_USE_USER BIT(0)
+#define OTPC_USE_USER_MASK GENMASK(16, 16)
+#define OTPC_USER_FSM_ENABLE BIT(0)
+#define OTPC_USER_FSM_ENABLE_MASK GENMASK(16, 16)
+#define OTPC_SBPI_DONE BIT(1)
+#define OTPC_USER_DONE BIT(2)
+
+#define SBPI_DAP_ADDR 0x02
+#define SBPI_DAP_ADDR_SHIFT 8
+#define SBPI_DAP_ADDR_MASK GENMASK(31, 24)
+#define SBPI_CMD_VALID_MASK GENMASK(31, 16)
+#define SBPI_DAP_CMD_WRF 0xC0
+#define SBPI_DAP_REG_ECC 0x3A
+#define SBPI_ECC_ENABLE 0x00
+#define SBPI_ECC_DISABLE 0x09
+#define SBPI_ENABLE BIT(0)
+#define SBPI_ENABLE_MASK GENMASK(16, 16)
+
+#define OTPC_TIMEOUT 10000
+
+struct rockchip_otp_platdata {
+ void __iomem *base;
+ unsigned long secure_conf_base;
+ unsigned long otp_mask_base;
+};
+
+static int rockchip_otp_wait_status(struct rockchip_otp_platdata *otp,
+ u32 flag)
+{
+ int delay = OTPC_TIMEOUT;
+
+ while (!(readl(otp->base + OTPC_INT_STATUS) & flag)) {
+ udelay(1);
+ delay--;
+ if (delay <= 0) {
+ printf("%s: wait init status timeout\n", __func__);
+ return -ETIMEDOUT;
+ }
+ }
+
+ /* clean int status */
+ writel(flag, otp->base + OTPC_INT_STATUS);
+
+ return 0;
+}
+
+static int rockchip_otp_ecc_enable(struct rockchip_otp_platdata *otp,
+ bool enable)
+{
+ int ret = 0;
+
+ writel(SBPI_DAP_ADDR_MASK | (SBPI_DAP_ADDR << SBPI_DAP_ADDR_SHIFT),
+ otp->base + OTPC_SBPI_CTRL);
+
+ writel(SBPI_CMD_VALID_MASK | 0x1, otp->base + OTPC_SBPI_CMD_VALID_PRE);
+ writel(SBPI_DAP_CMD_WRF | SBPI_DAP_REG_ECC,
+ otp->base + OTPC_SBPI_CMD0_OFFSET);
+
+ if (enable)
+ writel(SBPI_ECC_ENABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
+ else
+ writel(SBPI_ECC_DISABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
+
+ writel(SBPI_ENABLE_MASK | SBPI_ENABLE, otp->base + OTPC_SBPI_CTRL);
+
+ ret = rockchip_otp_wait_status(otp, OTPC_SBPI_DONE);
+ if (ret < 0)
+ printf("%s timeout during ecc_enable\n", __func__);
+
+ return ret;
+}
+
+static int rockchip_px30_otp_read(struct udevice *dev, int offset,
+ void *buf, int size)
+{
+ struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
+ u8 *buffer = buf;
+ int ret = 0;
+
+ ret = rockchip_otp_ecc_enable(otp, false);
+ if (ret < 0) {
+ printf("%s rockchip_otp_ecc_enable err\n", __func__);
+ return ret;
+ }
+
+ writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
+ udelay(5);
+ while (size--) {
+ writel(offset++ | OTPC_USER_ADDR_MASK,
+ otp->base + OTPC_USER_ADDR);
+ writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK,
+ otp->base + OTPC_USER_ENABLE);
+
+ ret = rockchip_otp_wait_status(otp, OTPC_USER_DONE);
+ if (ret < 0) {
+ printf("%s timeout during read setup\n", __func__);
+ goto read_end;
+ }
+
+ *buffer++ = readb(otp->base + OTPC_USER_Q);
+ }
+
+read_end:
+ writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
+
+ return ret;
+}
+
+static int rockchip_otp_read(struct udevice *dev, int offset,
+ void *buf, int size)
+{
+ return rockchip_px30_otp_read(dev, offset, buf, size);
+}
+
+static const struct misc_ops rockchip_otp_ops = {
+ .read = rockchip_otp_read,
+};
+
+static int rockchip_otp_ofdata_to_platdata(struct udevice *dev)
+{
+ struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
+
+ otp->base = dev_read_addr_ptr(dev);
+
+ return 0;
+}
+
+static const struct udevice_id rockchip_otp_ids[] = {
+ {
+ .compatible = "rockchip,px30-otp",
+ .data = (ulong)&rockchip_px30_otp_read,
+ },
+ {
+ .compatible = "rockchip,rk3308-otp",
+ .data = (ulong)&rockchip_px30_otp_read,
+ },
+ {}
+};
+
+U_BOOT_DRIVER(rockchip_otp) = {
+ .name = "rockchip_otp",
+ .id = UCLASS_MISC,
+ .of_match = rockchip_otp_ids,
+ .ops = &rockchip_otp_ops,
+ .ofdata_to_platdata = rockchip_otp_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct rockchip_otp_platdata),
+};
diff --git a/drivers/net/gmac_rockchip.c b/drivers/net/gmac_rockchip.c
index 26a6121175..d2c52b4c46 100644
--- a/drivers/net/gmac_rockchip.c
+++ b/drivers/net/gmac_rockchip.c
@@ -14,6 +14,7 @@
#include <asm/arch-rockchip/periph.h>
#include <asm/arch-rockchip/clock.h>
#include <asm/arch-rockchip/hardware.h>
+#include <asm/arch-rockchip/grf_px30.h>
#include <asm/arch-rockchip/grf_rk322x.h>
#include <asm/arch-rockchip/grf_rk3288.h>
#include <asm/arch-rockchip/grf_rk3328.h>
@@ -72,6 +73,47 @@ static int gmac_rockchip_ofdata_to_platdata(struct udevice *dev)
return designware_eth_ofdata_to_platdata(dev);
}
+static int px30_gmac_fix_mac_speed(struct dw_eth_dev *priv)
+{
+ struct px30_grf *grf;
+ struct clk clk_speed;
+ int speed, ret;
+ enum {
+ PX30_GMAC_SPEED_SHIFT = 0x2,
+ PX30_GMAC_SPEED_MASK = BIT(2),
+ PX30_GMAC_SPEED_10M = 0,
+ PX30_GMAC_SPEED_100M = BIT(2),
+ };
+
+ ret = clk_get_by_name(priv->phydev->dev, "clk_mac_speed",
+ &clk_speed);
+ if (ret)
+ return ret;
+
+ switch (priv->phydev->speed) {
+ case 10:
+ speed = PX30_GMAC_SPEED_10M;
+ ret = clk_set_rate(&clk_speed, 2500000);
+ if (ret)
+ return ret;
+ break;
+ case 100:
+ speed = PX30_GMAC_SPEED_100M;
+ ret = clk_set_rate(&clk_speed, 25000000);
+ if (ret)
+ return ret;
+ break;
+ default:
+ debug("Unknown phy speed: %d\n", priv->phydev->speed);
+ return -EINVAL;
+ }
+
+ grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+ rk_clrsetreg(&grf->mac_con1, PX30_GMAC_SPEED_MASK, speed);
+
+ return 0;
+}
+
static int rk3228_gmac_fix_mac_speed(struct dw_eth_dev *priv)
{
struct rk322x_grf *grf;
@@ -257,6 +299,22 @@ static int rv1108_set_rmii_speed(struct dw_eth_dev *priv)
return 0;
}
+static void px30_gmac_set_to_rmii(struct gmac_rockchip_platdata *pdata)
+{
+ struct px30_grf *grf;
+ enum {
+ PX30_GMAC_PHY_INTF_SEL_SHIFT = 4,
+ PX30_GMAC_PHY_INTF_SEL_MASK = GENMASK(4, 6),
+ PX30_GMAC_PHY_INTF_SEL_RMII = BIT(6),
+ };
+
+ grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+
+ rk_clrsetreg(&grf->mac_con1,
+ PX30_GMAC_PHY_INTF_SEL_MASK,
+ PX30_GMAC_PHY_INTF_SEL_RMII);
+}
+
static void rk3228_gmac_set_to_rgmii(struct gmac_rockchip_platdata *pdata)
{
struct rk322x_grf *grf;
@@ -445,6 +503,10 @@ static int gmac_rockchip_probe(struct udevice *dev)
ulong rate;
int ret;
+ ret = clk_set_defaults(dev, 0);
+ if (ret)
+ debug("%s clk_set_defaults failed %d\n", __func__, ret);
+
ret = clk_get_by_index(dev, 0, &clk);
if (ret)
return ret;
@@ -569,6 +631,11 @@ const struct eth_ops gmac_rockchip_eth_ops = {
.write_hwaddr = designware_eth_write_hwaddr,
};
+const struct rk_gmac_ops px30_gmac_ops = {
+ .fix_mac_speed = px30_gmac_fix_mac_speed,
+ .set_to_rmii = px30_gmac_set_to_rmii,
+};
+
const struct rk_gmac_ops rk3228_gmac_ops = {
.fix_mac_speed = rk3228_gmac_fix_mac_speed,
.set_to_rgmii = rk3228_gmac_set_to_rgmii,
@@ -600,6 +667,8 @@ const struct rk_gmac_ops rv1108_gmac_ops = {
};
static const struct udevice_id rockchip_gmac_ids[] = {
+ { .compatible = "rockchip,px30-gmac",
+ .data = (ulong)&px30_gmac_ops },
{ .compatible = "rockchip,rk3228-gmac",
.data = (ulong)&rk3228_gmac_ops },
{ .compatible = "rockchip,rk3288-gmac",
diff --git a/drivers/pinctrl/rockchip/Makefile b/drivers/pinctrl/rockchip/Makefile
index a616d8587f..83913f668f 100644
--- a/drivers/pinctrl/rockchip/Makefile
+++ b/drivers/pinctrl/rockchip/Makefile
@@ -3,6 +3,7 @@
# Copyright (c) 2017 Rockchip Electronics Co., Ltd
obj-y += pinctrl-rockchip-core.o
+obj-$(CONFIG_ROCKCHIP_PX30) += pinctrl-px30.o
obj-$(CONFIG_ROCKCHIP_RK3036) += pinctrl-rk3036.o
obj-$(CONFIG_ROCKCHIP_RK3128) += pinctrl-rk3128.o
obj-$(CONFIG_ROCKCHIP_RK3188) += pinctrl-rk3188.o
diff --git a/drivers/pinctrl/rockchip/pinctrl-px30.c b/drivers/pinctrl/rockchip/pinctrl-px30.c
new file mode 100644
index 0000000000..bb56ae9fb3
--- /dev/null
+++ b/drivers/pinctrl/rockchip/pinctrl-px30.c
@@ -0,0 +1,368 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2019 Rockchip Electronics Co., Ltd
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/pinctrl.h>
+#include <regmap.h>
+#include <syscon.h>
+
+#include "pinctrl-rockchip.h"
+
+static struct rockchip_mux_route_data px30_mux_route_data[] = {
+ {
+ /* cif-d2m0 */
+ .bank_num = 2,
+ .pin = 0,
+ .func = 1,
+ .route_offset = 0x184,
+ .route_val = BIT(16 + 7),
+ }, {
+ /* cif-d2m1 */
+ .bank_num = 3,
+ .pin = 3,
+ .func = 3,
+ .route_offset = 0x184,
+ .route_val = BIT(16 + 7) | BIT(7),
+ }, {
+ /* pdm-m0 */
+ .bank_num = 3,
+ .pin = 22,
+ .func = 2,
+ .route_offset = 0x184,
+ .route_val = BIT(16 + 8),
+ }, {
+ /* pdm-m1 */
+ .bank_num = 2,
+ .pin = 22,
+ .func = 1,
+ .route_offset = 0x184,
+ .route_val = BIT(16 + 8) | BIT(8),
+ }, {
+ /* uart2-rxm0 */
+ .bank_num = 1,
+ .pin = 27,
+ .func = 2,
+ .route_offset = 0x184,
+ .route_val = BIT(16 + 10),
+ }, {
+ /* uart2-rxm1 */
+ .bank_num = 2,
+ .pin = 14,
+ .func = 2,
+ .route_offset = 0x184,
+ .route_val = BIT(16 + 10) | BIT(10),
+ }, {
+ /* uart3-rxm0 */
+ .bank_num = 0,
+ .pin = 17,
+ .func = 2,
+ .route_offset = 0x184,
+ .route_val = BIT(16 + 9),
+ }, {
+ /* uart3-rxm1 */
+ .bank_num = 1,
+ .pin = 15,
+ .func = 2,
+ .route_offset = 0x184,
+ .route_val = BIT(16 + 9) | BIT(9),
+ },
+};
+
+static int px30_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
+{
+ struct rockchip_pinctrl_priv *priv = bank->priv;
+ int iomux_num = (pin / 8);
+ struct regmap *regmap;
+ int reg, ret, mask, mux_type;
+ u8 bit;
+ u32 data, route_reg, route_val;
+
+ regmap = (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
+ ? priv->regmap_pmu : priv->regmap_base;
+
+ /* get basic quadrupel of mux registers and the correct reg inside */
+ mux_type = bank->iomux[iomux_num].type;
+ reg = bank->iomux[iomux_num].offset;
+ reg += rockchip_get_mux_data(mux_type, pin, &bit, &mask);
+
+ if (bank->route_mask & BIT(pin)) {
+ if (rockchip_get_mux_route(bank, pin, mux, &route_reg,
+ &route_val)) {
+ ret = regmap_write(regmap, route_reg, route_val);
+ if (ret)
+ return ret;
+ }
+ }
+
+ data = (mask << (bit + 16));
+ data |= (mux & mask) << bit;
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
+}
+
+#define PX30_PULL_PMU_OFFSET 0x10
+#define PX30_PULL_GRF_OFFSET 0x60
+#define PX30_PULL_BITS_PER_PIN 2
+#define PX30_PULL_PINS_PER_REG 8
+#define PX30_PULL_BANK_STRIDE 16
+
+static void px30_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
+ int pin_num, struct regmap **regmap,
+ int *reg, u8 *bit)
+{
+ struct rockchip_pinctrl_priv *priv = bank->priv;
+
+ /* The first 32 pins of the first bank are located in PMU */
+ if (bank->bank_num == 0) {
+ *regmap = priv->regmap_pmu;
+ *reg = PX30_PULL_PMU_OFFSET;
+ } else {
+ *regmap = priv->regmap_base;
+ *reg = PX30_PULL_GRF_OFFSET;
+
+ /* correct the offset, as we're starting with the 2nd bank */
+ *reg -= 0x10;
+ *reg += bank->bank_num * PX30_PULL_BANK_STRIDE;
+ }
+
+ *reg += ((pin_num / PX30_PULL_PINS_PER_REG) * 4);
+ *bit = (pin_num % PX30_PULL_PINS_PER_REG);
+ *bit *= PX30_PULL_BITS_PER_PIN;
+}
+
+static int px30_set_pull(struct rockchip_pin_bank *bank,
+ int pin_num, int pull)
+{
+ struct regmap *regmap;
+ int reg, ret;
+ u8 bit, type;
+ u32 data;
+
+ if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT)
+ return -ENOTSUPP;
+
+ px30_calc_pull_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ type = bank->pull_type[pin_num / 8];
+ ret = rockchip_translate_pull_value(type, pull);
+ if (ret < 0) {
+ debug("unsupported pull setting %d\n", pull);
+ return ret;
+ }
+
+ /* enable the write to the equivalent lower bits */
+ data = ((1 << ROCKCHIP_PULL_BITS_PER_PIN) - 1) << (bit + 16);
+ data |= (ret << bit);
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
+}
+
+#define PX30_DRV_PMU_OFFSET 0x20
+#define PX30_DRV_GRF_OFFSET 0xf0
+#define PX30_DRV_BITS_PER_PIN 2
+#define PX30_DRV_PINS_PER_REG 8
+#define PX30_DRV_BANK_STRIDE 16
+
+static void px30_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
+ int pin_num, struct regmap **regmap,
+ int *reg, u8 *bit)
+{
+ struct rockchip_pinctrl_priv *priv = bank->priv;
+
+ /* The first 32 pins of the first bank are located in PMU */
+ if (bank->bank_num == 0) {
+ *regmap = priv->regmap_pmu;
+ *reg = PX30_DRV_PMU_OFFSET;
+ } else {
+ *regmap = priv->regmap_base;
+ *reg = PX30_DRV_GRF_OFFSET;
+
+ /* correct the offset, as we're starting with the 2nd bank */
+ *reg -= 0x10;
+ *reg += bank->bank_num * PX30_DRV_BANK_STRIDE;
+ }
+
+ *reg += ((pin_num / PX30_DRV_PINS_PER_REG) * 4);
+ *bit = (pin_num % PX30_DRV_PINS_PER_REG);
+ *bit *= PX30_DRV_BITS_PER_PIN;
+}
+
+static int px30_set_drive(struct rockchip_pin_bank *bank,
+ int pin_num, int strength)
+{
+ struct regmap *regmap;
+ int reg, ret;
+ u32 data, rmask_bits, temp;
+ u8 bit;
+ int drv_type = bank->drv[pin_num / 8].drv_type;
+
+ px30_calc_drv_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ ret = rockchip_translate_drive_value(drv_type, strength);
+ if (ret < 0) {
+ debug("unsupported driver strength %d\n", strength);
+ return ret;
+ }
+
+ switch (drv_type) {
+ case DRV_TYPE_IO_1V8_3V0_AUTO:
+ case DRV_TYPE_IO_3V3_ONLY:
+ rmask_bits = ROCKCHIP_DRV_3BITS_PER_PIN;
+ switch (bit) {
+ case 0 ... 12:
+ /* regular case, nothing to do */
+ break;
+ case 15:
+ /*
+ * drive-strength offset is special, as it is spread
+ * over 2 registers, the bit data[15] contains bit 0
+ * of the value while temp[1:0] contains bits 2 and 1
+ */
+ data = (ret & 0x1) << 15;
+ temp = (ret >> 0x1) & 0x3;
+
+ data |= BIT(31);
+ ret = regmap_write(regmap, reg, data);
+ if (ret)
+ return ret;
+
+ temp |= (0x3 << 16);
+ reg += 0x4;
+ ret = regmap_write(regmap, reg, temp);
+
+ return ret;
+ case 18 ... 21:
+ /* setting fully enclosed in the second register */
+ reg += 4;
+ bit -= 16;
+ break;
+ default:
+ debug("unsupported bit: %d for pinctrl drive type: %d\n",
+ bit, drv_type);
+ return -EINVAL;
+ }
+ break;
+ case DRV_TYPE_IO_DEFAULT:
+ case DRV_TYPE_IO_1V8_OR_3V0:
+ case DRV_TYPE_IO_1V8_ONLY:
+ rmask_bits = ROCKCHIP_DRV_BITS_PER_PIN;
+ break;
+ default:
+ debug("unsupported pinctrl drive type: %d\n",
+ drv_type);
+ return -EINVAL;
+ }
+
+ /* enable the write to the equivalent lower bits */
+ data = ((1 << rmask_bits) - 1) << (bit + 16);
+ data |= (ret << bit);
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
+}
+
+#define PX30_SCHMITT_PMU_OFFSET 0x38
+#define PX30_SCHMITT_GRF_OFFSET 0xc0
+#define PX30_SCHMITT_PINS_PER_PMU_REG 16
+#define PX30_SCHMITT_BANK_STRIDE 16
+#define PX30_SCHMITT_PINS_PER_GRF_REG 8
+
+static int px30_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank,
+ int pin_num,
+ struct regmap **regmap,
+ int *reg, u8 *bit)
+{
+ struct rockchip_pinctrl_priv *priv = bank->priv;
+ int pins_per_reg;
+
+ if (bank->bank_num == 0) {
+ *regmap = priv->regmap_pmu;
+ *reg = PX30_SCHMITT_PMU_OFFSET;
+ pins_per_reg = PX30_SCHMITT_PINS_PER_PMU_REG;
+ } else {
+ *regmap = priv->regmap_base;
+ *reg = PX30_SCHMITT_GRF_OFFSET;
+ pins_per_reg = PX30_SCHMITT_PINS_PER_GRF_REG;
+ *reg += (bank->bank_num - 1) * PX30_SCHMITT_BANK_STRIDE;
+ }
+ *reg += ((pin_num / pins_per_reg) * 4);
+ *bit = pin_num % pins_per_reg;
+
+ return 0;
+}
+
+static int px30_set_schmitt(struct rockchip_pin_bank *bank,
+ int pin_num, int enable)
+{
+ struct regmap *regmap;
+ int reg;
+ u8 bit;
+ u32 data;
+
+ px30_calc_schmitt_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ /* enable the write to the equivalent lower bits */
+ data = BIT(bit + 16) | (enable << bit);
+
+ return regmap_write(regmap, reg, data);
+}
+
+static struct rockchip_pin_bank px30_pin_banks[] = {
+ PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", IOMUX_SOURCE_PMU,
+ IOMUX_SOURCE_PMU,
+ IOMUX_SOURCE_PMU,
+ IOMUX_SOURCE_PMU
+ ),
+ PIN_BANK_IOMUX_FLAGS(1, 32, "gpio1", IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT
+ ),
+ PIN_BANK_IOMUX_FLAGS(2, 32, "gpio2", IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT
+ ),
+ PIN_BANK_IOMUX_FLAGS(3, 32, "gpio3", IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT
+ ),
+};
+
+static struct rockchip_pin_ctrl px30_pin_ctrl = {
+ .pin_banks = px30_pin_banks,
+ .nr_banks = ARRAY_SIZE(px30_pin_banks),
+ .grf_mux_offset = 0x0,
+ .pmu_mux_offset = 0x0,
+ .grf_drv_offset = 0xf0,
+ .pmu_drv_offset = 0x20,
+ .iomux_routes = px30_mux_route_data,
+ .niomux_routes = ARRAY_SIZE(px30_mux_route_data),
+ .set_mux = px30_set_mux,
+ .set_pull = px30_set_pull,
+ .set_drive = px30_set_drive,
+ .set_schmitt = px30_set_schmitt,
+};
+
+static const struct udevice_id px30_pinctrl_ids[] = {
+ {
+ .compatible = "rockchip,px30-pinctrl",
+ .data = (ulong)&px30_pin_ctrl
+ },
+ { }
+};
+
+U_BOOT_DRIVER(pinctrl_px30) = {
+ .name = "rockchip_px30_pinctrl",
+ .id = UCLASS_PINCTRL,
+ .of_match = px30_pinctrl_ids,
+ .priv_auto_alloc_size = sizeof(struct rockchip_pinctrl_priv),
+ .ops = &rockchip_pinctrl_ops,
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+ .bind = dm_scan_fdt_dev,
+#endif
+ .probe = rockchip_pinctrl_probe,
+};
diff --git a/drivers/ram/Kconfig b/drivers/ram/Kconfig
index bb431ccfbf..b454ceb599 100644
--- a/drivers/ram/Kconfig
+++ b/drivers/ram/Kconfig
@@ -19,7 +19,7 @@ config SPL_RAM
config TPL_RAM
bool "Enable RAM support in TPL"
- depends on RAM && TPL_DM
+ depends on RAM
help
The RAM subsystem adds a small amount of overhead to the image.
If this is acceptable and you have a need to use RAM drivers in
diff --git a/drivers/ram/rockchip/Kconfig b/drivers/ram/rockchip/Kconfig
index 4f274e01b3..b75d581f57 100644
--- a/drivers/ram/rockchip/Kconfig
+++ b/drivers/ram/rockchip/Kconfig
@@ -5,10 +5,15 @@ config RAM_ROCKCHIP
help
This enables support for ram drivers Rockchip SoCs.
-if RAM_ROCKCHIP
+config ROCKCHIP_SDRAM_COMMON
+ bool "Enable rockchip sdram common driver"
+ depends on TPL_RAM || SPL_RAM
+ help
+ This enable sdram common driver
config RAM_ROCKCHIP_DEBUG
bool "Rockchip ram drivers debugging"
+ default y
help
This enables debugging ram driver API's for the platforms
based on Rockchip SoCs.
@@ -16,18 +21,10 @@ config RAM_ROCKCHIP_DEBUG
This is an option for developers to understand the ram drivers
initialization, configurations and etc.
-config RAM_RK3399
- bool "Ram driver for Rockchip RK3399"
- default ROCKCHIP_RK3399
- help
- This enables ram drivers support for the platforms based on
- Rockchip RK3399 SoC.
-
config RAM_RK3399_LPDDR4
bool "LPDDR4 support for Rockchip RK3399"
- depends on RAM_RK3399
+ depends on RAM_ROCKCHIP && ROCKCHIP_RK3399
help
This enables LPDDR4 sdram code support for the platforms based
on Rockchip RK3399 SoC.
-endif # RAM_ROCKCHIP
diff --git a/drivers/ram/rockchip/Makefile b/drivers/ram/rockchip/Makefile
index feb1f82d00..c3ec89ada4 100644
--- a/drivers/ram/rockchip/Makefile
+++ b/drivers/ram/rockchip/Makefile
@@ -3,11 +3,13 @@
# Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH
#
-obj-$(CONFIG_RAM_ROCKCHIP_DEBUG) += sdram_debug.o
+obj-$(CONFIG_ROCKCHIP_PX30) += sdram_px30.o sdram_pctl_px30.o sdram_phy_px30.o
obj-$(CONFIG_ROCKCHIP_RK3368) = dmc-rk3368.o
obj-$(CONFIG_ROCKCHIP_RK3128) = sdram_rk3128.o
obj-$(CONFIG_ROCKCHIP_RK3188) = sdram_rk3188.o
obj-$(CONFIG_ROCKCHIP_RK322X) = sdram_rk322x.o
obj-$(CONFIG_ROCKCHIP_RK3288) = sdram_rk3288.o
-obj-$(CONFIG_ROCKCHIP_RK3328) = sdram_rk3328.o
-obj-$(CONFIG_RAM_RK3399) += sdram_rk3399.o
+obj-$(CONFIG_ROCKCHIP_RK3308) = sdram_rk3308.o
+obj-$(CONFIG_ROCKCHIP_RK3328) = sdram_rk3328.o sdram_pctl_px30.o sdram_phy_px30.o
+obj-$(CONFIG_ROCKCHIP_RK3399) += sdram_rk3399.o
+obj-$(CONFIG_ROCKCHIP_SDRAM_COMMON) += sdram_common.o
diff --git a/drivers/ram/rockchip/dmc-rk3368.c b/drivers/ram/rockchip/dmc-rk3368.c
index e52fc3baad..9df8f8f4af 100644
--- a/drivers/ram/rockchip/dmc-rk3368.c
+++ b/drivers/ram/rockchip/dmc-rk3368.c
@@ -17,7 +17,7 @@
#include <asm/arch-rockchip/grf_rk3368.h>
#include <asm/arch-rockchip/ddr_rk3368.h>
#include <asm/arch-rockchip/sdram.h>
-#include <asm/arch-rockchip/sdram_common.h>
+#include <asm/arch-rockchip/sdram_rk3288.h>
struct dram_info {
struct ram_info info;
diff --git a/drivers/ram/rockchip/sdram-px30-ddr3-detect-333.inc b/drivers/ram/rockchip/sdram-px30-ddr3-detect-333.inc
new file mode 100644
index 0000000000..76cd8dc1a5
--- /dev/null
+++ b/drivers/ram/rockchip/sdram-px30-ddr3-detect-333.inc
@@ -0,0 +1,72 @@
+{
+ {
+ {
+ .rank = 0x1,
+ .col = 0xC,
+ .bk = 0x3,
+ .bw = 0x1,
+ .dbw = 0x0,
+ .row_3_4 = 0x0,
+ .cs0_row = 0x10,
+ .cs1_row = 0x10,
+ .cs0_high16bit_row = 0x10,
+ .cs1_high16bit_row = 0x10,
+ .ddrconfig = 0,
+ },
+ {
+ {0x290b0609},
+ {0x08020401},
+ {0x00000002},
+ {0x00001111},
+ {0x0000000c},
+ {0x00000222},
+ 0x000000ff
+ }
+ },
+ {
+ .ddr_freq = 333,
+ .dramtype = DDR3,
+ .num_channels = 1,
+ .stride = 0,
+ .odt = 0,
+ },
+ {
+ {
+ {0x00000000, 0x43041001}, /* MSTR */
+ {0x00000064, 0x0028003b}, /* RFSHTMG */
+ {0x000000d0, 0x00020053}, /* INIT0 */
+ {0x000000d4, 0x00020000}, /* INIT1 */
+ {0x000000d8, 0x00000100}, /* INIT2 */
+ {0x000000dc, 0x03200000}, /* INIT3 */
+ {0x000000e0, 0x00000000}, /* INIT4 */
+ {0x000000e4, 0x00090000}, /* INIT5 */
+ {0x000000f4, 0x000f012f}, /* RANKCTL */
+ {0x00000100, 0x07090b06}, /* DRAMTMG0 */
+ {0x00000104, 0x00050209}, /* DRAMTMG1 */
+ {0x00000108, 0x03030407}, /* DRAMTMG2 */
+ {0x0000010c, 0x00202006}, /* DRAMTMG3 */
+ {0x00000110, 0x03020204}, /* DRAMTMG4 */
+ {0x00000114, 0x03030202}, /* DRAMTMG5 */
+ {0x00000120, 0x00000903}, /* DRAMTMG8 */
+ {0x00000180, 0x00800020}, /* ZQCTL0 */
+ {0x00000184, 0x00000000}, /* ZQCTL1 */
+ {0x00000190, 0x07010001}, /* DFITMG0 */
+ {0x00000198, 0x07000101}, /* DFILPCFG0 */
+ {0x000001a0, 0xc0400003}, /* DFIUPD0 */
+ {0x00000240, 0x06000604}, /* ODTCFG */
+ {0x00000244, 0x00000201}, /* ODTMAP */
+ {0x00000250, 0x00001f00}, /* SCHED */
+ {0x00000490, 0x00000001}, /* PCTRL_0 */
+ {0xffffffff, 0xffffffff}
+ }
+ },
+ {
+ {
+ {0x00000004, 0x0000000a}, /* PHYREG01 */
+ {0x00000028, 0x00000006}, /* PHYREG0A */
+ {0x0000002c, 0x00000000}, /* PHYREG0B */
+ {0x00000030, 0x00000005}, /* PHYREG0C */
+ {0xffffffff, 0xffffffff}
+ }
+ }
+},
diff --git a/drivers/ram/rockchip/sdram-px30-ddr4-detect-333.inc b/drivers/ram/rockchip/sdram-px30-ddr4-detect-333.inc
new file mode 100644
index 0000000000..f804d28393
--- /dev/null
+++ b/drivers/ram/rockchip/sdram-px30-ddr4-detect-333.inc
@@ -0,0 +1,75 @@
+{
+ {
+ {
+ .rank = 0x1,
+ .col = 0xA,
+ .bk = 0x2,
+ .bw = 0x1,
+ .dbw = 0x0,
+ .row_3_4 = 0x0,
+ .cs0_row = 0x11,
+ .cs1_row = 0x0,
+ .cs0_high16bit_row = 0x11,
+ .cs1_high16bit_row = 0x0,
+ .ddrconfig = 0,
+ },
+ {
+ {0x4d110a08},
+ {0x06020501},
+ {0x00000002},
+ {0x00001111},
+ {0x0000000c},
+ {0x0000022a},
+ 0x000000ff
+ }
+ },
+ {
+ .ddr_freq = 333,
+ .dramtype = DDR4,
+ .num_channels = 1,
+ .stride = 0,
+ .odt = 0,
+ },
+ {
+ {
+ {0x00000000, 0x43049010}, /* MSTR */
+ {0x00000064, 0x0028003b}, /* RFSHTMG */
+ {0x000000d0, 0x00020053}, /* INIT0 */
+ {0x000000d4, 0x00220000}, /* INIT1 */
+ {0x000000d8, 0x00000100}, /* INIT2 */
+ {0x000000dc, 0x00040000}, /* INIT3 */
+ {0x000000e0, 0x00000000}, /* INIT4 */
+ {0x000000e4, 0x00110000}, /* INIT5 */
+ {0x000000e8, 0x00000420}, /* INIT6 */
+ {0x000000ec, 0x00000400}, /* INIT7 */
+ {0x000000f4, 0x000f012f}, /* RANKCTL */
+ {0x00000100, 0x09060b06}, /* DRAMTMG0 */
+ {0x00000104, 0x00020209}, /* DRAMTMG1 */
+ {0x00000108, 0x0505040a}, /* DRAMTMG2 */
+ {0x0000010c, 0x0040400c}, /* DRAMTMG3 */
+ {0x00000110, 0x05030206}, /* DRAMTMG4 */
+ {0x00000114, 0x03030202}, /* DRAMTMG5 */
+ {0x00000120, 0x03030b03}, /* DRAMTMG8 */
+ {0x00000124, 0x00020208}, /* DRAMTMG9 */
+ {0x00000180, 0x01000040}, /* ZQCTL0 */
+ {0x00000184, 0x00000000}, /* ZQCTL1 */
+ {0x00000190, 0x07030003}, /* DFITMG0 */
+ {0x00000198, 0x07000101}, /* DFILPCFG0 */
+ {0x000001a0, 0xc0400003}, /* DFIUPD0 */
+ {0x00000240, 0x06000604}, /* ODTCFG */
+ {0x00000244, 0x00000201}, /* ODTMAP */
+ {0x00000250, 0x00001f00}, /* SCHED */
+ {0x00000490, 0x00000001}, /* PCTRL_0 */
+ {0xffffffff, 0xffffffff}
+ }
+ },
+ {
+ {
+ {0x00000004, 0x0000000c}, /* PHYREG01 */
+ {0x00000028, 0x0000000a}, /* PHYREG0A */
+ {0x0000002c, 0x00000000}, /* PHYREG0B */
+ {0x00000030, 0x00000009}, /* PHYREG0C */
+ {0xffffffff, 0xffffffff}
+ }
+ }
+}, \ No newline at end of file
diff --git a/drivers/ram/rockchip/sdram-px30-ddr_skew.inc b/drivers/ram/rockchip/sdram-px30-ddr_skew.inc
new file mode 100644
index 0000000000..f24343dda1
--- /dev/null
+++ b/drivers/ram/rockchip/sdram-px30-ddr_skew.inc
@@ -0,0 +1,121 @@
+ {
+ 0x77,
+ 0x88,
+ 0x79,
+ 0x79,
+ 0x87,
+ 0x97,
+ 0x87,
+ 0x78,
+ 0x77,
+ 0x78,
+ 0x87,
+ 0x88,
+ 0x87,
+ 0x87,
+ 0x77
+ },
+ {
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x69,
+ 0x9,
+ },
+ {
+ 0x77,
+ 0x78,
+ 0x77,
+ 0x78,
+ 0x77,
+ 0x78,
+ 0x77,
+ 0x78,
+ 0x77,
+ 0x79,
+ 0x9,
+ },
+ {
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x69,
+ 0x9,
+ },
+ {
+ 0x77,
+ 0x78,
+ 0x77,
+ 0x77,
+ 0x77,
+ 0x77,
+ 0x77,
+ 0x77,
+ 0x77,
+ 0x79,
+ 0x9,
+ },
+ {
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x69,
+ 0x9,
+ },
+ {
+ 0x77,
+ 0x78,
+ 0x77,
+ 0x78,
+ 0x77,
+ 0x78,
+ 0x77,
+ 0x78,
+ 0x77,
+ 0x79,
+ 0x9,
+ },
+ {
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x69,
+ 0x9,
+ },
+ {
+ 0x77,
+ 0x78,
+ 0x77,
+ 0x77,
+ 0x77,
+ 0x77,
+ 0x77,
+ 0x77,
+ 0x77,
+ 0x79,
+ 0x9,
+ }
diff --git a/drivers/ram/rockchip/sdram-px30-lpddr2-detect-333.inc b/drivers/ram/rockchip/sdram-px30-lpddr2-detect-333.inc
new file mode 100644
index 0000000000..948ade483b
--- /dev/null
+++ b/drivers/ram/rockchip/sdram-px30-lpddr2-detect-333.inc
@@ -0,0 +1,73 @@
+{
+ {
+ {
+ .rank = 0x1,
+ .col = 0xC,
+ .bk = 0x3,
+ .bw = 0x1,
+ .dbw = 0x0,
+ .row_3_4 = 0x0,
+ .cs0_row = 0xF,
+ .cs1_row = 0xF,
+ .cs0_high16bit_row = 0xF,
+ .cs1_high16bit_row = 0xF,
+ .ddrconfig = 0,
+ },
+ {
+ {0x2b0c070a},
+ {0x08020303},
+ {0x00000002},
+ {0x00001111},
+ {0x0000000c},
+ {0x00000219},
+ 0x000000ff
+ }
+ },
+ {
+ .ddr_freq = 333,
+ .dramtype = LPDDR2,
+ .num_channels = 1,
+ .stride = 0,
+ .odt = 0,
+ },
+ {
+ {
+ {0x00000000, 0x41041004}, /* MSTR */
+ {0x00000064, 0x00140023}, /* RFSHTMG */
+ {0x000000d0, 0x00220002}, /* INIT0 */
+ {0x000000d4, 0x00010000}, /* INIT1 */
+ {0x000000d8, 0x00000703}, /* INIT2 */
+ {0x000000dc, 0x00630005}, /* INIT3 */
+ {0x000000e0, 0x00010000}, /* INIT4 */
+ {0x000000e4, 0x00070003}, /* INIT5 */
+ {0x000000f4, 0x000f012f}, /* RANKCTL */
+ {0x00000100, 0x07090b07}, /* DRAMTMG0 */
+ {0x00000104, 0x0002010b}, /* DRAMTMG1 */
+ {0x00000108, 0x02040506}, /* DRAMTMG2 */
+ {0x0000010c, 0x00303000}, /* DRAMTMG3 */
+ {0x00000110, 0x04010204}, /* DRAMTMG4 */
+ {0x00000114, 0x01010303}, /* DRAMTMG5 */
+ {0x00000118, 0x02020003}, /* DRAMTMG6 */
+ {0x00000120, 0x00000303}, /* DRAMTMG8 */
+ {0x00000138, 0x00000025}, /* DRAMTMG14 */
+ {0x00000180, 0x003c000f}, /* ZQCTL0 */
+ {0x00000184, 0x00900000}, /* ZQCTL1 */
+ {0x00000190, 0x07020001}, /* DFITMG0 */
+ {0x00000198, 0x07000101}, /* DFILPCFG0 */
+ {0x000001a0, 0xc0400003}, /* DFIUPD0 */
+ {0x00000240, 0x07030718}, /* ODTCFG */
+ {0x00000250, 0x00001f00}, /* SCHED */
+ {0x00000490, 0x00000001}, /* PCTRL_0 */
+ {0xffffffff, 0xffffffff}
+ }
+ },
+ {
+ {
+ {0x00000004, 0x00000009}, /* PHYREG01 */
+ {0x00000028, 0x00000007}, /* PHYREG0A */
+ {0x0000002c, 0x00000000}, /* PHYREG0B */
+ {0x00000030, 0x00000004}, /* PHYREG0C */
+ {0xffffffff, 0xffffffff}
+ }
+ }
+},
diff --git a/drivers/ram/rockchip/sdram-px30-lpddr3-detect-333.inc b/drivers/ram/rockchip/sdram-px30-lpddr3-detect-333.inc
new file mode 100644
index 0000000000..f694a0e5b0
--- /dev/null
+++ b/drivers/ram/rockchip/sdram-px30-lpddr3-detect-333.inc
@@ -0,0 +1,74 @@
+{
+ {
+ {
+ .rank = 0x1,
+ .col = 0xC,
+ .bk = 0x3,
+ .bw = 0x1,
+ .dbw = 0x0,
+ .row_3_4 = 0x0,
+ .cs0_row = 0x10,
+ .cs1_row = 0x10,
+ .cs0_high16bit_row = 0x10,
+ .cs1_high16bit_row = 0x10,
+ .ddrconfig = 0,
+ },
+ {
+ {0x290a060a},
+ {0x08020303},
+ {0x00000002},
+ {0x00001111},
+ {0x0000000c},
+ {0x0000021a},
+ 0x000000ff
+ }
+ },
+ {
+ .ddr_freq = 333,
+ .dramtype = LPDDR3,
+ .num_channels = 1,
+ .stride = 0,
+ .odt = 0,
+ },
+ {
+ {
+ {0x00000000, 0x43041008}, /* MSTR */
+ {0x00000064, 0x00140023}, /* RFSHTMG */
+ {0x000000d0, 0x00220002}, /* INIT0 */
+ {0x000000d4, 0x00010000}, /* INIT1 */
+ {0x000000d8, 0x00000703}, /* INIT2 */
+ {0x000000dc, 0x00830004}, /* INIT3 */
+ {0x000000e0, 0x00010000}, /* INIT4 */
+ {0x000000e4, 0x00070003}, /* INIT5 */
+ {0x000000f4, 0x000f012f}, /* RANKCTL */
+ {0x00000100, 0x06090b07}, /* DRAMTMG0 */
+ {0x00000104, 0x0002020b}, /* DRAMTMG1 */
+ {0x00000108, 0x02030506}, /* DRAMTMG2 */
+ {0x0000010c, 0x00505000}, /* DRAMTMG3 */
+ {0x00000110, 0x03020204}, /* DRAMTMG4 */
+ {0x00000114, 0x01010303}, /* DRAMTMG5 */
+ {0x00000118, 0x02020003}, /* DRAMTMG6 */
+ {0x00000120, 0x00000303}, /* DRAMTMG8 */
+ {0x00000138, 0x00000025}, /* DRAMTMG14 */
+ {0x00000180, 0x003c000f}, /* ZQCTL0 */
+ {0x00000184, 0x00900000}, /* ZQCTL1 */
+ {0x00000190, 0x07020000}, /* DFITMG0 */
+ {0x00000198, 0x07000101}, /* DFILPCFG0 */
+ {0x000001a0, 0xc0400003}, /* DFIUPD0 */
+ {0x00000240, 0x0900090c}, /* ODTCFG */
+ {0x00000244, 0x00000101}, /* ODTMAP */
+ {0x00000250, 0x00001f00}, /* SCHED */
+ {0x00000490, 0x00000001}, /* PCTRL_0 */
+ {0xffffffff, 0xffffffff}
+ }
+ },
+ {
+ {
+ {0x00000004, 0x0000000b}, /* PHYREG01 */
+ {0x00000028, 0x00000006}, /* PHYREG0A */
+ {0x0000002c, 0x00000000}, /* PHYREG0B */
+ {0x00000030, 0x00000003}, /* PHYREG0C */
+ {0xffffffff, 0xffffffff}
+ }
+ }
+},
diff --git a/drivers/ram/rockchip/sdram-rk3399-lpddr4-400.inc b/drivers/ram/rockchip/sdram-rk3399-lpddr4-400.inc
index c50a03d9dd..209ef57228 100644
--- a/drivers/ram/rockchip/sdram-rk3399-lpddr4-400.inc
+++ b/drivers/ram/rockchip/sdram-rk3399-lpddr4-400.inc
@@ -16,15 +16,23 @@
.row_3_4 = 0x0,
.cs0_row = 0xF,
.cs1_row = 0xF,
+ .cs0_high16bit_row = 0xF,
+ .cs1_high16bit_row = 0xF,
.ddrconfig = 1,
},
{
- .ddrtiminga0 = 0x80241d22,
- .ddrtimingb0 = 0x15050f08,
+ .ddrtiminga0 = {
+ 0x8010100d,
+ },
+ .ddrtimingb0 = {
+ 0x08020b04,
+ },
.ddrtimingc0 = {
0x00000602,
},
- .devtodev0 = 0x00002122,
+ .devtodev0 = {
+ 0x00002562,
+ },
.ddrmode = {
0x0000004c,
},
@@ -41,15 +49,23 @@
.row_3_4 = 0x0,
.cs0_row = 0xF,
.cs1_row = 0xF,
+ .cs0_high16bit_row = 0xF,
+ .cs1_high16bit_row = 0xF,
.ddrconfig = 1,
},
{
- .ddrtiminga0 = 0x80241d22,
- .ddrtimingb0 = 0x15050f08,
+ .ddrtiminga0 = {
+ 0x8010100d,
+ },
+ .ddrtimingb0 = {
+ 0x08020b04,
+ },
.ddrtimingc0 = {
0x00000602,
},
- .devtodev0 = 0x00002122,
+ .devtodev0 = {
+ 0x00002562,
+ },
.ddrmode = {
0x0000004c,
},
diff --git a/drivers/ram/rockchip/sdram-rk3399-lpddr4-800.inc b/drivers/ram/rockchip/sdram-rk3399-lpddr4-800.inc
index d8ae3359a3..7d11b4c563 100644
--- a/drivers/ram/rockchip/sdram-rk3399-lpddr4-800.inc
+++ b/drivers/ram/rockchip/sdram-rk3399-lpddr4-800.inc
@@ -16,15 +16,23 @@
.row_3_4 = 0x0,
.cs0_row = 0xF,
.cs1_row = 0xF,
+ .cs0_high16bit_row = 0xF,
+ .cs1_high16bit_row = 0xF,
.ddrconfig = 1,
},
{
- .ddrtiminga0 = 0x80241d22,
- .ddrtimingb0 = 0x15050f08,
+ .ddrtiminga0 = {
+ 0x801c1819,
+ },
+ .ddrtimingb0 = {
+ 0x10040c05,
+ },
.ddrtimingc0 = {
0x00000602,
},
- .devtodev0 = 0x00002122,
+ .devtodev0 = {
+ 0x00002672,
+ },
.ddrmode = {
0x0000004c,
},
@@ -41,15 +49,23 @@
.row_3_4 = 0x0,
.cs0_row = 0xF,
.cs1_row = 0xF,
+ .cs0_high16bit_row = 0xF,
+ .cs1_high16bit_row = 0xF,
.ddrconfig = 1,
},
{
- .ddrtiminga0 = 0x80241d22,
- .ddrtimingb0 = 0x15050f08,
+ .ddrtiminga0 = {
+ 0x80241d22,
+ },
+ .ddrtimingb0 = {
+ 0x15050f08,
+ },
.ddrtimingc0 = {
0x00000602,
},
- .devtodev0 = 0x00002122,
+ .devtodev0 = {
+ 0x00002122,
+ },
.ddrmode = {
0x0000004c,
},
diff --git a/drivers/ram/rockchip/sdram_common.c b/drivers/ram/rockchip/sdram_common.c
new file mode 100644
index 0000000000..6bc51572b2
--- /dev/null
+++ b/drivers/ram/rockchip/sdram_common.c
@@ -0,0 +1,429 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2018 Rockchip Electronics Co., Ltd.
+ */
+
+#include <common.h>
+#include <debug_uart.h>
+#include <ram.h>
+#include <asm/io.h>
+#include <asm/arch-rockchip/sdram.h>
+#include <asm/arch-rockchip/sdram_common.h>
+
+#ifdef CONFIG_RAM_ROCKCHIP_DEBUG
+void sdram_print_dram_type(unsigned char dramtype)
+{
+ switch (dramtype) {
+ case DDR3:
+ printascii("DDR3");
+ break;
+ case DDR4:
+ printascii("DDR4");
+ break;
+ case LPDDR2:
+ printascii("LPDDR2");
+ break;
+ case LPDDR3:
+ printascii("LPDDR3");
+ break;
+ case LPDDR4:
+ printascii("LPDDR4");
+ break;
+ default:
+ printascii("Unknown Device");
+ break;
+ }
+}
+
+void sdram_print_ddr_info(struct sdram_cap_info *cap_info,
+ struct sdram_base_params *base)
+{
+ u64 cap;
+ u32 bg;
+
+ bg = (cap_info->dbw == 0) ? 2 : 1;
+
+ sdram_print_dram_type(base->dramtype);
+
+ printascii(", ");
+ printdec(base->ddr_freq);
+ printascii("MHz\n");
+
+ printascii("BW=");
+ printdec(8 << cap_info->bw);
+ printascii(" Col=");
+ printdec(cap_info->col);
+ printascii(" Bk=");
+ printdec(0x1 << cap_info->bk);
+ if (base->dramtype == DDR4) {
+ printascii(" BG=");
+ printdec(1 << bg);
+ }
+ printascii(" CS0 Row=");
+ printdec(cap_info->cs0_row);
+ if (cap_info->cs0_high16bit_row !=
+ cap_info->cs0_row) {
+ printascii("/");
+ printdec(cap_info->cs0_high16bit_row);
+ }
+ if (cap_info->rank > 1) {
+ printascii(" CS1 Row=");
+ printdec(cap_info->cs1_row);
+ if (cap_info->cs1_high16bit_row !=
+ cap_info->cs1_row) {
+ printascii("/");
+ printdec(cap_info->cs1_high16bit_row);
+ }
+ }
+ printascii(" CS=");
+ printdec(cap_info->rank);
+ printascii(" Die BW=");
+ printdec(8 << cap_info->dbw);
+
+ cap = sdram_get_cs_cap(cap_info, 3, base->dramtype);
+ if (cap_info->row_3_4)
+ cap = cap * 3 / 4;
+
+ printascii(" Size=");
+ printdec(cap >> 20);
+ printascii("MB\n");
+}
+
+void sdram_print_stride(unsigned int stride)
+{
+ switch (stride) {
+ case 0xc:
+ printf("128B stride\n");
+ break;
+ case 5:
+ case 9:
+ case 0xd:
+ case 0x11:
+ case 0x19:
+ printf("256B stride\n");
+ break;
+ case 0xa:
+ case 0xe:
+ case 0x12:
+ printf("512B stride\n");
+ break;
+ case 0xf:
+ printf("4K stride\n");
+ break;
+ case 0x1f:
+ printf("32MB + 256B stride\n");
+ break;
+ default:
+ printf("no stride\n");
+ }
+}
+#endif
+
+/*
+ * cs: 0:cs0
+ * 1:cs1
+ * else cs0+cs1
+ * note: it didn't consider about row_3_4
+ */
+u64 sdram_get_cs_cap(struct sdram_cap_info *cap_info, u32 cs, u32 dram_type)
+{
+ u32 bg;
+ u64 cap[2];
+
+ if (dram_type == DDR4)
+ /* DDR4 8bit dram BG = 2(4bank groups),
+ * 16bit dram BG = 1 (2 bank groups)
+ */
+ bg = (cap_info->dbw == 0) ? 2 : 1;
+ else
+ bg = 0;
+ cap[0] = 1llu << (cap_info->bw + cap_info->col +
+ bg + cap_info->bk + cap_info->cs0_row);
+
+ if (cap_info->rank == 2)
+ cap[1] = 1llu << (cap_info->bw + cap_info->col +
+ bg + cap_info->bk + cap_info->cs1_row);
+ else
+ cap[1] = 0;
+
+ if (cs == 0)
+ return cap[0];
+ else if (cs == 1)
+ return cap[1];
+ else
+ return (cap[0] + cap[1]);
+}
+
+/* n: Unit bytes */
+void sdram_copy_to_reg(u32 *dest, const u32 *src, u32 n)
+{
+ int i;
+
+ for (i = 0; i < n / sizeof(u32); i++) {
+ writel(*src, dest);
+ src++;
+ dest++;
+ }
+}
+
+void sdram_org_config(struct sdram_cap_info *cap_info,
+ struct sdram_base_params *base,
+ u32 *p_os_reg2, u32 *p_os_reg3, u32 channel)
+{
+ *p_os_reg2 |= SYS_REG_ENC_DDRTYPE(base->dramtype);
+ *p_os_reg2 |= SYS_REG_ENC_NUM_CH(base->num_channels);
+
+ *p_os_reg2 |= SYS_REG_ENC_ROW_3_4(cap_info->row_3_4, channel);
+ *p_os_reg2 |= SYS_REG_ENC_CHINFO(channel);
+ *p_os_reg2 |= SYS_REG_ENC_RANK(cap_info->rank, channel);
+ *p_os_reg2 |= SYS_REG_ENC_COL(cap_info->col, channel);
+ *p_os_reg2 |= SYS_REG_ENC_BK(cap_info->bk, channel);
+ *p_os_reg2 |= SYS_REG_ENC_BW(cap_info->bw, channel);
+ *p_os_reg2 |= SYS_REG_ENC_DBW(cap_info->dbw, channel);
+
+ SYS_REG_ENC_CS0_ROW(cap_info->cs0_row, *p_os_reg2, *p_os_reg3, channel);
+ if (cap_info->cs1_row)
+ SYS_REG_ENC_CS1_ROW(cap_info->cs1_row, *p_os_reg2,
+ *p_os_reg3, channel);
+ *p_os_reg3 |= SYS_REG_ENC_CS1_COL(cap_info->col, channel);
+ *p_os_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION);
+}
+
+int sdram_detect_bw(struct sdram_cap_info *cap_info)
+{
+ return 0;
+}
+
+int sdram_detect_cs(struct sdram_cap_info *cap_info)
+{
+ return 0;
+}
+
+int sdram_detect_col(struct sdram_cap_info *cap_info,
+ u32 coltmp)
+{
+ void __iomem *test_addr;
+ u32 col;
+ u32 bw = cap_info->bw;
+
+ for (col = coltmp; col >= 9; col -= 1) {
+ writel(0, CONFIG_SYS_SDRAM_BASE);
+ test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
+ (1ul << (col + bw - 1ul)));
+ writel(PATTERN, test_addr);
+ if ((readl(test_addr) == PATTERN) &&
+ (readl(CONFIG_SYS_SDRAM_BASE) == 0))
+ break;
+ }
+ if (col == 8) {
+ printascii("col error\n");
+ return -1;
+ }
+
+ cap_info->col = col;
+
+ return 0;
+}
+
+int sdram_detect_bank(struct sdram_cap_info *cap_info,
+ u32 coltmp, u32 bktmp)
+{
+ void __iomem *test_addr;
+ u32 bk;
+ u32 bw = cap_info->bw;
+
+ test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
+ (1ul << (coltmp + bktmp + bw - 1ul)));
+ writel(0, CONFIG_SYS_SDRAM_BASE);
+ writel(PATTERN, test_addr);
+ if ((readl(test_addr) == PATTERN) &&
+ (readl(CONFIG_SYS_SDRAM_BASE) == 0))
+ bk = 3;
+ else
+ bk = 2;
+
+ cap_info->bk = bk;
+
+ return 0;
+}
+
+/* detect bg for ddr4 */
+int sdram_detect_bg(struct sdram_cap_info *cap_info,
+ u32 coltmp)
+{
+ void __iomem *test_addr;
+ u32 dbw;
+ u32 bw = cap_info->bw;
+
+ test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
+ (1ul << (coltmp + bw + 1ul)));
+ writel(0, CONFIG_SYS_SDRAM_BASE);
+ writel(PATTERN, test_addr);
+ if ((readl(test_addr) == PATTERN) &&
+ (readl(CONFIG_SYS_SDRAM_BASE) == 0))
+ dbw = 0;
+ else
+ dbw = 1;
+
+ cap_info->dbw = dbw;
+
+ return 0;
+}
+
+/* detect dbw for ddr3,lpddr2,lpddr3,lpddr4 */
+int sdram_detect_dbw(struct sdram_cap_info *cap_info, u32 dram_type)
+{
+ u32 row, col, bk, bw, cs_cap, cs;
+ u32 die_bw_0 = 0, die_bw_1 = 0;
+
+ if (dram_type == DDR3 || dram_type == LPDDR4) {
+ cap_info->dbw = 1;
+ } else if (dram_type == LPDDR3 || dram_type == LPDDR2) {
+ row = cap_info->cs0_row;
+ col = cap_info->col;
+ bk = cap_info->bk;
+ cs = cap_info->rank;
+ bw = cap_info->bw;
+ cs_cap = (1 << (row + col + bk + bw - 20));
+ if (bw == 2) {
+ if (cs_cap <= 0x2000000) /* 256Mb */
+ die_bw_0 = (col < 9) ? 2 : 1;
+ else if (cs_cap <= 0x10000000) /* 2Gb */
+ die_bw_0 = (col < 10) ? 2 : 1;
+ else if (cs_cap <= 0x40000000) /* 8Gb */
+ die_bw_0 = (col < 11) ? 2 : 1;
+ else
+ die_bw_0 = (col < 12) ? 2 : 1;
+ if (cs > 1) {
+ row = cap_info->cs1_row;
+ cs_cap = (1 << (row + col + bk + bw - 20));
+ if (cs_cap <= 0x2000000) /* 256Mb */
+ die_bw_0 = (col < 9) ? 2 : 1;
+ else if (cs_cap <= 0x10000000) /* 2Gb */
+ die_bw_0 = (col < 10) ? 2 : 1;
+ else if (cs_cap <= 0x40000000) /* 8Gb */
+ die_bw_0 = (col < 11) ? 2 : 1;
+ else
+ die_bw_0 = (col < 12) ? 2 : 1;
+ }
+ } else {
+ die_bw_1 = 1;
+ die_bw_0 = 1;
+ }
+ cap_info->dbw = (die_bw_0 > die_bw_1) ? die_bw_0 : die_bw_1;
+ }
+
+ return 0;
+}
+
+int sdram_detect_row(struct sdram_cap_info *cap_info,
+ u32 coltmp, u32 bktmp, u32 rowtmp)
+{
+ u32 row;
+ u32 bw = cap_info->bw;
+ void __iomem *test_addr;
+
+ for (row = rowtmp; row > 12; row--) {
+ writel(0, CONFIG_SYS_SDRAM_BASE);
+ test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
+ (1ul << (row + bktmp + coltmp + bw - 1ul)));
+ writel(PATTERN, test_addr);
+ if ((readl(test_addr) == PATTERN) &&
+ (readl(CONFIG_SYS_SDRAM_BASE) == 0))
+ break;
+ }
+ if (row == 12) {
+ printascii("row error");
+ return -1;
+ }
+
+ cap_info->cs0_row = row;
+
+ return 0;
+}
+
+int sdram_detect_row_3_4(struct sdram_cap_info *cap_info,
+ u32 coltmp, u32 bktmp)
+{
+ u32 row_3_4;
+ u32 bw = cap_info->bw;
+ u32 row = cap_info->cs0_row;
+ void __iomem *test_addr, *test_addr1;
+
+ test_addr = CONFIG_SYS_SDRAM_BASE;
+ test_addr1 = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
+ (0x3ul << (row + bktmp + coltmp + bw - 1ul - 1ul)));
+
+ writel(0, test_addr);
+ writel(PATTERN, test_addr1);
+ if ((readl(test_addr) == 0) && (readl(test_addr1) == PATTERN))
+ row_3_4 = 0;
+ else
+ row_3_4 = 1;
+
+ cap_info->row_3_4 = row_3_4;
+
+ return 0;
+}
+
+int sdram_detect_high_row(struct sdram_cap_info *cap_info)
+{
+ cap_info->cs0_high16bit_row = cap_info->cs0_row;
+ cap_info->cs1_high16bit_row = cap_info->cs1_row;
+
+ return 0;
+}
+
+int sdram_detect_cs1_row(struct sdram_cap_info *cap_info, u32 dram_type)
+{
+ void __iomem *test_addr;
+ u32 row = 0, bktmp, coltmp, bw;
+ ulong cs0_cap;
+ u32 byte_mask;
+
+ if (cap_info->rank == 2) {
+ cs0_cap = sdram_get_cs_cap(cap_info, 0, dram_type);
+
+ if (dram_type == DDR4) {
+ if (cap_info->dbw == 0)
+ bktmp = cap_info->bk + 2;
+ else
+ bktmp = cap_info->bk + 1;
+ } else {
+ bktmp = cap_info->bk;
+ }
+ bw = cap_info->bw;
+ coltmp = cap_info->col;
+
+ /*
+ * because px30 support axi split,min bandwidth
+ * is 8bit. if cs0 is 32bit, cs1 may 32bit or 16bit
+ * so we check low 16bit data when detect cs1 row.
+ * if cs0 is 16bit/8bit, we check low 8bit data.
+ */
+ if (bw == 2)
+ byte_mask = 0xFFFF;
+ else
+ byte_mask = 0xFF;
+
+ /* detect cs1 row */
+ for (row = cap_info->cs0_row; row > 12; row--) {
+ test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
+ cs0_cap +
+ (1ul << (row + bktmp + coltmp + bw - 1ul)));
+ writel(0, CONFIG_SYS_SDRAM_BASE + cs0_cap);
+ writel(PATTERN, test_addr);
+
+ if (((readl(test_addr) & byte_mask) ==
+ (PATTERN & byte_mask)) &&
+ ((readl(CONFIG_SYS_SDRAM_BASE + cs0_cap) &
+ byte_mask) == 0)) {
+ break;
+ }
+ }
+ }
+
+ cap_info->cs1_row = row;
+
+ return 0;
+}
diff --git a/drivers/ram/rockchip/sdram_debug.c b/drivers/ram/rockchip/sdram_debug.c
deleted file mode 100644
index 9cf662675b..0000000000
--- a/drivers/ram/rockchip/sdram_debug.c
+++ /dev/null
@@ -1,147 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
-/*
- * (C) Copyright 2019 Rockchip Electronics Co., Ltd
- * (C) Copyright 2019 Amarula Solutions.
- * Author: Jagan Teki <jagan@amarulasolutions.com>
- */
-
-#include <common.h>
-#include <debug_uart.h>
-#include <asm/arch-rockchip/sdram_common.h>
-
-void sdram_print_dram_type(unsigned char dramtype)
-{
- switch (dramtype) {
- case DDR3:
- printascii("DDR3");
- break;
- case DDR4:
- printascii("DDR4");
- break;
- case LPDDR2:
- printascii("LPDDR2");
- break;
- case LPDDR3:
- printascii("LPDDR3");
- break;
- case LPDDR4:
- printascii("LPDDR4");
- break;
- default:
- printascii("Unknown Device");
- break;
- }
-}
-
-/**
- * cs = 0, cs0
- * cs = 1, cs1
- * cs => 2, cs0+cs1
- * note: it didn't consider about row_3_4
- */
-u64 sdram_get_cs_cap(struct sdram_cap_info *cap_info, u32 cs, u32 dram_type)
-{
- u32 bg;
- u64 cap[2];
-
- if (dram_type == DDR4)
- /* DDR4 8bit dram BG = 2(4bank groups),
- * 16bit dram BG = 1 (2 bank groups)
- */
- bg = (cap_info->dbw == 0) ? 2 : 1;
- else
- bg = 0;
-
- cap[0] = 1llu << (cap_info->bw + cap_info->col +
- bg + cap_info->bk + cap_info->cs0_row);
-
- if (cap_info->rank == 2)
- cap[1] = 1llu << (cap_info->bw + cap_info->col +
- bg + cap_info->bk + cap_info->cs1_row);
- else
- cap[1] = 0;
-
- if (cs == 0)
- return cap[0];
- else if (cs == 1)
- return cap[1];
- else
- return (cap[0] + cap[1]);
-}
-
-void sdram_print_ddr_info(struct sdram_cap_info *cap_info,
- struct sdram_base_params *base)
-{
- u32 bg, cap;
-
- bg = (cap_info->dbw == 0) ? 2 : 1;
-
- sdram_print_dram_type(base->dramtype);
-
- printascii(", ");
- printdec(base->ddr_freq);
- printascii("MHz\n");
-
- printascii("BW=");
- printdec(8 << cap_info->bw);
-
- printascii(" Col=");
- printdec(cap_info->col);
-
- printascii(" Bk=");
- printdec(0x1 << cap_info->bk);
- if (base->dramtype == DDR4) {
- printascii(" BG=");
- printdec(1 << bg);
- }
-
- printascii(" CS0 Row=");
- printdec(cap_info->cs0_row);
- if (cap_info->rank > 1) {
- printascii(" CS1 Row=");
- printdec(cap_info->cs1_row);
- }
-
- printascii(" CS=");
- printdec(cap_info->rank);
-
- printascii(" Die BW=");
- printdec(8 << cap_info->dbw);
-
- cap = sdram_get_cs_cap(cap_info, 3, base->dramtype);
- if (cap_info->row_3_4)
- cap = cap * 3 / 4;
-
- printascii(" Size=");
- printdec(cap >> 20);
- printascii("MB\n");
-}
-
-void sdram_print_stride(unsigned int stride)
-{
- switch (stride) {
- case 0xc:
- printf("128B stride\n");
- break;
- case 5:
- case 9:
- case 0xd:
- case 0x11:
- case 0x19:
- printf("256B stride\n");
- break;
- case 0xa:
- case 0xe:
- case 0x12:
- printf("512B stride\n");
- break;
- case 0xf:
- printf("4K stride\n");
- break;
- case 0x1f:
- printf("32MB + 256B stride\n");
- break;
- default:
- printf("no stride\n");
- }
-}
diff --git a/drivers/ram/rockchip/sdram_pctl_px30.c b/drivers/ram/rockchip/sdram_pctl_px30.c
new file mode 100644
index 0000000000..1839cebb67
--- /dev/null
+++ b/drivers/ram/rockchip/sdram_pctl_px30.c
@@ -0,0 +1,205 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2018 Rockchip Electronics Co., Ltd.
+ */
+
+#include <common.h>
+#include <ram.h>
+#include <asm/io.h>
+#include <asm/arch-rockchip/sdram.h>
+#include <asm/arch-rockchip/sdram_pctl_px30.h>
+
+/*
+ * rank = 1: cs0
+ * rank = 2: cs1
+ */
+void pctl_read_mr(void __iomem *pctl_base, u32 rank, u32 mr_num)
+{
+ writel((rank << 4) | (1 << 0), pctl_base + DDR_PCTL2_MRCTRL0);
+ writel((mr_num << 8), pctl_base + DDR_PCTL2_MRCTRL1);
+ setbits_le32(pctl_base + DDR_PCTL2_MRCTRL0, 1u << 31);
+ while (readl(pctl_base + DDR_PCTL2_MRCTRL0) & (1u << 31))
+ continue;
+ while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY)
+ continue;
+}
+
+/* rank = 1: cs0
+ * rank = 2: cs1
+ * rank = 3: cs0 & cs1
+ * note: be careful of keep mr original val
+ */
+int pctl_write_mr(void __iomem *pctl_base, u32 rank, u32 mr_num, u32 arg,
+ u32 dramtype)
+{
+ while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY)
+ continue;
+ if (dramtype == DDR3 || dramtype == DDR4) {
+ writel((mr_num << 12) | (rank << 4) | (0 << 0),
+ pctl_base + DDR_PCTL2_MRCTRL0);
+ writel(arg, pctl_base + DDR_PCTL2_MRCTRL1);
+ } else {
+ writel((rank << 4) | (0 << 0),
+ pctl_base + DDR_PCTL2_MRCTRL0);
+ writel((mr_num << 8) | (arg & 0xff),
+ pctl_base + DDR_PCTL2_MRCTRL1);
+ }
+
+ setbits_le32(pctl_base + DDR_PCTL2_MRCTRL0, 1u << 31);
+ while (readl(pctl_base + DDR_PCTL2_MRCTRL0) & (1u << 31))
+ continue;
+ while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY)
+ continue;
+
+ return 0;
+}
+
+/*
+ * rank : 1:cs0, 2:cs1, 3:cs0&cs1
+ * vrefrate: 4500: 45%,
+ */
+int pctl_write_vrefdq(void __iomem *pctl_base, u32 rank, u32 vrefrate,
+ u32 dramtype)
+{
+ u32 tccd_l, value;
+ u32 dis_auto_zq = 0;
+
+ if (dramtype != DDR4 || vrefrate < 4500 ||
+ vrefrate > 9200)
+ return (-1);
+
+ tccd_l = (readl(pctl_base + DDR_PCTL2_DRAMTMG4) >> 16) & 0xf;
+ tccd_l = (tccd_l - 4) << 10;
+
+ if (vrefrate > 7500) {
+ /* range 1 */
+ value = ((vrefrate - 6000) / 65) | tccd_l;
+ } else {
+ /* range 2 */
+ value = ((vrefrate - 4500) / 65) | tccd_l | (1 << 6);
+ }
+
+ dis_auto_zq = pctl_dis_zqcs_aref(pctl_base);
+
+ /* enable vrefdq calibratin */
+ pctl_write_mr(pctl_base, rank, 6, value | (1 << 7), dramtype);
+ udelay(1);/* tvrefdqe */
+ /* write vrefdq value */
+ pctl_write_mr(pctl_base, rank, 6, value | (1 << 7), dramtype);
+ udelay(1);/* tvref_time */
+ pctl_write_mr(pctl_base, rank, 6, value | (0 << 7), dramtype);
+ udelay(1);/* tvrefdqx */
+
+ pctl_rest_zqcs_aref(pctl_base, dis_auto_zq);
+
+ return 0;
+}
+
+static int upctl2_update_ref_reg(void __iomem *pctl_base)
+{
+ u32 ret;
+
+ ret = readl(pctl_base + DDR_PCTL2_RFSHCTL3) ^ (1 << 1);
+ writel(ret, pctl_base + DDR_PCTL2_RFSHCTL3);
+
+ return 0;
+}
+
+u32 pctl_dis_zqcs_aref(void __iomem *pctl_base)
+{
+ u32 dis_auto_zq = 0;
+
+ /* disable zqcs */
+ if (!(readl(pctl_base + DDR_PCTL2_ZQCTL0) &
+ (1ul << 31))) {
+ dis_auto_zq = 1;
+ setbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1 << 31);
+ }
+
+ /* disable auto refresh */
+ setbits_le32(pctl_base + DDR_PCTL2_RFSHCTL3, 1);
+
+ upctl2_update_ref_reg(pctl_base);
+
+ return dis_auto_zq;
+}
+
+void pctl_rest_zqcs_aref(void __iomem *pctl_base, u32 dis_auto_zq)
+{
+ /* restore zqcs */
+ if (dis_auto_zq)
+ clrbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1 << 31);
+
+ /* restore auto refresh */
+ clrbits_le32(pctl_base + DDR_PCTL2_RFSHCTL3, 1);
+
+ upctl2_update_ref_reg(pctl_base);
+}
+
+u32 pctl_remodify_sdram_params(struct ddr_pctl_regs *pctl_regs,
+ struct sdram_cap_info *cap_info,
+ u32 dram_type)
+{
+ u32 tmp = 0, tmp_adr = 0, i;
+
+ for (i = 0; pctl_regs->pctl[i][0] != 0xFFFFFFFF; i++) {
+ if (pctl_regs->pctl[i][0] == 0) {
+ tmp = pctl_regs->pctl[i][1];/* MSTR */
+ tmp_adr = i;
+ }
+ }
+
+ tmp &= ~((3ul << 30) | (3ul << 24) | (3ul << 12));
+
+ switch (cap_info->dbw) {
+ case 2:
+ tmp |= (3ul << 30);
+ break;
+ case 1:
+ tmp |= (2ul << 30);
+ break;
+ case 0:
+ default:
+ tmp |= (1ul << 30);
+ break;
+ }
+
+ /*
+ * If DDR3 or DDR4 MSTR.active_ranks=1,
+ * it will gate memory clock when enter power down.
+ * Force set active_ranks to 3 to workaround it.
+ */
+ if (cap_info->rank == 2 || dram_type == DDR3 ||
+ dram_type == DDR4)
+ tmp |= 3 << 24;
+ else
+ tmp |= 1 << 24;
+
+ tmp |= (2 - cap_info->bw) << 12;
+
+ pctl_regs->pctl[tmp_adr][1] = tmp;
+
+ return 0;
+}
+
+int pctl_cfg(void __iomem *pctl_base, struct ddr_pctl_regs *pctl_regs,
+ u32 sr_idle, u32 pd_idle)
+{
+ u32 i;
+
+ for (i = 0; pctl_regs->pctl[i][0] != 0xFFFFFFFF; i++) {
+ writel(pctl_regs->pctl[i][1],
+ pctl_base + pctl_regs->pctl[i][0]);
+ }
+ clrsetbits_le32(pctl_base + DDR_PCTL2_PWRTMG,
+ (0xff << 16) | 0x1f,
+ ((sr_idle & 0xff) << 16) | (pd_idle & 0x1f));
+
+ clrsetbits_le32(pctl_base + DDR_PCTL2_HWLPCTL,
+ 0xfff << 16,
+ 5 << 16);
+ /* disable zqcs */
+ setbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1u << 31);
+
+ return 0;
+}
diff --git a/drivers/ram/rockchip/sdram_phy_px30.c b/drivers/ram/rockchip/sdram_phy_px30.c
new file mode 100644
index 0000000000..5de73770a8
--- /dev/null
+++ b/drivers/ram/rockchip/sdram_phy_px30.c
@@ -0,0 +1,205 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2018 Rockchip Electronics Co., Ltd.
+ */
+
+#include <common.h>
+#include <ram.h>
+#include <asm/io.h>
+#include <asm/arch-rockchip/sdram.h>
+#include <asm/arch-rockchip/sdram_common.h>
+#include <asm/arch-rockchip/sdram_phy_px30.h>
+
+static void sdram_phy_dll_bypass_set(void __iomem *phy_base, u32 freq)
+{
+ u32 tmp;
+ u32 i, j;
+ u32 dqs_dll_freq;
+
+ setbits_le32(PHY_REG(phy_base, 0x13), 1 << 4);
+ clrbits_le32(PHY_REG(phy_base, 0x14), 1 << 3);
+ for (i = 0; i < 4; i++) {
+ j = 0x26 + i * 0x10;
+ setbits_le32(PHY_REG(phy_base, j), 1 << 4);
+ clrbits_le32(PHY_REG(phy_base, j + 0x1), 1 << 3);
+ }
+
+ if (freq <= 400)
+ /* DLL bypass */
+ setbits_le32(PHY_REG(phy_base, 0xa4), 0x1f);
+ else
+ clrbits_le32(PHY_REG(phy_base, 0xa4), 0x1f);
+
+ #ifdef CONFIG_ROCKCHIP_RK3328
+ dqs_dll_freq = 680;
+ #else
+ dqs_dll_freq = 801;
+ #endif
+
+ if (freq <= dqs_dll_freq)
+ tmp = 2;
+ else
+ tmp = 1;
+
+ for (i = 0; i < 4; i++) {
+ j = 0x28 + i * 0x10;
+ writel(tmp, PHY_REG(phy_base, j));
+ }
+}
+
+static void sdram_phy_set_ds_odt(void __iomem *phy_base,
+ u32 dram_type)
+{
+ u32 cmd_drv, clk_drv, dqs_drv, dqs_odt;
+ u32 i, j;
+
+ if (dram_type == DDR3) {
+ cmd_drv = PHY_DDR3_RON_RTT_34ohm;
+ clk_drv = PHY_DDR3_RON_RTT_45ohm;
+ dqs_drv = PHY_DDR3_RON_RTT_34ohm;
+ dqs_odt = PHY_DDR3_RON_RTT_225ohm;
+ } else {
+ cmd_drv = PHY_DDR4_LPDDR3_RON_RTT_34ohm;
+ clk_drv = PHY_DDR4_LPDDR3_RON_RTT_43ohm;
+ dqs_drv = PHY_DDR4_LPDDR3_RON_RTT_34ohm;
+ if (dram_type == LPDDR2)
+ dqs_odt = PHY_DDR4_LPDDR3_RON_RTT_DISABLE;
+ else
+ dqs_odt = PHY_DDR4_LPDDR3_RON_RTT_240ohm;
+ }
+ /* DS */
+ writel(cmd_drv, PHY_REG(phy_base, 0x11));
+ clrsetbits_le32(PHY_REG(phy_base, 0x12), 0x1f << 3, cmd_drv << 3);
+ writel(clk_drv, PHY_REG(phy_base, 0x16));
+ writel(clk_drv, PHY_REG(phy_base, 0x18));
+
+ for (i = 0; i < 4; i++) {
+ j = 0x20 + i * 0x10;
+ writel(dqs_drv, PHY_REG(phy_base, j));
+ writel(dqs_drv, PHY_REG(phy_base, j + 0xf));
+ /* ODT */
+ writel(dqs_odt, PHY_REG(phy_base, j + 0x1));
+ writel(dqs_odt, PHY_REG(phy_base, j + 0xe));
+ }
+}
+
+void phy_soft_reset(void __iomem *phy_base)
+{
+ clrbits_le32(PHY_REG(phy_base, 0), 0x3 << 2);
+ udelay(1);
+ setbits_le32(PHY_REG(phy_base, 0), ANALOG_DERESET);
+ udelay(5);
+ setbits_le32(PHY_REG(phy_base, 0), DIGITAL_DERESET);
+ udelay(1);
+}
+
+void phy_dram_set_bw(void __iomem *phy_base, u32 bw)
+{
+ if (bw == 2) {
+ clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 0xf << 4);
+ setbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
+ setbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
+ } else if (bw == 1) {
+ clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 3 << 4);
+ clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
+ clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
+ } else if (bw == 0) {
+ clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 1 << 4);
+ clrbits_le32(PHY_REG(phy_base, 0x36), 1 << 3);
+ clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
+ clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
+ }
+
+ phy_soft_reset(phy_base);
+}
+
+int phy_data_training(void __iomem *phy_base, u32 cs, u32 dramtype)
+{
+ u32 ret;
+ u32 odt_val;
+ u32 i, j;
+
+ odt_val = readl(PHY_REG(phy_base, 0x2e));
+
+ for (i = 0; i < 4; i++) {
+ j = 0x20 + i * 0x10;
+ writel(PHY_DDR3_RON_RTT_225ohm, PHY_REG(phy_base, j + 0x1));
+ writel(0, PHY_REG(phy_base, j + 0xe));
+ }
+
+ if (dramtype == DDR4) {
+ clrsetbits_le32(PHY_REG(phy_base, 0x29), 0x3, 0);
+ clrsetbits_le32(PHY_REG(phy_base, 0x39), 0x3, 0);
+ clrsetbits_le32(PHY_REG(phy_base, 0x49), 0x3, 0);
+ clrsetbits_le32(PHY_REG(phy_base, 0x59), 0x3, 0);
+ }
+ /* choose training cs */
+ clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs));
+ /* enable gate training */
+ clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs) | 1);
+ udelay(50);
+ ret = readl(PHY_REG(phy_base, 0xff));
+ /* disable gate training */
+ clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs) | 0);
+ #ifndef CONFIG_ROCKCHIP_RK3328
+ clrbits_le32(PHY_REG(phy_base, 2), 0x30);
+ #endif
+
+ if (dramtype == DDR4) {
+ clrsetbits_le32(PHY_REG(phy_base, 0x29), 0x3, 0x2);
+ clrsetbits_le32(PHY_REG(phy_base, 0x39), 0x3, 0x2);
+ clrsetbits_le32(PHY_REG(phy_base, 0x49), 0x3, 0x2);
+ clrsetbits_le32(PHY_REG(phy_base, 0x59), 0x3, 0x2);
+ }
+
+ if (ret & 0x10) {
+ ret = -1;
+ } else {
+ ret = (ret & 0xf) ^ (readl(PHY_REG(phy_base, 0)) >> 4);
+ ret = (ret == 0) ? 0 : -1;
+ }
+
+ for (i = 0; i < 4; i++) {
+ j = 0x20 + i * 0x10;
+ writel(odt_val, PHY_REG(phy_base, j + 0x1));
+ writel(odt_val, PHY_REG(phy_base, j + 0xe));
+ }
+ return ret;
+}
+
+void phy_cfg(void __iomem *phy_base,
+ struct ddr_phy_regs *phy_regs, struct ddr_phy_skew *skew,
+ struct sdram_base_params *base, u32 bw)
+{
+ u32 i;
+
+ sdram_phy_dll_bypass_set(phy_base, base->ddr_freq);
+ for (i = 0; phy_regs->phy[i][0] != 0xFFFFFFFF; i++) {
+ writel(phy_regs->phy[i][1],
+ phy_base + phy_regs->phy[i][0]);
+ }
+ if (bw == 2) {
+ clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 0xf << 4);
+ } else if (bw == 1) {
+ clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 3 << 4);
+ /* disable DQS2,DQS3 tx dll for saving power */
+ clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
+ clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
+ } else {
+ clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 1 << 4);
+ /* disable DQS2,DQS3 tx dll for saving power */
+ clrbits_le32(PHY_REG(phy_base, 0x36), 1 << 3);
+ clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
+ clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
+ }
+ sdram_phy_set_ds_odt(phy_base, base->dramtype);
+
+ /* deskew */
+ setbits_le32(PHY_REG(phy_base, 2), 8);
+ sdram_copy_to_reg(PHY_REG(phy_base, 0xb0),
+ &skew->a0_a1_skew[0], 15 * 4);
+ sdram_copy_to_reg(PHY_REG(phy_base, 0x70),
+ &skew->cs0_dm0_skew[0], 44 * 4);
+ sdram_copy_to_reg(PHY_REG(phy_base, 0xc0),
+ &skew->cs1_dm0_skew[0], 44 * 4);
+}
diff --git a/drivers/ram/rockchip/sdram_px30.c b/drivers/ram/rockchip/sdram_px30.c
new file mode 100644
index 0000000000..729255493a
--- /dev/null
+++ b/drivers/ram/rockchip/sdram_px30.c
@@ -0,0 +1,751 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2018 Rockchip Electronics Co., Ltd.
+ */
+
+#include <common.h>
+#include <debug_uart.h>
+#include <dm.h>
+#include <ram.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_px30.h>
+#include <asm/arch-rockchip/grf_px30.h>
+#include <asm/arch-rockchip/hardware.h>
+#include <asm/arch-rockchip/sdram.h>
+#include <asm/arch-rockchip/sdram_px30.h>
+
+struct dram_info {
+#ifdef CONFIG_TPL_BUILD
+ struct ddr_pctl_regs *pctl;
+ struct ddr_phy_regs *phy;
+ struct px30_cru *cru;
+ struct msch_regs *msch;
+ struct px30_ddr_grf_regs *ddr_grf;
+ struct px30_grf *grf;
+#endif
+ struct ram_info info;
+ struct px30_pmugrf *pmugrf;
+};
+
+#ifdef CONFIG_TPL_BUILD
+
+u8 ddr_cfg_2_rbc[] = {
+ /*
+ * [6:4] max row: 13+n
+ * [3] bank(0:4bank,1:8bank)
+ * [2:0] col(10+n)
+ */
+ ((5 << 4) | (1 << 3) | 0), /* 0 */
+ ((5 << 4) | (1 << 3) | 1), /* 1 */
+ ((4 << 4) | (1 << 3) | 2), /* 2 */
+ ((3 << 4) | (1 << 3) | 3), /* 3 */
+ ((2 << 4) | (1 << 3) | 4), /* 4 */
+ ((5 << 4) | (0 << 3) | 2), /* 5 */
+ ((4 << 4) | (1 << 3) | 2), /* 6 */
+ /*((0<<3)|3),*/ /* 12 for ddr4 */
+ /*((1<<3)|1),*/ /* 13 B,C exchange for rkvdec */
+};
+
+/*
+ * for ddr4 if ddrconfig=7, upctl should set 7 and noc should
+ * set to 1 for more efficient.
+ * noc ddrconf, upctl addrmap
+ * 1 7
+ * 2 8
+ * 3 9
+ * 12 10
+ * 5 11
+ */
+u8 d4_rbc_2_d3_rbc[] = {
+ 1, /* 7 */
+ 2, /* 8 */
+ 3, /* 9 */
+ 12, /* 10 */
+ 5, /* 11 */
+};
+
+/*
+ * row higher than cs should be disabled by set to 0xf
+ * rank addrmap calculate by real cap.
+ */
+u32 addrmap[][8] = {
+ /* map0 map1, map2, map3, map4, map5
+ * map6, map7, map8
+ * -------------------------------------------------------
+ * bk2-0 col 5-2 col 9-6 col 11-10 row 11-0
+ * row 15-12 row 17-16 bg1,0
+ * -------------------------------------------------------
+ * 4,3,2 5-2 9-6 6
+ * 3,2
+ */
+ {0x00060606, 0x00000000, 0x1f1f0000, 0x00001f1f, 0x05050505,
+ 0x05050505, 0x00000505, 0x3f3f}, /* 0 */
+ {0x00070707, 0x00000000, 0x1f000000, 0x00001f1f, 0x06060606,
+ 0x06060606, 0x06060606, 0x3f3f}, /* 1 */
+ {0x00080808, 0x00000000, 0x00000000, 0x00001f1f, 0x07070707,
+ 0x07070707, 0x00000f07, 0x3f3f}, /* 2 */
+ {0x00090909, 0x00000000, 0x00000000, 0x00001f00, 0x08080808,
+ 0x08080808, 0x00000f0f, 0x3f3f}, /* 3 */
+ {0x000a0a0a, 0x00000000, 0x00000000, 0x00000000, 0x09090909,
+ 0x0f090909, 0x00000f0f, 0x3f3f}, /* 4 */
+ {0x00080808, 0x00000000, 0x00000000, 0x00001f1f, 0x06060606,
+ 0x06060606, 0x00000606, 0x3f3f}, /* 5 */
+ {0x00080808, 0x00000000, 0x00000000, 0x00001f1f, 0x07070707,
+ 0x07070707, 0x00000f0f, 0x3f3f}, /* 6 */
+ {0x003f0808, 0x00000006, 0x1f1f0000, 0x00001f1f, 0x06060606,
+ 0x06060606, 0x00000606, 0x0600}, /* 7 */
+ {0x003f0909, 0x00000007, 0x1f000000, 0x00001f1f, 0x07070707,
+ 0x07070707, 0x00000f07, 0x0700}, /* 8 */
+ {0x003f0a0a, 0x01010100, 0x01010101, 0x00001f1f, 0x08080808,
+ 0x08080808, 0x00000f0f, 0x0801}, /* 9 */
+ {0x003f0909, 0x01010100, 0x01010101, 0x00001f1f, 0x07070707,
+ 0x07070707, 0x00000f07, 0x3f01}, /* 10 */
+ {0x003f0808, 0x00000007, 0x1f000000, 0x00001f1f, 0x06060606,
+ 0x06060606, 0x00000606, 0x3f00}, /* 11 */
+ /* when ddr4 12 map to 10, when ddr3 12 unused */
+ {0x003f0909, 0x01010100, 0x01010101, 0x00001f1f, 0x07070707,
+ 0x07070707, 0x00000f07, 0x3f01}, /* 10 */
+ {0x00070706, 0x00000000, 0x1f010000, 0x00001f1f, 0x06060606,
+ 0x06060606, 0x00000606, 0x3f3f}, /* 13 */
+};
+
+#define PMUGRF_BASE_ADDR 0xFF010000
+#define CRU_BASE_ADDR 0xFF2B0000
+#define GRF_BASE_ADDR 0xFF140000
+#define DDRC_BASE_ADDR 0xFF600000
+#define DDR_PHY_BASE_ADDR 0xFF2A0000
+#define SERVER_MSCH0_BASE_ADDR 0xFF530000
+#define DDR_GRF_BASE_ADDR 0xff630000
+
+struct dram_info dram_info;
+
+struct px30_sdram_params sdram_configs[] = {
+#include "sdram-px30-ddr3-detect-333.inc"
+};
+
+struct ddr_phy_skew skew = {
+#include "sdram-px30-ddr_skew.inc"
+};
+
+static void rkclk_ddr_reset(struct dram_info *dram,
+ u32 ctl_srstn, u32 ctl_psrstn,
+ u32 phy_srstn, u32 phy_psrstn)
+{
+ writel(upctl2_srstn_req(ctl_srstn) | upctl2_psrstn_req(ctl_psrstn) |
+ upctl2_asrstn_req(ctl_srstn),
+ &dram->cru->softrst_con[1]);
+ writel(ddrphy_srstn_req(phy_srstn) | ddrphy_psrstn_req(phy_psrstn),
+ &dram->cru->softrst_con[2]);
+}
+
+static void rkclk_set_dpll(struct dram_info *dram, unsigned int hz)
+{
+ unsigned int refdiv, postdiv1, postdiv2, fbdiv;
+ int delay = 1000;
+ u32 mhz = hz / MHz;
+
+ refdiv = 1;
+ if (mhz <= 300) {
+ postdiv1 = 4;
+ postdiv2 = 2;
+ } else if (mhz <= 400) {
+ postdiv1 = 6;
+ postdiv2 = 1;
+ } else if (mhz <= 600) {
+ postdiv1 = 4;
+ postdiv2 = 1;
+ } else if (mhz <= 800) {
+ postdiv1 = 3;
+ postdiv2 = 1;
+ } else if (mhz <= 1600) {
+ postdiv1 = 2;
+ postdiv2 = 1;
+ } else {
+ postdiv1 = 1;
+ postdiv2 = 1;
+ }
+ fbdiv = (mhz * refdiv * postdiv1 * postdiv2) / 24;
+
+ writel(DPLL_MODE(CLOCK_FROM_XIN_OSC), &dram->cru->mode);
+
+ writel(POSTDIV1(postdiv1) | FBDIV(fbdiv), &dram->cru->pll[1].con0);
+ writel(DSMPD(1) | POSTDIV2(postdiv2) | REFDIV(refdiv),
+ &dram->cru->pll[1].con1);
+
+ while (delay > 0) {
+ udelay(1);
+ if (LOCK(readl(&dram->cru->pll[1].con1)))
+ break;
+ delay--;
+ }
+
+ writel(DPLL_MODE(CLOCK_FROM_PLL), &dram->cru->mode);
+}
+
+static void rkclk_configure_ddr(struct dram_info *dram,
+ struct px30_sdram_params *sdram_params)
+{
+ /* for inno ddr phy need 2*freq */
+ rkclk_set_dpll(dram, sdram_params->base.ddr_freq * MHz * 2);
+}
+
+/* return ddrconfig value
+ * (-1), find ddrconfig fail
+ * other, the ddrconfig value
+ * only support cs0_row >= cs1_row
+ */
+static unsigned int calculate_ddrconfig(struct px30_sdram_params *sdram_params)
+{
+ struct sdram_cap_info *cap_info = &sdram_params->ch.cap_info;
+ u32 bw, die_bw, col, bank;
+ u32 i, tmp;
+ u32 ddrconf = -1;
+
+ bw = cap_info->bw;
+ die_bw = cap_info->dbw;
+ col = cap_info->col;
+ bank = cap_info->bk;
+
+ if (sdram_params->base.dramtype == DDR4) {
+ if (die_bw == 0)
+ ddrconf = 7 + bw;
+ else
+ ddrconf = 12 - bw;
+ ddrconf = d4_rbc_2_d3_rbc[ddrconf - 7];
+ } else {
+ tmp = ((bank - 2) << 3) | (col + bw - 10);
+ for (i = 0; i < 7; i++)
+ if ((ddr_cfg_2_rbc[i] & 0xf) == tmp) {
+ ddrconf = i;
+ break;
+ }
+ if (i > 6)
+ printascii("calculate ddrconfig error\n");
+ }
+
+ return ddrconf;
+}
+
+/*
+ * calculate controller dram address map, and setting to register.
+ * argument sdram_params->ch.ddrconf must be right value before
+ * call this function.
+ */
+static void set_ctl_address_map(struct dram_info *dram,
+ struct px30_sdram_params *sdram_params)
+{
+ struct sdram_cap_info *cap_info = &sdram_params->ch.cap_info;
+ void __iomem *pctl_base = dram->pctl;
+ u32 cs_pst, bg, max_row, ddrconf;
+ u32 i;
+
+ if (sdram_params->base.dramtype == DDR4)
+ /*
+ * DDR4 8bit dram BG = 2(4bank groups),
+ * 16bit dram BG = 1 (2 bank groups)
+ */
+ bg = (cap_info->dbw == 0) ? 2 : 1;
+ else
+ bg = 0;
+
+ cs_pst = cap_info->bw + cap_info->col +
+ bg + cap_info->bk + cap_info->cs0_row;
+ if (cs_pst >= 32 || cap_info->rank == 1)
+ writel(0x1f, pctl_base + DDR_PCTL2_ADDRMAP0);
+ else
+ writel(cs_pst - 8, pctl_base + DDR_PCTL2_ADDRMAP0);
+
+ ddrconf = cap_info->ddrconfig;
+ if (sdram_params->base.dramtype == DDR4) {
+ for (i = 0; i < ARRAY_SIZE(d4_rbc_2_d3_rbc); i++) {
+ if (d4_rbc_2_d3_rbc[i] == ddrconf) {
+ ddrconf = 7 + i;
+ break;
+ }
+ }
+ }
+
+ sdram_copy_to_reg((u32 *)(pctl_base + DDR_PCTL2_ADDRMAP1),
+ &addrmap[ddrconf][0], 8 * 4);
+ max_row = cs_pst - 1 - 8 - (addrmap[ddrconf][5] & 0xf);
+
+ if (max_row < 12)
+ printascii("set addrmap fail\n");
+ /* need to disable row ahead of rank by set to 0xf */
+ for (i = 17; i > max_row; i--)
+ clrsetbits_le32(pctl_base + DDR_PCTL2_ADDRMAP6 +
+ ((i - 12) * 8 / 32) * 4,
+ 0xf << ((i - 12) * 8 % 32),
+ 0xf << ((i - 12) * 8 % 32));
+
+ if ((sdram_params->base.dramtype == LPDDR3 ||
+ sdram_params->base.dramtype == LPDDR2) &&
+ cap_info->row_3_4)
+ setbits_le32(pctl_base + DDR_PCTL2_ADDRMAP6, 1 << 31);
+ if (sdram_params->base.dramtype == DDR4 && cap_info->bw != 0x2)
+ setbits_le32(pctl_base + DDR_PCTL2_PCCFG, 1 << 8);
+}
+
+/*
+ * rank = 1: cs0
+ * rank = 2: cs1
+ */
+int read_mr(struct dram_info *dram, u32 rank, u32 mr_num)
+{
+ void __iomem *ddr_grf_base = dram->ddr_grf;
+
+ pctl_read_mr(dram->pctl, rank, mr_num);
+
+ return (readl(ddr_grf_base + DDR_GRF_STATUS(0)) & 0xff);
+}
+
+#define MIN(a, b) (((a) > (b)) ? (b) : (a))
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+static u32 check_rd_gate(struct dram_info *dram)
+{
+ void __iomem *phy_base = dram->phy;
+
+ u32 max_val = 0;
+ u32 min_val = 0xff;
+ u32 gate[4];
+ u32 i, bw;
+
+ bw = (readl(PHY_REG(phy_base, 0x0)) >> 4) & 0xf;
+ switch (bw) {
+ case 0x1:
+ bw = 1;
+ break;
+ case 0x3:
+ bw = 2;
+ break;
+ case 0xf:
+ default:
+ bw = 4;
+ break;
+ }
+
+ for (i = 0; i < bw; i++) {
+ gate[i] = readl(PHY_REG(phy_base, 0xfb + i));
+ max_val = MAX(max_val, gate[i]);
+ min_val = MIN(min_val, gate[i]);
+ }
+
+ if (max_val > 0x80 || min_val < 0x20)
+ return -1;
+ else
+ return 0;
+}
+
+static int data_training(struct dram_info *dram, u32 cs, u32 dramtype)
+{
+ void __iomem *pctl_base = dram->pctl;
+ u32 dis_auto_zq = 0;
+ u32 pwrctl;
+ u32 ret;
+
+ /* disable auto low-power */
+ pwrctl = readl(pctl_base + DDR_PCTL2_PWRCTL);
+ writel(0, pctl_base + DDR_PCTL2_PWRCTL);
+
+ dis_auto_zq = pctl_dis_zqcs_aref(dram->pctl);
+
+ ret = phy_data_training(dram->phy, cs, dramtype);
+
+ pctl_rest_zqcs_aref(dram->pctl, dis_auto_zq);
+
+ /* restore auto low-power */
+ writel(pwrctl, pctl_base + DDR_PCTL2_PWRCTL);
+
+ return ret;
+}
+
+static void dram_set_bw(struct dram_info *dram, u32 bw)
+{
+ phy_dram_set_bw(dram->phy, bw);
+}
+
+static void set_ddrconfig(struct dram_info *dram, u32 ddrconfig)
+{
+ writel(ddrconfig | (ddrconfig << 8), &dram->msch->deviceconf);
+ rk_clrsetreg(&dram->grf->soc_noc_con[1], 0x3 << 14, 0 << 14);
+}
+
+static void sdram_msch_config(struct msch_regs *msch,
+ struct sdram_msch_timings *noc_timings,
+ struct sdram_cap_info *cap_info,
+ struct sdram_base_params *base)
+{
+ u64 cs_cap[2];
+
+ cs_cap[0] = sdram_get_cs_cap(cap_info, 0, base->dramtype);
+ cs_cap[1] = sdram_get_cs_cap(cap_info, 1, base->dramtype);
+ writel(((((cs_cap[1] >> 20) / 64) & 0xff) << 8) |
+ (((cs_cap[0] >> 20) / 64) & 0xff),
+ &msch->devicesize);
+
+ writel(noc_timings->ddrtiminga0.d32,
+ &msch->ddrtiminga0);
+ writel(noc_timings->ddrtimingb0.d32,
+ &msch->ddrtimingb0);
+ writel(noc_timings->ddrtimingc0.d32,
+ &msch->ddrtimingc0);
+ writel(noc_timings->devtodev0.d32,
+ &msch->devtodev0);
+ writel(noc_timings->ddrmode.d32, &msch->ddrmode);
+ writel(noc_timings->ddr4timing.d32,
+ &msch->ddr4timing);
+ writel(noc_timings->agingx0, &msch->agingx0);
+ writel(noc_timings->agingx0, &msch->aging0);
+ writel(noc_timings->agingx0, &msch->aging1);
+ writel(noc_timings->agingx0, &msch->aging2);
+ writel(noc_timings->agingx0, &msch->aging3);
+}
+
+static void dram_all_config(struct dram_info *dram,
+ struct px30_sdram_params *sdram_params)
+{
+ struct sdram_cap_info *cap_info = &sdram_params->ch.cap_info;
+ u32 sys_reg2 = 0;
+ u32 sys_reg3 = 0;
+
+ set_ddrconfig(dram, cap_info->ddrconfig);
+ sdram_org_config(cap_info, &sdram_params->base, &sys_reg2,
+ &sys_reg3, 0);
+ writel(sys_reg2, &dram->pmugrf->os_reg[2]);
+ writel(sys_reg3, &dram->pmugrf->os_reg[3]);
+ sdram_msch_config(dram->msch, &sdram_params->ch.noc_timings, cap_info,
+ &sdram_params->base);
+}
+
+static void enable_low_power(struct dram_info *dram,
+ struct px30_sdram_params *sdram_params)
+{
+ void __iomem *pctl_base = dram->pctl;
+ void __iomem *phy_base = dram->phy;
+ void __iomem *ddr_grf_base = dram->ddr_grf;
+ u32 grf_lp_con;
+
+ /*
+ * bit0: grf_upctl_axi_cg_en = 1 enable upctl2 axi clk auto gating
+ * bit1: grf_upctl_apb_cg_en = 1 ungated axi,core clk for apb access
+ * bit2: grf_upctl_core_cg_en = 1 enable upctl2 core clk auto gating
+ * bit3: grf_selfref_type2_en = 0 disable core clk gating when type2 sr
+ * bit4: grf_upctl_syscreq_cg_en = 1
+ * ungating coreclk when c_sysreq assert
+ * bit8-11: grf_auto_sr_dly = 6
+ */
+ writel(0x1f1f0617, &dram->ddr_grf->ddr_grf_con[1]);
+
+ if (sdram_params->base.dramtype == DDR4)
+ grf_lp_con = (0x7 << 16) | (1 << 1);
+ else if (sdram_params->base.dramtype == DDR3)
+ grf_lp_con = (0x7 << 16) | (1 << 0);
+ else
+ grf_lp_con = (0x7 << 16) | (1 << 2);
+
+ /* en lpckdis_en */
+ grf_lp_con = grf_lp_con | (0x1 << (9 + 16)) | (0x1 << 9);
+ writel(grf_lp_con, ddr_grf_base + DDR_GRF_LP_CON);
+
+ /* off digit module clock when enter power down */
+ setbits_le32(PHY_REG(phy_base, 7), 1 << 7);
+
+ /* enable sr, pd */
+ if (PD_IDLE == 0)
+ clrbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 1));
+ else
+ setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 1));
+ if (SR_IDLE == 0)
+ clrbits_le32(pctl_base + DDR_PCTL2_PWRCTL, 1);
+ else
+ setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, 1);
+ setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 3));
+}
+
+/*
+ * pre_init: 0: pre init for dram cap detect
+ * 1: detect correct cap(except cs1 row)info, than reinit
+ * 2: after reinit, we detect cs1_row, if cs1_row not equal
+ * to cs0_row and cs is in middle on ddrconf map, we need
+ * to reinit dram, than set the correct ddrconf.
+ */
+static int sdram_init_(struct dram_info *dram,
+ struct px30_sdram_params *sdram_params, u32 pre_init)
+{
+ struct sdram_cap_info *cap_info = &sdram_params->ch.cap_info;
+ void __iomem *pctl_base = dram->pctl;
+
+ rkclk_ddr_reset(dram, 1, 1, 1, 1);
+ udelay(10);
+ /*
+ * dereset ddr phy psrstn to config pll,
+ * if using phy pll psrstn must be dereset
+ * before config pll
+ */
+ rkclk_ddr_reset(dram, 1, 1, 1, 0);
+ rkclk_configure_ddr(dram, sdram_params);
+
+ /* release phy srst to provide clk to ctrl */
+ rkclk_ddr_reset(dram, 1, 1, 0, 0);
+ udelay(10);
+ phy_soft_reset(dram->phy);
+ /* release ctrl presetn, and config ctl registers */
+ rkclk_ddr_reset(dram, 1, 0, 0, 0);
+ pctl_cfg(dram->pctl, &sdram_params->pctl_regs, SR_IDLE, PD_IDLE);
+ cap_info->ddrconfig = calculate_ddrconfig(sdram_params);
+ set_ctl_address_map(dram, sdram_params);
+ phy_cfg(dram->phy, &sdram_params->phy_regs, sdram_params->skew,
+ &sdram_params->base, cap_info->bw);
+
+ /* enable dfi_init_start to init phy after ctl srstn deassert */
+ setbits_le32(pctl_base + DDR_PCTL2_DFIMISC, (1 << 5) | (1 << 4));
+
+ rkclk_ddr_reset(dram, 0, 0, 0, 0);
+ /* wait for dfi_init_done and dram init complete */
+ while ((readl(pctl_base + DDR_PCTL2_STAT) & 0x7) == 0)
+ continue;
+
+ if (sdram_params->base.dramtype == LPDDR3)
+ pctl_write_mr(dram->pctl, 3, 11, 3, LPDDR3);
+
+ /* do ddr gate training */
+redo_cs0_training:
+ if (data_training(dram, 0, sdram_params->base.dramtype) != 0) {
+ if (pre_init != 0)
+ printascii("DTT cs0 error\n");
+ return -1;
+ }
+ if (check_rd_gate(dram)) {
+ printascii("re training cs0");
+ goto redo_cs0_training;
+ }
+
+ if (sdram_params->base.dramtype == LPDDR3) {
+ if ((read_mr(dram, 1, 8) & 0x3) != 0x3)
+ return -1;
+ } else if (sdram_params->base.dramtype == LPDDR2) {
+ if ((read_mr(dram, 1, 8) & 0x3) != 0x0)
+ return -1;
+ }
+ /* for px30: when 2cs, both 2 cs should be training */
+ if (pre_init != 0 && cap_info->rank == 2) {
+redo_cs1_training:
+ if (data_training(dram, 1, sdram_params->base.dramtype) != 0) {
+ printascii("DTT cs1 error\n");
+ return -1;
+ }
+ if (check_rd_gate(dram)) {
+ printascii("re training cs1");
+ goto redo_cs1_training;
+ }
+ }
+
+ if (sdram_params->base.dramtype == DDR4)
+ pctl_write_vrefdq(dram->pctl, 0x3, 5670,
+ sdram_params->base.dramtype);
+
+ dram_all_config(dram, sdram_params);
+ enable_low_power(dram, sdram_params);
+
+ return 0;
+}
+
+static int dram_detect_cap(struct dram_info *dram,
+ struct px30_sdram_params *sdram_params,
+ unsigned char channel)
+{
+ struct sdram_cap_info *cap_info = &sdram_params->ch.cap_info;
+
+ /*
+ * for ddr3: ddrconf = 3
+ * for ddr4: ddrconf = 12
+ * for lpddr3: ddrconf = 3
+ * default bw = 1
+ */
+ u32 bk, bktmp;
+ u32 col, coltmp;
+ u32 rowtmp;
+ u32 cs;
+ u32 bw = 1;
+ u32 dram_type = sdram_params->base.dramtype;
+
+ if (dram_type != DDR4) {
+ /* detect col and bk for ddr3/lpddr3 */
+ coltmp = 12;
+ bktmp = 3;
+ if (dram_type == LPDDR2)
+ rowtmp = 15;
+ else
+ rowtmp = 16;
+
+ if (sdram_detect_col(cap_info, coltmp) != 0)
+ goto cap_err;
+ sdram_detect_bank(cap_info, coltmp, bktmp);
+ sdram_detect_dbw(cap_info, dram_type);
+ } else {
+ /* detect bg for ddr4 */
+ coltmp = 10;
+ bktmp = 4;
+ rowtmp = 17;
+
+ col = 10;
+ bk = 2;
+ cap_info->col = col;
+ cap_info->bk = bk;
+ sdram_detect_bg(cap_info, coltmp);
+ }
+
+ /* detect row */
+ if (sdram_detect_row(cap_info, coltmp, bktmp, rowtmp) != 0)
+ goto cap_err;
+
+ /* detect row_3_4 */
+ sdram_detect_row_3_4(cap_info, coltmp, bktmp);
+
+ /* bw and cs detect using data training */
+ if (data_training(dram, 1, dram_type) == 0)
+ cs = 1;
+ else
+ cs = 0;
+ cap_info->rank = cs + 1;
+
+ dram_set_bw(dram, 2);
+ if (data_training(dram, 0, dram_type) == 0)
+ bw = 2;
+ else
+ bw = 1;
+ cap_info->bw = bw;
+
+ cap_info->cs0_high16bit_row = cap_info->cs0_row;
+ if (cs) {
+ cap_info->cs1_row = cap_info->cs0_row;
+ cap_info->cs1_high16bit_row = cap_info->cs0_row;
+ } else {
+ cap_info->cs1_row = 0;
+ cap_info->cs1_high16bit_row = 0;
+ }
+
+ return 0;
+cap_err:
+ return -1;
+}
+
+/* return: 0 = success, other = fail */
+static int sdram_init_detect(struct dram_info *dram,
+ struct px30_sdram_params *sdram_params)
+{
+ struct sdram_cap_info *cap_info = &sdram_params->ch.cap_info;
+ u32 ret;
+ u32 sys_reg = 0;
+ u32 sys_reg3 = 0;
+
+ if (sdram_init_(dram, sdram_params, 0) != 0)
+ return -1;
+
+ if (dram_detect_cap(dram, sdram_params, 0) != 0)
+ return -1;
+
+ /* modify bw, cs related timing */
+ pctl_remodify_sdram_params(&sdram_params->pctl_regs, cap_info,
+ sdram_params->base.dramtype);
+ /* reinit sdram by real dram cap */
+ ret = sdram_init_(dram, sdram_params, 1);
+ if (ret != 0)
+ goto out;
+
+ /* redetect cs1 row */
+ sdram_detect_cs1_row(cap_info, sdram_params->base.dramtype);
+ if (cap_info->cs1_row) {
+ sys_reg = readl(&dram->pmugrf->os_reg[2]);
+ sys_reg3 = readl(&dram->pmugrf->os_reg[3]);
+ SYS_REG_ENC_CS1_ROW(cap_info->cs1_row,
+ sys_reg, sys_reg3, 0);
+ writel(sys_reg, &dram->pmugrf->os_reg[2]);
+ writel(sys_reg3, &dram->pmugrf->os_reg[3]);
+ }
+
+ ret = sdram_detect_high_row(cap_info);
+
+out:
+ return ret;
+}
+
+struct px30_sdram_params
+ *get_default_sdram_config(void)
+{
+ sdram_configs[0].skew = &skew;
+
+ return &sdram_configs[0];
+}
+
+/* return: 0 = success, other = fail */
+int sdram_init(void)
+{
+ struct px30_sdram_params *sdram_params;
+ int ret = 0;
+
+ dram_info.phy = (void *)DDR_PHY_BASE_ADDR;
+ dram_info.pctl = (void *)DDRC_BASE_ADDR;
+ dram_info.grf = (void *)GRF_BASE_ADDR;
+ dram_info.cru = (void *)CRU_BASE_ADDR;
+ dram_info.msch = (void *)SERVER_MSCH0_BASE_ADDR;
+ dram_info.ddr_grf = (void *)DDR_GRF_BASE_ADDR;
+ dram_info.pmugrf = (void *)PMUGRF_BASE_ADDR;
+
+ sdram_params = get_default_sdram_config();
+ ret = sdram_init_detect(&dram_info, sdram_params);
+
+ if (ret)
+ goto error;
+
+ sdram_print_ddr_info(&sdram_params->ch.cap_info, &sdram_params->base);
+
+ printascii("out\n");
+ return ret;
+error:
+ return (-1);
+}
+#else
+
+static int px30_dmc_probe(struct udevice *dev)
+{
+ struct dram_info *priv = dev_get_priv(dev);
+
+ priv->pmugrf = syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF);
+ debug("%s: grf=%p\n", __func__, priv->pmugrf);
+ priv->info.base = CONFIG_SYS_SDRAM_BASE;
+ priv->info.size =
+ rockchip_sdram_size((phys_addr_t)&priv->pmugrf->os_reg[2]);
+
+ return 0;
+}
+
+static int px30_dmc_get_info(struct udevice *dev, struct ram_info *info)
+{
+ struct dram_info *priv = dev_get_priv(dev);
+
+ *info = priv->info;
+
+ return 0;
+}
+
+static struct ram_ops px30_dmc_ops = {
+ .get_info = px30_dmc_get_info,
+};
+
+static const struct udevice_id px30_dmc_ids[] = {
+ { .compatible = "rockchip,px30-dmc" },
+ { }
+};
+
+U_BOOT_DRIVER(dmc_px30) = {
+ .name = "rockchip_px30_dmc",
+ .id = UCLASS_RAM,
+ .of_match = px30_dmc_ids,
+ .ops = &px30_dmc_ops,
+ .probe = px30_dmc_probe,
+ .priv_auto_alloc_size = sizeof(struct dram_info),
+};
+#endif /* CONFIG_TPL_BUILD */
diff --git a/drivers/ram/rockchip/sdram_rk3128.c b/drivers/ram/rockchip/sdram_rk3128.c
index bfabc22a7d..8486653c6f 100644
--- a/drivers/ram/rockchip/sdram_rk3128.c
+++ b/drivers/ram/rockchip/sdram_rk3128.c
@@ -9,7 +9,7 @@
#include <syscon.h>
#include <asm/arch-rockchip/clock.h>
#include <asm/arch-rockchip/grf_rk3128.h>
-#include <asm/arch-rockchip/sdram_common.h>
+#include <asm/arch-rockchip/sdram.h>
struct dram_info {
struct ram_info info;
diff --git a/drivers/ram/rockchip/sdram_rk3188.c b/drivers/ram/rockchip/sdram_rk3188.c
index 00e52ec949..d3e4316ef0 100644
--- a/drivers/ram/rockchip/sdram_rk3188.c
+++ b/drivers/ram/rockchip/sdram_rk3188.c
@@ -21,7 +21,7 @@
#include <asm/arch-rockchip/grf_rk3188.h>
#include <asm/arch-rockchip/pmu_rk3188.h>
#include <asm/arch-rockchip/sdram.h>
-#include <asm/arch-rockchip/sdram_common.h>
+#include <asm/arch-rockchip/sdram_rk3288.h>
#include <linux/err.h>
struct chan_info {
diff --git a/drivers/ram/rockchip/sdram_rk322x.c b/drivers/ram/rockchip/sdram_rk322x.c
index 94893e17cf..223f048161 100644
--- a/drivers/ram/rockchip/sdram_rk322x.c
+++ b/drivers/ram/rockchip/sdram_rk322x.c
@@ -17,7 +17,7 @@
#include <asm/arch-rockchip/hardware.h>
#include <asm/arch-rockchip/sdram_rk322x.h>
#include <asm/arch-rockchip/uart.h>
-#include <asm/arch-rockchip/sdram_common.h>
+#include <asm/arch-rockchip/sdram.h>
#include <asm/types.h>
#include <linux/err.h>
diff --git a/drivers/ram/rockchip/sdram_rk3288.c b/drivers/ram/rockchip/sdram_rk3288.c
index 5775254007..690751d074 100644
--- a/drivers/ram/rockchip/sdram_rk3288.c
+++ b/drivers/ram/rockchip/sdram_rk3288.c
@@ -21,7 +21,7 @@
#include <asm/arch-rockchip/grf_rk3288.h>
#include <asm/arch-rockchip/pmu_rk3288.h>
#include <asm/arch-rockchip/sdram.h>
-#include <asm/arch-rockchip/sdram_common.h>
+#include <asm/arch-rockchip/sdram_rk3288.h>
#include <linux/err.h>
#include <power/regulator.h>
#include <power/rk8xx_pmic.h>
diff --git a/drivers/ram/rockchip/sdram_rk3308.c b/drivers/ram/rockchip/sdram_rk3308.c
new file mode 100644
index 0000000000..310df79123
--- /dev/null
+++ b/drivers/ram/rockchip/sdram_rk3308.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * (C) Copyright 2019 Rockchip Electronics Co., Ltd.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <ram.h>
+#include <syscon.h>
+#include <asm/arch/grf_rk3308.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/sdram.h>
+
+struct dram_info {
+ struct ram_info info;
+ struct rk3308_grf *grf;
+};
+
+static int rk3308_dmc_probe(struct udevice *dev)
+{
+ struct dram_info *priv = dev_get_priv(dev);
+
+ priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+ priv->info.base = CONFIG_SYS_SDRAM_BASE;
+ priv->info.size = rockchip_sdram_size((phys_addr_t)&priv->grf->os_reg2);
+
+ return 0;
+}
+
+static int rk3308_dmc_get_info(struct udevice *dev, struct ram_info *info)
+{
+ struct dram_info *priv = dev_get_priv(dev);
+
+ *info = priv->info;
+
+ return 0;
+}
+
+static struct ram_ops rk3308_dmc_ops = {
+ .get_info = rk3308_dmc_get_info,
+};
+
+static const struct udevice_id rk3308_dmc_ids[] = {
+ { .compatible = "rockchip,rk3308-dmc" },
+ { }
+};
+
+U_BOOT_DRIVER(dmc_rk3308) = {
+ .name = "rockchip_rk3308_dmc",
+ .id = UCLASS_RAM,
+ .of_match = rk3308_dmc_ids,
+ .ops = &rk3308_dmc_ops,
+ .probe = rk3308_dmc_probe,
+ .priv_auto_alloc_size = sizeof(struct dram_info),
+};
diff --git a/drivers/ram/rockchip/sdram_rk3328.c b/drivers/ram/rockchip/sdram_rk3328.c
index e84c9be6a2..69521cef69 100644
--- a/drivers/ram/rockchip/sdram_rk3328.c
+++ b/drivers/ram/rockchip/sdram_rk3328.c
@@ -14,17 +14,17 @@
#include <asm/arch-rockchip/clock.h>
#include <asm/arch-rockchip/cru_rk3328.h>
#include <asm/arch-rockchip/grf_rk3328.h>
-#include <asm/arch-rockchip/sdram_common.h>
+#include <asm/arch-rockchip/sdram.h>
#include <asm/arch-rockchip/sdram_rk3328.h>
#include <asm/arch-rockchip/uart.h>
struct dram_info {
#ifdef CONFIG_TPL_BUILD
- struct rk3328_ddr_pctl_regs *pctl;
- struct rk3328_ddr_phy_regs *phy;
+ struct ddr_pctl_regs *pctl;
+ struct ddr_phy_regs *phy;
struct clk ddr_clk;
struct rk3328_cru *cru;
- struct rk3328_msch_regs *msch;
+ struct msch_regs *msch;
struct rk3328_ddr_grf_regs *ddr_grf;
#endif
struct ram_info info;
@@ -71,10 +71,11 @@ static void rkclk_ddr_reset(struct dram_info *dram,
writel(ddrctrl_asrstn_req(ctl_srstn), &dram->cru->softrst_con[9]);
}
-static void rkclk_set_dpll(struct dram_info *dram, unsigned int mhz)
+static void rkclk_set_dpll(struct dram_info *dram, unsigned int hz)
{
unsigned int refdiv, postdiv1, postdiv2, fbdiv;
int delay = 1000;
+ u32 mhz = hz / MHZ;
refdiv = 1;
if (mhz <= 300) {
@@ -122,52 +123,7 @@ static void rkclk_configure_ddr(struct dram_info *dram,
clrbits_le32(PHY_REG(phy_base, 0xef), 1 << 7);
/* for inno ddr phy need 2*freq */
- rkclk_set_dpll(dram, sdram_params->ddr_freq * 2);
-}
-
-static void phy_soft_reset(struct dram_info *dram)
-{
- void __iomem *phy_base = dram->phy;
-
- clrbits_le32(PHY_REG(phy_base, 0), 0x3 << 2);
- udelay(1);
- setbits_le32(PHY_REG(phy_base, 0), ANALOG_DERESET);
- udelay(5);
- setbits_le32(PHY_REG(phy_base, 0), DIGITAL_DERESET);
- udelay(1);
-}
-
-static int pctl_cfg(struct dram_info *dram,
- struct rk3328_sdram_params *sdram_params)
-{
- u32 i;
- void __iomem *pctl_base = dram->pctl;
-
- for (i = 0; sdram_params->pctl_regs.pctl[i][0] != 0xFFFFFFFF; i++) {
- writel(sdram_params->pctl_regs.pctl[i][1],
- pctl_base + sdram_params->pctl_regs.pctl[i][0]);
- }
- clrsetbits_le32(pctl_base + DDR_PCTL2_PWRTMG,
- (0xff << 16) | 0x1f,
- ((SR_IDLE & 0xff) << 16) | (PD_IDLE & 0x1f));
- /*
- * dfi_lp_en_pd=1,dfi_lp_wakeup_pd=2
- * hw_lp_idle_x32=1
- */
- if (sdram_params->dramtype == LPDDR3) {
- setbits_le32(pctl_base + DDR_PCTL2_DFILPCFG0, 1);
- clrsetbits_le32(pctl_base + DDR_PCTL2_DFILPCFG0,
- 0xf << 4,
- 2 << 4);
- }
- clrsetbits_le32(pctl_base + DDR_PCTL2_HWLPCTL,
- 0xfff << 16,
- 1 << 16);
- /* disable zqcs */
- setbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1u << 31);
- setbits_le32(pctl_base + 0x2000 + DDR_PCTL2_ZQCTL0, 1u << 31);
-
- return 0;
+ rkclk_set_dpll(dram, sdram_params->base.ddr_freq * MHZ * 2);
}
/* return ddrconfig value
@@ -175,62 +131,39 @@ static int pctl_cfg(struct dram_info *dram,
* other, the ddrconfig value
* only support cs0_row >= cs1_row
*/
-static unsigned int calculate_ddrconfig(struct rk3328_sdram_params *sdram_params)
+static u32 calculate_ddrconfig(struct rk3328_sdram_params *sdram_params)
{
- static const u16 ddr_cfg_2_rbc[] = {
- /***************************
- * [5:4] row(13+n)
- * [3] cs(0:0 cs, 1:2 cs)
- * [2] bank(0:0bank,1:8bank)
- * [1:0] col(11+n)
- ****************************/
- /* row, cs, bank, col */
- ((3 << 4) | (0 << 3) | (1 << 2) | 0),
- ((3 << 4) | (0 << 3) | (1 << 2) | 1),
- ((2 << 4) | (0 << 3) | (1 << 2) | 2),
- ((3 << 4) | (0 << 3) | (1 << 2) | 2),
- ((2 << 4) | (0 << 3) | (1 << 2) | 3),
- ((3 << 4) | (1 << 3) | (1 << 2) | 0),
- ((3 << 4) | (1 << 3) | (1 << 2) | 1),
- ((2 << 4) | (1 << 3) | (1 << 2) | 2),
- ((3 << 4) | (0 << 3) | (0 << 2) | 1),
- ((2 << 4) | (0 << 3) | (1 << 2) | 1),
- };
-
- static const u16 ddr4_cfg_2_rbc[] = {
- /***************************
- * [6] cs 0:0cs 1:2 cs
- * [5:3] row(13+n)
- * [2] cs(0:0 cs, 1:2 cs)
- * [1] bw 0: 16bit 1:32bit
- * [0] diebw 0:8bit 1:16bit
- ***************************/
- /* cs, row, cs, bw, diebw */
- ((0 << 6) | (3 << 3) | (0 << 2) | (1 << 1) | 0),
- ((1 << 6) | (2 << 3) | (0 << 2) | (1 << 1) | 0),
- ((0 << 6) | (4 << 3) | (0 << 2) | (0 << 1) | 0),
- ((1 << 6) | (3 << 3) | (0 << 2) | (0 << 1) | 0),
- ((0 << 6) | (4 << 3) | (0 << 2) | (1 << 1) | 1),
- ((1 << 6) | (3 << 3) | (0 << 2) | (1 << 1) | 1),
- ((1 << 6) | (4 << 3) | (0 << 2) | (0 << 1) | 1),
- ((0 << 6) | (2 << 3) | (1 << 2) | (1 << 1) | 0),
- ((0 << 6) | (3 << 3) | (1 << 2) | (0 << 1) | 0),
- ((0 << 6) | (3 << 3) | (1 << 2) | (1 << 1) | 1),
- ((0 << 6) | (4 << 3) | (1 << 2) | (0 << 1) | 1),
- };
-
+ struct sdram_cap_info *cap_info = &sdram_params->ch.cap_info;
u32 cs, bw, die_bw, col, row, bank;
+ u32 cs1_row;
u32 i, tmp;
u32 ddrconf = -1;
- cs = sdram_ch.rank;
- bw = sdram_ch.bw;
- die_bw = sdram_ch.dbw;
- col = sdram_ch.col;
- row = sdram_ch.cs0_row;
- bank = sdram_ch.bk;
+ cs = cap_info->rank;
+ bw = cap_info->bw;
+ die_bw = cap_info->dbw;
+ col = cap_info->col;
+ row = cap_info->cs0_row;
+ cs1_row = cap_info->cs1_row;
+ bank = cap_info->bk;
+
+ if (sdram_params->base.dramtype == DDR4) {
+ /* when DDR_TEST, CS always at MSB position for easy test */
+ if (cs == 2 && row == cs1_row) {
+ /* include 2cs cap both 2^n or both (2^n - 2^(n-2)) */
+ tmp = ((row - 13) << 3) | (1 << 2) | (bw & 0x2) |
+ die_bw;
+ for (i = 17; i < 21; i++) {
+ if (((tmp & 0x7) ==
+ (ddr4_cfg_2_rbc[i - 10] & 0x7)) &&
+ ((tmp & 0x3c) <=
+ (ddr4_cfg_2_rbc[i - 10] & 0x3c))) {
+ ddrconf = i;
+ goto out;
+ }
+ }
+ }
- if (sdram_params->dramtype == DDR4) {
tmp = ((cs - 1) << 6) | ((row - 13) << 3) | (bw & 0x2) | die_bw;
for (i = 10; i < 17; i++) {
if (((tmp & 0x7) == (ddr4_cfg_2_rbc[i - 10] & 0x7)) &&
@@ -246,6 +179,18 @@ static unsigned int calculate_ddrconfig(struct rk3328_sdram_params *sdram_params
goto out;
}
+ /* when DDR_TEST, CS always at MSB position for easy test */
+ if (cs == 2 && row == cs1_row) {
+ /* include 2cs cap both 2^n or both (2^n - 2^(n-2)) */
+ for (i = 5; i < 8; i++) {
+ if ((bw + col - 11) == (ddr_cfg_2_rbc[i] &
+ 0x3)) {
+ ddrconf = i;
+ goto out;
+ }
+ }
+ }
+
tmp = ((row - 13) << 4) | (1 << 2) | ((bw + col - 11) << 0);
for (i = 0; i < 5; i++)
if (((tmp & 0xf) == (ddr_cfg_2_rbc[i] & 0xf)) &&
@@ -257,23 +202,11 @@ static unsigned int calculate_ddrconfig(struct rk3328_sdram_params *sdram_params
out:
if (ddrconf > 20)
- printf("calculate_ddrconfig error\n");
+ printf("calculate ddrconfig error\n");
return ddrconf;
}
-/* n: Unit bytes */
-static void copy_to_reg(u32 *dest, u32 *src, u32 n)
-{
- int i;
-
- for (i = 0; i < n / sizeof(u32); i++) {
- writel(*src, dest);
- src++;
- dest++;
- }
-}
-
/*******
* calculate controller dram address map, and setting to register.
* argument sdram_ch.ddrconf must be right value before
@@ -282,273 +215,42 @@ static void copy_to_reg(u32 *dest, u32 *src, u32 n)
static void set_ctl_address_map(struct dram_info *dram,
struct rk3328_sdram_params *sdram_params)
{
+ struct sdram_cap_info *cap_info = &sdram_params->ch.cap_info;
void __iomem *pctl_base = dram->pctl;
- copy_to_reg((u32 *)(pctl_base + DDR_PCTL2_ADDRMAP0),
- &addrmap[sdram_ch.ddrconfig][0], 9 * 4);
- if (sdram_params->dramtype == LPDDR3 && sdram_ch.row_3_4)
+ sdram_copy_to_reg((u32 *)(pctl_base + DDR_PCTL2_ADDRMAP0),
+ &addrmap[cap_info->ddrconfig][0], 9 * 4);
+ if (sdram_params->base.dramtype == LPDDR3 && cap_info->row_3_4)
setbits_le32(pctl_base + DDR_PCTL2_ADDRMAP6, 1 << 31);
- if (sdram_params->dramtype == DDR4 && sdram_ch.bw == 0x1)
+ if (sdram_params->base.dramtype == DDR4 && cap_info->bw == 0x1)
setbits_le32(pctl_base + DDR_PCTL2_PCCFG, 1 << 8);
- if (sdram_ch.rank == 1)
+ if (cap_info->rank == 1)
clrsetbits_le32(pctl_base + DDR_PCTL2_ADDRMAP0, 0x1f, 0x1f);
}
-static void phy_dll_bypass_set(struct dram_info *dram, u32 freq)
-{
- u32 tmp;
- void __iomem *phy_base = dram->phy;
-
- setbits_le32(PHY_REG(phy_base, 0x13), 1 << 4);
- clrbits_le32(PHY_REG(phy_base, 0x14), 1 << 3);
- setbits_le32(PHY_REG(phy_base, 0x26), 1 << 4);
- clrbits_le32(PHY_REG(phy_base, 0x27), 1 << 3);
- setbits_le32(PHY_REG(phy_base, 0x36), 1 << 4);
- clrbits_le32(PHY_REG(phy_base, 0x37), 1 << 3);
- setbits_le32(PHY_REG(phy_base, 0x46), 1 << 4);
- clrbits_le32(PHY_REG(phy_base, 0x47), 1 << 3);
- setbits_le32(PHY_REG(phy_base, 0x56), 1 << 4);
- clrbits_le32(PHY_REG(phy_base, 0x57), 1 << 3);
-
- if (freq <= 400)
- /* DLL bypass */
- setbits_le32(PHY_REG(phy_base, 0xa4), 0x1f);
- else
- clrbits_le32(PHY_REG(phy_base, 0xa4), 0x1f);
- if (freq <= 680)
- tmp = 2;
- else
- tmp = 1;
- writel(tmp, PHY_REG(phy_base, 0x28));
- writel(tmp, PHY_REG(phy_base, 0x38));
- writel(tmp, PHY_REG(phy_base, 0x48));
- writel(tmp, PHY_REG(phy_base, 0x58));
-}
-
-static void set_ds_odt(struct dram_info *dram,
- struct rk3328_sdram_params *sdram_params)
-{
- u32 cmd_drv, clk_drv, dqs_drv, dqs_odt;
- void __iomem *phy_base = dram->phy;
-
- if (sdram_params->dramtype == DDR3) {
- cmd_drv = PHY_DDR3_RON_RTT_34ohm;
- clk_drv = PHY_DDR3_RON_RTT_45ohm;
- dqs_drv = PHY_DDR3_RON_RTT_34ohm;
- dqs_odt = PHY_DDR3_RON_RTT_225ohm;
- } else {
- cmd_drv = PHY_DDR4_LPDDR3_RON_RTT_34ohm;
- clk_drv = PHY_DDR4_LPDDR3_RON_RTT_43ohm;
- dqs_drv = PHY_DDR4_LPDDR3_RON_RTT_34ohm;
- dqs_odt = PHY_DDR4_LPDDR3_RON_RTT_240ohm;
- }
- /* DS */
- writel(cmd_drv, PHY_REG(phy_base, 0x11));
- clrsetbits_le32(PHY_REG(phy_base, 0x12), 0x1f << 3, cmd_drv << 3);
- writel(clk_drv, PHY_REG(phy_base, 0x16));
- writel(clk_drv, PHY_REG(phy_base, 0x18));
- writel(dqs_drv, PHY_REG(phy_base, 0x20));
- writel(dqs_drv, PHY_REG(phy_base, 0x2f));
- writel(dqs_drv, PHY_REG(phy_base, 0x30));
- writel(dqs_drv, PHY_REG(phy_base, 0x3f));
- writel(dqs_drv, PHY_REG(phy_base, 0x40));
- writel(dqs_drv, PHY_REG(phy_base, 0x4f));
- writel(dqs_drv, PHY_REG(phy_base, 0x50));
- writel(dqs_drv, PHY_REG(phy_base, 0x5f));
- /* ODT */
- writel(dqs_odt, PHY_REG(phy_base, 0x21));
- writel(dqs_odt, PHY_REG(phy_base, 0x2e));
- writel(dqs_odt, PHY_REG(phy_base, 0x31));
- writel(dqs_odt, PHY_REG(phy_base, 0x3e));
- writel(dqs_odt, PHY_REG(phy_base, 0x41));
- writel(dqs_odt, PHY_REG(phy_base, 0x4e));
- writel(dqs_odt, PHY_REG(phy_base, 0x51));
- writel(dqs_odt, PHY_REG(phy_base, 0x5e));
-}
-
-static void phy_cfg(struct dram_info *dram,
- struct rk3328_sdram_params *sdram_params)
-{
- u32 i;
- void __iomem *phy_base = dram->phy;
-
- phy_dll_bypass_set(dram, sdram_params->ddr_freq);
- for (i = 0; sdram_params->phy_regs.phy[i][0] != 0xFFFFFFFF; i++) {
- writel(sdram_params->phy_regs.phy[i][1],
- phy_base + sdram_params->phy_regs.phy[i][0]);
- }
- if (sdram_ch.bw == 2) {
- clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 0xf << 4);
- } else {
- clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 3 << 4);
- /* disable DQS2,DQS3 tx dll for saving power */
- clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
- clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
- }
- set_ds_odt(dram, sdram_params);
- /* deskew */
- setbits_le32(PHY_REG(phy_base, 2), 8);
- copy_to_reg(PHY_REG(phy_base, 0xb0),
- &sdram_params->skew.a0_a1_skew[0], 15 * 4);
- copy_to_reg(PHY_REG(phy_base, 0x70),
- &sdram_params->skew.cs0_dm0_skew[0], 44 * 4);
- copy_to_reg(PHY_REG(phy_base, 0xc0),
- &sdram_params->skew.cs1_dm0_skew[0], 44 * 4);
-}
-
-static int update_refresh_reg(struct dram_info *dram)
-{
- void __iomem *pctl_base = dram->pctl;
- u32 ret;
-
- ret = readl(pctl_base + DDR_PCTL2_RFSHCTL3) ^ (1 << 1);
- writel(ret, pctl_base + DDR_PCTL2_RFSHCTL3);
-
- return 0;
-}
-
static int data_training(struct dram_info *dram, u32 cs, u32 dramtype)
{
- u32 ret;
- u32 dis_auto_zq = 0;
- void __iomem *pctl_base = dram->pctl;
- void __iomem *phy_base = dram->phy;
-
- /* disable zqcs */
- if (!(readl(pctl_base + DDR_PCTL2_ZQCTL0) &
- (1ul << 31))) {
- dis_auto_zq = 1;
- setbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1 << 31);
- }
- /* disable auto refresh */
- setbits_le32(pctl_base + DDR_PCTL2_RFSHCTL3, 1);
- update_refresh_reg(dram);
-
- if (dramtype == DDR4) {
- clrsetbits_le32(PHY_REG(phy_base, 0x29), 0x3, 0);
- clrsetbits_le32(PHY_REG(phy_base, 0x39), 0x3, 0);
- clrsetbits_le32(PHY_REG(phy_base, 0x49), 0x3, 0);
- clrsetbits_le32(PHY_REG(phy_base, 0x59), 0x3, 0);
- }
- /* choose training cs */
- clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs));
- /* enable gate training */
- clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs) | 1);
- udelay(50);
- ret = readl(PHY_REG(phy_base, 0xff));
- /* disable gate training */
- clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs) | 0);
- /* restore zqcs */
- if (dis_auto_zq)
- clrbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1 << 31);
- /* restore auto refresh */
- clrbits_le32(pctl_base + DDR_PCTL2_RFSHCTL3, 1);
- update_refresh_reg(dram);
-
- if (dramtype == DDR4) {
- clrsetbits_le32(PHY_REG(phy_base, 0x29), 0x3, 0x2);
- clrsetbits_le32(PHY_REG(phy_base, 0x39), 0x3, 0x2);
- clrsetbits_le32(PHY_REG(phy_base, 0x49), 0x3, 0x2);
- clrsetbits_le32(PHY_REG(phy_base, 0x59), 0x3, 0x2);
- }
-
- if (ret & 0x10) {
- ret = -1;
- } else {
- ret = (ret & 0xf) ^ (readl(PHY_REG(phy_base, 0)) >> 4);
- ret = (ret == 0) ? 0 : -1;
- }
- return ret;
-}
-
-/* rank = 1: cs0
- * rank = 2: cs1
- * rank = 3: cs0 & cs1
- * note: be careful of keep mr original val
- */
-static int write_mr(struct dram_info *dram, u32 rank, u32 mr_num, u32 arg,
- u32 dramtype)
-{
void __iomem *pctl_base = dram->pctl;
-
- while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY)
- continue;
- if (dramtype == DDR3 || dramtype == DDR4) {
- writel((mr_num << 12) | (rank << 4) | (0 << 0),
- pctl_base + DDR_PCTL2_MRCTRL0);
- writel(arg, pctl_base + DDR_PCTL2_MRCTRL1);
- } else {
- writel((rank << 4) | (0 << 0),
- pctl_base + DDR_PCTL2_MRCTRL0);
- writel((mr_num << 8) | (arg & 0xff),
- pctl_base + DDR_PCTL2_MRCTRL1);
- }
-
- setbits_le32(pctl_base + DDR_PCTL2_MRCTRL0, 1u << 31);
- while (readl(pctl_base + DDR_PCTL2_MRCTRL0) & (1u << 31))
- continue;
- while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY)
- continue;
-
- return 0;
-}
-
-/*
- * rank : 1:cs0, 2:cs1, 3:cs0&cs1
- * vrefrate: 4500: 45%,
- */
-static int write_vrefdq(struct dram_info *dram, u32 rank, u32 vrefrate,
- u32 dramtype)
-{
- u32 tccd_l, value;
u32 dis_auto_zq = 0;
- void __iomem *pctl_base = dram->pctl;
+ u32 pwrctl;
+ u32 ret;
- if (dramtype != DDR4 || vrefrate < 4500 || vrefrate > 9200)
- return -1;
+ /* disable auto low-power */
+ pwrctl = readl(pctl_base + DDR_PCTL2_PWRCTL);
+ writel(0, pctl_base + DDR_PCTL2_PWRCTL);
- tccd_l = (readl(pctl_base + DDR_PCTL2_DRAMTMG4) >> 16) & 0xf;
- tccd_l = (tccd_l - 4) << 10;
+ dis_auto_zq = pctl_dis_zqcs_aref(dram->pctl);
- if (vrefrate > 7500) {
- /* range 1 */
- value = ((vrefrate - 6000) / 65) | tccd_l;
- } else {
- /* range 2 */
- value = ((vrefrate - 4500) / 65) | tccd_l | (1 << 6);
- }
+ ret = phy_data_training(dram->phy, cs, dramtype);
- /* disable zqcs */
- if (!(readl(pctl_base + DDR_PCTL2_ZQCTL0) &
- (1ul << 31))) {
- dis_auto_zq = 1;
- setbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1 << 31);
- }
- /* disable auto refresh */
- setbits_le32(pctl_base + DDR_PCTL2_RFSHCTL3, 1);
- update_refresh_reg(dram);
-
- /* enable vrefdq calibratin */
- write_mr(dram, rank, 6, value | (1 << 7), dramtype);
- udelay(1);/* tvrefdqe */
- /* write vrefdq value */
- write_mr(dram, rank, 6, value | (1 << 7), dramtype);
- udelay(1);/* tvref_time */
- write_mr(dram, rank, 6, value | (0 << 7), dramtype);
- udelay(1);/* tvrefdqx */
-
- /* restore zqcs */
- if (dis_auto_zq)
- clrbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1 << 31);
- /* restore auto refresh */
- clrbits_le32(pctl_base + DDR_PCTL2_RFSHCTL3, 1);
- update_refresh_reg(dram);
+ pctl_rest_zqcs_aref(dram->pctl, dis_auto_zq);
- return 0;
-}
+ /* restore auto low-power */
+ writel(pwrctl, pctl_base + DDR_PCTL2_PWRCTL);
-#define _MAX_(x, y) ((x) > (y) ? (x) : (y))
+ return ret;
+}
static void rx_deskew_switch_adjust(struct dram_info *dram)
{
@@ -557,7 +259,7 @@ static void rx_deskew_switch_adjust(struct dram_info *dram)
void __iomem *phy_base = dram->phy;
for (i = 0; i < 4; i++)
- gate_val = _MAX_(readl(PHY_REG(phy_base, 0xfb + i)), gate_val);
+ gate_val = MAX(readl(PHY_REG(phy_base, 0xfb + i)), gate_val);
deskew_val = (gate_val >> 3) + 1;
deskew_val = (deskew_val > 0x1f) ? 0x1f : deskew_val;
@@ -566,8 +268,6 @@ static void rx_deskew_switch_adjust(struct dram_info *dram)
(deskew_val & 0x1c) << 2);
}
-#undef _MAX_
-
static void tx_deskew_switch_adjust(struct dram_info *dram)
{
void __iomem *phy_base = dram->phy;
@@ -580,40 +280,39 @@ static void set_ddrconfig(struct dram_info *dram, u32 ddrconfig)
writel(ddrconfig, &dram->msch->ddrconf);
}
+static void sdram_msch_config(struct msch_regs *msch,
+ struct sdram_msch_timings *noc_timings)
+{
+ writel(noc_timings->ddrtiming.d32, &msch->ddrtiming);
+
+ writel(noc_timings->ddrmode.d32, &msch->ddrmode);
+ writel(noc_timings->readlatency, &msch->readlatency);
+
+ writel(noc_timings->activate.d32, &msch->activate);
+ writel(noc_timings->devtodev.d32, &msch->devtodev);
+ writel(noc_timings->ddr4timing.d32, &msch->ddr4_timing);
+ writel(noc_timings->agingx0, &msch->aging0);
+ writel(noc_timings->agingx0, &msch->aging1);
+ writel(noc_timings->agingx0, &msch->aging2);
+ writel(noc_timings->agingx0, &msch->aging3);
+ writel(noc_timings->agingx0, &msch->aging4);
+ writel(noc_timings->agingx0, &msch->aging5);
+}
+
static void dram_all_config(struct dram_info *dram,
struct rk3328_sdram_params *sdram_params)
{
- u32 sys_reg = 0, tmp = 0;
-
- set_ddrconfig(dram, sdram_ch.ddrconfig);
-
- sys_reg |= SYS_REG_ENC_DDRTYPE(sdram_params->dramtype);
- sys_reg |= SYS_REG_ENC_ROW_3_4(sdram_ch.row_3_4, 0);
- sys_reg |= SYS_REG_ENC_RANK(sdram_ch.rank, 0);
- sys_reg |= SYS_REG_ENC_COL(sdram_ch.col, 0);
- sys_reg |= SYS_REG_ENC_BK(sdram_ch.bk, 0);
- SYS_REG_ENC_CS0_ROW(sdram_ch.cs0_row, sys_reg, tmp, 0);
- if (sdram_ch.cs1_row)
- SYS_REG_ENC_CS1_ROW(sdram_ch.cs1_row, sys_reg, tmp, 0);
- sys_reg |= SYS_REG_ENC_BW(sdram_ch.bw, 0);
- sys_reg |= SYS_REG_ENC_DBW(sdram_ch.dbw, 0);
-
- writel(sys_reg, &dram->grf->os_reg[2]);
-
- writel(sdram_ch.noc_timings.ddrtiming.d32, &dram->msch->ddrtiming);
-
- writel(sdram_ch.noc_timings.ddrmode.d32, &dram->msch->ddrmode);
- writel(sdram_ch.noc_timings.readlatency, &dram->msch->readlatency);
-
- writel(sdram_ch.noc_timings.activate.d32, &dram->msch->activate);
- writel(sdram_ch.noc_timings.devtodev.d32, &dram->msch->devtodev);
- writel(sdram_ch.noc_timings.ddr4timing.d32, &dram->msch->ddr4_timing);
- writel(sdram_ch.noc_timings.agingx0, &dram->msch->aging0);
- writel(sdram_ch.noc_timings.agingx0, &dram->msch->aging1);
- writel(sdram_ch.noc_timings.agingx0, &dram->msch->aging2);
- writel(sdram_ch.noc_timings.agingx0, &dram->msch->aging3);
- writel(sdram_ch.noc_timings.agingx0, &dram->msch->aging4);
- writel(sdram_ch.noc_timings.agingx0, &dram->msch->aging5);
+ struct sdram_cap_info *cap_info = &sdram_params->ch.cap_info;
+ u32 sys_reg2 = 0;
+ u32 sys_reg3 = 0;
+
+ set_ddrconfig(dram, cap_info->ddrconfig);
+ sdram_org_config(cap_info, &sdram_params->base, &sys_reg2,
+ &sys_reg3, 0);
+ writel(sys_reg2, &dram->grf->os_reg[2]);
+ writel(sys_reg3, &dram->grf->os_reg[3]);
+
+ sdram_msch_config(dram->msch, &sdram_ch.noc_timings);
}
static void enable_low_power(struct dram_info *dram,
@@ -641,6 +340,7 @@ static void enable_low_power(struct dram_info *dram,
static int sdram_init(struct dram_info *dram,
struct rk3328_sdram_params *sdram_params, u32 pre_init)
{
+ struct sdram_cap_info *cap_info = &sdram_params->ch.cap_info;
void __iomem *pctl_base = dram->pctl;
rkclk_ddr_reset(dram, 1, 1, 1, 1);
@@ -652,30 +352,18 @@ static int sdram_init(struct dram_info *dram,
*/
rkclk_ddr_reset(dram, 1, 1, 1, 0);
rkclk_configure_ddr(dram, sdram_params);
- if (pre_init == 0) {
- switch (sdram_params->dramtype) {
- case DDR3:
- printf("DDR3\n");
- break;
- case DDR4:
- printf("DDR4\n");
- break;
- case LPDDR3:
- default:
- printf("LPDDR3\n");
- break;
- }
- }
+
/* release phy srst to provide clk to ctrl */
rkclk_ddr_reset(dram, 1, 1, 0, 0);
udelay(10);
- phy_soft_reset(dram);
+ phy_soft_reset(dram->phy);
/* release ctrl presetn, and config ctl registers */
rkclk_ddr_reset(dram, 1, 0, 0, 0);
- pctl_cfg(dram, sdram_params);
- sdram_ch.ddrconfig = calculate_ddrconfig(sdram_params);
+ pctl_cfg(dram->pctl, &sdram_params->pctl_regs, SR_IDLE, PD_IDLE);
+ cap_info->ddrconfig = calculate_ddrconfig(sdram_params);
set_ctl_address_map(dram, sdram_params);
- phy_cfg(dram, sdram_params);
+ phy_cfg(dram->phy, &sdram_params->phy_regs, &sdram_params->skew,
+ &sdram_params->base, cap_info->bw);
/* enable dfi_init_start to init phy after ctl srstn deassert */
setbits_le32(pctl_base + DDR_PCTL2_DFIMISC, (1 << 5) | (1 << 4));
@@ -685,13 +373,18 @@ static int sdram_init(struct dram_info *dram,
continue;
/* do ddr gate training */
- if (data_training(dram, 0, sdram_params->dramtype) != 0) {
+ if (data_training(dram, 0, sdram_params->base.dramtype) != 0) {
+ printf("data training error\n");
+ return -1;
+ }
+ if (data_training(dram, 1, sdram_params->base.dramtype) != 0) {
printf("data training error\n");
return -1;
}
- if (sdram_params->dramtype == DDR4)
- write_vrefdq(dram, 0x3, 5670, sdram_params->dramtype);
+ if (sdram_params->base.dramtype == DDR4)
+ pctl_write_vrefdq(dram->pctl, 0x3, 5670,
+ sdram_params->base.dramtype);
if (pre_init == 0) {
rx_deskew_switch_adjust(dram);
@@ -708,7 +401,7 @@ static u64 dram_detect_cap(struct dram_info *dram,
struct rk3328_sdram_params *sdram_params,
unsigned char channel)
{
- void __iomem *pctl_base = dram->pctl;
+ struct sdram_cap_info *cap_info = &sdram_params->ch.cap_info;
/*
* for ddr3: ddrconf = 3
@@ -718,14 +411,10 @@ static u64 dram_detect_cap(struct dram_info *dram,
*/
u32 bk, bktmp;
u32 col, coltmp;
- u32 row, rowtmp, row_3_4;
- void __iomem *test_addr, *test_addr1;
- u32 dbw;
+ u32 rowtmp;
u32 cs;
u32 bw = 1;
- u64 cap = 0;
- u32 dram_type = sdram_params->dramtype;
- u32 pwrctl;
+ u32 dram_type = sdram_params->base.dramtype;
if (dram_type != DDR4) {
/* detect col and bk for ddr3/lpddr3 */
@@ -733,33 +422,10 @@ static u64 dram_detect_cap(struct dram_info *dram,
bktmp = 3;
rowtmp = 16;
- for (col = coltmp; col >= 9; col -= 1) {
- writel(0, SDRAM_ADDR);
- test_addr = (void __iomem *)(SDRAM_ADDR +
- (1ul << (col + bw - 1ul)));
- writel(PATTERN, test_addr);
- if ((readl(test_addr) == PATTERN) &&
- (readl(SDRAM_ADDR) == 0))
- break;
- }
- if (col == 8) {
- printf("col error\n");
+ if (sdram_detect_col(cap_info, coltmp) != 0)
goto cap_err;
- }
-
- test_addr = (void __iomem *)(SDRAM_ADDR +
- (1ul << (coltmp + bktmp + bw - 1ul)));
- writel(0, SDRAM_ADDR);
- writel(PATTERN, test_addr);
- if ((readl(test_addr) == PATTERN) &&
- (readl(SDRAM_ADDR) == 0))
- bk = 3;
- else
- bk = 2;
- if (dram_type == LPDDR3)
- dbw = 2;
- else
- dbw = 1;
+ sdram_detect_bank(cap_info, coltmp, bktmp);
+ sdram_detect_dbw(cap_info, dram_type);
} else {
/* detect bg for ddr4 */
coltmp = 10;
@@ -768,178 +434,49 @@ static u64 dram_detect_cap(struct dram_info *dram,
col = 10;
bk = 2;
- test_addr = (void __iomem *)(SDRAM_ADDR +
- (1ul << (coltmp + bw + 1ul)));
- writel(0, SDRAM_ADDR);
- writel(PATTERN, test_addr);
- if ((readl(test_addr) == PATTERN) &&
- (readl(SDRAM_ADDR) == 0))
- dbw = 0;
- else
- dbw = 1;
+ cap_info->col = col;
+ cap_info->bk = bk;
+ sdram_detect_bg(cap_info, coltmp);
}
+
/* detect row */
- for (row = rowtmp; row > 12; row--) {
- writel(0, SDRAM_ADDR);
- test_addr = (void __iomem *)(SDRAM_ADDR +
- (1ul << (row + bktmp + coltmp + bw - 1ul)));
- writel(PATTERN, test_addr);
- if ((readl(test_addr) == PATTERN) &&
- (readl(SDRAM_ADDR) == 0))
- break;
- }
- if (row == 12) {
- printf("row error");
+ if (sdram_detect_row(cap_info, coltmp, bktmp, rowtmp) != 0)
goto cap_err;
- }
- /* detect row_3_4 */
- test_addr = SDRAM_ADDR;
- test_addr1 = (void __iomem *)(SDRAM_ADDR +
- (0x3ul << (row + bktmp + coltmp + bw - 1ul - 1ul)));
-
- writel(0, test_addr);
- writel(PATTERN, test_addr1);
- if ((readl(test_addr) == 0) &&
- (readl(test_addr1) == PATTERN))
- row_3_4 = 0;
- else
- row_3_4 = 1;
- /* disable auto low-power */
- pwrctl = readl(pctl_base + DDR_PCTL2_PWRCTL);
- writel(0, pctl_base + DDR_PCTL2_PWRCTL);
+ /* detect row_3_4 */
+ sdram_detect_row_3_4(cap_info, coltmp, bktmp);
- /* bw and cs detect using phy read gate training */
+ /* bw and cs detect using data training */
if (data_training(dram, 1, dram_type) == 0)
cs = 1;
else
cs = 0;
+ cap_info->rank = cs + 1;
bw = 2;
+ cap_info->bw = bw;
- /* restore auto low-power */
- writel(pwrctl, pctl_base + DDR_PCTL2_PWRCTL);
-
- sdram_ch.rank = cs + 1;
- sdram_ch.col = col;
- sdram_ch.bk = bk;
- sdram_ch.dbw = dbw;
- sdram_ch.bw = bw;
- sdram_ch.cs0_row = row;
- if (cs)
- sdram_ch.cs1_row = row;
- else
- sdram_ch.cs1_row = 0;
- sdram_ch.row_3_4 = row_3_4;
-
- if (dram_type == DDR4)
- cap = 1llu << (cs + row + bk + col + ((dbw == 0) ? 2 : 1) + bw);
- else
- cap = 1llu << (cs + row + bk + col + bw);
-
- return cap;
-
-cap_err:
- return 0;
-}
-
-static u32 remodify_sdram_params(struct rk3328_sdram_params *sdram_params)
-{
- u32 tmp = 0, tmp_adr = 0, i;
-
- for (i = 0; sdram_params->pctl_regs.pctl[i][0] != 0xFFFFFFFF; i++) {
- if (sdram_params->pctl_regs.pctl[i][0] == 0) {
- tmp = sdram_params->pctl_regs.pctl[i][1];/* MSTR */
- tmp_adr = i;
- }
- }
-
- tmp &= ~((3ul << 30) | (3ul << 24) | (3ul << 12));
-
- switch (sdram_ch.dbw) {
- case 2:
- tmp |= (3ul << 30);
- break;
- case 1:
- tmp |= (2ul << 30);
- break;
- case 0:
- default:
- tmp |= (1ul << 30);
- break;
+ cap_info->cs0_high16bit_row = cap_info->cs0_row;
+ if (cs) {
+ cap_info->cs1_row = cap_info->cs0_row;
+ cap_info->cs1_high16bit_row = cap_info->cs0_row;
+ } else {
+ cap_info->cs1_row = 0;
+ cap_info->cs1_high16bit_row = 0;
}
- if (sdram_ch.rank == 2)
- tmp |= 3 << 24;
- else
- tmp |= 1 << 24;
-
- tmp |= (2 - sdram_ch.bw) << 12;
-
- sdram_params->pctl_regs.pctl[tmp_adr][1] = tmp;
-
- if (sdram_ch.bw == 2)
- sdram_ch.noc_timings.ddrtiming.b.bwratio = 0;
- else
- sdram_ch.noc_timings.ddrtiming.b.bwratio = 1;
-
return 0;
-}
-
-static int dram_detect_cs1_row(struct rk3328_sdram_params *sdram_params,
- unsigned char channel)
-{
- u32 ret = 0;
- u32 cs1_bit;
- void __iomem *test_addr, *cs1_addr;
- u32 row, bktmp, coltmp, bw;
- u32 ddrconf = sdram_ch.ddrconfig;
-
- if (sdram_ch.rank == 2) {
- cs1_bit = addrmap[ddrconf][0] + 8;
-
- if (cs1_bit > 31)
- goto out;
-
- cs1_addr = (void __iomem *)(1ul << cs1_bit);
- if (cs1_bit < 20)
- cs1_bit = 1;
- else
- cs1_bit = 0;
-
- if (sdram_params->dramtype == DDR4) {
- if (sdram_ch.dbw == 0)
- bktmp = sdram_ch.bk + 2;
- else
- bktmp = sdram_ch.bk + 1;
- } else {
- bktmp = sdram_ch.bk;
- }
- bw = sdram_ch.bw;
- coltmp = sdram_ch.col;
-
- /* detect cs1 row */
- for (row = sdram_ch.cs0_row; row > 12; row--) {
- test_addr = (void __iomem *)(SDRAM_ADDR + cs1_addr +
- (1ul << (row + cs1_bit + bktmp +
- coltmp + bw - 1ul)));
- writel(0, SDRAM_ADDR + cs1_addr);
- writel(PATTERN, test_addr);
- if ((readl(test_addr) == PATTERN) &&
- (readl(SDRAM_ADDR + cs1_addr) == 0)) {
- ret = row;
- break;
- }
- }
- }
-
-out:
- return ret;
+cap_err:
+ return -1;
}
static int sdram_init_detect(struct dram_info *dram,
struct rk3328_sdram_params *sdram_params)
{
+ u32 sys_reg = 0;
+ u32 sys_reg3 = 0;
+ struct sdram_cap_info *cap_info = &sdram_params->ch.cap_info;
+
debug("Starting SDRAM initialization...\n");
memcpy(&sdram_ch, &sdram_params->ch,
@@ -949,13 +486,29 @@ static int sdram_init_detect(struct dram_info *dram,
dram_detect_cap(dram, sdram_params, 0);
/* modify bw, cs related timing */
- remodify_sdram_params(sdram_params);
+ pctl_remodify_sdram_params(&sdram_params->pctl_regs, cap_info,
+ sdram_params->base.dramtype);
+
+ if (cap_info->bw == 2)
+ sdram_ch.noc_timings.ddrtiming.b.bwratio = 0;
+ else
+ sdram_ch.noc_timings.ddrtiming.b.bwratio = 1;
+
/* reinit sdram by real dram cap */
sdram_init(dram, sdram_params, 0);
/* redetect cs1 row */
- sdram_ch.cs1_row =
- dram_detect_cs1_row(sdram_params, 0);
+ sdram_detect_cs1_row(cap_info, sdram_params->base.dramtype);
+ if (cap_info->cs1_row) {
+ sys_reg = readl(&dram->grf->os_reg[2]);
+ sys_reg3 = readl(&dram->grf->os_reg[3]);
+ SYS_REG_ENC_CS1_ROW(cap_info->cs1_row,
+ sys_reg, sys_reg3, 0);
+ writel(sys_reg, &dram->grf->os_reg[2]);
+ writel(sys_reg3, &dram->grf->os_reg[3]);
+ }
+
+ sdram_print_ddr_info(&sdram_params->ch.cap_info, &sdram_params->base);
return 0;
}
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c
index ed70137ce7..7b2bba03fe 100644
--- a/drivers/ram/rockchip/sdram_rk3399.c
+++ b/drivers/ram/rockchip/sdram_rk3399.c
@@ -18,7 +18,7 @@
#include <asm/arch-rockchip/grf_rk3399.h>
#include <asm/arch-rockchip/pmu_rk3399.h>
#include <asm/arch-rockchip/hardware.h>
-#include <asm/arch-rockchip/sdram_common.h>
+#include <asm/arch-rockchip/sdram.h>
#include <asm/arch-rockchip/sdram_rk3399.h>
#include <linux/err.h>
#include <time.h>
@@ -44,6 +44,11 @@
#define CS0_MR22_VAL 0
#define CS1_MR22_VAL 3
+/* LPDDR3 DRAM DS */
+#define LPDDR3_DS_34 0x1
+#define LPDDR3_DS_40 0x2
+#define LPDDR3_DS_48 0x3
+
#define CRU_SFTRST_DDR_CTRL(ch, n) ((0x1 << (8 + 16 + (ch) * 4)) | \
((n) << (8 + (ch) * 4)))
#define CRU_SFTRST_DDR_PHY(ch, n) ((0x1 << (9 + 16 + (ch) * 4)) | \
@@ -52,7 +57,7 @@ struct chan_info {
struct rk3399_ddr_pctl_regs *pctl;
struct rk3399_ddr_pi_regs *pi;
struct rk3399_ddr_publ_regs *publ;
- struct rk3399_msch_regs *msch;
+ struct msch_regs *msch;
};
struct dram_info {
@@ -74,10 +79,15 @@ struct dram_info {
};
struct sdram_rk3399_ops {
- int (*data_training)(struct dram_info *dram, u32 channel, u8 rank,
- struct rk3399_sdram_params *sdram);
- int (*set_rate)(struct dram_info *dram,
- struct rk3399_sdram_params *params);
+ int (*data_training_first)(struct dram_info *dram, u32 channel, u8 rank,
+ struct rk3399_sdram_params *sdram);
+ int (*set_rate_index)(struct dram_info *dram,
+ struct rk3399_sdram_params *params);
+ void (*modify_param)(const struct chan_info *chan,
+ struct rk3399_sdram_params *params);
+ struct rk3399_sdram_params *
+ (*get_phy_index_params)(u32 phy_fn,
+ struct rk3399_sdram_params *params);
};
#if defined(CONFIG_TPL_BUILD) || \
@@ -144,38 +154,21 @@ struct io_setting {
32, /* rd_vref; (unit %, range 3.3% - 48.7%) */
},
{
- 800 * MHz,
+ 933 * MHz,
0,
/* dram side */
1, /* dq_odt; */
0, /* ca_odt; */
- 1, /* pdds; */
+ 3, /* pdds; */
0x72, /* dq_vref; */
0x72, /* ca_vref; */
/* phy side */
- PHY_DRV_ODT_40, /* rd_odt; */
- PHY_DRV_ODT_48, /* wr_dq_drv; */
+ PHY_DRV_ODT_80, /* rd_odt; */
+ PHY_DRV_ODT_40, /* wr_dq_drv; */
PHY_DRV_ODT_40, /* wr_ca_drv; */
PHY_DRV_ODT_40, /* wr_ckcs_drv; */
1, /* rd_odt_en; */
- 17, /* rd_vref; (unit %, range 3.3% - 48.7%) */
- },
- {
- 933 * MHz,
- 0,
- /* dram side */
- 3, /* dq_odt; */
- 0, /* ca_odt; */
- 6, /* pdds; */
- 0x59, /* dq_vref; 32% */
- 0x72, /* ca_vref; */
- /* phy side */
- PHY_DRV_ODT_HI_Z, /* rd_odt; */
- PHY_DRV_ODT_48, /* wr_dq_drv; */
- PHY_DRV_ODT_40, /* wr_ca_drv; */
- PHY_DRV_ODT_40, /* wr_ckcs_drv; */
- 0, /* rd_odt_en; */
- 32, /* rd_vref; (unit %, range 3.3% - 48.7%) */
+ 20, /* rd_vref; (unit %, range 3.3% - 48.7%) */
},
{
1066 * MHz,
@@ -183,24 +176,19 @@ struct io_setting {
/* dram side */
6, /* dq_odt; */
0, /* ca_odt; */
- 1, /* pdds; */
+ 3, /* pdds; */
0x10, /* dq_vref; */
0x72, /* ca_vref; */
/* phy side */
- PHY_DRV_ODT_40, /* rd_odt; */
+ PHY_DRV_ODT_80, /* rd_odt; */
PHY_DRV_ODT_60, /* wr_dq_drv; */
PHY_DRV_ODT_40, /* wr_ca_drv; */
PHY_DRV_ODT_40, /* wr_ckcs_drv; */
1, /* rd_odt_en; */
- 17, /* rd_vref; (unit %, range 3.3% - 48.7%) */
+ 20, /* rd_vref; (unit %, range 3.3% - 48.7%) */
},
};
-/**
- * phy = 0, PHY boot freq
- * phy = 1, PHY index 0
- * phy = 2, PHY index 1
- */
static struct io_setting *
lpddr4_get_io_settings(const struct rk3399_sdram_params *params, u32 mr5)
{
@@ -223,32 +211,21 @@ lpddr4_get_io_settings(const struct rk3399_sdram_params *params, u32 mr5)
return io;
}
-static void *get_denali_phy(const struct chan_info *chan,
- struct rk3399_sdram_params *params, bool reg)
-{
- return reg ? &chan->publ->denali_phy : &params->phy_regs.denali_phy;
-}
-
static void *get_denali_ctl(const struct chan_info *chan,
struct rk3399_sdram_params *params, bool reg)
{
return reg ? &chan->pctl->denali_ctl : &params->pctl_regs.denali_ctl;
}
-static void *get_ddrc0_con(struct dram_info *dram, u8 channel)
+static void *get_denali_phy(const struct chan_info *chan,
+ struct rk3399_sdram_params *params, bool reg)
{
- return (channel == 0) ? &dram->grf->ddrc0_con0 : &dram->grf->ddrc0_con1;
+ return reg ? &chan->publ->denali_phy : &params->phy_regs.denali_phy;
}
-static void copy_to_reg(u32 *dest, const u32 *src, u32 n)
+static void *get_ddrc0_con(struct dram_info *dram, u8 channel)
{
- int i;
-
- for (i = 0; i < n / sizeof(u32); i++) {
- writel(*src, dest);
- src++;
- dest++;
- }
+ return (channel == 0) ? &dram->grf->ddrc0_con0 : &dram->grf->ddrc1_con0;
}
static void rkclk_ddr_reset(struct rk3399_cru *cru, u32 channel, u32 ctl,
@@ -319,7 +296,8 @@ static void set_memory_map(const struct chan_info *chan, u32 channel,
if (sdram_ch->cap_info.ddrconfig < 2 ||
sdram_ch->cap_info.ddrconfig == 4)
row = 16;
- else if (sdram_ch->cap_info.ddrconfig == 3)
+ else if (sdram_ch->cap_info.ddrconfig == 3 ||
+ sdram_ch->cap_info.ddrconfig == 5)
row = 14;
else
row = 15;
@@ -344,7 +322,7 @@ static void set_memory_map(const struct chan_info *chan, u32 channel,
((3 - sdram_ch->cap_info.bk) << 16) |
((16 - row) << 24));
- if (IS_ENABLED(CONFIG_RAM_RK3399_LPDDR4)) {
+ if (params->base.dramtype == LPDDR4) {
if (cs_map == 1)
cs_map = 0x5;
else if (cs_map == 2)
@@ -363,11 +341,12 @@ static int phy_io_config(const struct chan_info *chan,
const struct rk3399_sdram_params *params, u32 mr5)
{
u32 *denali_phy = chan->publ->denali_phy;
+ u32 *denali_ctl = chan->pctl->denali_ctl;
u32 vref_mode_dq, vref_value_dq, vref_mode_ac, vref_value_ac;
u32 mode_sel;
- u32 reg_value;
- u32 drv_value, odt_value;
u32 speed;
+ u32 reg_value;
+ u32 ds_value, odt_value;
/* vref setting & mode setting */
if (params->base.dramtype == LPDDR4) {
@@ -393,12 +372,12 @@ static int phy_io_config(const struct chan_info *chan,
} else if (params->base.dramtype == LPDDR3) {
if (params->base.odt == 1) {
vref_mode_dq = 0x5; /* LPDDR3 ODT */
- drv_value = (readl(&denali_phy[6]) >> 12) & 0xf;
+ ds_value = readl(&denali_ctl[138]) & 0xf;
odt_value = (readl(&denali_phy[6]) >> 4) & 0xf;
- if (drv_value == PHY_DRV_ODT_48) {
+ if (ds_value == LPDDR3_DS_48) {
switch (odt_value) {
case PHY_DRV_ODT_240:
- vref_value_dq = 0x16;
+ vref_value_dq = 0x1B;
break;
case PHY_DRV_ODT_120:
vref_value_dq = 0x26;
@@ -410,7 +389,7 @@ static int phy_io_config(const struct chan_info *chan,
debug("Invalid ODT value.\n");
return -EINVAL;
}
- } else if (drv_value == PHY_DRV_ODT_40) {
+ } else if (ds_value == LPDDR3_DS_40) {
switch (odt_value) {
case PHY_DRV_ODT_240:
vref_value_dq = 0x19;
@@ -425,7 +404,7 @@ static int phy_io_config(const struct chan_info *chan,
debug("Invalid ODT value.\n");
return -EINVAL;
}
- } else if (drv_value == PHY_DRV_ODT_34_3) {
+ } else if (ds_value == LPDDR3_DS_34) {
switch (odt_value) {
case PHY_DRV_ODT_240:
vref_value_dq = 0x17;
@@ -496,7 +475,7 @@ static int phy_io_config(const struct chan_info *chan,
/* PHY_939 PHY_PAD_CS_DRIVE */
clrsetbits_le32(&denali_phy[939], 0x7 << 14, mode_sel << 14);
- if (IS_ENABLED(CONFIG_RAM_RK3399_LPDDR4)) {
+ if (params->base.dramtype == LPDDR4) {
/* BOOSTP_EN & BOOSTN_EN */
reg_value = ((PHY_BOOSTP_EN << 4) | PHY_BOOSTN_EN);
/* PHY_925 PHY_PAD_FDBK_DRIVE2 */
@@ -537,14 +516,7 @@ static int phy_io_config(const struct chan_info *chan,
}
/* speed setting */
- if (params->base.ddr_freq < 400)
- speed = 0x0;
- else if (params->base.ddr_freq < 800)
- speed = 0x1;
- else if (params->base.ddr_freq < 1200)
- speed = 0x2;
- else
- speed = 0x3;
+ speed = 0x2;
/* PHY_924 PHY_PAD_FDBK_DRIVE */
clrsetbits_le32(&denali_phy[924], 0x3 << 21, speed << 21);
@@ -563,7 +535,7 @@ static int phy_io_config(const struct chan_info *chan,
/* PHY_939 PHY_PAD_CS_DRIVE */
clrsetbits_le32(&denali_phy[939], 0x3 << 17, speed << 17);
- if (IS_ENABLED(CONFIG_RAM_RK3399_LPDDR4)) {
+ if (params->base.dramtype == LPDDR4) {
/* RX_CM_INPUT */
reg_value = PHY_RX_CM_INPUT;
/* PHY_924 PHY_PAD_FDBK_DRIVE */
@@ -610,16 +582,17 @@ static void set_ds_odt(const struct chan_info *chan,
tsel_rd_select_n = io->rd_odt;
tsel_idle_select_p = PHY_DRV_ODT_HI_Z;
- tsel_idle_select_n = PHY_DRV_ODT_240;
+ tsel_idle_select_n = PHY_DRV_ODT_HI_Z;
tsel_wr_select_dq_p = io->wr_dq_drv;
- tsel_wr_select_dq_n = PHY_DRV_ODT_40;
+ tsel_wr_select_dq_n = PHY_DRV_ODT_34_3;
tsel_wr_select_ca_p = io->wr_ca_drv;
- tsel_wr_select_ca_n = PHY_DRV_ODT_40;
+ tsel_wr_select_ca_n = PHY_DRV_ODT_34_3;
tsel_ckcs_select_p = io->wr_ckcs_drv;
tsel_ckcs_select_n = PHY_DRV_ODT_34_3;
+
switch (tsel_rd_select_n) {
case PHY_DRV_ODT_240:
soc_odt = 1;
@@ -659,8 +632,8 @@ static void set_ds_odt(const struct chan_info *chan,
tsel_wr_select_dq_p = PHY_DRV_ODT_34_3;
tsel_wr_select_dq_n = PHY_DRV_ODT_34_3;
- tsel_wr_select_ca_p = PHY_DRV_ODT_48;
- tsel_wr_select_ca_n = PHY_DRV_ODT_48;
+ tsel_wr_select_ca_p = PHY_DRV_ODT_34_3;
+ tsel_wr_select_ca_n = PHY_DRV_ODT_34_3;
tsel_ckcs_select_p = PHY_DRV_ODT_34_3;
tsel_ckcs_select_n = PHY_DRV_ODT_34_3;
@@ -733,7 +706,7 @@ static void set_ds_odt(const struct chan_info *chan,
/* phy_adr_tsel_select_ 8bits DENALI_PHY_544/672/800 offset_0 */
reg_value = tsel_wr_select_ca_n | (tsel_wr_select_ca_p << 0x4);
- if (IS_ENABLED(CONFIG_RAM_RK3399_LPDDR4)) {
+ if (params->base.dramtype == LPDDR4) {
/* LPDDR4 these register read always return 0, so
* can not use clrsetbits_le32(), need to write32
*/
@@ -766,9 +739,9 @@ static void set_ds_odt(const struct chan_info *chan,
/* phy_pad_fdbk_drive 23bit DENALI_PHY_924/925 */
clrsetbits_le32(&denali_phy[924], 0xff,
- tsel_wr_select_dq_n | (tsel_wr_select_dq_p << 4));
+ tsel_wr_select_ca_n | (tsel_wr_select_ca_p << 4));
clrsetbits_le32(&denali_phy[925], 0xff,
- tsel_rd_select_n | (tsel_rd_select_p << 4));
+ tsel_wr_select_dq_n | (tsel_wr_select_dq_p << 4));
/* phy_dq_tsel_enable_X 3bits DENALI_PHY_5/133/261/389 offset_16 */
reg_value = (tsel_rd_en | (tsel_wr_en << 1) | (tsel_idle_en << 2))
@@ -810,46 +783,107 @@ static void set_ds_odt(const struct chan_info *chan,
phy_io_config(chan, params, mr5);
}
-static void pctl_start(struct dram_info *dram, u8 channel)
+static void pctl_start(struct dram_info *dram,
+ struct rk3399_sdram_params *params,
+ u32 channel_mask)
{
- const struct chan_info *chan = &dram->chan[channel];
- u32 *denali_ctl = chan->pctl->denali_ctl;
- u32 *denali_phy = chan->publ->denali_phy;
- u32 *ddrc0_con = get_ddrc0_con(dram, channel);
+ const struct chan_info *chan_0 = &dram->chan[0];
+ const struct chan_info *chan_1 = &dram->chan[1];
+
+ u32 *denali_ctl_0 = chan_0->pctl->denali_ctl;
+ u32 *denali_phy_0 = chan_0->publ->denali_phy;
+ u32 *ddrc0_con_0 = get_ddrc0_con(dram, 0);
+ u32 *denali_ctl_1 = chan_1->pctl->denali_ctl;
+ u32 *denali_phy_1 = chan_1->publ->denali_phy;
+ u32 *ddrc1_con_0 = get_ddrc0_con(dram, 1);
u32 count = 0;
u32 byte, tmp;
- writel(0x01000000, &ddrc0_con);
+ /* PHY_DLL_RST_EN */
+ if (channel_mask & 1) {
+ writel(0x01000000, &ddrc0_con_0);
+ clrsetbits_le32(&denali_phy_0[957], 0x3 << 24, 0x2 << 24);
+ }
- clrsetbits_le32(&denali_phy[957], 0x3 << 24, 0x2 << 24);
+ if (channel_mask & 1) {
+ count = 0;
+ while (!(readl(&denali_ctl_0[203]) & (1 << 3))) {
+ if (count > 1000) {
+ printf("%s: Failed to init pctl channel 0\n",
+ __func__);
+ while (1)
+ ;
+ }
+ udelay(1);
+ count++;
+ }
- while (!(readl(&denali_ctl[203]) & (1 << 3))) {
- if (count > 1000) {
- printf("%s: Failed to init pctl for channel %d\n",
- __func__, channel);
- while (1)
- ;
+ writel(0x01000100, &ddrc0_con_0);
+ for (byte = 0; byte < 4; byte++) {
+ tmp = 0x820;
+ writel((tmp << 16) | tmp,
+ &denali_phy_0[53 + (128 * byte)]);
+ writel((tmp << 16) | tmp,
+ &denali_phy_0[54 + (128 * byte)]);
+ writel((tmp << 16) | tmp,
+ &denali_phy_0[55 + (128 * byte)]);
+ writel((tmp << 16) | tmp,
+ &denali_phy_0[56 + (128 * byte)]);
+ writel((tmp << 16) | tmp,
+ &denali_phy_0[57 + (128 * byte)]);
+ clrsetbits_le32(&denali_phy_0[58 + (128 * byte)],
+ 0xffff, tmp);
}
+ clrsetbits_le32(&denali_ctl_0[68], PWRUP_SREFRESH_EXIT,
+ dram->pwrup_srefresh_exit[0]);
+ }
- udelay(1);
- count++;
+ if (channel_mask & 2) {
+ writel(0x01000000, &ddrc1_con_0);
+ clrsetbits_le32(&denali_phy_1[957], 0x3 << 24, 0x2 << 24);
}
+ if (channel_mask & 2) {
+ count = 0;
+ while (!(readl(&denali_ctl_1[203]) & (1 << 3))) {
+ if (count > 1000) {
+ printf("%s: Failed to init pctl channel 1\n",
+ __func__);
+ while (1)
+ ;
+ }
+ udelay(1);
+ count++;
+ }
- writel(0x01000100, &ddrc0_con);
+ writel(0x01000100, &ddrc1_con_0);
+ for (byte = 0; byte < 4; byte++) {
+ tmp = 0x820;
+ writel((tmp << 16) | tmp,
+ &denali_phy_1[53 + (128 * byte)]);
+ writel((tmp << 16) | tmp,
+ &denali_phy_1[54 + (128 * byte)]);
+ writel((tmp << 16) | tmp,
+ &denali_phy_1[55 + (128 * byte)]);
+ writel((tmp << 16) | tmp,
+ &denali_phy_1[56 + (128 * byte)]);
+ writel((tmp << 16) | tmp,
+ &denali_phy_1[57 + (128 * byte)]);
+ clrsetbits_le32(&denali_phy_1[58 + (128 * byte)],
+ 0xffff, tmp);
+ }
- for (byte = 0; byte < 4; byte++) {
- tmp = 0x820;
- writel((tmp << 16) | tmp, &denali_phy[53 + (128 * byte)]);
- writel((tmp << 16) | tmp, &denali_phy[54 + (128 * byte)]);
- writel((tmp << 16) | tmp, &denali_phy[55 + (128 * byte)]);
- writel((tmp << 16) | tmp, &denali_phy[56 + (128 * byte)]);
- writel((tmp << 16) | tmp, &denali_phy[57 + (128 * byte)]);
+ clrsetbits_le32(&denali_ctl_1[68], PWRUP_SREFRESH_EXIT,
+ dram->pwrup_srefresh_exit[1]);
- clrsetbits_le32(&denali_phy[58 + (128 * byte)], 0xffff, tmp);
+ /*
+ * restore channel 1 RESET original setting
+ * to avoid 240ohm too weak to prevent ESD test
+ */
+ if (params->base.dramtype == LPDDR4)
+ clrsetbits_le32(&denali_phy_1[937], 0xff,
+ params->phy_regs.denali_phy[937] &
+ 0xFF);
}
-
- clrsetbits_le32(&denali_ctl[68], PWRUP_SREFRESH_EXIT,
- dram->pwrup_srefresh_exit[channel]);
}
static int pctl_cfg(struct dram_info *dram, const struct chan_info *chan,
@@ -861,13 +895,16 @@ static int pctl_cfg(struct dram_info *dram, const struct chan_info *chan,
const u32 *params_ctl = params->pctl_regs.denali_ctl;
const u32 *params_phy = params->phy_regs.denali_phy;
u32 tmp, tmp1, tmp2;
+ struct rk3399_sdram_params *params_cfg;
+ u32 byte;
+ dram->ops->modify_param(chan, params);
/*
* work around controller bug:
* Do not program DRAM_CLASS until NO_PHY_IND_TRAIN_INT is programmed
*/
- copy_to_reg(&denali_ctl[1], &params_ctl[1],
- sizeof(struct rk3399_ddr_pctl_regs) - 4);
+ sdram_copy_to_reg(&denali_ctl[1], &params_ctl[1],
+ sizeof(struct rk3399_ddr_pctl_regs) - 4);
writel(params_ctl[0], &denali_ctl[0]);
/*
@@ -884,8 +921,8 @@ static int pctl_cfg(struct dram_info *dram, const struct chan_info *chan,
writel(tmp + tmp1, &denali_ctl[14]);
}
- copy_to_reg(denali_pi, &params->pi_regs.denali_pi[0],
- sizeof(struct rk3399_ddr_pi_regs));
+ sdram_copy_to_reg(denali_pi, &params->pi_regs.denali_pi[0],
+ sizeof(struct rk3399_ddr_pi_regs));
/* rank count need to set for init */
set_memory_map(chan, channel, params);
@@ -894,7 +931,7 @@ static int pctl_cfg(struct dram_info *dram, const struct chan_info *chan,
writel(params->phy_regs.denali_phy[911], &denali_phy[911]);
writel(params->phy_regs.denali_phy[912], &denali_phy[912]);
- if (IS_ENABLED(CONFIG_RAM_RK3399_LPDDR4)) {
+ if (params->base.dramtype == LPDDR4) {
writel(params->phy_regs.denali_phy[898], &denali_phy[898]);
writel(params->phy_regs.denali_phy[919], &denali_phy[919]);
}
@@ -927,41 +964,67 @@ static int pctl_cfg(struct dram_info *dram, const struct chan_info *chan,
}
}
- copy_to_reg(&denali_phy[896], &params_phy[896], (958 - 895) * 4);
- copy_to_reg(&denali_phy[0], &params_phy[0], (90 - 0 + 1) * 4);
- copy_to_reg(&denali_phy[128], &params_phy[128], (218 - 128 + 1) * 4);
- copy_to_reg(&denali_phy[256], &params_phy[256], (346 - 256 + 1) * 4);
- copy_to_reg(&denali_phy[384], &params_phy[384], (474 - 384 + 1) * 4);
- copy_to_reg(&denali_phy[512], &params_phy[512], (549 - 512 + 1) * 4);
- copy_to_reg(&denali_phy[640], &params_phy[640], (677 - 640 + 1) * 4);
- copy_to_reg(&denali_phy[768], &params_phy[768], (805 - 768 + 1) * 4);
- set_ds_odt(chan, params, true, 0);
+ sdram_copy_to_reg(&denali_phy[896], &params_phy[896], (958 - 895) * 4);
+ sdram_copy_to_reg(&denali_phy[0], &params_phy[0], (90 - 0 + 1) * 4);
+ sdram_copy_to_reg(&denali_phy[128], &params_phy[128],
+ (218 - 128 + 1) * 4);
+ sdram_copy_to_reg(&denali_phy[256], &params_phy[256],
+ (346 - 256 + 1) * 4);
+ sdram_copy_to_reg(&denali_phy[384], &params_phy[384],
+ (474 - 384 + 1) * 4);
+ sdram_copy_to_reg(&denali_phy[512], &params_phy[512],
+ (549 - 512 + 1) * 4);
+ sdram_copy_to_reg(&denali_phy[640], &params_phy[640],
+ (677 - 640 + 1) * 4);
+ sdram_copy_to_reg(&denali_phy[768], &params_phy[768],
+ (805 - 768 + 1) * 4);
- /*
- * phy_dqs_tsel_wr_timing_X 8bits DENALI_PHY_84/212/340/468 offset_8
- * dqs_tsel_wr_end[7:4] add Half cycle
- */
- tmp = (readl(&denali_phy[84]) >> 8) & 0xff;
- clrsetbits_le32(&denali_phy[84], 0xff << 8, (tmp + 0x10) << 8);
- tmp = (readl(&denali_phy[212]) >> 8) & 0xff;
- clrsetbits_le32(&denali_phy[212], 0xff << 8, (tmp + 0x10) << 8);
- tmp = (readl(&denali_phy[340]) >> 8) & 0xff;
- clrsetbits_le32(&denali_phy[340], 0xff << 8, (tmp + 0x10) << 8);
- tmp = (readl(&denali_phy[468]) >> 8) & 0xff;
- clrsetbits_le32(&denali_phy[468], 0xff << 8, (tmp + 0x10) << 8);
+ if (params->base.dramtype == LPDDR4)
+ params_cfg = dram->ops->get_phy_index_params(1, params);
+ else
+ params_cfg = dram->ops->get_phy_index_params(0, params);
+
+ clrsetbits_le32(&params_cfg->phy_regs.denali_phy[896], 0x3 << 8,
+ 0 << 8);
+ writel(params_cfg->phy_regs.denali_phy[896], &denali_phy[896]);
+
+ writel(params->phy_regs.denali_phy[83] + (0x10 << 16),
+ &denali_phy[83]);
+ writel(params->phy_regs.denali_phy[84] + (0x10 << 8),
+ &denali_phy[84]);
+ writel(params->phy_regs.denali_phy[211] + (0x10 << 16),
+ &denali_phy[211]);
+ writel(params->phy_regs.denali_phy[212] + (0x10 << 8),
+ &denali_phy[212]);
+ writel(params->phy_regs.denali_phy[339] + (0x10 << 16),
+ &denali_phy[339]);
+ writel(params->phy_regs.denali_phy[340] + (0x10 << 8),
+ &denali_phy[340]);
+ writel(params->phy_regs.denali_phy[467] + (0x10 << 16),
+ &denali_phy[467]);
+ writel(params->phy_regs.denali_phy[468] + (0x10 << 8),
+ &denali_phy[468]);
- /*
- * phy_dqs_tsel_wr_timing_X 8bits DENALI_PHY_83/211/339/467 offset_8
- * dq_tsel_wr_end[7:4] add Half cycle
- */
- tmp = (readl(&denali_phy[83]) >> 16) & 0xff;
- clrsetbits_le32(&denali_phy[83], 0xff << 16, (tmp + 0x10) << 16);
- tmp = (readl(&denali_phy[211]) >> 16) & 0xff;
- clrsetbits_le32(&denali_phy[211], 0xff << 16, (tmp + 0x10) << 16);
- tmp = (readl(&denali_phy[339]) >> 16) & 0xff;
- clrsetbits_le32(&denali_phy[339], 0xff << 16, (tmp + 0x10) << 16);
- tmp = (readl(&denali_phy[467]) >> 16) & 0xff;
- clrsetbits_le32(&denali_phy[467], 0xff << 16, (tmp + 0x10) << 16);
+ if (params->base.dramtype == LPDDR4) {
+ /*
+ * to improve write dqs and dq phase from 1.5ns to 3.5ns
+ * at 50MHz. this's the measure result from oscilloscope
+ * of dqs and dq write signal.
+ */
+ for (byte = 0; byte < 4; byte++) {
+ tmp = 0x680;
+ clrsetbits_le32(&denali_phy[1 + (128 * byte)],
+ 0xfff << 8, tmp << 8);
+ }
+ /*
+ * to workaround 366ball two channel's RESET connect to
+ * one RESET signal of die
+ */
+ if (channel == 1)
+ clrsetbits_le32(&denali_phy[937], 0xff,
+ PHY_DRV_ODT_240 |
+ (PHY_DRV_ODT_240 << 0x4));
+ }
return 0;
}
@@ -1277,10 +1340,9 @@ static int data_training_wdql(const struct chan_info *chan, u32 channel,
/*
* disable PI_WDQLVL_VREF_EN before wdq leveling?
- * PI_181 PI_WDQLVL_VREF_EN:RW:8:1
+ * PI_117 PI_WDQLVL_VREF_EN:RW:8:1
*/
- clrbits_le32(&denali_pi[181], 0x1 << 8);
-
+ clrbits_le32(&denali_pi[117], 0x1 << 8);
/* PI_124 PI_WDQLVL_EN:RW:16:2 */
clrsetbits_le32(&denali_pi[124], 0x3 << 16, 0x2 << 16);
@@ -1392,7 +1454,7 @@ static void set_ddrconfig(const struct chan_info *chan,
unsigned char channel, u32 ddrconfig)
{
/* only need to set ddrconfig */
- struct rk3399_msch_regs *ddr_msch_regs = chan->msch;
+ struct msch_regs *ddr_msch_regs = chan->msch;
unsigned int cs0_cap = 0;
unsigned int cs1_cap = 0;
@@ -1413,52 +1475,43 @@ static void set_ddrconfig(const struct chan_info *chan,
&ddr_msch_regs->ddrsize);
}
+static void sdram_msch_config(struct msch_regs *msch,
+ struct sdram_msch_timings *noc_timings)
+{
+ writel(noc_timings->ddrtiminga0.d32,
+ &msch->ddrtiminga0.d32);
+ writel(noc_timings->ddrtimingb0.d32,
+ &msch->ddrtimingb0.d32);
+ writel(noc_timings->ddrtimingc0.d32,
+ &msch->ddrtimingc0.d32);
+ writel(noc_timings->devtodev0.d32,
+ &msch->devtodev0.d32);
+ writel(noc_timings->ddrmode.d32,
+ &msch->ddrmode.d32);
+}
+
static void dram_all_config(struct dram_info *dram,
- const struct rk3399_sdram_params *params)
+ struct rk3399_sdram_params *params)
{
u32 sys_reg2 = 0;
u32 sys_reg3 = 0;
unsigned int channel, idx;
- sys_reg2 |= SYS_REG_ENC_DDRTYPE(params->base.dramtype);
- sys_reg2 |= SYS_REG_ENC_NUM_CH(params->base.num_channels);
-
for (channel = 0, idx = 0;
(idx < params->base.num_channels) && (channel < 2);
channel++) {
- const struct rk3399_sdram_channel *info = &params->ch[channel];
- struct rk3399_msch_regs *ddr_msch_regs;
- const struct rk3399_msch_timings *noc_timing;
+ struct msch_regs *ddr_msch_regs;
+ struct sdram_msch_timings *noc_timing;
if (params->ch[channel].cap_info.col == 0)
continue;
idx++;
- sys_reg2 |= SYS_REG_ENC_ROW_3_4(info->cap_info.row_3_4, channel);
- sys_reg2 |= SYS_REG_ENC_CHINFO(channel);
- sys_reg2 |= SYS_REG_ENC_RANK(info->cap_info.rank, channel);
- sys_reg2 |= SYS_REG_ENC_COL(info->cap_info.col, channel);
- sys_reg2 |= SYS_REG_ENC_BK(info->cap_info.bk, channel);
- sys_reg2 |= SYS_REG_ENC_BW(info->cap_info.bw, channel);
- sys_reg2 |= SYS_REG_ENC_DBW(info->cap_info.dbw, channel);
- SYS_REG_ENC_CS0_ROW(info->cap_info.cs0_row, sys_reg2, sys_reg3, channel);
- if (info->cap_info.cs1_row)
- SYS_REG_ENC_CS1_ROW(info->cap_info.cs1_row, sys_reg2,
- sys_reg3, channel);
- sys_reg3 |= SYS_REG_ENC_CS1_COL(info->cap_info.col, channel);
- sys_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION);
-
+ sdram_org_config(&params->ch[channel].cap_info,
+ &params->base, &sys_reg2,
+ &sys_reg3, channel);
ddr_msch_regs = dram->chan[channel].msch;
noc_timing = &params->ch[channel].noc_timings;
- writel(noc_timing->ddrtiminga0,
- &ddr_msch_regs->ddrtiminga0);
- writel(noc_timing->ddrtimingb0,
- &ddr_msch_regs->ddrtimingb0);
- writel(noc_timing->ddrtimingc0.d32,
- &ddr_msch_regs->ddrtimingc0);
- writel(noc_timing->devtodev0,
- &ddr_msch_regs->devtodev0);
- writel(noc_timing->ddrmode.d32,
- &ddr_msch_regs->ddrmode);
+ sdram_msch_config(ddr_msch_regs, noc_timing);
/**
* rank 1 memory clock disable (dfi_dram_clk_disable = 1)
@@ -1494,7 +1547,7 @@ static void set_cap_relate_config(const struct chan_info *chan,
{
u32 *denali_ctl = chan->pctl->denali_ctl;
u32 tmp;
- struct rk3399_msch_timings *noc_timing;
+ struct sdram_msch_timings *noc_timing;
if (params->base.dramtype == LPDDR3) {
tmp = (8 << params->ch[channel].cap_info.bw) /
@@ -1566,9 +1619,14 @@ static u32 calculate_ddrconfig(struct rk3399_sdram_params *params, u32 channel)
return i;
}
+static void set_ddr_stride(struct rk3399_pmusgrf_regs *pmusgrf, u32 stride)
+{
+ rk_clrsetreg(&pmusgrf->soc_con4, 0x1f << 10, stride << 10);
+}
+
#if !defined(CONFIG_RAM_RK3399_LPDDR4)
-static int default_data_training(struct dram_info *dram, u32 channel, u8 rank,
- struct rk3399_sdram_params *params)
+static int data_training_first(struct dram_info *dram, u32 channel, u8 rank,
+ struct rk3399_sdram_params *params)
{
u8 training_flag = PI_READ_GATE_TRAINING;
@@ -1629,31 +1687,72 @@ static int switch_to_phy_index1(struct dram_info *dram,
return 0;
}
+struct rk3399_sdram_params
+ *get_phy_index_params(u32 phy_fn,
+ struct rk3399_sdram_params *params)
+{
+ if (phy_fn == 0)
+ return params;
+ else
+ return NULL;
+}
+
+void modify_param(const struct chan_info *chan,
+ struct rk3399_sdram_params *params)
+{
+ struct rk3399_sdram_params *params_cfg;
+ u32 *denali_pi_params;
+
+ denali_pi_params = params->pi_regs.denali_pi;
+
+ /* modify PHY F0/F1/F2 params */
+ params_cfg = get_phy_index_params(0, params);
+ set_ds_odt(chan, params_cfg, false, 0);
+
+ clrsetbits_le32(&denali_pi_params[45], 0x1 << 24, 0x1 << 24);
+ clrsetbits_le32(&denali_pi_params[61], 0x1 << 24, 0x1 << 24);
+ clrsetbits_le32(&denali_pi_params[76], 0x1 << 24, 0x1 << 24);
+ clrsetbits_le32(&denali_pi_params[77], 0x1, 0x1);
+}
#else
-struct rk3399_sdram_params lpddr4_timings[] = {
- #include "sdram-rk3399-lpddr4-400.inc"
- #include "sdram-rk3399-lpddr4-800.inc"
+struct rk3399_sdram_params dfs_cfgs_lpddr4[] = {
+#include "sdram-rk3399-lpddr4-400.inc"
+#include "sdram-rk3399-lpddr4-800.inc"
};
+static struct rk3399_sdram_params
+ *lpddr4_get_phy_index_params(u32 phy_fn,
+ struct rk3399_sdram_params *params)
+{
+ if (phy_fn == 0)
+ return params;
+ else if (phy_fn == 1)
+ return &dfs_cfgs_lpddr4[1];
+ else if (phy_fn == 2)
+ return &dfs_cfgs_lpddr4[0];
+ else
+ return NULL;
+}
+
static void *get_denali_pi(const struct chan_info *chan,
struct rk3399_sdram_params *params, bool reg)
{
return reg ? &chan->pi->denali_pi : &params->pi_regs.denali_pi;
}
-static u32 lpddr4_get_phy(struct rk3399_sdram_params *params, u32 ctl)
+static u32 lpddr4_get_phy_fn(struct rk3399_sdram_params *params, u32 ctl_fn)
{
- u32 lpddr4_phy[] = {1, 0, 0xb};
+ u32 lpddr4_phy_fn[] = {1, 0, 0xb};
- return lpddr4_phy[ctl];
+ return lpddr4_phy_fn[ctl_fn];
}
-static u32 lpddr4_get_ctl(struct rk3399_sdram_params *params, u32 phy)
+static u32 lpddr4_get_ctl_fn(struct rk3399_sdram_params *params, u32 phy_fn)
{
- u32 lpddr4_ctl[] = {1, 0, 2};
+ u32 lpddr4_ctl_fn[] = {1, 0, 2};
- return lpddr4_ctl[phy];
+ return lpddr4_ctl_fn[phy_fn];
}
static u32 get_ddr_stride(struct rk3399_pmusgrf_regs *pmusgrf)
@@ -1661,12 +1760,7 @@ static u32 get_ddr_stride(struct rk3399_pmusgrf_regs *pmusgrf)
return ((readl(&pmusgrf->soc_con4) >> 10) & 0x1F);
}
-static void set_ddr_stride(struct rk3399_pmusgrf_regs *pmusgrf, u32 stride)
-{
- rk_clrsetreg(&pmusgrf->soc_con4, 0x1f << 10, stride << 10);
-}
-
-/**
+/*
* read mr_num mode register
* rank = 1: cs0
* rank = 2: cs1
@@ -1797,7 +1891,7 @@ end:
}
static void set_lpddr4_dq_odt(const struct chan_info *chan,
- struct rk3399_sdram_params *params, u32 ctl,
+ struct rk3399_sdram_params *params, u32 ctl_fn,
bool en, bool ctl_phy_reg, u32 mr5)
{
u32 *denali_ctl = get_denali_ctl(chan, params, ctl_phy_reg);
@@ -1805,14 +1899,13 @@ static void set_lpddr4_dq_odt(const struct chan_info *chan,
struct io_setting *io;
u32 reg_value;
- if (!en)
- return;
-
io = lpddr4_get_io_settings(params, mr5);
+ if (en)
+ reg_value = io->dq_odt;
+ else
+ reg_value = 0;
- reg_value = io->dq_odt;
-
- switch (ctl) {
+ switch (ctl_fn) {
case 0:
clrsetbits_le32(&denali_ctl[139], 0x7 << 24, reg_value << 24);
clrsetbits_le32(&denali_ctl[153], 0x7 << 24, reg_value << 24);
@@ -1845,7 +1938,7 @@ static void set_lpddr4_dq_odt(const struct chan_info *chan,
}
static void set_lpddr4_ca_odt(const struct chan_info *chan,
- struct rk3399_sdram_params *params, u32 ctl,
+ struct rk3399_sdram_params *params, u32 ctl_fn,
bool en, bool ctl_phy_reg, u32 mr5)
{
u32 *denali_ctl = get_denali_ctl(chan, params, ctl_phy_reg);
@@ -1853,14 +1946,13 @@ static void set_lpddr4_ca_odt(const struct chan_info *chan,
struct io_setting *io;
u32 reg_value;
- if (!en)
- return;
-
io = lpddr4_get_io_settings(params, mr5);
+ if (en)
+ reg_value = io->ca_odt;
+ else
+ reg_value = 0;
- reg_value = io->ca_odt;
-
- switch (ctl) {
+ switch (ctl_fn) {
case 0:
clrsetbits_le32(&denali_ctl[139], 0x7 << 28, reg_value << 28);
clrsetbits_le32(&denali_ctl[153], 0x7 << 28, reg_value << 28);
@@ -1893,7 +1985,7 @@ static void set_lpddr4_ca_odt(const struct chan_info *chan,
}
static void set_lpddr4_MR3(const struct chan_info *chan,
- struct rk3399_sdram_params *params, u32 ctl,
+ struct rk3399_sdram_params *params, u32 ctl_fn,
bool ctl_phy_reg, u32 mr5)
{
u32 *denali_ctl = get_denali_ctl(chan, params, ctl_phy_reg);
@@ -1905,7 +1997,7 @@ static void set_lpddr4_MR3(const struct chan_info *chan,
reg_value = ((io->pdds << 3) | 1);
- switch (ctl) {
+ switch (ctl_fn) {
case 0:
clrsetbits_le32(&denali_ctl[138], 0xFFFF, reg_value);
clrsetbits_le32(&denali_ctl[152], 0xFFFF, reg_value);
@@ -1940,7 +2032,7 @@ static void set_lpddr4_MR3(const struct chan_info *chan,
}
static void set_lpddr4_MR12(const struct chan_info *chan,
- struct rk3399_sdram_params *params, u32 ctl,
+ struct rk3399_sdram_params *params, u32 ctl_fn,
bool ctl_phy_reg, u32 mr5)
{
u32 *denali_ctl = get_denali_ctl(chan, params, ctl_phy_reg);
@@ -1952,7 +2044,7 @@ static void set_lpddr4_MR12(const struct chan_info *chan,
reg_value = io->ca_vref;
- switch (ctl) {
+ switch (ctl_fn) {
case 0:
clrsetbits_le32(&denali_ctl[140], 0xFFFF << 16,
reg_value << 16);
@@ -1989,7 +2081,7 @@ static void set_lpddr4_MR12(const struct chan_info *chan,
}
static void set_lpddr4_MR14(const struct chan_info *chan,
- struct rk3399_sdram_params *params, u32 ctl,
+ struct rk3399_sdram_params *params, u32 ctl_fn,
bool ctl_phy_reg, u32 mr5)
{
u32 *denali_ctl = get_denali_ctl(chan, params, ctl_phy_reg);
@@ -2001,7 +2093,7 @@ static void set_lpddr4_MR14(const struct chan_info *chan,
reg_value = io->dq_vref;
- switch (ctl) {
+ switch (ctl_fn) {
case 0:
clrsetbits_le32(&denali_ctl[142], 0xFFFF << 16,
reg_value << 16);
@@ -2037,22 +2129,73 @@ static void set_lpddr4_MR14(const struct chan_info *chan,
}
}
+void lpddr4_modify_param(const struct chan_info *chan,
+ struct rk3399_sdram_params *params)
+{
+ struct rk3399_sdram_params *params_cfg;
+ u32 *denali_ctl_params;
+ u32 *denali_pi_params;
+ u32 *denali_phy_params;
+
+ denali_ctl_params = params->pctl_regs.denali_ctl;
+ denali_pi_params = params->pi_regs.denali_pi;
+ denali_phy_params = params->phy_regs.denali_phy;
+
+ set_lpddr4_dq_odt(chan, params, 2, true, false, 0);
+ set_lpddr4_ca_odt(chan, params, 2, true, false, 0);
+ set_lpddr4_MR3(chan, params, 2, false, 0);
+ set_lpddr4_MR12(chan, params, 2, false, 0);
+ set_lpddr4_MR14(chan, params, 2, false, 0);
+ params_cfg = lpddr4_get_phy_index_params(0, params);
+ set_ds_odt(chan, params_cfg, false, 0);
+ /* read two cycle preamble */
+ clrsetbits_le32(&denali_ctl_params[200], 0x3 << 24, 0x3 << 24);
+ clrsetbits_le32(&denali_phy_params[7], 0x3 << 24, 0x3 << 24);
+ clrsetbits_le32(&denali_phy_params[135], 0x3 << 24, 0x3 << 24);
+ clrsetbits_le32(&denali_phy_params[263], 0x3 << 24, 0x3 << 24);
+ clrsetbits_le32(&denali_phy_params[391], 0x3 << 24, 0x3 << 24);
+
+ /* boot frequency two cycle preamble */
+ clrsetbits_le32(&denali_phy_params[2], 0x3 << 16, 0x3 << 16);
+ clrsetbits_le32(&denali_phy_params[130], 0x3 << 16, 0x3 << 16);
+ clrsetbits_le32(&denali_phy_params[258], 0x3 << 16, 0x3 << 16);
+ clrsetbits_le32(&denali_phy_params[386], 0x3 << 16, 0x3 << 16);
+
+ clrsetbits_le32(&denali_pi_params[45], 0x3 << 8, 0x3 << 8);
+ clrsetbits_le32(&denali_pi_params[58], 0x1, 0x1);
+
+ /*
+ * bypass mode need PHY_SLICE_PWR_RDC_DISABLE_x = 1,
+ * boot frequency mode use bypass mode
+ */
+ setbits_le32(&denali_phy_params[10], 1 << 16);
+ setbits_le32(&denali_phy_params[138], 1 << 16);
+ setbits_le32(&denali_phy_params[266], 1 << 16);
+ setbits_le32(&denali_phy_params[394], 1 << 16);
+
+ clrsetbits_le32(&denali_pi_params[45], 0x1 << 24, 0x1 << 24);
+ clrsetbits_le32(&denali_pi_params[61], 0x1 << 24, 0x1 << 24);
+ clrsetbits_le32(&denali_pi_params[76], 0x1 << 24, 0x1 << 24);
+ clrsetbits_le32(&denali_pi_params[77], 0x1, 0x1);
+}
+
static void lpddr4_copy_phy(struct dram_info *dram,
- struct rk3399_sdram_params *params, u32 phy,
- struct rk3399_sdram_params *timings,
+ struct rk3399_sdram_params *params, u32 phy_fn,
+ struct rk3399_sdram_params *params_cfg,
u32 channel)
{
u32 *denali_ctl, *denali_phy;
u32 *denali_phy_params;
u32 speed = 0;
- u32 ctl, mr5;
+ u32 ctl_fn, mr5;
denali_ctl = dram->chan[channel].pctl->denali_ctl;
denali_phy = dram->chan[channel].publ->denali_phy;
- denali_phy_params = timings->phy_regs.denali_phy;
+ denali_phy_params = params_cfg->phy_regs.denali_phy;
/* switch index */
- clrsetbits_le32(&denali_phy_params[896], 0x3 << 8, phy << 8);
+ clrsetbits_le32(&denali_phy_params[896], 0x3 << 8,
+ phy_fn << 8);
writel(denali_phy_params[896], &denali_phy[896]);
/* phy_pll_ctrl_ca, phy_pll_ctrl */
@@ -2112,14 +2255,14 @@ static void lpddr4_copy_phy(struct dram_info *dram,
* phy_clk_wrdqz_slave_delay_x
* phy_clk_wrdqs_slave_delay_x
*/
- copy_to_reg((u32 *)&denali_phy[59], (u32 *)&denali_phy_params[59],
- (63 - 58) * 4);
- copy_to_reg((u32 *)&denali_phy[187], (u32 *)&denali_phy_params[187],
- (191 - 186) * 4);
- copy_to_reg((u32 *)&denali_phy[315], (u32 *)&denali_phy_params[315],
- (319 - 314) * 4);
- copy_to_reg((u32 *)&denali_phy[443], (u32 *)&denali_phy_params[443],
- (447 - 442) * 4);
+ sdram_copy_to_reg((u32 *)&denali_phy[59],
+ (u32 *)&denali_phy_params[59], (63 - 58) * 4);
+ sdram_copy_to_reg((u32 *)&denali_phy[187],
+ (u32 *)&denali_phy_params[187], (191 - 186) * 4);
+ sdram_copy_to_reg((u32 *)&denali_phy[315],
+ (u32 *)&denali_phy_params[315], (319 - 314) * 4);
+ sdram_copy_to_reg((u32 *)&denali_phy[443],
+ (u32 *)&denali_phy_params[443], (447 - 442) * 4);
/*
* phy_dqs_tsel_wr_timing_x 8bits denali_phy_84/212/340/468 offset_8
@@ -2218,31 +2361,30 @@ static void lpddr4_copy_phy(struct dram_info *dram,
* phy_wrlvl_delay_period_threshold_x
* phy_wrlvl_early_force_zero_x
*/
- copy_to_reg((u32 *)&denali_phy[64], (u32 *)&denali_phy_params[64],
- (67 - 63) * 4);
+ sdram_copy_to_reg((u32 *)&denali_phy[64],
+ (u32 *)&denali_phy_params[64], (67 - 63) * 4);
clrsetbits_le32(&denali_phy[68], 0xfffffc00,
denali_phy_params[68] & 0xfffffc00);
- copy_to_reg((u32 *)&denali_phy[69], (u32 *)&denali_phy_params[69],
- (79 - 68) * 4);
- copy_to_reg((u32 *)&denali_phy[192], (u32 *)&denali_phy_params[192],
- (195 - 191) * 4);
+ sdram_copy_to_reg((u32 *)&denali_phy[69],
+ (u32 *)&denali_phy_params[69], (79 - 68) * 4);
+ sdram_copy_to_reg((u32 *)&denali_phy[192],
+ (u32 *)&denali_phy_params[192], (195 - 191) * 4);
clrsetbits_le32(&denali_phy[196], 0xfffffc00,
denali_phy_params[196] & 0xfffffc00);
- copy_to_reg((u32 *)&denali_phy[197], (u32 *)&denali_phy_params[197],
- (207 - 196) * 4);
- copy_to_reg((u32 *)&denali_phy[320], (u32 *)&denali_phy_params[320],
- (323 - 319) * 4);
+ sdram_copy_to_reg((u32 *)&denali_phy[197],
+ (u32 *)&denali_phy_params[197], (207 - 196) * 4);
+ sdram_copy_to_reg((u32 *)&denali_phy[320],
+ (u32 *)&denali_phy_params[320], (323 - 319) * 4);
clrsetbits_le32(&denali_phy[324], 0xfffffc00,
denali_phy_params[324] & 0xfffffc00);
- copy_to_reg((u32 *)&denali_phy[325], (u32 *)&denali_phy_params[325],
- (335 - 324) * 4);
-
- copy_to_reg((u32 *)&denali_phy[448], (u32 *)&denali_phy_params[448],
- (451 - 447) * 4);
+ sdram_copy_to_reg((u32 *)&denali_phy[325],
+ (u32 *)&denali_phy_params[325], (335 - 324) * 4);
+ sdram_copy_to_reg((u32 *)&denali_phy[448],
+ (u32 *)&denali_phy_params[448], (451 - 447) * 4);
clrsetbits_le32(&denali_phy[452], 0xfffffc00,
denali_phy_params[452] & 0xfffffc00);
- copy_to_reg((u32 *)&denali_phy[453], (u32 *)&denali_phy_params[453],
- (463 - 452) * 4);
+ sdram_copy_to_reg((u32 *)&denali_phy[453],
+ (u32 *)&denali_phy_params[453], (463 - 452) * 4);
/* phy_two_cyc_preamble_x */
clrsetbits_le32(&denali_phy[7], 0x3 << 24,
@@ -2255,11 +2397,11 @@ static void lpddr4_copy_phy(struct dram_info *dram,
denali_phy_params[391] & (0x3 << 24));
/* speed */
- if (timings->base.ddr_freq < 400 * MHz)
+ if (params_cfg->base.ddr_freq < 400)
speed = 0x0;
- else if (timings->base.ddr_freq < 800 * MHz)
+ else if (params_cfg->base.ddr_freq < 800)
speed = 0x1;
- else if (timings->base.ddr_freq < 1200 * MHz)
+ else if (params_cfg->base.ddr_freq < 1200)
speed = 0x2;
/* phy_924 phy_pad_fdbk_drive */
@@ -2279,52 +2421,63 @@ static void lpddr4_copy_phy(struct dram_info *dram,
/* phy_939 phy_pad_cs_drive */
clrsetbits_le32(&denali_phy[939], 0x3 << 17, speed << 17);
- read_mr(dram->chan[channel].pctl, 1, 5, &mr5);
- set_ds_odt(&dram->chan[channel], timings, true, mr5);
+ if (params_cfg->base.dramtype == LPDDR4) {
+ read_mr(dram->chan[channel].pctl, 1, 5, &mr5);
+ set_ds_odt(&dram->chan[channel], params_cfg, true, mr5);
+
+ ctl_fn = lpddr4_get_ctl_fn(params_cfg, phy_fn);
+ set_lpddr4_dq_odt(&dram->chan[channel], params_cfg,
+ ctl_fn, true, true, mr5);
+ set_lpddr4_ca_odt(&dram->chan[channel], params_cfg,
+ ctl_fn, true, true, mr5);
+ set_lpddr4_MR3(&dram->chan[channel], params_cfg,
+ ctl_fn, true, mr5);
+ set_lpddr4_MR12(&dram->chan[channel], params_cfg,
+ ctl_fn, true, mr5);
+ set_lpddr4_MR14(&dram->chan[channel], params_cfg,
+ ctl_fn, true, mr5);
- ctl = lpddr4_get_ctl(timings, phy);
- set_lpddr4_dq_odt(&dram->chan[channel], timings, ctl, true, true, mr5);
- set_lpddr4_ca_odt(&dram->chan[channel], timings, ctl, true, true, mr5);
- set_lpddr4_MR3(&dram->chan[channel], timings, ctl, true, mr5);
- set_lpddr4_MR12(&dram->chan[channel], timings, ctl, true, mr5);
- set_lpddr4_MR14(&dram->chan[channel], timings, ctl, true, mr5);
-
- /*
- * if phy_sw_master_mode_x not bypass mode,
- * clear phy_slice_pwr_rdc_disable.
- * note: need use timings, not ddr_publ_regs
- */
- if (!((denali_phy_params[86] >> 8) & (1 << 2))) {
- clrbits_le32(&denali_phy[10], 1 << 16);
- clrbits_le32(&denali_phy[138], 1 << 16);
- clrbits_le32(&denali_phy[266], 1 << 16);
- clrbits_le32(&denali_phy[394], 1 << 16);
- }
+ /*
+ * if phy_sw_master_mode_x not bypass mode,
+ * clear phy_slice_pwr_rdc_disable.
+ * note: need use timings, not ddr_publ_regs
+ */
+ if (!((denali_phy_params[86] >> 8) & (1 << 2))) {
+ clrbits_le32(&denali_phy[10], 1 << 16);
+ clrbits_le32(&denali_phy[138], 1 << 16);
+ clrbits_le32(&denali_phy[266], 1 << 16);
+ clrbits_le32(&denali_phy[394], 1 << 16);
+ }
- /*
- * when PHY_PER_CS_TRAINING_EN=1, W2W_DIFFCS_DLY_Fx can't
- * smaller than 8
- * NOTE: need use timings, not ddr_publ_regs
- */
- if ((denali_phy_params[84] >> 16) & 1) {
- if (((readl(&denali_ctl[217 + ctl]) >> 16) & 0x1f) < 8)
- clrsetbits_le32(&denali_ctl[217 + ctl],
- 0x1f << 16, 8 << 16);
+ /*
+ * when PHY_PER_CS_TRAINING_EN=1, W2W_DIFFCS_DLY_Fx can't
+ * smaller than 8
+ * NOTE: need use timings, not ddr_publ_regs
+ */
+ if ((denali_phy_params[84] >> 16) & 1) {
+ if (((readl(&denali_ctl[217 + ctl_fn]) >>
+ 16) & 0x1f) < 8)
+ clrsetbits_le32(&denali_ctl[217 + ctl_fn],
+ 0x1f << 16,
+ 8 << 16);
+ }
}
}
static void lpddr4_set_phy(struct dram_info *dram,
- struct rk3399_sdram_params *params, u32 phy,
- struct rk3399_sdram_params *timings)
+ struct rk3399_sdram_params *params, u32 phy_fn,
+ struct rk3399_sdram_params *params_cfg)
{
u32 channel;
for (channel = 0; channel < 2; channel++)
- lpddr4_copy_phy(dram, params, phy, timings, channel);
+ lpddr4_copy_phy(dram, params, phy_fn, params_cfg,
+ channel);
}
static int lpddr4_set_ctl(struct dram_info *dram,
- struct rk3399_sdram_params *params, u32 ctl, u32 hz)
+ struct rk3399_sdram_params *params,
+ u32 fn, u32 hz)
{
u32 channel;
int ret_clk, ret;
@@ -2343,7 +2496,7 @@ static int lpddr4_set_ctl(struct dram_info *dram,
/* change freq */
writel((((0x3 << 4) | (1 << 2) | 1) << 16) |
- (ctl << 4) | (1 << 2) | 1, &dram->cic->cic_ctrl0);
+ (fn << 4) | (1 << 2) | 1, &dram->cic->cic_ctrl0);
while (!(readl(&dram->cic->cic_status0) & (1 << 2)))
;
@@ -2366,12 +2519,12 @@ static int lpddr4_set_ctl(struct dram_info *dram,
clrbits_le32(&dram->pmu->pmu_noc_auto_ena, (0x3 << 7));
/* lpddr4 ctl2 can not do training, all training will fail */
- if (!(params->base.dramtype == LPDDR4 && ctl == 2)) {
+ if (!(params->base.dramtype == LPDDR4 && fn == 2)) {
for (channel = 0; channel < 2; channel++) {
if (!(params->ch[channel].cap_info.col))
continue;
ret = data_training(dram, channel, params,
- PI_FULL_TRAINING);
+ PI_FULL_TRAINING);
if (ret)
printf("%s: channel %d training failed!\n",
__func__, channel);
@@ -2387,35 +2540,237 @@ static int lpddr4_set_ctl(struct dram_info *dram,
static int lpddr4_set_rate(struct dram_info *dram,
struct rk3399_sdram_params *params)
{
- u32 ctl;
- u32 phy;
+ u32 ctl_fn;
+ u32 phy_fn;
- for (ctl = 0; ctl < 2; ctl++) {
- phy = lpddr4_get_phy(params, ctl);
+ for (ctl_fn = 0; ctl_fn < 2; ctl_fn++) {
+ phy_fn = lpddr4_get_phy_fn(params, ctl_fn);
- lpddr4_set_phy(dram, params, phy, &lpddr4_timings[ctl]);
- lpddr4_set_ctl(dram, params, ctl,
- lpddr4_timings[ctl].base.ddr_freq);
+ lpddr4_set_phy(dram, params, phy_fn, &dfs_cfgs_lpddr4[ctl_fn]);
+ lpddr4_set_ctl(dram, params, ctl_fn,
+ dfs_cfgs_lpddr4[ctl_fn].base.ddr_freq);
- debug("%s: change freq to %d mhz %d, %d\n", __func__,
- lpddr4_timings[ctl].base.ddr_freq / MHz, ctl, phy);
+ printf("%s: change freq to %d mhz %d, %d\n", __func__,
+ dfs_cfgs_lpddr4[ctl_fn].base.ddr_freq, ctl_fn, phy_fn);
}
return 0;
}
#endif /* CONFIG_RAM_RK3399_LPDDR4 */
+/* CS0,n=1
+ * CS1,n=2
+ * CS0 & CS1, n=3
+ * cs0_cap: MB unit
+ */
+static void dram_set_cs(const struct chan_info *chan, u32 cs_map, u32 cs0_cap,
+ unsigned char dramtype)
+{
+ u32 *denali_ctl = chan->pctl->denali_ctl;
+ u32 *denali_pi = chan->pi->denali_pi;
+ struct msch_regs *ddr_msch_regs = chan->msch;
+
+ clrsetbits_le32(&denali_ctl[196], 0x3, cs_map);
+ writel((cs0_cap / 32) | (((4096 - cs0_cap) / 32) << 8),
+ &ddr_msch_regs->ddrsize);
+ if (dramtype == LPDDR4) {
+ if (cs_map == 1)
+ cs_map = 0x5;
+ else if (cs_map == 2)
+ cs_map = 0xa;
+ else
+ cs_map = 0xF;
+ }
+ /*PI_41 PI_CS_MAP:RW:24:4*/
+ clrsetbits_le32(&denali_pi[41],
+ 0xf << 24, cs_map << 24);
+ if (cs_map == 1 && dramtype == DDR3)
+ writel(0x2EC7FFFF, &denali_pi[34]);
+}
+
+static void dram_set_bw(const struct chan_info *chan, u32 bw)
+{
+ u32 *denali_ctl = chan->pctl->denali_ctl;
+
+ if (bw == 2)
+ clrbits_le32(&denali_ctl[196], 1 << 16);
+ else
+ setbits_le32(&denali_ctl[196], 1 << 16);
+}
+
+static void dram_set_max_col(const struct chan_info *chan, u32 bw, u32 *pcol)
+{
+ u32 *denali_ctl = chan->pctl->denali_ctl;
+ struct msch_regs *ddr_msch_regs = chan->msch;
+ u32 *denali_pi = chan->pi->denali_pi;
+ u32 ddrconfig;
+
+ clrbits_le32(&denali_ctl[191], 0xf);
+ clrsetbits_le32(&denali_ctl[190],
+ (7 << 24),
+ ((16 - ((bw == 2) ? 14 : 15)) << 24));
+ /*PI_199 PI_COL_DIFF:RW:0:4*/
+ clrbits_le32(&denali_pi[199], 0xf);
+ /*PI_155 PI_ROW_DIFF:RW:24:3*/
+ clrsetbits_le32(&denali_pi[155],
+ (7 << 24),
+ ((16 - 12) << 24));
+ ddrconfig = (bw == 2) ? 3 : 2;
+ writel(ddrconfig | (ddrconfig << 8), &ddr_msch_regs->ddrconf);
+ /* set max cs0 size */
+ writel((4096 / 32) | ((0 / 32) << 8),
+ &ddr_msch_regs->ddrsize);
+
+ *pcol = 12;
+}
+
+static void dram_set_max_bank(const struct chan_info *chan, u32 bw, u32 *pbank,
+ u32 *pcol)
+{
+ u32 *denali_ctl = chan->pctl->denali_ctl;
+ u32 *denali_pi = chan->pi->denali_pi;
+
+ clrbits_le32(&denali_ctl[191], 0xf);
+ clrbits_le32(&denali_ctl[190], (3 << 16));
+ /*PI_199 PI_COL_DIFF:RW:0:4*/
+ clrbits_le32(&denali_pi[199], 0xf);
+ /*PI_155 PI_BANK_DIFF:RW:16:2*/
+ clrbits_le32(&denali_pi[155], (3 << 16));
+
+ *pbank = 3;
+ *pcol = 12;
+}
+
+static void dram_set_max_row(const struct chan_info *chan, u32 bw, u32 *prow,
+ u32 *pbank, u32 *pcol)
+{
+ u32 *denali_ctl = chan->pctl->denali_ctl;
+ u32 *denali_pi = chan->pi->denali_pi;
+ struct msch_regs *ddr_msch_regs = chan->msch;
+
+ clrsetbits_le32(&denali_ctl[191], 0xf, 12 - 10);
+ clrbits_le32(&denali_ctl[190],
+ (0x3 << 16) | (0x7 << 24));
+ /*PI_199 PI_COL_DIFF:RW:0:4*/
+ clrsetbits_le32(&denali_pi[199], 0xf, 12 - 10);
+ /*PI_155 PI_ROW_DIFF:RW:24:3 PI_BANK_DIFF:RW:16:2*/
+ clrbits_le32(&denali_pi[155],
+ (0x3 << 16) | (0x7 << 24));
+ writel(1 | (1 << 8), &ddr_msch_regs->ddrconf);
+ /* set max cs0 size */
+ writel((4096 / 32) | ((0 / 32) << 8),
+ &ddr_msch_regs->ddrsize);
+
+ *prow = 16;
+ *pbank = 3;
+ *pcol = (bw == 2) ? 10 : 11;
+}
+
+static u64 dram_detect_cap(struct dram_info *dram,
+ struct rk3399_sdram_params *params,
+ unsigned char channel)
+{
+ const struct chan_info *chan = &dram->chan[channel];
+ struct sdram_cap_info *cap_info = &params->ch[channel].cap_info;
+ u32 bw;
+ u32 col_tmp;
+ u32 bk_tmp;
+ u32 row_tmp;
+ u32 cs0_cap;
+ u32 training_flag;
+ u32 ddrconfig;
+
+ /* detect bw */
+ bw = 2;
+ if (params->base.dramtype != LPDDR4) {
+ dram_set_bw(chan, bw);
+ cap_info->bw = bw;
+ if (data_training(dram, channel, params,
+ PI_READ_GATE_TRAINING)) {
+ bw = 1;
+ dram_set_bw(chan, 1);
+ cap_info->bw = bw;
+ if (data_training(dram, channel, params,
+ PI_READ_GATE_TRAINING)) {
+ printf("16bit error!!!\n");
+ goto error;
+ }
+ }
+ }
+ /*
+ * LPDDR3 CA training msut be trigger before other training.
+ * DDR3 is not have CA training.
+ */
+ if (params->base.dramtype == LPDDR3)
+ training_flag = PI_WRITE_LEVELING;
+ else
+ training_flag = PI_FULL_TRAINING;
+
+ if (params->base.dramtype != LPDDR4) {
+ if (data_training(dram, channel, params, training_flag)) {
+ printf("full training error!!!\n");
+ goto error;
+ }
+ }
+
+ /* detect col */
+ dram_set_max_col(chan, bw, &col_tmp);
+ if (sdram_detect_col(cap_info, col_tmp) != 0)
+ goto error;
+
+ /* detect bank */
+ dram_set_max_bank(chan, bw, &bk_tmp, &col_tmp);
+ sdram_detect_bank(cap_info, col_tmp, bk_tmp);
+
+ /* detect row */
+ dram_set_max_row(chan, bw, &row_tmp, &bk_tmp, &col_tmp);
+ if (sdram_detect_row(cap_info, col_tmp, bk_tmp, row_tmp) != 0)
+ goto error;
+
+ /* detect row_3_4 */
+ sdram_detect_row_3_4(cap_info, col_tmp, bk_tmp);
+
+ /* set ddrconfig */
+ cs0_cap = (1 << (cap_info->cs0_row + cap_info->col + cap_info->bk +
+ cap_info->bw - 20));
+ if (cap_info->row_3_4)
+ cs0_cap = cs0_cap * 3 / 4;
+
+ cap_info->cs1_row = cap_info->cs0_row;
+ set_memory_map(chan, channel, params);
+ ddrconfig = calculate_ddrconfig(params, channel);
+ if (-1 == ddrconfig)
+ goto error;
+ set_ddrconfig(chan, params, channel,
+ cap_info->ddrconfig);
+
+ /* detect cs1 row */
+ sdram_detect_cs1_row(cap_info, params->base.dramtype);
+
+ /* detect die bw */
+ sdram_detect_dbw(cap_info, params->base.dramtype);
+
+ return 0;
+error:
+ return (-1);
+}
+
static unsigned char calculate_stride(struct rk3399_sdram_params *params)
{
- unsigned int stride = params->base.stride;
- unsigned int channel, chinfo = 0;
+ unsigned int gstride_type;
+ unsigned int channel;
+ unsigned int chinfo = 0;
+ unsigned int cap = 0;
+ unsigned int stride = -1;
unsigned int ch_cap[2] = {0, 0};
- u64 cap;
+
+ gstride_type = STRIDE_256B;
for (channel = 0; channel < 2; channel++) {
unsigned int cs0_cap = 0;
unsigned int cs1_cap = 0;
- struct sdram_cap_info *cap_info = &params->ch[channel].cap_info;
+ struct sdram_cap_info *cap_info =
+ &params->ch[channel].cap_info;
if (cap_info->col == 0)
continue;
@@ -2433,49 +2788,124 @@ static unsigned char calculate_stride(struct rk3399_sdram_params *params)
chinfo |= 1 << channel;
}
- /* stride calculation for 1 channel */
- if (params->base.num_channels == 1 && chinfo & 1)
- return 0x17; /* channel a */
-
- /* stride calculation for 2 channels, default gstride type is 256B */
- if (ch_cap[0] == ch_cap[1]) {
- cap = ch_cap[0] + ch_cap[1];
- switch (cap) {
- /* 512MB */
- case 512:
- stride = 0;
- break;
- /* 1GB */
- case 1024:
- stride = 0x5;
- break;
+ cap = ch_cap[0] + ch_cap[1];
+ if (params->base.num_channels == 1) {
+ if (chinfo & 1) /* channel a only */
+ stride = 0x17;
+ else /* channel b only */
+ stride = 0x18;
+ } else {/* 2 channel */
+ if (ch_cap[0] == ch_cap[1]) {
+ /* interleaved */
+ if (gstride_type == PART_STRIDE) {
+ /*
+ * first 64MB no interleaved other 256B interleaved
+ * if 786M+768M.useful space from 0-1280MB and
+ * 1536MB-1792MB
+ * if 1.5G+1.5G(continuous).useful space from 0-2560MB
+ * and 3072MB-3584MB
+ */
+ stride = 0x1F;
+ } else {
+ switch (cap) {
+ /* 512MB */
+ case 512:
+ stride = 0;
+ break;
+ /* 1GB unstride or 256B stride*/
+ case 1024:
+ stride = (gstride_type == UN_STRIDE) ?
+ 0x1 : 0x5;
+ break;
+ /*
+ * 768MB + 768MB same as total 2GB memory
+ * useful space: 0-768MB 1GB-1792MB
+ */
+ case 1536:
+ /* 2GB unstride or 256B or 512B stride */
+ case 2048:
+ stride = (gstride_type == UN_STRIDE) ?
+ 0x2 :
+ ((gstride_type == STRIDE_512B) ?
+ 0xA : 0x9);
+ break;
+ /* 1536MB + 1536MB */
+ case 3072:
+ stride = (gstride_type == UN_STRIDE) ?
+ 0x3 :
+ ((gstride_type == STRIDE_512B) ?
+ 0x12 : 0x11);
+ break;
+ /* 4GB unstride or 128B,256B,512B,4KB stride */
+ case 4096:
+ stride = (gstride_type == UN_STRIDE) ?
+ 0x3 : (0xC + gstride_type);
+ break;
+ }
+ }
+ }
+ if (ch_cap[0] == 2048 && ch_cap[1] == 1024) {
+ /* 2GB + 1GB */
+ stride = (gstride_type == UN_STRIDE) ? 0x3 : 0x19;
+ }
/*
- * 768MB + 768MB same as total 2GB memory
- * useful space: 0-768MB 1GB-1792MB
+ * remain two channel capability not equal OR capability
+ * power function of 2
*/
- case 1536:
- /* 2GB */
- case 2048:
- stride = 0x9;
- break;
- /* 1536MB + 1536MB */
- case 3072:
- stride = 0x11;
- break;
- /* 4GB */
- case 4096:
- stride = 0xD;
- break;
- default:
- printf("%s: Unable to calculate stride for ", __func__);
- print_size((cap * (1 << 20)), " capacity\n");
- break;
+ if (stride == (-1)) {
+ switch ((ch_cap[0] > ch_cap[1]) ?
+ ch_cap[0] : ch_cap[1]) {
+ case 256: /* 256MB + 128MB */
+ stride = 0;
+ break;
+ case 512: /* 512MB + 256MB */
+ stride = 1;
+ break;
+ case 1024:/* 1GB + 128MB/256MB/384MB/512MB/768MB */
+ stride = 2;
+ break;
+ case 2048: /* 2GB + 128MB/256MB/384MB/512MB/768MB/1GB */
+ stride = 3;
+ break;
+ default:
+ break;
+ }
}
+ if (stride == (-1))
+ goto error;
+ }
+ switch (stride) {
+ case 0xc:
+ printf("128B stride\n");
+ break;
+ case 5:
+ case 9:
+ case 0xd:
+ case 0x11:
+ case 0x19:
+ printf("256B stride\n");
+ break;
+ case 0xa:
+ case 0xe:
+ case 0x12:
+ printf("512B stride\n");
+ break;
+ case 0xf:
+ printf("4K stride\n");
+ break;
+ case 0x1f:
+ printf("32MB + 256B stride\n");
+ break;
+ default:
+ printf("no stride\n");
}
sdram_print_stride(stride);
return stride;
+error:
+ printf("Cap not support!\n");
+ return (-1);
}
static void clear_channel_params(struct rk3399_sdram_params *params, u8 channel)
@@ -2491,39 +2921,13 @@ static void clear_channel_params(struct rk3399_sdram_params *params, u8 channel)
params->ch[channel].cap_info.ddrconfig = 0;
}
-static int pctl_init(struct dram_info *dram, struct rk3399_sdram_params *params)
-{
- int channel;
- int ret;
-
- for (channel = 0; channel < 2; channel++) {
- const struct chan_info *chan = &dram->chan[channel];
- struct rk3399_cru *cru = dram->cru;
- struct rk3399_ddr_publ_regs *publ = chan->publ;
-
- phy_pctrl_reset(cru, channel);
- phy_dll_bypass_set(publ, params->base.ddr_freq);
-
- ret = pctl_cfg(dram, chan, channel, params);
- if (ret < 0) {
- printf("%s: pctl config failed\n", __func__);
- return ret;
- }
-
- /* start to trigger initialization */
- pctl_start(dram, channel);
- }
-
- return 0;
-}
-
static int sdram_init(struct dram_info *dram,
struct rk3399_sdram_params *params)
{
unsigned char dramtype = params->base.dramtype;
unsigned int ddr_freq = params->base.ddr_freq;
int channel, ch, rank;
- int ret;
+ u32 tmp, ret;
debug("Starting SDRAM initialization...\n");
@@ -2534,22 +2938,35 @@ static int sdram_init(struct dram_info *dram,
return -E2BIG;
}
+ /* detect rank */
for (ch = 0; ch < 2; ch++) {
params->ch[ch].cap_info.rank = 2;
for (rank = 2; rank != 0; rank--) {
- ret = pctl_init(dram, params);
- if (ret < 0) {
- printf("%s: pctl init failed\n", __func__);
- return ret;
+ for (channel = 0; channel < 2; channel++) {
+ const struct chan_info *chan =
+ &dram->chan[channel];
+ struct rk3399_cru *cru = dram->cru;
+ struct rk3399_ddr_publ_regs *publ = chan->publ;
+
+ phy_pctrl_reset(cru, channel);
+ phy_dll_bypass_set(publ, ddr_freq);
+ pctl_cfg(dram, chan, channel, params);
}
+ /* start to trigger initialization */
+ pctl_start(dram, params, 3);
+
/* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */
if (dramtype == LPDDR3)
udelay(10);
+ tmp = (rank == 2) ? 3 : 1;
+ dram_set_cs(&dram->chan[ch], tmp, 2048,
+ params->base.dramtype);
params->ch[ch].cap_info.rank = rank;
- ret = dram->ops->data_training(dram, ch, rank, params);
+ ret = dram->ops->data_training_first(dram, ch,
+ rank, params);
if (!ret) {
debug("%s: data trained for rank %d, ch %d\n",
__func__, rank, ch);
@@ -2563,38 +2980,37 @@ static int sdram_init(struct dram_info *dram,
params->base.num_channels = 0;
for (channel = 0; channel < 2; channel++) {
const struct chan_info *chan = &dram->chan[channel];
- struct sdram_cap_info *cap_info = &params->ch[channel].cap_info;
- u8 training_flag = PI_FULL_TRAINING;
+ struct sdram_cap_info *cap_info =
+ &params->ch[channel].cap_info;
if (cap_info->rank == 0) {
- clear_channel_params(params, channel);
+ clear_channel_params(params, 1);
continue;
} else {
params->base.num_channels++;
}
- debug("Channel ");
- debug(channel ? "1: " : "0: ");
+ printf("Channel ");
+ printf(channel ? "1: " : "0: ");
- /* LPDDR3 should have write and read gate training */
- if (params->base.dramtype == LPDDR3)
- training_flag = PI_WRITE_LEVELING |
- PI_READ_GATE_TRAINING;
+ if (channel == 0)
+ set_ddr_stride(dram->pmusgrf, 0x17);
+ else
+ set_ddr_stride(dram->pmusgrf, 0x18);
- if (params->base.dramtype != LPDDR4) {
- ret = data_training(dram, channel, params,
- training_flag);
- if (!ret) {
- debug("%s: data train failed for channel %d\n",
- __func__, ret);
- continue;
- }
+ if (dram_detect_cap(dram, params, channel)) {
+ printf("Cap error!\n");
+ continue;
}
sdram_print_ddr_info(cap_info, &params->base);
set_memory_map(chan, channel, params);
- cap_info->ddrconfig = calculate_ddrconfig(params, channel);
-
+ cap_info->ddrconfig =
+ calculate_ddrconfig(params, channel);
+ if (-1 == cap_info->ddrconfig) {
+ printf("no ddrconfig find, Cap not support!\n");
+ continue;
+ }
set_ddrconfig(chan, params, channel, cap_info->ddrconfig);
set_cap_relate_config(chan, params, channel);
}
@@ -2608,7 +3024,8 @@ static int sdram_init(struct dram_info *dram,
params->base.stride = calculate_stride(params);
dram_all_config(dram, params);
- dram->ops->set_rate(dram, params);
+
+ dram->ops->set_rate_index(dram, params);
debug("Finish SDRAM initialization...\n");
return 0;
@@ -2655,11 +3072,15 @@ static int conv_of_platdata(struct udevice *dev)
static const struct sdram_rk3399_ops rk3399_ops = {
#if !defined(CONFIG_RAM_RK3399_LPDDR4)
- .data_training = default_data_training,
- .set_rate = switch_to_phy_index1,
+ .data_training_first = data_training_first,
+ .set_rate_index = switch_to_phy_index1,
+ .modify_param = modify_param,
+ .get_phy_index_params = get_phy_index_params,
#else
- .data_training = lpddr4_mr_detect,
- .set_rate = lpddr4_set_rate,
+ .data_training_first = lpddr4_mr_detect,
+ .set_rate_index = lpddr4_set_rate,
+ .modify_param = lpddr4_modify_param,
+ .get_phy_index_params = lpddr4_get_phy_index_params,
#endif
};
diff --git a/drivers/usb/phy/rockchip_usb2_phy.c b/drivers/usb/phy/rockchip_usb2_phy.c
index 16e899954a..69e408b6c1 100644
--- a/drivers/usb/phy/rockchip_usb2_phy.c
+++ b/drivers/usb/phy/rockchip_usb2_phy.c
@@ -5,7 +5,6 @@
#include <common.h>
#include <asm/io.h>
-#include <linux/libfdt.h>
#include "../gadget/dwc2_udc_otg_priv.h"
@@ -71,8 +70,8 @@ void otg_phy_init(struct dwc2_udc *dev)
for (i = 0; i < ARRAY_SIZE(rockchip_usb2_phy_dt_ids); i++) {
of_id = &rockchip_usb2_phy_dt_ids[i];
- if (fdt_node_check_compatible(gd->fdt_blob, pdata->phy_of_node,
- of_id->compatible) == 0) {
+ if (ofnode_device_is_compatible(pdata->phy_of_node,
+ of_id->compatible)){
phy_cfg = (struct rockchip_usb2_phy_cfg *)of_id->data;
break;
}