summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2022-04-05 20:45:22 +0300
committerTom Rini <trini@konsulko.com>2022-04-05 20:45:22 +0300
commit59bffec43a657598b194b9eb30dc01eec06078c7 (patch)
tree80a668bc14a348be6be49a9808e811a7f4bb82c4 /drivers
parent037ef53cf01c522073a0a930c84c3ca858f032e1 (diff)
parentda61ee662554f98fac0ab19c6b893edd82edb098 (diff)
downloadu-boot-59bffec43a657598b194b9eb30dc01eec06078c7.tar.xz
Merge branch '2022-04-04-platform-updates'
- Updates for exynos78x0 and TI K3 platforms
Diffstat (limited to 'drivers')
-rw-r--r--drivers/misc/k3_esm.c53
-rw-r--r--drivers/ram/k3-am654-ddrss.c15
-rw-r--r--drivers/ram/k3-ddrss/k3-ddrss.c138
3 files changed, 198 insertions, 8 deletions
diff --git a/drivers/misc/k3_esm.c b/drivers/misc/k3_esm.c
index cc2a23dd66..41faeb3d85 100644
--- a/drivers/misc/k3_esm.c
+++ b/drivers/misc/k3_esm.c
@@ -16,17 +16,57 @@
#define ESM_SFT_RST 0x0c
#define ESM_SFT_RST_KEY 0x0f
+#define ESM_EN 0x08
+#define ESM_EN_KEY 0x0f
#define ESM_STS(i) (0x404 + (i) / 32 * 0x20)
+#define ESM_STS_MASK(i) (1 << ((i) % 32))
#define ESM_PIN_EN_SET_OFFSET(i) (0x414 + (i) / 32 * 0x20)
-#define ESM_PIN_MASK(i) BIT((i) & 0x1f)
+#define ESM_PIN_MASK(i) (1 << ((i) % 32))
+#define ESM_INTR_EN_SET_OFFSET(i) (0x408 + (i) / 32 * 0x20)
+#define ESM_INTR_MASK(i) (1 << ((i) % 32))
+#define ESM_INTR_PRIO_SET_OFFSET(i) (0x410 + (i) / 32 * 0x20)
+#define ESM_INTR_PRIO_MASK(i) (1 << ((i) % 32))
static void esm_pin_enable(void __iomem *base, int pin)
{
+ u32 value;
+
+ value = readl(base + ESM_PIN_EN_SET_OFFSET(pin));
+ value |= ESM_PIN_MASK(pin);
/* Enable event */
- writel(ESM_PIN_MASK(pin), base + ESM_PIN_EN_SET_OFFSET(pin));
+ writel(value, base + ESM_PIN_EN_SET_OFFSET(pin));
+}
+
+static void esm_intr_enable(void __iomem *base, int pin)
+{
+ u32 value;
+
+ value = readl(base + ESM_INTR_EN_SET_OFFSET(pin));
+ value |= ESM_INTR_MASK(pin);
+ /* Enable Interrupt event */
+ writel(value, base + ESM_INTR_EN_SET_OFFSET(pin));
+}
+
+static void esm_intr_prio_set(void __iomem *base, int pin)
+{
+ u32 value;
+
+ value = readl(base + ESM_INTR_PRIO_SET_OFFSET(pin));
+ value |= ESM_INTR_PRIO_MASK(pin);
+ /* Set to priority */
+ writel(value, base + ESM_INTR_PRIO_SET_OFFSET(pin));
}
+static void esm_clear_raw_status(void __iomem *base, int pin)
+{
+ u32 value;
+
+ value = readl(base + ESM_STS(pin));
+ value |= ESM_STS_MASK(pin);
+ /* Clear Event status */
+ writel(value, base + ESM_STS(pin));
+}
/**
* k3_esm_probe: configures ESM based on DT data
*
@@ -67,8 +107,15 @@ static int k3_esm_probe(struct udevice *dev)
/* Clear any pending events */
writel(ESM_SFT_RST_KEY, base + ESM_SFT_RST);
- for (i = 0; i < num_pins; i++)
+ for (i = 0; i < num_pins; i++) {
+ esm_intr_prio_set(base, pins[i]);
+ esm_clear_raw_status(base, pins[i]);
esm_pin_enable(base, pins[i]);
+ esm_intr_enable(base, pins[i]);
+ }
+
+ /* Enable ESM */
+ writel(ESM_EN_KEY, base + ESM_EN);
free_pins:
kfree(pins);
diff --git a/drivers/ram/k3-am654-ddrss.c b/drivers/ram/k3-am654-ddrss.c
index 4ec12bf42e..4453c247b2 100644
--- a/drivers/ram/k3-am654-ddrss.c
+++ b/drivers/ram/k3-am654-ddrss.c
@@ -265,6 +265,16 @@ static void am654_ddrss_phy_configuration(struct am654_ddrss_desc *ddrss)
ddrss_phy_writel(DDRSS_DDRPHY_ACIOCR5, ioctl->ddrphy_aciocr5);
ddrss_phy_writel(DDRSS_DDRPHY_IOVCR0, ioctl->ddrphy_iovcr0);
+ ddrss_phy_writel(DDRSS_DDRPHY_DX2GCR0, cfg->ddrphy_dx2gcr0);
+ ddrss_phy_writel(DDRSS_DDRPHY_DX2GCR1, cfg->ddrphy_dx2gcr1);
+ ddrss_phy_writel(DDRSS_DDRPHY_DX2GCR2, cfg->ddrphy_dx2gcr2);
+ ddrss_phy_writel(DDRSS_DDRPHY_DX2GCR3, cfg->ddrphy_dx2gcr3);
+
+ ddrss_phy_writel(DDRSS_DDRPHY_DX3GCR0, cfg->ddrphy_dx3gcr0);
+ ddrss_phy_writel(DDRSS_DDRPHY_DX3GCR1, cfg->ddrphy_dx3gcr1);
+ ddrss_phy_writel(DDRSS_DDRPHY_DX3GCR2, cfg->ddrphy_dx3gcr2);
+ ddrss_phy_writel(DDRSS_DDRPHY_DX3GCR3, cfg->ddrphy_dx3gcr3);
+
ddrss_phy_writel(DDRSS_DDRPHY_DX4GCR0, cfg->ddrphy_dx4gcr0);
ddrss_phy_writel(DDRSS_DDRPHY_DX4GCR1, cfg->ddrphy_dx4gcr1);
ddrss_phy_writel(DDRSS_DDRPHY_DX4GCR2, cfg->ddrphy_dx4gcr2);
@@ -874,9 +884,8 @@ static int am654_ddrss_power_on(struct am654_ddrss_desc *ddrss)
device_get_supply_regulator(ddrss->dev, "vtt-supply",
&ddrss->vtt_supply);
ret = regulator_set_value(ddrss->vtt_supply, 3300000);
- if (ret)
- return ret;
- debug("VTT regulator enabled\n");
+ if (ret == 0)
+ debug("VTT regulator enabled\n");
#endif
return 0;
diff --git a/drivers/ram/k3-ddrss/k3-ddrss.c b/drivers/ram/k3-ddrss/k3-ddrss.c
index 25e3976e65..2467f122a8 100644
--- a/drivers/ram/k3-ddrss/k3-ddrss.c
+++ b/drivers/ram/k3-ddrss/k3-ddrss.c
@@ -6,9 +6,12 @@
*/
#include <common.h>
+#include <config.h>
#include <clk.h>
+#include <div64.h>
#include <dm.h>
#include <dm/device_compat.h>
+#include <fdt_support.h>
#include <ram.h>
#include <hang.h>
#include <log.h>
@@ -30,6 +33,19 @@
#define DDRSS_V2A_R1_MAT_REG 0x0020
#define DDRSS_ECC_CTRL_REG 0x0120
+#define DDRSS_ECC_CTRL_REG_ECC_EN BIT(0)
+#define DDRSS_ECC_CTRL_REG_RMW_EN BIT(1)
+#define DDRSS_ECC_CTRL_REG_ECC_CK BIT(2)
+#define DDRSS_ECC_CTRL_REG_WR_ALLOC BIT(4)
+
+#define DDRSS_ECC_R0_STR_ADDR_REG 0x0130
+#define DDRSS_ECC_R0_END_ADDR_REG 0x0134
+#define DDRSS_ECC_R1_STR_ADDR_REG 0x0138
+#define DDRSS_ECC_R1_END_ADDR_REG 0x013c
+#define DDRSS_ECC_R2_STR_ADDR_REG 0x0140
+#define DDRSS_ECC_R2_END_ADDR_REG 0x0144
+#define DDRSS_ECC_1B_ERR_CNT_REG 0x0150
+
#define SINGLE_DDR_SUBSYSTEM 0x1
#define MULTI_DDR_SUBSYSTEM 0x2
@@ -102,10 +118,18 @@ struct k3_msmc {
enum emif_active active;
};
+#define K3_DDRSS_MAX_ECC_REGIONS 3
+
+struct k3_ddrss_ecc_region {
+ u32 start;
+ u32 range;
+};
+
struct k3_ddrss_desc {
struct udevice *dev;
void __iomem *ddrss_ss_cfg;
void __iomem *ddrss_ctrl_mmr;
+ void __iomem *ddrss_ctl_cfg;
struct power_domain ddrcfg_pwrdmn;
struct power_domain ddrdata_pwrdmn;
struct clk ddr_clk;
@@ -118,6 +142,9 @@ struct k3_ddrss_desc {
lpddr4_obj *driverdt;
lpddr4_config config;
lpddr4_privatedata pd;
+ struct k3_ddrss_ecc_region ecc_regions[K3_DDRSS_MAX_ECC_REGIONS];
+ u64 ecc_reserved_space;
+ bool ti_ecc_enabled;
};
struct reginitdata {
@@ -319,7 +346,7 @@ static int k3_ddrss_ofdata_to_priv(struct udevice *dev)
dev_err(dev, "No reg property for DDRSS wrapper logic\n");
return -EINVAL;
}
- ddrss->ddrss_ss_cfg = (void *)reg;
+ ddrss->ddrss_ctl_cfg = (void *)reg;
reg = dev_read_addr_name(dev, "ctrl_mmr_lp4");
if (reg == FDT_ADDR_T_NONE) {
@@ -328,6 +355,14 @@ static int k3_ddrss_ofdata_to_priv(struct udevice *dev)
}
ddrss->ddrss_ctrl_mmr = (void *)reg;
+ reg = dev_read_addr_name(dev, "ss_cfg");
+ if (reg == FDT_ADDR_T_NONE) {
+ dev_dbg(dev, "No reg property for SS Config region, but this is optional so continuing.\n");
+ ddrss->ddrss_ss_cfg = NULL;
+ } else {
+ ddrss->ddrss_ss_cfg = (void *)reg;
+ }
+
ret = power_domain_get_by_index(dev, &ddrss->ddrcfg_pwrdmn, 0);
if (ret) {
dev_err(dev, "power_domain_get() failed: %d\n", ret);
@@ -371,6 +406,8 @@ static int k3_ddrss_ofdata_to_priv(struct udevice *dev)
if (ret)
dev_err(dev, "ddr fhs cnt not populated %d\n", ret);
+ ddrss->ti_ecc_enabled = dev_read_bool(dev, "ti,ecc-enable");
+
return ret;
}
@@ -403,7 +440,7 @@ void k3_lpddr4_init(struct k3_ddrss_desc *ddrss)
hang();
}
- config->ctlbase = (struct lpddr4_ctlregs_s *)ddrss->ddrss_ss_cfg;
+ config->ctlbase = (struct lpddr4_ctlregs_s *)ddrss->ddrss_ctl_cfg;
config->infohandler = (lpddr4_infocallback) k3_lpddr4_info_handler;
status = driverdt->init(pd, config);
@@ -512,6 +549,60 @@ void k3_lpddr4_start(struct k3_ddrss_desc *ddrss)
}
}
+static void k3_ddrss_set_ecc_range_r0(u32 base, u32 start_address, u32 size)
+{
+ writel((start_address) >> 16, base + DDRSS_ECC_R0_STR_ADDR_REG);
+ writel((start_address + size - 1) >> 16, base + DDRSS_ECC_R0_END_ADDR_REG);
+}
+
+static void k3_ddrss_preload_ecc_mem_region(u32 *addr, u32 size, u32 word)
+{
+ int i;
+
+ printf("ECC is enabled, priming DDR which will take several seconds.\n");
+
+ for (i = 0; i < (size / 4); i++)
+ addr[i] = word;
+}
+
+static void k3_ddrss_lpddr4_ecc_calc_reserved_mem(struct k3_ddrss_desc *ddrss)
+{
+ fdtdec_setup_mem_size_base_lowest();
+
+ ddrss->ecc_reserved_space = gd->ram_size;
+ do_div(ddrss->ecc_reserved_space, 9);
+
+ /* Round to clean number */
+ ddrss->ecc_reserved_space = 1ull << (fls(ddrss->ecc_reserved_space));
+}
+
+static void k3_ddrss_lpddr4_ecc_init(struct k3_ddrss_desc *ddrss)
+{
+ u32 ecc_region_start = ddrss->ecc_regions[0].start;
+ u32 ecc_range = ddrss->ecc_regions[0].range;
+ u32 base = (u32)ddrss->ddrss_ss_cfg;
+ u32 val;
+
+ /* Only Program region 0 which covers full ddr space */
+ k3_ddrss_set_ecc_range_r0(base, ecc_region_start - gd->ram_base, ecc_range);
+
+ /* Enable ECC, RMW, WR_ALLOC */
+ writel(DDRSS_ECC_CTRL_REG_ECC_EN | DDRSS_ECC_CTRL_REG_RMW_EN |
+ DDRSS_ECC_CTRL_REG_WR_ALLOC, base + DDRSS_ECC_CTRL_REG);
+
+ /* Preload ECC Mem region with 0's */
+ k3_ddrss_preload_ecc_mem_region((u32 *)ecc_region_start, ecc_range,
+ 0x00000000);
+
+ /* Clear Error Count Register */
+ writel(0x1, base + DDRSS_ECC_1B_ERR_CNT_REG);
+
+ /* Enable ECC Check */
+ val = readl(base + DDRSS_ECC_CTRL_REG);
+ val |= DDRSS_ECC_CTRL_REG_ECC_CK;
+ writel(val, base + DDRSS_ECC_CTRL_REG);
+}
+
static int k3_ddrss_probe(struct udevice *dev)
{
int ret;
@@ -546,9 +637,52 @@ static int k3_ddrss_probe(struct udevice *dev)
k3_lpddr4_start(ddrss);
+ if (ddrss->ti_ecc_enabled) {
+ if (!ddrss->ddrss_ss_cfg) {
+ printf("%s: ss_cfg is required if ecc is enabled but not provided.",
+ __func__);
+ return -EINVAL;
+ }
+
+ k3_ddrss_lpddr4_ecc_calc_reserved_mem(ddrss);
+
+ /* Always configure one region that covers full DDR space */
+ ddrss->ecc_regions[0].start = gd->ram_base;
+ ddrss->ecc_regions[0].range = gd->ram_size - ddrss->ecc_reserved_space;
+ k3_ddrss_lpddr4_ecc_init(ddrss);
+ }
+
return ret;
}
+int k3_ddrss_ddr_fdt_fixup(struct udevice *dev, void *blob, struct bd_info *bd)
+{
+ struct k3_ddrss_desc *ddrss = dev_get_priv(dev);
+ u64 start[CONFIG_NR_DRAM_BANKS];
+ u64 size[CONFIG_NR_DRAM_BANKS];
+ int bank;
+
+ if (ddrss->ecc_reserved_space == 0)
+ return 0;
+
+ for (bank = CONFIG_NR_DRAM_BANKS - 1; bank >= 0; bank--) {
+ if (ddrss->ecc_reserved_space > bd->bi_dram[bank].size) {
+ ddrss->ecc_reserved_space -= bd->bi_dram[bank].size;
+ bd->bi_dram[bank].size = 0;
+ } else {
+ bd->bi_dram[bank].size -= ddrss->ecc_reserved_space;
+ break;
+ }
+ }
+
+ for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
+ start[bank] = bd->bi_dram[bank].start;
+ size[bank] = bd->bi_dram[bank].size;
+ }
+
+ return fdt_fixup_memory_banks(blob, start, size, CONFIG_NR_DRAM_BANKS);
+}
+
static int k3_ddrss_get_info(struct udevice *dev, struct ram_info *info)
{
return 0;