summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/nand/davinci_nand.c2
-rw-r--r--drivers/mtd/nand/omap_gpmc.c46
-rw-r--r--drivers/net/keystone_net.c35
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/exynos_fb.c18
-rw-r--r--drivers/video/exynos_fimd.c43
-rw-r--r--drivers/video/parade.c220
7 files changed, 308 insertions, 57 deletions
diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
index a079b1e..02a1130 100644
--- a/drivers/mtd/nand/davinci_nand.c
+++ b/drivers/mtd/nand/davinci_nand.c
@@ -306,8 +306,8 @@ static struct nand_ecclayout nand_davinci_4bit_layout_oobfirst = {
};
#if defined CONFIG_KEYSTONE_RBL_NAND
-#if defined(CONFIG_SYS_NAND_PAGE_2K)
static struct nand_ecclayout nand_keystone_rbl_4bit_layout_oobfirst = {
+#if defined(CONFIG_SYS_NAND_PAGE_2K)
.eccbytes = 40,
.eccpos = {
6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c
index 1acf06b..db1599e 100644
--- a/drivers/mtd/nand/omap_gpmc.c
+++ b/drivers/mtd/nand/omap_gpmc.c
@@ -27,10 +27,22 @@
static u8 bch8_polynomial[] = {0xef, 0x51, 0x2e, 0x09, 0xed, 0x93, 0x9a, 0xc2,
0x97, 0x79, 0xe5, 0x24, 0xb5};
#endif
-static uint8_t cs;
+static uint8_t cs_next;
static __maybe_unused struct nand_ecclayout omap_ecclayout;
/*
+ * Driver configurations
+ */
+struct omap_nand_info {
+ struct bch_control *control;
+ enum omap_ecc ecc_scheme;
+ int cs;
+};
+
+/* We are wasting a bit of memory but al least we are safe */
+static struct omap_nand_info omap_nand_info[GPMC_MAX_CS];
+
+/*
* omap_nand_hwcontrol - Set the address pointers corretly for the
* following address/data/command operation
*/
@@ -38,6 +50,8 @@ static void omap_nand_hwcontrol(struct mtd_info *mtd, int32_t cmd,
uint32_t ctrl)
{
register struct nand_chip *this = mtd->priv;
+ struct omap_nand_info *info = this->priv;
+ int cs = info->cs;
/*
* Point the IO_ADDR to DATA and ADDRESS registers instead
@@ -148,24 +162,6 @@ static int __maybe_unused omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
}
/*
- * Driver configurations
- */
-struct omap_nand_info {
- struct bch_control *control;
- enum omap_ecc ecc_scheme;
-};
-
-/*
- * This can be a single instance cause all current users have only one NAND
- * with nearly the same setup (BCH8, some with ELM and others with sw BCH
- * library).
- * When some users with other BCH strength will exists this have to change!
- */
-static __maybe_unused struct omap_nand_info omap_nand_info = {
- .control = NULL
-};
-
-/*
* omap_reverse_list - re-orders list elements in reverse order [internal]
* @list: pointer to start of list
* @length: length of list
@@ -198,6 +194,7 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode)
unsigned int eccsize1 = 0x00, eccsize0 = 0x00, bch_wrapmode = 0x00;
u32 ecc_size_config_val = 0;
u32 ecc_config_val = 0;
+ int cs = info->cs;
/* configure GPMC for specific ecc-scheme */
switch (info->ecc_scheme) {
@@ -478,11 +475,11 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
oob += eccbytes) {
chip->ecc.hwctl(mtd, NAND_ECC_READ);
/* read data */
- chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_pos, page);
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_pos, -1);
chip->read_buf(mtd, p, eccsize);
/* read respective ecc from oob area */
- chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, page);
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, -1);
chip->read_buf(mtd, oob, eccbytes);
/* read syndrome */
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
@@ -826,7 +823,7 @@ int __maybe_unused omap_nand_switch_ecc(uint32_t hardware, uint32_t eccstrength)
int board_nand_init(struct nand_chip *nand)
{
int32_t gpmc_config = 0;
- cs = 0;
+ int cs = cs_next++;
int err = 0;
/*
* xloader/Uboot's gpmc configuration would have configured GPMC for
@@ -856,7 +853,9 @@ int board_nand_init(struct nand_chip *nand)
nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
- nand->priv = &omap_nand_info;
+ omap_nand_info[cs].control = NULL;
+ omap_nand_info[cs].cs = cs;
+ nand->priv = &omap_nand_info[cs];
nand->cmd_ctrl = omap_nand_hwcontrol;
nand->options |= NAND_NO_PADDING | NAND_CACHEPRG;
nand->chip_delay = 100;
@@ -890,6 +889,5 @@ int board_nand_init(struct nand_chip *nand)
nand->read_buf = nand_read_buf;
nand->dev_ready = omap_spl_dev_ready;
#endif
-
return 0;
}
diff --git a/drivers/net/keystone_net.c b/drivers/net/keystone_net.c
index f95c928..d22b722 100644
--- a/drivers/net/keystone_net.c
+++ b/drivers/net/keystone_net.c
@@ -290,13 +290,12 @@ int mac_sl_reset(u32 port)
return GMACSL_RET_INVALID_PORT;
/* Set the soft reset bit */
- DEVICE_REG32_W(DEVICE_EMACSL_BASE(port) +
- CPGMACSL_REG_RESET, CPGMAC_REG_RESET_VAL_RESET);
+ writel(CPGMAC_REG_RESET_VAL_RESET,
+ DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_RESET);
/* Wait for the bit to clear */
for (i = 0; i < DEVICE_EMACSL_RESET_POLL_COUNT; i++) {
- v = DEVICE_REG32_R(DEVICE_EMACSL_BASE(port) +
- CPGMACSL_REG_RESET);
+ v = readl(DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_RESET);
if ((v & CPGMAC_REG_RESET_VAL_RESET_MASK) !=
CPGMAC_REG_RESET_VAL_RESET)
return GMACSL_RET_OK;
@@ -321,8 +320,7 @@ int mac_sl_config(u_int16_t port, struct mac_sl_cfg *cfg)
/* Must wait if the device is undergoing reset */
for (i = 0; i < DEVICE_EMACSL_RESET_POLL_COUNT; i++) {
- v = DEVICE_REG32_R(DEVICE_EMACSL_BASE(port) +
- CPGMACSL_REG_RESET);
+ v = readl(DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_RESET);
if ((v & CPGMAC_REG_RESET_VAL_RESET_MASK) !=
CPGMAC_REG_RESET_VAL_RESET)
break;
@@ -331,11 +329,8 @@ int mac_sl_config(u_int16_t port, struct mac_sl_cfg *cfg)
if (i == DEVICE_EMACSL_RESET_POLL_COUNT)
return GMACSL_RET_CONFIG_FAIL_RESET_ACTIVE;
- DEVICE_REG32_W(DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_MAXLEN,
- cfg->max_rx_len);
-
- DEVICE_REG32_W(DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_CTL,
- cfg->ctl);
+ writel(cfg->max_rx_len, DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_MAXLEN);
+ writel(cfg->ctl, DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_CTL);
return ret;
}
@@ -345,24 +340,24 @@ int ethss_config(u32 ctl, u32 max_pkt_size)
u32 i;
/* Max length register */
- DEVICE_REG32_W(DEVICE_CPSW_BASE + CPSW_REG_MAXLEN, max_pkt_size);
+ writel(max_pkt_size, DEVICE_CPSW_BASE + CPSW_REG_MAXLEN);
/* Control register */
- DEVICE_REG32_W(DEVICE_CPSW_BASE + CPSW_REG_CTL, ctl);
+ writel(ctl, DEVICE_CPSW_BASE + CPSW_REG_CTL);
/* All statistics enabled by default */
- DEVICE_REG32_W(DEVICE_CPSW_BASE + CPSW_REG_STAT_PORT_EN,
- CPSW_REG_VAL_STAT_ENABLE_ALL);
+ writel(CPSW_REG_VAL_STAT_ENABLE_ALL,
+ DEVICE_CPSW_BASE + CPSW_REG_STAT_PORT_EN);
/* Reset and enable the ALE */
- DEVICE_REG32_W(DEVICE_CPSW_BASE + CPSW_REG_ALE_CONTROL,
- CPSW_REG_VAL_ALE_CTL_RESET_AND_ENABLE |
- CPSW_REG_VAL_ALE_CTL_BYPASS);
+ writel(CPSW_REG_VAL_ALE_CTL_RESET_AND_ENABLE |
+ CPSW_REG_VAL_ALE_CTL_BYPASS,
+ DEVICE_CPSW_BASE + CPSW_REG_ALE_CONTROL);
/* All ports put into forward mode */
for (i = 0; i < DEVICE_CPSW_NUM_PORTS; i++)
- DEVICE_REG32_W(DEVICE_CPSW_BASE + CPSW_REG_ALE_PORTCTL(i),
- CPSW_REG_VAL_PORTCTL_FORWARD_MODE);
+ writel(CPSW_REG_VAL_PORTCTL_FORWARD_MODE,
+ DEVICE_CPSW_BASE + CPSW_REG_ALE_PORTCTL(i));
return 0;
}
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 0914ea1..14a6781 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -43,3 +43,4 @@ obj-$(CONFIG_VIDEO_TEGRA) += tegra.o
obj-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o
obj-$(CONFIG_FORMIKE) += formike.o
obj-$(CONFIG_AM335X_LCD) += am335x-fb.o
+obj-$(CONFIG_VIDEO_PARADE) += parade.o
diff --git a/drivers/video/exynos_fb.c b/drivers/video/exynos_fb.c
index e1e0d80..180a3b4 100644
--- a/drivers/video/exynos_fb.c
+++ b/drivers/video/exynos_fb.c
@@ -27,17 +27,13 @@ DECLARE_GLOBAL_DATA_PTR;
static unsigned int panel_width, panel_height;
-/*
- * board_init_f(arch/arm/lib/board.c) calls lcd_setmem() which needs
- * panel_info.vl_col, panel_info.vl_row and panel_info.vl_bpix to reserve
- * FB memory at a very early stage, i.e even before exynos_fimd_parse_dt()
- * is called. So, we are forced to statically assign it.
- */
#ifdef CONFIG_OF_CONTROL
vidinfo_t panel_info = {
- .vl_col = LCD_XRES,
- .vl_row = LCD_YRES,
- .vl_bpix = LCD_COLOR16,
+ /*
+ * Insert a value here so that we don't end up in the BSS
+ * Reference: drivers/video/tegra.c
+ */
+ .vl_col = -1,
};
#endif
@@ -141,7 +137,7 @@ static void lcd_panel_on(vidinfo_t *vid)
}
#ifdef CONFIG_OF_CONTROL
-int exynos_fimd_parse_dt(const void *blob)
+int exynos_lcd_early_init(const void *blob)
{
unsigned int node;
node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS_FIMD);
@@ -286,8 +282,6 @@ void lcd_ctrl_init(void *lcdbase)
set_lcd_clk();
#ifdef CONFIG_OF_CONTROL
- if (exynos_fimd_parse_dt(gd->fdt_blob))
- debug("Can't get proper panel info\n");
#ifdef CONFIG_EXYNOS_MIPI_DSIM
exynos_init_dsim_platform_data(&panel_info);
#endif
diff --git a/drivers/video/exynos_fimd.c b/drivers/video/exynos_fimd.c
index cebbba7..f67fa81 100644
--- a/drivers/video/exynos_fimd.c
+++ b/drivers/video/exynos_fimd.c
@@ -251,6 +251,45 @@ void exynos_fimd_window_off(unsigned int win_id)
writel(cfg, &fimd_ctrl->winshmap);
}
+#ifdef CONFIG_OF_CONTROL
+/*
+* The reset value for FIMD SYSMMU register MMU_CTRL is 3
+* on Exynos5420 and newer versions.
+* This means FIMD SYSMMU is on by default on Exynos5420
+* and newer versions.
+* Since in u-boot we don't use SYSMMU, we should disable
+* those FIMD SYSMMU.
+* Note that there are 2 SYSMMU for FIMD: m0 and m1.
+* m0 handles windows 0 and 4, and m1 handles windows 1, 2 and 3.
+* We disable both of them here.
+*/
+void exynos_fimd_disable_sysmmu(void)
+{
+ u32 *sysmmufimd;
+ unsigned int node;
+ int node_list[2];
+ int count;
+ int i;
+
+ count = fdtdec_find_aliases_for_id(gd->fdt_blob, "fimd",
+ COMPAT_SAMSUNG_EXYNOS_SYSMMU, node_list, 2);
+ for (i = 0; i < count; i++) {
+ node = node_list[i];
+ if (node <= 0) {
+ debug("Can't get device node for fimd sysmmu\n");
+ return;
+ }
+
+ sysmmufimd = (u32 *)fdtdec_get_addr(gd->fdt_blob, node, "reg");
+ if (!sysmmufimd) {
+ debug("Can't get base address for sysmmu fimdm0");
+ return;
+ }
+
+ writel(0x0, sysmmufimd);
+ }
+}
+#endif
void exynos_fimd_lcd_init(vidinfo_t *vid)
{
@@ -268,6 +307,10 @@ void exynos_fimd_lcd_init(vidinfo_t *vid)
node, "reg");
if (fimd_ctrl == NULL)
debug("Can't get the FIMD base address\n");
+
+ if (fdtdec_get_bool(gd->fdt_blob, node, "samsung,disable-sysmmu"))
+ exynos_fimd_disable_sysmmu();
+
#else
fimd_ctrl = (struct exynos_fb *)samsung_get_base_fimd();
#endif
diff --git a/drivers/video/parade.c b/drivers/video/parade.c
new file mode 100644
index 0000000..0f543f6
--- /dev/null
+++ b/drivers/video/parade.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * This file is a driver for Parade dP<->LVDS bridges. The original submission
+ * is for the ps8625 chip.
+ */
+#include <config.h>
+#include <common.h>
+#include <i2c.h>
+#include <fdtdec.h>
+
+/*
+ * Initialization of the chip is a process of writing certaing values into
+ * certain registers over i2c bus. The chip in fact responds to a range of
+ * addresses on the i2c bus, so for each written value three parameters are
+ * required: i2c address, register address and the actual value.
+ *
+ * The base address is derived from the device tree, only address offset is
+ * stored in the table below.
+ */
+/**
+ * struct reg_data() - data for a parade register write
+ *
+ * @addr_off offset from the i2c base address for parade
+ * @reg_addr register address to write
+ * @value value to be written
+ */
+struct reg_data {
+ uint8_t addr_off;
+ uint8_t reg;
+ uint8_t value;
+} _packed;
+
+#define END_OF_TABLE 0xff /* Ficticious offset */
+
+static const struct reg_data parade_values[] = {
+ {0x02, 0xa1, 0x01}, /* HPD low */
+ /*
+ * SW setting
+ * [1:0] SW output 1.2V voltage is lower to 96%
+ */
+ {0x04, 0x14, 0x01},
+ /*
+ * RCO SS setting
+ * [5:4] = b01 0.5%, b10 1%, b11 1.5%
+ */
+ {0x04, 0xe3, 0x20},
+ {0x04, 0xe2, 0x80}, /* [7] RCO SS enable */
+ /*
+ * RPHY Setting
+ * [3:2] CDR tune wait cycle before
+ * measure for fine tune b00: 1us,
+ * 01: 0.5us, 10:2us, 11:4us.
+ */
+ {0x04, 0x8a, 0x0c},
+ {0x04, 0x89, 0x08}, /* [3] RFD always on */
+ /*
+ * CTN lock in/out:
+ * 20000ppm/80000ppm. Lock out 2
+ * times.
+ */
+ {0x04, 0x71, 0x2d},
+ /*
+ * 2.7G CDR settings
+ * NOF=40LSB for HBR CDR setting
+ */
+ {0x04, 0x7d, 0x07},
+ {0x04, 0x7b, 0x00}, /* [1:0] Fmin=+4bands */
+ {0x04, 0x7a, 0xfd}, /* [7:5] DCO_FTRNG=+-40% */
+ /*
+ * 1.62G CDR settings
+ * [5:2]NOF=64LSB [1:0]DCO scale is 2/5
+ */
+ {0x04, 0xc0, 0x12},
+ {0x04, 0xc1, 0x92}, /* Gitune=-37% */
+ {0x04, 0xc2, 0x1c}, /* Fbstep=100% */
+ {0x04, 0x32, 0x80}, /* [7] LOS signal disable */
+ /*
+ * RPIO Setting
+ * [7:4] LVDS driver bias current :
+ * 75% (250mV swing)
+ */
+ {0x04, 0x00, 0xb0},
+ /*
+ * [7:6] Right-bar GPIO output strength is 8mA
+ */
+ {0x04, 0x15, 0x40},
+ /* EQ Training State Machine Setting */
+ {0x04, 0x54, 0x10}, /* RCO calibration start */
+ /* [4:0] MAX_LANE_COUNT set to one lane */
+ {0x01, 0x02, 0x81},
+ /* [4:0] LANE_COUNT_SET set to one lane */
+ {0x01, 0x21, 0x81},
+ {0x00, 0x52, 0x20},
+ {0x00, 0xf1, 0x03}, /* HPD CP toggle enable */
+ {0x00, 0x62, 0x41},
+ /* Counter number, add 1ms counter delay */
+ {0x00, 0xf6, 0x01},
+ /*
+ * [6]PWM function control by
+ * DPCD0040f[7], default is PWM
+ * block always works.
+ */
+ {0x00, 0x77, 0x06},
+ /*
+ * 04h Adjust VTotal tolerance to
+ * fix the 30Hz no display issue
+ */
+ {0x00, 0x4c, 0x04},
+ /* DPCD00400='h00, Parade OUI = 'h001cf8 */
+ {0x01, 0xc0, 0x00},
+ {0x01, 0xc1, 0x1c}, /* DPCD00401='h1c */
+ {0x01, 0xc2, 0xf8}, /* DPCD00402='hf8 */
+ /*
+ * DPCD403~408 = ASCII code
+ * D2SLV5='h4432534c5635
+ */
+ {0x01, 0xc3, 0x44},
+ {0x01, 0xc4, 0x32}, /* DPCD404 */
+ {0x01, 0xc5, 0x53}, /* DPCD405 */
+ {0x01, 0xc6, 0x4c}, /* DPCD406 */
+ {0x01, 0xc7, 0x56}, /* DPCD407 */
+ {0x01, 0xc8, 0x35}, /* DPCD408 */
+ /*
+ * DPCD40A, Initial Code major revision
+ * '01'
+ */
+ {0x01, 0xca, 0x01},
+ /* DPCD40B, Initial Code minor revision '05' */
+ {0x01, 0xcb, 0x05},
+ /* DPCD720, Select internal PWM */
+ {0x01, 0xa5, 0xa0},
+ /*
+ * FFh for 100% PWM of brightness, 0h for 0%
+ * brightness
+ */
+ {0x01, 0xa7, 0xff},
+ /*
+ * Set LVDS output as 6bit-VESA mapping,
+ * single LVDS channel
+ */
+ {0x01, 0xcc, 0x13},
+ /* Enable SSC set by register */
+ {0x02, 0xb1, 0x20},
+ /*
+ * Set SSC enabled and +/-1% central
+ * spreading
+ */
+ {0x04, 0x10, 0x16},
+ /* MPU Clock source: LC => RCO */
+ {0x04, 0x59, 0x60},
+ {0x04, 0x54, 0x14}, /* LC -> RCO */
+ {0x02, 0xa1, 0x91}, /* HPD high */
+ {END_OF_TABLE}
+};
+
+/**
+ * Write values table into the Parade eDP bridge
+ *
+ * @return 0 on success, non-0 on failure
+ */
+
+static int parade_write_regs(int base_addr, const struct reg_data *table)
+{
+ int ret = 0;
+
+ while (!ret && (table->addr_off != END_OF_TABLE)) {
+ ret = i2c_write(base_addr + table->addr_off,
+ table->reg, 1,
+ (uint8_t *)&table->value,
+ sizeof(table->value));
+ table++;
+ }
+ return ret;
+}
+
+int parade_init(const void *blob)
+{
+ int bus, old_bus;
+ int parent;
+ int node;
+ int addr;
+ int ret;
+
+ node = fdtdec_next_compatible(blob, 0, COMPAT_PARADE_PS8625);
+ if (node < 0)
+ return 0;
+
+ parent = fdt_parent_offset(blob, node);
+ if (parent < 0) {
+ debug("%s: Could not find parent i2c node\n", __func__);
+ return -1;
+ }
+ addr = fdtdec_get_int(blob, node, "reg", -1);
+ if (addr < 0) {
+ debug("%s: Could not find i2c address\n", __func__);
+ return -1;
+ }
+
+ bus = i2c_get_bus_num_fdt(parent);
+ old_bus = i2c_get_bus_num();
+
+ debug("%s: Using i2c bus %d\n", __func__, bus);
+
+ /*
+ * TODO(sjg@chromium.org): Hmmm we seem to need some sort of delay
+ * here.
+ */
+ mdelay(40);
+ i2c_set_bus_num(bus);
+ ret = parade_write_regs(addr, parade_values);
+
+ i2c_set_bus_num(old_bus);
+
+ return ret;
+}