summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig51
-rw-r--r--drivers/Makefile3
-rw-r--r--drivers/block/Kconfig0
-rw-r--r--drivers/block/dwc_ahsata.c17
-rw-r--r--drivers/core/Kconfig0
-rw-r--r--drivers/core/Makefile2
-rw-r--r--drivers/core/device.c9
-rw-r--r--drivers/crypto/Kconfig0
-rw-r--r--drivers/ddr/fsl/ctrl_regs.c37
-rw-r--r--drivers/ddr/fsl/ddr4_dimm_params.c12
-rw-r--r--drivers/ddr/fsl/fsl_ddr_gen4.c3
-rw-r--r--drivers/ddr/fsl/interactive.c2
-rw-r--r--drivers/ddr/fsl/main.c244
-rw-r--r--drivers/ddr/fsl/options.c27
-rw-r--r--drivers/ddr/fsl/util.c26
-rw-r--r--drivers/demo/Makefile2
-rw-r--r--drivers/dfu/Kconfig0
-rw-r--r--drivers/dma/Kconfig0
-rw-r--r--drivers/dma/fsl_dma.c2
-rw-r--r--drivers/gpio/Kconfig0
-rw-r--r--drivers/hwmon/Kconfig0
-rw-r--r--drivers/i2c/Kconfig0
-rw-r--r--drivers/i2c/ihs_i2c.c4
-rw-r--r--drivers/input/Kconfig0
-rw-r--r--drivers/misc/Kconfig0
-rw-r--r--drivers/mmc/Kconfig0
-rw-r--r--drivers/mmc/fsl_esdhc.c2
-rw-r--r--drivers/mtd/Kconfig1
-rw-r--r--drivers/mtd/mtdcore.c4
-rw-r--r--drivers/mtd/nand/Kconfig42
-rw-r--r--drivers/mtd/nand/Makefile2
-rw-r--r--drivers/mtd/nand/am335x_spl_bch.c12
-rw-r--r--drivers/mtd/nand/atmel_nand.c22
-rw-r--r--drivers/mtd/nand/atmel_nand_ecc.h3
-rw-r--r--drivers/mtd/nand/davinci_nand.c1
-rw-r--r--drivers/mtd/nand/denali.c1205
-rw-r--r--drivers/mtd/nand/denali.h467
-rw-r--r--drivers/mtd/nand/denali_spl.c231
-rw-r--r--drivers/mtd/nand/fsl_elbc_nand.c8
-rw-r--r--drivers/mtd/nand/fsl_ifc_nand.c21
-rw-r--r--drivers/mtd/nand/nand_base.c4
-rw-r--r--drivers/mtd/spi/sandbox.c114
-rw-r--r--drivers/mtd/spi/sf_params.c4
-rw-r--r--drivers/mtd/spi/spi_spl_load.c6
-rw-r--r--drivers/net/Kconfig0
-rw-r--r--drivers/net/e1000.c2
-rw-r--r--drivers/net/fec_mxc.c42
-rw-r--r--drivers/net/fm/t1040.c2
-rw-r--r--drivers/pci/Kconfig0
-rw-r--r--drivers/pci/pci.c4
-rw-r--r--drivers/pci/pcie_imx.c40
-rw-r--r--drivers/pcmcia/Kconfig0
-rw-r--r--drivers/power/Kconfig0
-rw-r--r--drivers/rtc/Kconfig0
-rw-r--r--drivers/serial/Kconfig0
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/serial-uclass.c3
-rw-r--r--drivers/serial/serial.c2
-rw-r--r--drivers/serial/serial_lpuart.c19
-rw-r--r--drivers/serial/serial_uniphier.c204
-rw-r--r--drivers/serial/usbtty.c4
-rw-r--r--drivers/sound/Kconfig0
-rw-r--r--drivers/spi/Kconfig0
-rw-r--r--drivers/spi/kirkwood_spi.c27
-rw-r--r--drivers/spi/mxc_spi.c48
-rw-r--r--drivers/tpm/Kconfig0
-rw-r--r--drivers/usb/Kconfig0
-rw-r--r--drivers/usb/eth/smsc95xx.c1
-rw-r--r--drivers/usb/gadget/designware_udc.c4
-rw-r--r--drivers/usb/gadget/ep0.c2
-rw-r--r--drivers/usb/gadget/f_fastboot.c44
-rw-r--r--drivers/usb/gadget/mpc8xx_udc.c4
-rw-r--r--drivers/usb/gadget/pxa27x_udc.c2
-rw-r--r--drivers/usb/host/ehci-atmel.c8
-rw-r--r--drivers/usb/host/ohci-at91.c8
-rw-r--r--drivers/video/Kconfig0
-rw-r--r--drivers/watchdog/Kconfig0
77 files changed, 2753 insertions, 308 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
new file mode 100644
index 0000000..128736d
--- /dev/null
+++ b/drivers/Kconfig
@@ -0,0 +1,51 @@
+menu "Device Drivers"
+
+source "drivers/core/Kconfig"
+
+source "drivers/pci/Kconfig"
+
+source "drivers/pcmcia/Kconfig"
+
+source "drivers/mtd/Kconfig"
+
+source "drivers/block/Kconfig"
+
+source "drivers/misc/Kconfig"
+
+source "drivers/net/Kconfig"
+
+source "drivers/input/Kconfig"
+
+source "drivers/serial/Kconfig"
+
+source "drivers/tpm/Kconfig"
+
+source "drivers/i2c/Kconfig"
+
+source "drivers/spi/Kconfig"
+
+source "drivers/gpio/Kconfig"
+
+source "drivers/power/Kconfig"
+
+source "drivers/hwmon/Kconfig"
+
+source "drivers/watchdog/Kconfig"
+
+source "drivers/video/Kconfig"
+
+source "drivers/sound/Kconfig"
+
+source "drivers/usb/Kconfig"
+
+source "drivers/dfu/Kconfig"
+
+source "drivers/mmc/Kconfig"
+
+source "drivers/rtc/Kconfig"
+
+source "drivers/dma/Kconfig"
+
+source "drivers/crypto/Kconfig"
+
+endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index b22b109..d8361d9 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -1,3 +1,5 @@
+obj-$(CONFIG_DM) += core/
+obj-$(CONFIG_DM_DEMO) += demo/
obj-$(CONFIG_BIOSEMU) += bios_emulator/
obj-y += block/
obj-$(CONFIG_BOOTCOUNT_LIMIT) += bootcount/
@@ -16,3 +18,4 @@ obj-y += watchdog/
obj-$(CONFIG_QE) += qe/
obj-y += memory/
obj-y += pwm/
+obj-y += input/
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/block/Kconfig
diff --git a/drivers/block/dwc_ahsata.c b/drivers/block/dwc_ahsata.c
index 15d65d7..29f478b 100644
--- a/drivers/block/dwc_ahsata.c
+++ b/drivers/block/dwc_ahsata.c
@@ -864,6 +864,23 @@ u32 ata_low_level_rw_lba28(int dev, u32 blknr, lbaint_t blkcnt,
return blkcnt;
}
+int sata_port_status(int dev, int port)
+{
+ struct sata_port_regs *port_mmio;
+ struct ahci_probe_ent *probe_ent = NULL;
+
+ if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1))
+ return -EINVAL;
+
+ if (sata_dev_desc[dev].priv == NULL)
+ return -ENODEV;
+
+ probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv;
+ port_mmio = (struct sata_port_regs *)probe_ent->port[port].port_mmio;
+
+ return readl(&(port_mmio->ssts)) && SATA_PORT_SSTS_DET_MASK;
+}
+
/*
* SATA interface between low level driver and command layer
*/
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/core/Kconfig
diff --git a/drivers/core/Makefile b/drivers/core/Makefile
index 90b2a7f..c7905b1 100644
--- a/drivers/core/Makefile
+++ b/drivers/core/Makefile
@@ -4,4 +4,4 @@
# SPDX-License-Identifier: GPL-2.0+
#
-obj-$(CONFIG_DM) := device.o lists.o root.o uclass.o util.o
+obj-y := device.o lists.o root.o uclass.o util.o
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 166b073..32e80e8 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -106,13 +106,18 @@ int device_bind(struct udevice *parent, struct driver *drv, const char *name,
* a 'requested' sequence, and will be resolved (and ->seq updated)
* when the device is probed.
*/
- dev->req_seq = fdtdec_get_int(gd->fdt_blob, of_offset, "reg", -1);
dev->seq = -1;
+#ifdef CONFIG_OF_CONTROL
+ dev->req_seq = fdtdec_get_int(gd->fdt_blob, of_offset, "reg", -1);
+ if (!IS_ERR_VALUE(dev->req_seq))
+ dev->req_seq &= INT_MAX;
if (uc->uc_drv->name && of_offset != -1) {
fdtdec_get_alias_seq(gd->fdt_blob, uc->uc_drv->name, of_offset,
&dev->req_seq);
}
-
+#else
+ dev->req_seq = -1;
+#endif
if (!dev->platdata && drv->platdata_auto_alloc_size)
dev->flags |= DM_FLAG_ALLOC_PDATA;
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/crypto/Kconfig
diff --git a/drivers/ddr/fsl/ctrl_regs.c b/drivers/ddr/fsl/ctrl_regs.c
index d9cac22..9a156bf 100644
--- a/drivers/ddr/fsl/ctrl_regs.c
+++ b/drivers/ddr/fsl/ctrl_regs.c
@@ -297,10 +297,13 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr,
unsigned char taxpd_mclk = 0;
/* Mode register set cycle time (tMRD). */
unsigned char tmrd_mclk;
+#if defined(CONFIG_SYS_FSL_DDR4) || defined(CONFIG_SYS_FSL_DDR3)
+ const unsigned int mclk_ps = get_memory_clk_period_ps();
+#endif
#ifdef CONFIG_SYS_FSL_DDR4
/* tXP=max(4nCK, 6ns) */
- int txp = max((get_memory_clk_period_ps() * 4), 6000); /* unit=ps */
+ int txp = max(mclk_ps * 4, 6000); /* unit=ps */
trwt_mclk = 2;
twrt_mclk = 1;
act_pd_exit_mclk = picos_to_mclk(txp);
@@ -311,16 +314,19 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr,
*/
tmrd_mclk = max(24, picos_to_mclk(15000));
#elif defined(CONFIG_SYS_FSL_DDR3)
+ unsigned int data_rate = get_ddr_freq(0);
+ int txp;
/*
* (tXARD and tXARDS). Empirical?
* The DDR3 spec has not tXARD,
* we use the tXP instead of it.
- * tXP=max(3nCK, 7.5ns) for DDR3.
+ * tXP=max(3nCK, 7.5ns) for DDR3-800, 1066
+ * max(3nCK, 6ns) for DDR3-1333, 1600, 1866, 2133
* spec has not the tAXPD, we use
* tAXPD=1, need design to confirm.
*/
- int txp = max((get_memory_clk_period_ps() * 3), 7500); /* unit=ps */
- unsigned int data_rate = get_ddr_freq(0);
+ txp = max(mclk_ps * 3, (mclk_ps > 1540 ? 7500 : 6000));
+
tmrd_mclk = 4;
/* set the turnaround time */
@@ -578,6 +584,9 @@ static void set_timing_cfg_2(fsl_ddr_cfg_regs_t *ddr,
unsigned char cke_pls;
/* Window for four activates (tFAW) */
unsigned short four_act;
+#ifdef CONFIG_SYS_FSL_DDR3
+ const unsigned int mclk_ps = get_memory_clk_period_ps();
+#endif
/* FIXME add check that this must be less than acttorw_mclk */
add_lat_mclk = additive_latency;
@@ -619,10 +628,17 @@ static void set_timing_cfg_2(fsl_ddr_cfg_regs_t *ddr,
#ifdef CONFIG_SYS_FSL_DDR4
cpo = 0;
cke_pls = max(3, picos_to_mclk(5000));
+#elif defined(CONFIG_SYS_FSL_DDR3)
+ /*
+ * cke pulse = max(3nCK, 7.5ns) for DDR3-800
+ * max(3nCK, 5.625ns) for DDR3-1066, 1333
+ * max(3nCK, 5ns) for DDR3-1600, 1866, 2133
+ */
+ cke_pls = max(3, picos_to_mclk(mclk_ps > 1870 ? 7500 :
+ (mclk_ps > 1245 ? 5625 : 5000)));
#else
- cke_pls = picos_to_mclk(popts->tcke_clock_pulse_width_ps);
+ cke_pls = FSL_DDR_MIN_TCKE_PULSE_WIDTH_DDR;
#endif
-
four_act = picos_to_mclk(popts->tfaw_window_four_activates_ps);
ddr->timing_cfg_2 = (0
@@ -1886,9 +1902,12 @@ static void set_timing_cfg_9(fsl_ddr_cfg_regs_t *ddr)
debug("FSLDDR: timing_cfg_9 = 0x%08x\n", ddr->timing_cfg_9);
}
+/* This function needs to be called after set_ddr_sdram_cfg() is called */
static void set_ddr_dq_mapping(fsl_ddr_cfg_regs_t *ddr,
const dimm_params_t *dimm_params)
{
+ unsigned int acc_ecc_en = (ddr->ddr_sdram_cfg >> 2) & 0x1;
+
ddr->dq_map_0 = ((dimm_params->dq_mapping[0] & 0x3F) << 26) |
((dimm_params->dq_mapping[1] & 0x3F) << 20) |
((dimm_params->dq_mapping[2] & 0x3F) << 14) |
@@ -1907,9 +1926,11 @@ static void set_ddr_dq_mapping(fsl_ddr_cfg_regs_t *ddr,
((dimm_params->dq_mapping[15] & 0x3F) << 8) |
((dimm_params->dq_mapping[16] & 0x3F) << 2);
+ /* dq_map for ECC[4:7] is set to 0 if accumulated ECC is enabled */
ddr->dq_map_3 = ((dimm_params->dq_mapping[17] & 0x3F) << 26) |
((dimm_params->dq_mapping[8] & 0x3F) << 20) |
- ((dimm_params->dq_mapping[9] & 0x3F) << 14) |
+ (acc_ecc_en ? 0 :
+ (dimm_params->dq_mapping[9] & 0x3F) << 14) |
dimm_params->dq_mapping_ors;
debug("FSLDDR: dq_map_0 = 0x%08x\n", ddr->dq_map_0);
@@ -2276,7 +2297,7 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,
if (ip_rev > 0x40400)
unq_mrs_en = 1;
- if (ip_rev > 0x40700)
+ if ((ip_rev > 0x40700) && (popts->cswl_override != 0))
ddr->debug[18] = popts->cswl_override;
set_ddr_sdram_cfg_2(ddr, popts, unq_mrs_en);
diff --git a/drivers/ddr/fsl/ddr4_dimm_params.c b/drivers/ddr/fsl/ddr4_dimm_params.c
index 4745b7f..2418dca 100644
--- a/drivers/ddr/fsl/ddr4_dimm_params.c
+++ b/drivers/ddr/fsl/ddr4_dimm_params.c
@@ -113,7 +113,7 @@ compute_ranksize(const struct ddr4_spd_eeprom_s *spd)
#define spd_to_ps(mtb, ftb) \
(mtb * pdimm->mtb_ps + (ftb * pdimm->ftb_10th_ps) / 10)
/*
- * ddr_compute_dimm_parameters for DDR3 SPD
+ * ddr_compute_dimm_parameters for DDR4 SPD
*
* Compute DIMM parameters based upon the SPD information in spd.
* Writes the results to the dimm_params_t structure pointed by pdimm.
@@ -165,17 +165,17 @@ ddr_compute_dimm_parameters(const generic_spd_eeprom_t *spd,
+ pdimm->ec_sdram_width;
pdimm->device_width = 1 << ((spd->organization & 0x7) + 2);
- /* These are the types defined by the JEDEC DDR3 SPD spec */
+ /* These are the types defined by the JEDEC SPD spec */
pdimm->mirrored_dimm = 0;
pdimm->registered_dimm = 0;
- switch (spd->module_type & DDR3_SPD_MODULETYPE_MASK) {
- case DDR3_SPD_MODULETYPE_RDIMM:
+ switch (spd->module_type & DDR4_SPD_MODULETYPE_MASK) {
+ case DDR4_SPD_MODULETYPE_RDIMM:
/* Registered/buffered DIMMs */
pdimm->registered_dimm = 1;
break;
- case DDR3_SPD_MODULETYPE_UDIMM:
- case DDR3_SPD_MODULETYPE_SO_DIMM:
+ case DDR4_SPD_MODULETYPE_UDIMM:
+ case DDR4_SPD_MODULETYPE_SO_DIMM:
/* Unbuffered DIMMs */
if (spd->mod_section.unbuffered.addr_mapping & 0x1)
pdimm->mirrored_dimm = 1;
diff --git a/drivers/ddr/fsl/fsl_ddr_gen4.c b/drivers/ddr/fsl/fsl_ddr_gen4.c
index bfc76b3..e024db9 100644
--- a/drivers/ddr/fsl/fsl_ddr_gen4.c
+++ b/drivers/ddr/fsl/fsl_ddr_gen4.c
@@ -216,7 +216,7 @@ step2:
* For example, 2GB on 666MT/s 64-bit bus takes about 402ms
* Let's wait for 800ms
*/
- bus_width = 3 - ((ddr->sdram_cfg & SDRAM_CFG_DBW_MASK)
+ bus_width = 3 - ((ddr_in32(&ddr->sdram_cfg) & SDRAM_CFG_DBW_MASK)
>> SDRAM_CFG_DBW_SHIFT);
timeout = ((total_gb_size_per_controller << (6 - bus_width)) * 100 /
(get_ddr_freq(0) >> 20)) << 2;
@@ -233,5 +233,4 @@ step2:
if (timeout <= 0)
printf("Waiting for D_INIT timeout. Memory may not work.\n");
-
}
diff --git a/drivers/ddr/fsl/interactive.c b/drivers/ddr/fsl/interactive.c
index 6aa16b2..32ba6d8 100644
--- a/drivers/ddr/fsl/interactive.c
+++ b/drivers/ddr/fsl/interactive.c
@@ -517,7 +517,6 @@ static void fsl_ddr_options_edit(fsl_ddr_info_t *pinfo,
CTRL_OPTIONS(rcw_2),
CTRL_OPTIONS(ddr_cdr1),
CTRL_OPTIONS(ddr_cdr2),
- CTRL_OPTIONS(tcke_clock_pulse_width_ps),
CTRL_OPTIONS(tfaw_window_four_activates_ps),
CTRL_OPTIONS(trwt_override),
CTRL_OPTIONS(trwt),
@@ -808,7 +807,6 @@ static void print_memctl_options(const memctl_options_t *popts)
CTRL_OPTIONS(rcw_2),
CTRL_OPTIONS_HEX(ddr_cdr1),
CTRL_OPTIONS_HEX(ddr_cdr2),
- CTRL_OPTIONS(tcke_clock_pulse_width_ps),
CTRL_OPTIONS(tfaw_window_four_activates_ps),
CTRL_OPTIONS(trwt_override),
CTRL_OPTIONS(trwt),
diff --git a/drivers/ddr/fsl/main.c b/drivers/ddr/fsl/main.c
index 5e001fc..b43b669 100644
--- a/drivers/ddr/fsl/main.c
+++ b/drivers/ddr/fsl/main.c
@@ -135,7 +135,7 @@ __attribute__((weak, alias("__get_spd")))
void get_spd(generic_spd_eeprom_t *spd, u8 i2c_address);
void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd,
- unsigned int ctrl_num)
+ unsigned int ctrl_num, unsigned int dimm_slots_per_ctrl)
{
unsigned int i;
unsigned int i2c_address = 0;
@@ -145,14 +145,14 @@ void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd,
return;
}
- for (i = 0; i < CONFIG_DIMM_SLOTS_PER_CTLR; i++) {
+ for (i = 0; i < dimm_slots_per_ctrl; i++) {
i2c_address = spd_i2c_addr[ctrl_num][i];
get_spd(&(ctrl_dimms_spd[i]), i2c_address);
}
}
#else
void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd,
- unsigned int ctrl_num)
+ unsigned int ctrl_num, unsigned int dimm_slots_per_ctrl)
{
}
#endif /* SPD_EEPROM_ADDRESSx */
@@ -231,9 +231,11 @@ const char * step_to_string(unsigned int step) {
static unsigned long long __step_assign_addresses(fsl_ddr_info_t *pinfo,
unsigned int dbw_cap_adj[])
{
- int i, j;
+ unsigned int i, j;
unsigned long long total_mem, current_mem_base, total_ctlr_mem;
unsigned long long rank_density, ctlr_density = 0;
+ unsigned int first_ctrl = pinfo->first_ctrl;
+ unsigned int last_ctrl = first_ctrl + pinfo->num_ctrls - 1;
/*
* If a reduced data width is requested, but the SPD
@@ -241,7 +243,7 @@ static unsigned long long __step_assign_addresses(fsl_ddr_info_t *pinfo,
* computed dimm capacities accordingly before
* assigning addresses.
*/
- for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ for (i = first_ctrl; i <= last_ctrl; i++) {
unsigned int found = 0;
switch (pinfo->memctl_opts[i].data_bus_width) {
@@ -295,12 +297,12 @@ static unsigned long long __step_assign_addresses(fsl_ddr_info_t *pinfo,
debug("dbw_cap_adj[%d]=%d\n", i, dbw_cap_adj[i]);
}
- current_mem_base = CONFIG_SYS_FSL_DDR_SDRAM_BASE_PHY;
+ current_mem_base = pinfo->mem_base;
total_mem = 0;
- if (pinfo->memctl_opts[0].memctl_interleaving) {
- rank_density = pinfo->dimm_params[0][0].rank_density >>
- dbw_cap_adj[0];
- switch (pinfo->memctl_opts[0].ba_intlv_ctl &
+ if (pinfo->memctl_opts[first_ctrl].memctl_interleaving) {
+ rank_density = pinfo->dimm_params[first_ctrl][0].rank_density >>
+ dbw_cap_adj[first_ctrl];
+ switch (pinfo->memctl_opts[first_ctrl].ba_intlv_ctl &
FSL_DDR_CS0_CS1_CS2_CS3) {
case FSL_DDR_CS0_CS1_CS2_CS3:
ctlr_density = 4 * rank_density;
@@ -316,7 +318,7 @@ static unsigned long long __step_assign_addresses(fsl_ddr_info_t *pinfo,
}
debug("rank density is 0x%llx, ctlr density is 0x%llx\n",
rank_density, ctlr_density);
- for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ for (i = first_ctrl; i <= last_ctrl; i++) {
if (pinfo->memctl_opts[i].memctl_interleaving) {
switch (pinfo->memctl_opts[i].memctl_interleaving_mode) {
case FSL_DDR_256B_INTERLEAVING:
@@ -372,7 +374,7 @@ static unsigned long long __step_assign_addresses(fsl_ddr_info_t *pinfo,
* Simple linear assignment if memory
* controllers are not interleaved.
*/
- for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ for (i = first_ctrl; i <= last_ctrl; i++) {
total_ctlr_mem = 0;
pinfo->common_timing_params[i].base_address =
current_mem_base;
@@ -408,18 +410,23 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
{
unsigned int i, j;
unsigned long long total_mem = 0;
- int assert_reset;
+ int assert_reset = 0;
+ unsigned int first_ctrl = pinfo->first_ctrl;
+ unsigned int last_ctrl = first_ctrl + pinfo->num_ctrls - 1;
+ __maybe_unused int retval;
+ __maybe_unused bool goodspd = false;
+ __maybe_unused int dimm_slots_per_ctrl = pinfo->dimm_slots_per_ctrl;
fsl_ddr_cfg_regs_t *ddr_reg = pinfo->fsl_ddr_config_reg;
common_timing_params_t *timing_params = pinfo->common_timing_params;
- assert_reset = board_need_mem_reset();
+ if (pinfo->board_need_mem_reset)
+ assert_reset = pinfo->board_need_mem_reset();
/* data bus width capacity adjust shift amount */
unsigned int dbw_capacity_adjust[CONFIG_NUM_DDR_CONTROLLERS];
- for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ for (i = first_ctrl; i <= last_ctrl; i++)
dbw_capacity_adjust[i] = 0;
- }
debug("starting at step %u (%s)\n",
start_step, step_to_string(start_step));
@@ -428,28 +435,28 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
case STEP_GET_SPD:
#if defined(CONFIG_DDR_SPD) || defined(CONFIG_SPD_EEPROM)
/* STEP 1: Gather all DIMM SPD data */
- for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
- fsl_ddr_get_spd(pinfo->spd_installed_dimms[i], i);
+ for (i = first_ctrl; i <= last_ctrl; i++) {
+ fsl_ddr_get_spd(pinfo->spd_installed_dimms[i], i,
+ dimm_slots_per_ctrl);
}
case STEP_COMPUTE_DIMM_PARMS:
/* STEP 2: Compute DIMM parameters from SPD data */
- for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ for (i = first_ctrl; i <= last_ctrl; i++) {
for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
- unsigned int retval;
generic_spd_eeprom_t *spd =
&(pinfo->spd_installed_dimms[i][j]);
dimm_params_t *pdimm =
&(pinfo->dimm_params[i][j]);
-
retval = compute_dimm_parameters(spd, pdimm, i);
#ifdef CONFIG_SYS_DDR_RAW_TIMING
if (!i && !j && retval) {
printf("SPD error on controller %d! "
"Trying fallback to raw timing "
"calculation\n", i);
- fsl_ddr_get_dimm_params(pdimm, i, j);
+ retval = fsl_ddr_get_dimm_params(pdimm,
+ i, j);
}
#else
if (retval == 2) {
@@ -463,13 +470,26 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
debug("Warning: compute_dimm_parameters"
" non-zero return value for memctl=%u "
"dimm=%u\n", i, j);
+ } else {
+ goodspd = true;
}
}
}
+ if (!goodspd) {
+ /*
+ * No valid SPD found
+ * Throw an error if this is for main memory, i.e.
+ * first_ctrl == 0. Otherwise, siliently return 0
+ * as the memory size.
+ */
+ if (first_ctrl == 0)
+ printf("Error: No valid SPD detected.\n");
+ return 0;
+ }
#elif defined(CONFIG_SYS_DDR_RAW_TIMING)
case STEP_COMPUTE_DIMM_PARMS:
- for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ for (i = first_ctrl; i <= last_ctrl; i++) {
for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
dimm_params_t *pdimm =
&(pinfo->dimm_params[i][j]);
@@ -483,7 +503,7 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
* STEP 3: Compute a common set of timing parameters
* suitable for all of the DIMMs on each memory controller
*/
- for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ for (i = first_ctrl; i <= last_ctrl; i++) {
debug("Computing lowest common DIMM"
" parameters for memctl=%u\n", i);
compute_lowest_common_dimm_parameters(
@@ -494,7 +514,7 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
case STEP_GATHER_OPTS:
/* STEP 4: Gather configuration requirements from user */
- for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ for (i = first_ctrl; i <= last_ctrl; i++) {
debug("Reloading memory controller "
"configuration options for memctl=%u\n", i);
/*
@@ -516,9 +536,13 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
if (timing_params[i].all_dimms_registered)
assert_reset = 1;
}
- if (assert_reset) {
- debug("Asserting mem reset\n");
- board_assert_mem_reset();
+ if (assert_reset && !size_only) {
+ if (pinfo->board_mem_reset) {
+ debug("Asserting mem reset\n");
+ pinfo->board_mem_reset();
+ } else {
+ debug("Asserting mem reset missing\n");
+ }
}
case STEP_ASSIGN_ADDRESSES:
@@ -530,7 +554,7 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
case STEP_COMPUTE_REGS:
/* STEP 6: compute controller register values */
debug("FSL Memory ctrl register computation\n");
- for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ for (i = first_ctrl; i <= last_ctrl; i++) {
if (timing_params[i].ndimms_present == 0) {
memset(&ddr_reg[i], 0,
sizeof(fsl_ddr_cfg_regs_t));
@@ -558,7 +582,7 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
*/
unsigned int max_end = 0;
- for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ for (i = first_ctrl; i <= last_ctrl; i++) {
for (j = 0; j < CONFIG_CHIP_SELECTS_PER_CTRL; j++) {
fsl_ddr_cfg_regs_t *reg = &ddr_reg[i];
if (reg->cs[j].config & 0x80000000) {
@@ -578,53 +602,45 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
}
total_mem = 1 + (((unsigned long long)max_end << 24ULL) |
- 0xFFFFFFULL) - CONFIG_SYS_FSL_DDR_SDRAM_BASE_PHY;
+ 0xFFFFFFULL) - pinfo->mem_base;
}
return total_mem;
}
-/*
- * fsl_ddr_sdram() -- this is the main function to be called by
- * initdram() in the board file.
- *
- * It returns amount of memory configured in bytes.
- */
-phys_size_t fsl_ddr_sdram(void)
+phys_size_t __fsl_ddr_sdram(fsl_ddr_info_t *pinfo)
{
- unsigned int i;
+ unsigned int i, first_ctrl, last_ctrl;
#ifdef CONFIG_PPC
unsigned int law_memctl = LAW_TRGT_IF_DDR_1;
#endif
unsigned long long total_memory;
- fsl_ddr_info_t info;
- int deassert_reset;
+ int deassert_reset = 0;
- /* Reset info structure. */
- memset(&info, 0, sizeof(fsl_ddr_info_t));
+ first_ctrl = pinfo->first_ctrl;
+ last_ctrl = first_ctrl + pinfo->num_ctrls - 1;
/* Compute it once normally. */
#ifdef CONFIG_FSL_DDR_INTERACTIVE
if (tstc() && (getc() == 'd')) { /* we got a key press of 'd' */
- total_memory = fsl_ddr_interactive(&info, 0);
+ total_memory = fsl_ddr_interactive(pinfo, 0);
} else if (fsl_ddr_interactive_env_var_exists()) {
- total_memory = fsl_ddr_interactive(&info, 1);
+ total_memory = fsl_ddr_interactive(pinfo, 1);
} else
#endif
- total_memory = fsl_ddr_compute(&info, STEP_GET_SPD, 0);
+ total_memory = fsl_ddr_compute(pinfo, STEP_GET_SPD, 0);
/* setup 3-way interleaving before enabling DDRC */
- if (info.memctl_opts[0].memctl_interleaving) {
- switch (info.memctl_opts[0].memctl_interleaving_mode) {
- case FSL_DDR_3WAY_1KB_INTERLEAVING:
- case FSL_DDR_3WAY_4KB_INTERLEAVING:
- case FSL_DDR_3WAY_8KB_INTERLEAVING:
- fsl_ddr_set_intl3r(
- info.memctl_opts[0].memctl_interleaving_mode);
- break;
- default:
- break;
- }
+ switch (pinfo->memctl_opts[first_ctrl].memctl_interleaving_mode) {
+ case FSL_DDR_3WAY_1KB_INTERLEAVING:
+ case FSL_DDR_3WAY_4KB_INTERLEAVING:
+ case FSL_DDR_3WAY_8KB_INTERLEAVING:
+ fsl_ddr_set_intl3r(
+ pinfo->memctl_opts[first_ctrl].
+ memctl_interleaving_mode);
+ break;
+ default:
+ break;
}
/*
@@ -637,14 +653,15 @@ phys_size_t fsl_ddr_sdram(void)
* For non-registered DIMMs, initialization can go through but it is
* also OK to follow the same flow.
*/
- deassert_reset = board_need_mem_reset();
- for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
- if (info.common_timing_params[i].all_dimms_registered)
+ if (pinfo->board_need_mem_reset)
+ deassert_reset = pinfo->board_need_mem_reset();
+ for (i = first_ctrl; i <= last_ctrl; i++) {
+ if (pinfo->common_timing_params[i].all_dimms_registered)
deassert_reset = 1;
}
- for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ for (i = first_ctrl; i <= last_ctrl; i++) {
debug("Programming controller %u\n", i);
- if (info.common_timing_params[i].ndimms_present == 0) {
+ if (pinfo->common_timing_params[i].ndimms_present == 0) {
debug("No dimms present on controller %u; "
"skipping programming\n", i);
continue;
@@ -653,45 +670,58 @@ phys_size_t fsl_ddr_sdram(void)
* The following call with step = 1 returns before enabling
* the controller. It has to finish with step = 2 later.
*/
- fsl_ddr_set_memctl_regs(&(info.fsl_ddr_config_reg[i]), i,
+ fsl_ddr_set_memctl_regs(&(pinfo->fsl_ddr_config_reg[i]), i,
deassert_reset ? 1 : 0);
}
if (deassert_reset) {
/* Use board FPGA or GPIO to deassert reset signal */
- debug("Deasserting mem reset\n");
- board_deassert_mem_reset();
- for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ if (pinfo->board_mem_de_reset) {
+ debug("Deasserting mem reset\n");
+ pinfo->board_mem_de_reset();
+ } else {
+ debug("Deasserting mem reset missing\n");
+ }
+ for (i = first_ctrl; i <= last_ctrl; i++) {
/* Call with step = 2 to continue initialization */
- fsl_ddr_set_memctl_regs(&(info.fsl_ddr_config_reg[i]),
+ fsl_ddr_set_memctl_regs(&(pinfo->fsl_ddr_config_reg[i]),
i, 2);
}
}
#ifdef CONFIG_PPC
/* program LAWs */
- for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
- if (info.memctl_opts[i].memctl_interleaving) {
- switch (info.memctl_opts[i].memctl_interleaving_mode) {
+ for (i = first_ctrl; i <= last_ctrl; i++) {
+ if (pinfo->memctl_opts[i].memctl_interleaving) {
+ switch (pinfo->memctl_opts[i].
+ memctl_interleaving_mode) {
case FSL_DDR_CACHE_LINE_INTERLEAVING:
case FSL_DDR_PAGE_INTERLEAVING:
case FSL_DDR_BANK_INTERLEAVING:
case FSL_DDR_SUPERBANK_INTERLEAVING:
+ if (i % 2)
+ break;
if (i == 0) {
law_memctl = LAW_TRGT_IF_DDR_INTRLV;
- fsl_ddr_set_lawbar(&info.common_timing_params[i],
+ fsl_ddr_set_lawbar(
+ &pinfo->common_timing_params[i],
law_memctl, i);
- } else if (i == 2) {
+ }
+#if CONFIG_NUM_DDR_CONTROLLERS > 3
+ else if (i == 2) {
law_memctl = LAW_TRGT_IF_DDR_INTLV_34;
- fsl_ddr_set_lawbar(&info.common_timing_params[i],
+ fsl_ddr_set_lawbar(
+ &pinfo->common_timing_params[i],
law_memctl, i);
}
+#endif
break;
case FSL_DDR_3WAY_1KB_INTERLEAVING:
case FSL_DDR_3WAY_4KB_INTERLEAVING:
case FSL_DDR_3WAY_8KB_INTERLEAVING:
law_memctl = LAW_TRGT_IF_DDR_INTLV_123;
if (i == 0) {
- fsl_ddr_set_lawbar(&info.common_timing_params[i],
+ fsl_ddr_set_lawbar(
+ &pinfo->common_timing_params[i],
law_memctl, i);
}
break;
@@ -700,7 +730,8 @@ phys_size_t fsl_ddr_sdram(void)
case FSL_DDR_4WAY_8KB_INTERLEAVING:
law_memctl = LAW_TRGT_IF_DDR_INTLV_1234;
if (i == 0)
- fsl_ddr_set_lawbar(&info.common_timing_params[i],
+ fsl_ddr_set_lawbar(
+ &pinfo->common_timing_params[i],
law_memctl, i);
/* place holder for future 4-way interleaving */
break;
@@ -724,8 +755,8 @@ phys_size_t fsl_ddr_sdram(void)
default:
break;
}
- fsl_ddr_set_lawbar(&info.common_timing_params[i],
- law_memctl, i);
+ fsl_ddr_set_lawbar(&pinfo->common_timing_params[i],
+ law_memctl, i);
}
}
#endif
@@ -734,7 +765,7 @@ phys_size_t fsl_ddr_sdram(void)
#if !defined(CONFIG_PHYS_64BIT)
/* Check for 4G or more. Bad. */
- if (total_memory >= (1ull << 32)) {
+ if ((first_ctrl == 0) && (total_memory >= (1ull << 32))) {
puts("Detected ");
print_size(total_memory, " of memory\n");
printf(" This U-Boot only supports < 4G of DDR\n");
@@ -748,8 +779,56 @@ phys_size_t fsl_ddr_sdram(void)
}
/*
- * fsl_ddr_sdram_size() - This function only returns the size of the total
- * memory without setting ddr control registers.
+ * fsl_ddr_sdram(void) -- this is the main function to be
+ * called by initdram() in the board file.
+ *
+ * It returns amount of memory configured in bytes.
+ */
+phys_size_t fsl_ddr_sdram(void)
+{
+ fsl_ddr_info_t info;
+
+ /* Reset info structure. */
+ memset(&info, 0, sizeof(fsl_ddr_info_t));
+ info.mem_base = CONFIG_SYS_FSL_DDR_SDRAM_BASE_PHY;
+ info.first_ctrl = 0;
+ info.num_ctrls = CONFIG_SYS_FSL_DDR_MAIN_NUM_CTRLS;
+ info.dimm_slots_per_ctrl = CONFIG_DIMM_SLOTS_PER_CTLR;
+ info.board_need_mem_reset = board_need_mem_reset;
+ info.board_mem_reset = board_assert_mem_reset;
+ info.board_mem_de_reset = board_deassert_mem_reset;
+
+ return __fsl_ddr_sdram(&info);
+}
+
+#ifdef CONFIG_SYS_FSL_OTHER_DDR_NUM_CTRLS
+phys_size_t fsl_other_ddr_sdram(unsigned long long base,
+ unsigned int first_ctrl,
+ unsigned int num_ctrls,
+ unsigned int dimm_slots_per_ctrl,
+ int (*board_need_reset)(void),
+ void (*board_reset)(void),
+ void (*board_de_reset)(void))
+{
+ fsl_ddr_info_t info;
+
+ /* Reset info structure. */
+ memset(&info, 0, sizeof(fsl_ddr_info_t));
+ info.mem_base = base;
+ info.first_ctrl = first_ctrl;
+ info.num_ctrls = num_ctrls;
+ info.dimm_slots_per_ctrl = dimm_slots_per_ctrl;
+ info.board_need_mem_reset = board_need_reset;
+ info.board_mem_reset = board_reset;
+ info.board_mem_de_reset = board_de_reset;
+
+ return __fsl_ddr_sdram(&info);
+}
+#endif
+
+/*
+ * fsl_ddr_sdram_size(first_ctrl, last_intlv) - This function only returns the
+ * size of the total memory without setting ddr control registers.
*/
phys_size_t
fsl_ddr_sdram_size(void)
@@ -758,6 +837,11 @@ fsl_ddr_sdram_size(void)
unsigned long long total_memory = 0;
memset(&info, 0 , sizeof(fsl_ddr_info_t));
+ info.mem_base = CONFIG_SYS_FSL_DDR_SDRAM_BASE_PHY;
+ info.first_ctrl = 0;
+ info.num_ctrls = CONFIG_SYS_FSL_DDR_MAIN_NUM_CTRLS;
+ info.dimm_slots_per_ctrl = CONFIG_DIMM_SLOTS_PER_CTLR;
+ info.board_need_mem_reset = NULL;
/* Compute it once normally. */
total_memory = fsl_ddr_compute(&info, STEP_GET_SPD, 1);
diff --git a/drivers/ddr/fsl/options.c b/drivers/ddr/fsl/options.c
index 5986e1a..6d098d1 100644
--- a/drivers/ddr/fsl/options.c
+++ b/drivers/ddr/fsl/options.c
@@ -777,10 +777,6 @@ unsigned int populate_memctl_options(int all_dimms_registered,
*/
popts->bstopre = 0x100;
- /* Minimum CKE pulse width -- tCKE(MIN) */
- popts->tcke_clock_pulse_width_ps
- = mclk_to_picos(FSL_DDR_MIN_TCKE_PULSE_WIDTH_DDR);
-
/*
* Window for four activates -- tFAW
*
@@ -1065,18 +1061,21 @@ void check_interleaving_options(fsl_ddr_info_t *pinfo)
unsigned int check_intlv, check_n_row_addr, check_n_col_addr;
unsigned long long check_rank_density;
struct dimm_params_s *dimm;
+ int first_ctrl = pinfo->first_ctrl;
+ int last_ctrl = first_ctrl + pinfo->num_ctrls - 1;
+
/*
* Check if all controllers are configured for memory
* controller interleaving. Identical dimms are recommended. At least
* the size, row and col address should be checked.
*/
j = 0;
- check_n_ranks = pinfo->dimm_params[0][0].n_ranks;
- check_rank_density = pinfo->dimm_params[0][0].rank_density;
- check_n_row_addr = pinfo->dimm_params[0][0].n_row_addr;
- check_n_col_addr = pinfo->dimm_params[0][0].n_col_addr;
- check_intlv = pinfo->memctl_opts[0].memctl_interleaving_mode;
- for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ check_n_ranks = pinfo->dimm_params[first_ctrl][0].n_ranks;
+ check_rank_density = pinfo->dimm_params[first_ctrl][0].rank_density;
+ check_n_row_addr = pinfo->dimm_params[first_ctrl][0].n_row_addr;
+ check_n_col_addr = pinfo->dimm_params[first_ctrl][0].n_col_addr;
+ check_intlv = pinfo->memctl_opts[first_ctrl].memctl_interleaving_mode;
+ for (i = first_ctrl; i <= last_ctrl; i++) {
dimm = &pinfo->dimm_params[i][0];
if (!pinfo->memctl_opts[i].memctl_interleaving) {
continue;
@@ -1094,7 +1093,7 @@ void check_interleaving_options(fsl_ddr_info_t *pinfo)
}
if (intlv_invalid) {
- for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++)
+ for (i = first_ctrl; i <= last_ctrl; i++)
pinfo->memctl_opts[i].memctl_interleaving = 0;
printf("Not all DIMMs are identical. "
"Memory controller interleaving disabled.\n");
@@ -1123,10 +1122,10 @@ void check_interleaving_options(fsl_ddr_info_t *pinfo)
}
debug("%d of %d controllers are interleaving.\n", j, k);
if (j && (j != k)) {
- for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++)
+ for (i = first_ctrl; i <= last_ctrl; i++)
pinfo->memctl_opts[i].memctl_interleaving = 0;
- printf("Not all controllers have compatible "
- "interleaving mode. All disabled.\n");
+ if ((last_ctrl - first_ctrl) > 1)
+ puts("Not all controllers have compatible interleaving mode. All disabled.\n");
}
}
debug("Checking interleaving options completed\n");
diff --git a/drivers/ddr/fsl/util.c b/drivers/ddr/fsl/util.c
index 7a22aa3..58b519b 100644
--- a/drivers/ddr/fsl/util.c
+++ b/drivers/ddr/fsl/util.c
@@ -149,7 +149,7 @@ u32 fsl_ddr_get_intl3r(void)
return val;
}
-void board_add_ram_info(int use_default)
+void print_ddr_info(unsigned int start_ctrl)
{
struct ccsr_ddr __iomem *ddr =
(struct ccsr_ddr __iomem *)(CONFIG_SYS_FSL_DDR_ADDR);
@@ -164,17 +164,25 @@ void board_add_ram_info(int use_default)
int cas_lat;
#if CONFIG_NUM_DDR_CONTROLLERS >= 2
- if (!(sdram_cfg & SDRAM_CFG_MEM_EN)) {
+ if ((!(sdram_cfg & SDRAM_CFG_MEM_EN)) ||
+ (start_ctrl == 1)) {
ddr = (void __iomem *)CONFIG_SYS_FSL_DDR2_ADDR;
sdram_cfg = ddr_in32(&ddr->sdram_cfg);
}
#endif
#if CONFIG_NUM_DDR_CONTROLLERS >= 3
- if (!(sdram_cfg & SDRAM_CFG_MEM_EN)) {
+ if ((!(sdram_cfg & SDRAM_CFG_MEM_EN)) ||
+ (start_ctrl == 2)) {
ddr = (void __iomem *)CONFIG_SYS_FSL_DDR3_ADDR;
sdram_cfg = ddr_in32(&ddr->sdram_cfg);
}
#endif
+
+ if (!(sdram_cfg & SDRAM_CFG_MEM_EN)) {
+ puts(" (DDR not enabled)\n");
+ return;
+ }
+
puts(" (DDR");
switch ((sdram_cfg & SDRAM_CFG_SDRAM_TYPE_MASK) >>
SDRAM_CFG_SDRAM_TYPE_SHIFT) {
@@ -241,7 +249,7 @@ void board_add_ram_info(int use_default)
#endif
#endif
#if (CONFIG_NUM_DDR_CONTROLLERS >= 2)
- if (cs0_config & 0x20000000) {
+ if ((cs0_config & 0x20000000) && (start_ctrl == 0)) {
puts("\n");
puts(" DDR Controller Interleaving Mode: ");
@@ -290,3 +298,13 @@ void board_add_ram_info(int use_default)
}
}
}
+
+void __weak detail_board_ddr_info(void)
+{
+ print_ddr_info(0);
+}
+
+void board_add_ram_info(int use_default)
+{
+ detail_board_ddr_info();
+}
diff --git a/drivers/demo/Makefile b/drivers/demo/Makefile
index baaa2ba..171ddf3 100644
--- a/drivers/demo/Makefile
+++ b/drivers/demo/Makefile
@@ -4,6 +4,6 @@
# SPDX-License-Identifier: GPL-2.0+
#
-obj-$(CONFIG_DM_DEMO) += demo-uclass.o demo-pdata.o
+obj-y += demo-uclass.o demo-pdata.o
obj-$(CONFIG_DM_DEMO_SIMPLE) += demo-simple.o
obj-$(CONFIG_DM_DEMO_SHAPE) += demo-shape.o
diff --git a/drivers/dfu/Kconfig b/drivers/dfu/Kconfig
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/dfu/Kconfig
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/dma/Kconfig
diff --git a/drivers/dma/fsl_dma.c b/drivers/dma/fsl_dma.c
index 45e49c7..7ef7f12 100644
--- a/drivers/dma/fsl_dma.c
+++ b/drivers/dma/fsl_dma.c
@@ -96,7 +96,7 @@ int dmacpy(phys_addr_t dest, phys_addr_t src, phys_size_t count) {
uint xfer_size;
while (count) {
- xfer_size = MIN(FSL_DMA_MAX_SIZE, count);
+ xfer_size = min(FSL_DMA_MAX_SIZE, count);
out_dma32(&dma->dar, (u32) (dest & 0xFFFFFFFF));
out_dma32(&dma->sar, (u32) (src & 0xFFFFFFFF));
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/gpio/Kconfig
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/hwmon/Kconfig
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/i2c/Kconfig
diff --git a/drivers/i2c/ihs_i2c.c b/drivers/i2c/ihs_i2c.c
index fe66ce2..19fbe59 100644
--- a/drivers/i2c/ihs_i2c.c
+++ b/drivers/i2c/ihs_i2c.c
@@ -84,7 +84,7 @@ static int ihs_i2c_address(uchar chip, uint addr, int alen, bool hold_bus)
int shift = (alen-1) * 8;
while (alen) {
- int transfer = MIN(alen, 2);
+ int transfer = min(alen, 2);
uchar buf[2];
bool is_last = alen <= transfer;
@@ -113,7 +113,7 @@ static int ihs_i2c_access(struct i2c_adapter *adap, uchar chip, uint addr,
return 1;
while (len) {
- int transfer = MIN(len, 2);
+ int transfer = min(len, 2);
if (ihs_i2c_transfer(chip, buffer, transfer, read,
len <= transfer))
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/input/Kconfig
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/misc/Kconfig
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/mmc/Kconfig
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
index 97d0389..2640607 100644
--- a/drivers/mmc/fsl_esdhc.c
+++ b/drivers/mmc/fsl_esdhc.c
@@ -610,7 +610,7 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg)
#endif
cfg->cfg.f_min = 400000;
- cfg->cfg.f_max = MIN(gd->arch.sdhc_clk, 52000000);
+ cfg->cfg.f_max = min(gd->arch.sdhc_clk, 52000000);
cfg->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
new file mode 100644
index 0000000..415ab4e
--- /dev/null
+++ b/drivers/mtd/Kconfig
@@ -0,0 +1 @@
+source "drivers/mtd/nand/Kconfig"
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index e0b7e3a..cb27ff2 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -803,7 +803,7 @@ void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset,
*truncated = 0;
*len_incl_bad = 0;
- if (!mtd->block_isbad) {
+ if (!mtd->_block_isbad) {
*len_incl_bad = length;
return;
}
@@ -819,7 +819,7 @@ void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset,
block_len = mtd->erasesize - (offset & (mtd->erasesize - 1));
- if (!mtd->block_isbad(mtd, offset & ~(mtd->erasesize - 1)))
+ if (!mtd->_block_isbad(mtd, offset & ~(mtd->erasesize - 1)))
len_excl_bad += block_len;
*len_incl_bad += block_len;
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
new file mode 100644
index 0000000..75c2c06
--- /dev/null
+++ b/drivers/mtd/nand/Kconfig
@@ -0,0 +1,42 @@
+menu "NAND Device Support"
+
+if !SPL_BUILD
+
+config NAND_DENALI
+ bool "Support Denali NAND controller"
+ help
+ Enable support for the Denali NAND controller.
+
+config SYS_NAND_DENALI_64BIT
+ bool "Use 64-bit variant of Denali NAND controller"
+ depends on NAND_DENALI
+ help
+ The Denali NAND controller IP has some variations in terms of
+ the bus interface. The DMA setup sequence is completely differenct
+ between 32bit / 64bit AXI bus variants.
+
+ If your Denali NAND controller is the 64-bit variant, say Y.
+ Otherwise (32 bit), say N.
+
+config NAND_DENALI_SPARE_AREA_SKIP_BYTES
+ int "Number of bytes skipped in OOB area"
+ depends on NAND_DENALI
+ range 0 63
+ help
+ This option specifies the number of bytes to skip from the beginning
+ of OOB area before last ECC sector data starts. This is potentially
+ used to preserve the bad block marker in the OOB area.
+
+endif
+
+if SPL_BUILD
+
+config SPL_NAND_DENALI
+ bool "Support Denali NAND controller for SPL"
+ help
+ This is a small implementation of the Denali NAND controller
+ for use on SPL.
+
+endif
+
+endmenu
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index bf1312a..47eb34f 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -12,6 +12,7 @@ NORMAL_DRIVERS=y
endif
obj-$(CONFIG_SPL_NAND_AM33XX_BCH) += am335x_spl_bch.o
+obj-$(CONFIG_SPL_NAND_DENALI) += denali_spl.o
obj-$(CONFIG_SPL_NAND_DOCG4) += docg4_spl.o
obj-$(CONFIG_SPL_NAND_SIMPLE) += nand_spl_simple.o
obj-$(CONFIG_SPL_NAND_LOAD) += nand_spl_load.o
@@ -42,6 +43,7 @@ obj-$(CONFIG_NAND_ECC_BCH) += nand_bch.o
obj-$(CONFIG_NAND_ATMEL) += atmel_nand.o
obj-$(CONFIG_DRIVER_NAND_BFIN) += bfin_nand.o
obj-$(CONFIG_NAND_DAVINCI) += davinci_nand.o
+obj-$(CONFIG_NAND_DENALI) += denali.o
obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o
obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o
obj-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o
diff --git a/drivers/mtd/nand/am335x_spl_bch.c b/drivers/mtd/nand/am335x_spl_bch.c
index ce65d8e..bf8b2ee 100644
--- a/drivers/mtd/nand/am335x_spl_bch.c
+++ b/drivers/mtd/nand/am335x_spl_bch.c
@@ -64,14 +64,18 @@ static int nand_command(int block, int page, uint32_t offs,
NAND_CTRL_ALE | NAND_CTRL_CHANGE); /* A[7:0] */
hwctrl(&nand_info[0], (offs >> 8) & 0xff, NAND_CTRL_ALE); /* A[11:9] */
/* Row address */
- hwctrl(&nand_info[0], (page_addr & 0xff), NAND_CTRL_ALE); /* A[19:12] */
- hwctrl(&nand_info[0], ((page_addr >> 8) & 0xff),
+ if (cmd != NAND_CMD_RNDOUT) {
+ hwctrl(&nand_info[0], (page_addr & 0xff),
+ NAND_CTRL_ALE); /* A[19:12] */
+ hwctrl(&nand_info[0], ((page_addr >> 8) & 0xff),
NAND_CTRL_ALE); /* A[27:20] */
#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE
- /* One more address cycle for devices > 128MiB */
- hwctrl(&nand_info[0], (page_addr >> 16) & 0x0f,
+ /* One more address cycle for devices > 128MiB */
+ hwctrl(&nand_info[0], (page_addr >> 16) & 0x0f,
NAND_CTRL_ALE); /* A[31:28] */
#endif
+ }
+
hwctrl(&nand_info[0], NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
if (cmd == NAND_CMD_READ0) {
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index e73834d..9114a86 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -164,7 +164,7 @@ static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector)
/* Fill odd syndromes */
for (i = 0; i < host->pmecc_corr_cap; i++) {
- value = readl(&host->pmecc->rem_port[sector].rem[i / 2]);
+ value = pmecc_readl(host->pmecc, rem_port[sector].rem[i / 2]);
if (i & 1)
value >>= 16;
value &= 0xffff;
@@ -392,10 +392,11 @@ static int pmecc_err_location(struct mtd_info *mtd)
int16_t *smu = host->pmecc_smu;
int timeout = PMECC_MAX_TIMEOUT_US;
- writel(PMERRLOC_DISABLE, &host->pmerrloc->eldis);
+ pmecc_writel(host->pmerrloc, eldis, PMERRLOC_DISABLE);
for (i = 0; i <= host->pmecc_lmu[cap + 1] >> 1; i++) {
- writel(smu[(cap + 1) * num + i], &host->pmerrloc->sigma[i]);
+ pmecc_writel(host->pmerrloc, sigma[i],
+ smu[(cap + 1) * num + i]);
err_nbr++;
}
@@ -403,12 +404,12 @@ static int pmecc_err_location(struct mtd_info *mtd)
if (sector_size == 1024)
val |= PMERRLOC_ELCFG_SECTOR_1024;
- writel(val, &host->pmerrloc->elcfg);
- writel(sector_size * 8 + host->pmecc_degree * cap,
- &host->pmerrloc->elen);
+ pmecc_writel(host->pmerrloc, elcfg, val);
+ pmecc_writel(host->pmerrloc, elen,
+ sector_size * 8 + host->pmecc_degree * cap);
while (--timeout) {
- if (readl(&host->pmerrloc->elisr) & PMERRLOC_CALC_DONE)
+ if (pmecc_readl(host->pmerrloc, elisr) & PMERRLOC_CALC_DONE)
break;
WATCHDOG_RESET();
udelay(1);
@@ -419,7 +420,7 @@ static int pmecc_err_location(struct mtd_info *mtd)
return -1;
}
- roots_nbr = (readl(&host->pmerrloc->elisr) & PMERRLOC_ERR_NUM_MASK)
+ roots_nbr = (pmecc_readl(host->pmerrloc, elisr) & PMERRLOC_ERR_NUM_MASK)
>> 8;
/* Number of roots == degree of smu hence <= cap */
if (roots_nbr == host->pmecc_lmu[cap + 1] >> 1)
@@ -443,7 +444,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
sector_size = host->pmecc_sector_size;
while (err_nbr) {
- tmp = readl(&host->pmerrloc->el[i]) - 1;
+ tmp = pmecc_readl(host->pmerrloc, el[i]) - 1;
byte_pos = tmp / 8;
bit_pos = tmp % 8;
@@ -597,7 +598,7 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
pos = i * host->pmecc_bytes_per_sector + j;
chip->oob_poi[eccpos[pos]] =
- readb(&host->pmecc->ecc_port[i].ecc[j]);
+ pmecc_readb(host->pmecc, ecc_port[i].ecc[j]);
}
}
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
@@ -881,6 +882,7 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
return -ENOMEM;
}
+ nand->options |= NAND_NO_SUBPAGE_WRITE;
nand->ecc.read_page = atmel_nand_pmecc_read_page;
nand->ecc.write_page = atmel_nand_pmecc_write_page;
nand->ecc.strength = cap;
diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h
index 55d7711..92d4ec5 100644
--- a/drivers/mtd/nand/atmel_nand_ecc.h
+++ b/drivers/mtd/nand/atmel_nand_ecc.h
@@ -34,6 +34,9 @@
#define pmecc_readl(addr, reg) \
readl(&addr->reg)
+#define pmecc_readb(addr, reg) \
+ readb(&addr->reg)
+
#define pmecc_writel(addr, reg, value) \
writel((value), &addr->reg)
diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
index 02a1130..41689b5 100644
--- a/drivers/mtd/nand/davinci_nand.c
+++ b/drivers/mtd/nand/davinci_nand.c
@@ -363,6 +363,7 @@ static struct nand_ecclayout nand_keystone_rbl_4bit_layout_oobfirst = {
* @raw: use _raw version of write_page
*/
static int nand_davinci_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+ uint32_t offset, int data_len,
const uint8_t *buf, int oob_required,
int page, int cached, int raw)
{
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
new file mode 100644
index 0000000..ba3de1a
--- /dev/null
+++ b/drivers/mtd/nand/denali.c
@@ -0,0 +1,1205 @@
+/*
+ * Copyright (C) 2014 Panasonic Corporation
+ * Copyright (C) 2013-2014, Altera Corporation <www.altera.com>
+ * Copyright (C) 2009-2010, Intel Corporation and its suppliers.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <nand.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+
+#include "denali.h"
+
+#define NAND_DEFAULT_TIMINGS -1
+
+static int onfi_timing_mode = NAND_DEFAULT_TIMINGS;
+
+/* We define a macro here that combines all interrupts this driver uses into
+ * a single constant value, for convenience. */
+#define DENALI_IRQ_ALL (INTR_STATUS__DMA_CMD_COMP | \
+ INTR_STATUS__ECC_TRANSACTION_DONE | \
+ INTR_STATUS__ECC_ERR | \
+ INTR_STATUS__PROGRAM_FAIL | \
+ INTR_STATUS__LOAD_COMP | \
+ INTR_STATUS__PROGRAM_COMP | \
+ INTR_STATUS__TIME_OUT | \
+ INTR_STATUS__ERASE_FAIL | \
+ INTR_STATUS__RST_COMP | \
+ INTR_STATUS__ERASE_COMP | \
+ INTR_STATUS__ECC_UNCOR_ERR | \
+ INTR_STATUS__INT_ACT | \
+ INTR_STATUS__LOCKED_BLK)
+
+/* indicates whether or not the internal value for the flash bank is
+ * valid or not */
+#define CHIP_SELECT_INVALID -1
+
+#define SUPPORT_8BITECC 1
+
+/*
+ * this macro allows us to convert from an MTD structure to our own
+ * device context (denali) structure.
+ */
+#define mtd_to_denali(m) (((struct nand_chip *)mtd->priv)->priv)
+
+/* These constants are defined by the driver to enable common driver
+ * configuration options. */
+#define SPARE_ACCESS 0x41
+#define MAIN_ACCESS 0x42
+#define MAIN_SPARE_ACCESS 0x43
+
+#define DENALI_UNLOCK_START 0x10
+#define DENALI_UNLOCK_END 0x11
+#define DENALI_LOCK 0x21
+#define DENALI_LOCK_TIGHT 0x31
+#define DENALI_BUFFER_LOAD 0x60
+#define DENALI_BUFFER_WRITE 0x62
+
+#define DENALI_READ 0
+#define DENALI_WRITE 0x100
+
+/* types of device accesses. We can issue commands and get status */
+#define COMMAND_CYCLE 0
+#define ADDR_CYCLE 1
+#define STATUS_CYCLE 2
+
+/* this is a helper macro that allows us to
+ * format the bank into the proper bits for the controller */
+#define BANK(x) ((x) << 24)
+
+/* Interrupts are cleared by writing a 1 to the appropriate status bit */
+static inline void clear_interrupt(struct denali_nand_info *denali,
+ uint32_t irq_mask)
+{
+ uint32_t intr_status_reg;
+
+ intr_status_reg = INTR_STATUS(denali->flash_bank);
+
+ writel(irq_mask, denali->flash_reg + intr_status_reg);
+}
+
+static uint32_t read_interrupt_status(struct denali_nand_info *denali)
+{
+ uint32_t intr_status_reg;
+
+ intr_status_reg = INTR_STATUS(denali->flash_bank);
+
+ return readl(denali->flash_reg + intr_status_reg);
+}
+
+static void clear_interrupts(struct denali_nand_info *denali)
+{
+ uint32_t status;
+
+ status = read_interrupt_status(denali);
+ clear_interrupt(denali, status);
+
+ denali->irq_status = 0;
+}
+
+static void denali_irq_enable(struct denali_nand_info *denali,
+ uint32_t int_mask)
+{
+ int i;
+
+ for (i = 0; i < denali->max_banks; ++i)
+ writel(int_mask, denali->flash_reg + INTR_EN(i));
+}
+
+static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask)
+{
+ unsigned long timeout = 1000000;
+ uint32_t intr_status;
+
+ do {
+ intr_status = read_interrupt_status(denali) & DENALI_IRQ_ALL;
+ if (intr_status & irq_mask) {
+ denali->irq_status &= ~irq_mask;
+ /* our interrupt was detected */
+ break;
+ }
+ udelay(1);
+ timeout--;
+ } while (timeout != 0);
+
+ if (timeout == 0) {
+ /* timeout */
+ printf("Denali timeout with interrupt status %08x\n",
+ read_interrupt_status(denali));
+ intr_status = 0;
+ }
+ return intr_status;
+}
+
+/*
+ * Certain operations for the denali NAND controller use an indexed mode to
+ * read/write data. The operation is performed by writing the address value
+ * of the command to the device memory followed by the data. This function
+ * abstracts this common operation.
+*/
+static void index_addr(struct denali_nand_info *denali,
+ uint32_t address, uint32_t data)
+{
+ writel(address, denali->flash_mem + INDEX_CTRL_REG);
+ writel(data, denali->flash_mem + INDEX_DATA_REG);
+}
+
+/* Perform an indexed read of the device */
+static void index_addr_read_data(struct denali_nand_info *denali,
+ uint32_t address, uint32_t *pdata)
+{
+ writel(address, denali->flash_mem + INDEX_CTRL_REG);
+ *pdata = readl(denali->flash_mem + INDEX_DATA_REG);
+}
+
+/* We need to buffer some data for some of the NAND core routines.
+ * The operations manage buffering that data. */
+static void reset_buf(struct denali_nand_info *denali)
+{
+ denali->buf.head = 0;
+ denali->buf.tail = 0;
+}
+
+static void write_byte_to_buf(struct denali_nand_info *denali, uint8_t byte)
+{
+ denali->buf.buf[denali->buf.tail++] = byte;
+}
+
+/* resets a specific device connected to the core */
+static void reset_bank(struct denali_nand_info *denali)
+{
+ uint32_t irq_status;
+ uint32_t irq_mask = INTR_STATUS__RST_COMP |
+ INTR_STATUS__TIME_OUT;
+
+ clear_interrupts(denali);
+
+ writel(1 << denali->flash_bank, denali->flash_reg + DEVICE_RESET);
+
+ irq_status = wait_for_irq(denali, irq_mask);
+ if (irq_status & INTR_STATUS__TIME_OUT)
+ debug("reset bank failed.\n");
+}
+
+/* Reset the flash controller */
+static uint32_t denali_nand_reset(struct denali_nand_info *denali)
+{
+ uint32_t i;
+
+ for (i = 0; i < denali->max_banks; i++)
+ writel(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT,
+ denali->flash_reg + INTR_STATUS(i));
+
+ for (i = 0; i < denali->max_banks; i++) {
+ writel(1 << i, denali->flash_reg + DEVICE_RESET);
+ while (!(readl(denali->flash_reg + INTR_STATUS(i)) &
+ (INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT)))
+ if (readl(denali->flash_reg + INTR_STATUS(i)) &
+ INTR_STATUS__TIME_OUT)
+ debug("NAND Reset operation timed out on bank"
+ " %d\n", i);
+ }
+
+ for (i = 0; i < denali->max_banks; i++)
+ writel(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT,
+ denali->flash_reg + INTR_STATUS(i));
+
+ return 0;
+}
+
+/*
+ * this routine calculates the ONFI timing values for a given mode and
+ * programs the clocking register accordingly. The mode is determined by
+ * the get_onfi_nand_para routine.
+ */
+static void nand_onfi_timing_set(struct denali_nand_info *denali,
+ uint16_t mode)
+{
+ uint32_t trea[6] = {40, 30, 25, 20, 20, 16};
+ uint32_t trp[6] = {50, 25, 17, 15, 12, 10};
+ uint32_t treh[6] = {30, 15, 15, 10, 10, 7};
+ uint32_t trc[6] = {100, 50, 35, 30, 25, 20};
+ uint32_t trhoh[6] = {0, 15, 15, 15, 15, 15};
+ uint32_t trloh[6] = {0, 0, 0, 0, 5, 5};
+ uint32_t tcea[6] = {100, 45, 30, 25, 25, 25};
+ uint32_t tadl[6] = {200, 100, 100, 100, 70, 70};
+ uint32_t trhw[6] = {200, 100, 100, 100, 100, 100};
+ uint32_t trhz[6] = {200, 100, 100, 100, 100, 100};
+ uint32_t twhr[6] = {120, 80, 80, 60, 60, 60};
+ uint32_t tcs[6] = {70, 35, 25, 25, 20, 15};
+
+ uint32_t tclsrising = 1;
+ uint32_t data_invalid_rhoh, data_invalid_rloh, data_invalid;
+ uint32_t dv_window = 0;
+ uint32_t en_lo, en_hi;
+ uint32_t acc_clks;
+ uint32_t addr_2_data, re_2_we, re_2_re, we_2_re, cs_cnt;
+
+ en_lo = DIV_ROUND_UP(trp[mode], CLK_X);
+ en_hi = DIV_ROUND_UP(treh[mode], CLK_X);
+ if ((en_hi * CLK_X) < (treh[mode] + 2))
+ en_hi++;
+
+ if ((en_lo + en_hi) * CLK_X < trc[mode])
+ en_lo += DIV_ROUND_UP((trc[mode] - (en_lo + en_hi) * CLK_X),
+ CLK_X);
+
+ if ((en_lo + en_hi) < CLK_MULTI)
+ en_lo += CLK_MULTI - en_lo - en_hi;
+
+ while (dv_window < 8) {
+ data_invalid_rhoh = en_lo * CLK_X + trhoh[mode];
+
+ data_invalid_rloh = (en_lo + en_hi) * CLK_X + trloh[mode];
+
+ data_invalid =
+ data_invalid_rhoh <
+ data_invalid_rloh ? data_invalid_rhoh : data_invalid_rloh;
+
+ dv_window = data_invalid - trea[mode];
+
+ if (dv_window < 8)
+ en_lo++;
+ }
+
+ acc_clks = DIV_ROUND_UP(trea[mode], CLK_X);
+
+ while (((acc_clks * CLK_X) - trea[mode]) < 3)
+ acc_clks++;
+
+ if ((data_invalid - acc_clks * CLK_X) < 2)
+ debug("%s, Line %d: Warning!\n", __FILE__, __LINE__);
+
+ addr_2_data = DIV_ROUND_UP(tadl[mode], CLK_X);
+ re_2_we = DIV_ROUND_UP(trhw[mode], CLK_X);
+ re_2_re = DIV_ROUND_UP(trhz[mode], CLK_X);
+ we_2_re = DIV_ROUND_UP(twhr[mode], CLK_X);
+ cs_cnt = DIV_ROUND_UP((tcs[mode] - trp[mode]), CLK_X);
+ if (!tclsrising)
+ cs_cnt = DIV_ROUND_UP(tcs[mode], CLK_X);
+ if (cs_cnt == 0)
+ cs_cnt = 1;
+
+ if (tcea[mode]) {
+ while (((cs_cnt * CLK_X) + trea[mode]) < tcea[mode])
+ cs_cnt++;
+ }
+
+ /* Sighting 3462430: Temporary hack for MT29F128G08CJABAWP:B */
+ if ((readl(denali->flash_reg + MANUFACTURER_ID) == 0) &&
+ (readl(denali->flash_reg + DEVICE_ID) == 0x88))
+ acc_clks = 6;
+
+ writel(acc_clks, denali->flash_reg + ACC_CLKS);
+ writel(re_2_we, denali->flash_reg + RE_2_WE);
+ writel(re_2_re, denali->flash_reg + RE_2_RE);
+ writel(we_2_re, denali->flash_reg + WE_2_RE);
+ writel(addr_2_data, denali->flash_reg + ADDR_2_DATA);
+ writel(en_lo, denali->flash_reg + RDWR_EN_LO_CNT);
+ writel(en_hi, denali->flash_reg + RDWR_EN_HI_CNT);
+ writel(cs_cnt, denali->flash_reg + CS_SETUP_CNT);
+}
+
+/* queries the NAND device to see what ONFI modes it supports. */
+static uint32_t get_onfi_nand_para(struct denali_nand_info *denali)
+{
+ int i;
+ /*
+ * we needn't to do a reset here because driver has already
+ * reset all the banks before
+ */
+ if (!(readl(denali->flash_reg + ONFI_TIMING_MODE) &
+ ONFI_TIMING_MODE__VALUE))
+ return -EIO;
+
+ for (i = 5; i > 0; i--) {
+ if (readl(denali->flash_reg + ONFI_TIMING_MODE) &
+ (0x01 << i))
+ break;
+ }
+
+ nand_onfi_timing_set(denali, i);
+
+ /* By now, all the ONFI devices we know support the page cache */
+ /* rw feature. So here we enable the pipeline_rw_ahead feature */
+ return 0;
+}
+
+static void get_samsung_nand_para(struct denali_nand_info *denali,
+ uint8_t device_id)
+{
+ if (device_id == 0xd3) { /* Samsung K9WAG08U1A */
+ /* Set timing register values according to datasheet */
+ writel(5, denali->flash_reg + ACC_CLKS);
+ writel(20, denali->flash_reg + RE_2_WE);
+ writel(12, denali->flash_reg + WE_2_RE);
+ writel(14, denali->flash_reg + ADDR_2_DATA);
+ writel(3, denali->flash_reg + RDWR_EN_LO_CNT);
+ writel(2, denali->flash_reg + RDWR_EN_HI_CNT);
+ writel(2, denali->flash_reg + CS_SETUP_CNT);
+ }
+}
+
+static void get_toshiba_nand_para(struct denali_nand_info *denali)
+{
+ uint32_t tmp;
+
+ /* Workaround to fix a controller bug which reports a wrong */
+ /* spare area size for some kind of Toshiba NAND device */
+ if ((readl(denali->flash_reg + DEVICE_MAIN_AREA_SIZE) == 4096) &&
+ (readl(denali->flash_reg + DEVICE_SPARE_AREA_SIZE) == 64)) {
+ writel(216, denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
+ tmp = readl(denali->flash_reg + DEVICES_CONNECTED) *
+ readl(denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
+ writel(tmp, denali->flash_reg + LOGICAL_PAGE_SPARE_SIZE);
+ }
+}
+
+static void get_hynix_nand_para(struct denali_nand_info *denali,
+ uint8_t device_id)
+{
+ uint32_t main_size, spare_size;
+
+ switch (device_id) {
+ case 0xD5: /* Hynix H27UAG8T2A, H27UBG8U5A or H27UCG8VFA */
+ case 0xD7: /* Hynix H27UDG8VEM, H27UCG8UDM or H27UCG8V5A */
+ writel(128, denali->flash_reg + PAGES_PER_BLOCK);
+ writel(4096, denali->flash_reg + DEVICE_MAIN_AREA_SIZE);
+ writel(224, denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
+ main_size = 4096 *
+ readl(denali->flash_reg + DEVICES_CONNECTED);
+ spare_size = 224 *
+ readl(denali->flash_reg + DEVICES_CONNECTED);
+ writel(main_size, denali->flash_reg + LOGICAL_PAGE_DATA_SIZE);
+ writel(spare_size, denali->flash_reg + LOGICAL_PAGE_SPARE_SIZE);
+ writel(0, denali->flash_reg + DEVICE_WIDTH);
+ break;
+ default:
+ debug("Spectra: Unknown Hynix NAND (Device ID: 0x%x)."
+ "Will use default parameter values instead.\n",
+ device_id);
+ }
+}
+
+/*
+ * determines how many NAND chips are connected to the controller. Note for
+ * Intel CE4100 devices we don't support more than one device.
+ */
+static void find_valid_banks(struct denali_nand_info *denali)
+{
+ uint32_t id[denali->max_banks];
+ int i;
+
+ denali->total_used_banks = 1;
+ for (i = 0; i < denali->max_banks; i++) {
+ index_addr(denali, (uint32_t)(MODE_11 | (i << 24) | 0), 0x90);
+ index_addr(denali, (uint32_t)(MODE_11 | (i << 24) | 1), 0);
+ index_addr_read_data(denali,
+ (uint32_t)(MODE_11 | (i << 24) | 2),
+ &id[i]);
+
+ if (i == 0) {
+ if (!(id[i] & 0x0ff))
+ break;
+ } else {
+ if ((id[i] & 0x0ff) == (id[0] & 0x0ff))
+ denali->total_used_banks++;
+ else
+ break;
+ }
+ }
+}
+
+/*
+ * Use the configuration feature register to determine the maximum number of
+ * banks that the hardware supports.
+ */
+static void detect_max_banks(struct denali_nand_info *denali)
+{
+ uint32_t features = readl(denali->flash_reg + FEATURES);
+ denali->max_banks = 2 << (features & FEATURES__N_BANKS);
+}
+
+static void detect_partition_feature(struct denali_nand_info *denali)
+{
+ /*
+ * For MRST platform, denali->fwblks represent the
+ * number of blocks firmware is taken,
+ * FW is in protect partition and MTD driver has no
+ * permission to access it. So let driver know how many
+ * blocks it can't touch.
+ */
+ if (readl(denali->flash_reg + FEATURES) & FEATURES__PARTITION) {
+ if ((readl(denali->flash_reg + PERM_SRC_ID(1)) &
+ PERM_SRC_ID__SRCID) == SPECTRA_PARTITION_ID) {
+ denali->fwblks =
+ ((readl(denali->flash_reg + MIN_MAX_BANK(1)) &
+ MIN_MAX_BANK__MIN_VALUE) *
+ denali->blksperchip)
+ +
+ (readl(denali->flash_reg + MIN_BLK_ADDR(1)) &
+ MIN_BLK_ADDR__VALUE);
+ } else {
+ denali->fwblks = SPECTRA_START_BLOCK;
+ }
+ } else {
+ denali->fwblks = SPECTRA_START_BLOCK;
+ }
+}
+
+static uint32_t denali_nand_timing_set(struct denali_nand_info *denali)
+{
+ uint32_t id_bytes[5], addr;
+ uint8_t i, maf_id, device_id;
+
+ /* Use read id method to get device ID and other
+ * params. For some NAND chips, controller can't
+ * report the correct device ID by reading from
+ * DEVICE_ID register
+ * */
+ addr = (uint32_t)MODE_11 | BANK(denali->flash_bank);
+ index_addr(denali, (uint32_t)addr | 0, 0x90);
+ index_addr(denali, (uint32_t)addr | 1, 0);
+ for (i = 0; i < 5; i++)
+ index_addr_read_data(denali, addr | 2, &id_bytes[i]);
+ maf_id = id_bytes[0];
+ device_id = id_bytes[1];
+
+ if (readl(denali->flash_reg + ONFI_DEVICE_NO_OF_LUNS) &
+ ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE) { /* ONFI 1.0 NAND */
+ if (get_onfi_nand_para(denali))
+ return -EIO;
+ } else if (maf_id == 0xEC) { /* Samsung NAND */
+ get_samsung_nand_para(denali, device_id);
+ } else if (maf_id == 0x98) { /* Toshiba NAND */
+ get_toshiba_nand_para(denali);
+ } else if (maf_id == 0xAD) { /* Hynix NAND */
+ get_hynix_nand_para(denali, device_id);
+ }
+
+ find_valid_banks(denali);
+
+ detect_partition_feature(denali);
+
+ /* If the user specified to override the default timings
+ * with a specific ONFI mode, we apply those changes here.
+ */
+ if (onfi_timing_mode != NAND_DEFAULT_TIMINGS)
+ nand_onfi_timing_set(denali, onfi_timing_mode);
+
+ return 0;
+}
+
+/* validation function to verify that the controlling software is making
+ * a valid request
+ */
+static inline bool is_flash_bank_valid(int flash_bank)
+{
+ return flash_bank >= 0 && flash_bank < 4;
+}
+
+static void denali_irq_init(struct denali_nand_info *denali)
+{
+ uint32_t int_mask = 0;
+ int i;
+
+ /* Disable global interrupts */
+ writel(0, denali->flash_reg + GLOBAL_INT_ENABLE);
+
+ int_mask = DENALI_IRQ_ALL;
+
+ /* Clear all status bits */
+ for (i = 0; i < denali->max_banks; ++i)
+ writel(0xFFFF, denali->flash_reg + INTR_STATUS(i));
+
+ denali_irq_enable(denali, int_mask);
+}
+
+/* This helper function setups the registers for ECC and whether or not
+ * the spare area will be transferred. */
+static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en,
+ bool transfer_spare)
+{
+ int ecc_en_flag = 0, transfer_spare_flag = 0;
+
+ /* set ECC, transfer spare bits if needed */
+ ecc_en_flag = ecc_en ? ECC_ENABLE__FLAG : 0;
+ transfer_spare_flag = transfer_spare ? TRANSFER_SPARE_REG__FLAG : 0;
+
+ /* Enable spare area/ECC per user's request. */
+ writel(ecc_en_flag, denali->flash_reg + ECC_ENABLE);
+ /* applicable for MAP01 only */
+ writel(transfer_spare_flag, denali->flash_reg + TRANSFER_SPARE_REG);
+}
+
+/* sends a pipeline command operation to the controller. See the Denali NAND
+ * controller's user guide for more information (section 4.2.3.6).
+ */
+static int denali_send_pipeline_cmd(struct denali_nand_info *denali,
+ bool ecc_en, bool transfer_spare,
+ int access_type, int op)
+{
+ uint32_t addr, cmd, irq_status;
+ static uint32_t page_count = 1;
+
+ setup_ecc_for_xfer(denali, ecc_en, transfer_spare);
+
+ /* clear interrupts */
+ clear_interrupts(denali);
+
+ addr = BANK(denali->flash_bank) | denali->page;
+
+ /* setup the acccess type */
+ cmd = MODE_10 | addr;
+ index_addr(denali, cmd, access_type);
+
+ /* setup the pipeline command */
+ index_addr(denali, cmd, 0x2000 | op | page_count);
+
+ cmd = MODE_01 | addr;
+ writel(cmd, denali->flash_mem + INDEX_CTRL_REG);
+
+ if (op == DENALI_READ) {
+ /* wait for command to be accepted */
+ irq_status = wait_for_irq(denali, INTR_STATUS__LOAD_COMP);
+
+ if (irq_status == 0)
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/* helper function that simply writes a buffer to the flash */
+static int write_data_to_flash_mem(struct denali_nand_info *denali,
+ const uint8_t *buf, int len)
+{
+ uint32_t i = 0, *buf32;
+
+ /* verify that the len is a multiple of 4. see comment in
+ * read_data_from_flash_mem() */
+ BUG_ON((len % 4) != 0);
+
+ /* write the data to the flash memory */
+ buf32 = (uint32_t *)buf;
+ for (i = 0; i < len / 4; i++)
+ writel(*buf32++, denali->flash_mem + INDEX_DATA_REG);
+ return i * 4; /* intent is to return the number of bytes read */
+}
+
+/* helper function that simply reads a buffer from the flash */
+static int read_data_from_flash_mem(struct denali_nand_info *denali,
+ uint8_t *buf, int len)
+{
+ uint32_t i, *buf32;
+
+ /*
+ * we assume that len will be a multiple of 4, if not
+ * it would be nice to know about it ASAP rather than
+ * have random failures...
+ * This assumption is based on the fact that this
+ * function is designed to be used to read flash pages,
+ * which are typically multiples of 4...
+ */
+
+ BUG_ON((len % 4) != 0);
+
+ /* transfer the data from the flash */
+ buf32 = (uint32_t *)buf;
+ for (i = 0; i < len / 4; i++)
+ *buf32++ = readl(denali->flash_mem + INDEX_DATA_REG);
+
+ return i * 4; /* intent is to return the number of bytes read */
+}
+
+static void denali_mode_main_access(struct denali_nand_info *denali)
+{
+ uint32_t addr, cmd;
+
+ addr = BANK(denali->flash_bank) | denali->page;
+ cmd = MODE_10 | addr;
+ index_addr(denali, cmd, MAIN_ACCESS);
+}
+
+static void denali_mode_main_spare_access(struct denali_nand_info *denali)
+{
+ uint32_t addr, cmd;
+
+ addr = BANK(denali->flash_bank) | denali->page;
+ cmd = MODE_10 | addr;
+ index_addr(denali, cmd, MAIN_SPARE_ACCESS);
+}
+
+/* writes OOB data to the device */
+static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
+{
+ struct denali_nand_info *denali = mtd_to_denali(mtd);
+ uint32_t irq_status;
+ uint32_t irq_mask = INTR_STATUS__PROGRAM_COMP |
+ INTR_STATUS__PROGRAM_FAIL;
+ int status = 0;
+
+ denali->page = page;
+
+ if (denali_send_pipeline_cmd(denali, false, true, SPARE_ACCESS,
+ DENALI_WRITE) == 0) {
+ write_data_to_flash_mem(denali, buf, mtd->oobsize);
+
+ /* wait for operation to complete */
+ irq_status = wait_for_irq(denali, irq_mask);
+
+ if (irq_status == 0) {
+ dev_err(denali->dev, "OOB write failed\n");
+ status = -EIO;
+ }
+ } else {
+ printf("unable to send pipeline command\n");
+ status = -EIO;
+ }
+ return status;
+}
+
+/* reads OOB data from the device */
+static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
+{
+ struct denali_nand_info *denali = mtd_to_denali(mtd);
+ uint32_t irq_mask = INTR_STATUS__LOAD_COMP,
+ irq_status = 0, addr = 0x0, cmd = 0x0;
+
+ denali->page = page;
+
+ if (denali_send_pipeline_cmd(denali, false, true, SPARE_ACCESS,
+ DENALI_READ) == 0) {
+ read_data_from_flash_mem(denali, buf, mtd->oobsize);
+
+ /* wait for command to be accepted
+ * can always use status0 bit as the mask is identical for each
+ * bank. */
+ irq_status = wait_for_irq(denali, irq_mask);
+
+ if (irq_status == 0)
+ printf("page on OOB timeout %d\n", denali->page);
+
+ /* We set the device back to MAIN_ACCESS here as I observed
+ * instability with the controller if you do a block erase
+ * and the last transaction was a SPARE_ACCESS. Block erase
+ * is reliable (according to the MTD test infrastructure)
+ * if you are in MAIN_ACCESS.
+ */
+ addr = BANK(denali->flash_bank) | denali->page;
+ cmd = MODE_10 | addr;
+ index_addr(denali, cmd, MAIN_ACCESS);
+ }
+}
+
+/* this function examines buffers to see if they contain data that
+ * indicate that the buffer is part of an erased region of flash.
+ */
+static bool is_erased(uint8_t *buf, int len)
+{
+ int i = 0;
+ for (i = 0; i < len; i++)
+ if (buf[i] != 0xFF)
+ return false;
+ return true;
+}
+
+/* programs the controller to either enable/disable DMA transfers */
+static void denali_enable_dma(struct denali_nand_info *denali, bool en)
+{
+ uint32_t reg_val = 0x0;
+
+ if (en)
+ reg_val = DMA_ENABLE__FLAG;
+
+ writel(reg_val, denali->flash_reg + DMA_ENABLE);
+ readl(denali->flash_reg + DMA_ENABLE);
+}
+
+/* setups the HW to perform the data DMA */
+static void denali_setup_dma(struct denali_nand_info *denali, int op)
+{
+ uint32_t mode;
+ const int page_count = 1;
+ uint32_t addr = (uint32_t)denali->buf.dma_buf;
+
+ flush_dcache_range(addr, addr + sizeof(denali->buf.dma_buf));
+
+/* For Denali controller that is 64 bit bus IP core */
+#ifdef CONFIG_SYS_NAND_DENALI_64BIT
+ mode = MODE_10 | BANK(denali->flash_bank) | denali->page;
+
+ /* DMA is a three step process */
+
+ /* 1. setup transfer type, interrupt when complete,
+ burst len = 64 bytes, the number of pages */
+ index_addr(denali, mode, 0x01002000 | (64 << 16) | op | page_count);
+
+ /* 2. set memory low address bits 31:0 */
+ index_addr(denali, mode, addr);
+
+ /* 3. set memory high address bits 64:32 */
+ index_addr(denali, mode, 0);
+#else
+ mode = MODE_10 | BANK(denali->flash_bank);
+
+ /* DMA is a four step process */
+
+ /* 1. setup transfer type and # of pages */
+ index_addr(denali, mode | denali->page, 0x2000 | op | page_count);
+
+ /* 2. set memory high address bits 23:8 */
+ index_addr(denali, mode | ((uint32_t)(addr >> 16) << 8), 0x2200);
+
+ /* 3. set memory low address bits 23:8 */
+ index_addr(denali, mode | ((uint32_t)addr << 8), 0x2300);
+
+ /* 4. interrupt when complete, burst len = 64 bytes*/
+ index_addr(denali, mode | 0x14000, 0x2400);
+#endif
+}
+
+/* Common DMA function */
+static uint32_t denali_dma_configuration(struct denali_nand_info *denali,
+ uint32_t ops, bool raw_xfer,
+ uint32_t irq_mask, int oob_required)
+{
+ uint32_t irq_status = 0;
+ /* setup_ecc_for_xfer(bool ecc_en, bool transfer_spare) */
+ setup_ecc_for_xfer(denali, !raw_xfer, oob_required);
+
+ /* clear any previous interrupt flags */
+ clear_interrupts(denali);
+
+ /* enable the DMA */
+ denali_enable_dma(denali, true);
+
+ /* setup the DMA */
+ denali_setup_dma(denali, ops);
+
+ /* wait for operation to complete */
+ irq_status = wait_for_irq(denali, irq_mask);
+
+ /* if ECC fault happen, seems we need delay before turning off DMA.
+ * If not, the controller will go into non responsive condition */
+ if (irq_status & INTR_STATUS__ECC_UNCOR_ERR)
+ udelay(100);
+
+ /* disable the DMA */
+ denali_enable_dma(denali, false);
+
+ return irq_status;
+}
+
+static int write_page(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf, bool raw_xfer, int oob_required)
+{
+ struct denali_nand_info *denali = mtd_to_denali(mtd);
+
+ uint32_t irq_status = 0;
+ uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP;
+
+ denali->status = 0;
+
+ /* copy buffer into DMA buffer */
+ memcpy(denali->buf.dma_buf, buf, mtd->writesize);
+
+ /* need extra memcpy for raw transfer */
+ if (raw_xfer)
+ memcpy(denali->buf.dma_buf + mtd->writesize,
+ chip->oob_poi, mtd->oobsize);
+
+ /* setting up DMA */
+ irq_status = denali_dma_configuration(denali, DENALI_WRITE, raw_xfer,
+ irq_mask, oob_required);
+
+ /* if timeout happen, error out */
+ if (!(irq_status & INTR_STATUS__DMA_CMD_COMP)) {
+ debug("DMA timeout for denali write_page\n");
+ denali->status = NAND_STATUS_FAIL;
+ return -EIO;
+ }
+
+ if (irq_status & INTR_STATUS__LOCKED_BLK) {
+ debug("Failed as write to locked block\n");
+ denali->status = NAND_STATUS_FAIL;
+ return -EIO;
+ }
+ return 0;
+}
+
+/* NAND core entry points */
+
+/*
+ * this is the callback that the NAND core calls to write a page. Since
+ * writing a page with ECC or without is similar, all the work is done
+ * by write_page above.
+ */
+static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf, int oob_required)
+{
+ struct denali_nand_info *denali = mtd_to_denali(mtd);
+
+ /*
+ * for regular page writes, we let HW handle all the ECC
+ * data written to the device.
+ */
+ if (oob_required)
+ /* switch to main + spare access */
+ denali_mode_main_spare_access(denali);
+ else
+ /* switch to main access only */
+ denali_mode_main_access(denali);
+
+ return write_page(mtd, chip, buf, false, oob_required);
+}
+
+/*
+ * This is the callback that the NAND core calls to write a page without ECC.
+ * raw access is similar to ECC page writes, so all the work is done in the
+ * write_page() function above.
+ */
+static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf, int oob_required)
+{
+ struct denali_nand_info *denali = mtd_to_denali(mtd);
+
+ /*
+ * for raw page writes, we want to disable ECC and simply write
+ * whatever data is in the buffer.
+ */
+
+ if (oob_required)
+ /* switch to main + spare access */
+ denali_mode_main_spare_access(denali);
+ else
+ /* switch to main access only */
+ denali_mode_main_access(denali);
+
+ return write_page(mtd, chip, buf, true, oob_required);
+}
+
+static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+ int page)
+{
+ return write_oob_data(mtd, chip->oob_poi, page);
+}
+
+/* raw include ECC value and all the spare area */
+static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf, int oob_required, int page)
+{
+ struct denali_nand_info *denali = mtd_to_denali(mtd);
+
+ uint32_t irq_status, irq_mask = INTR_STATUS__DMA_CMD_COMP;
+
+ if (denali->page != page) {
+ debug("Missing NAND_CMD_READ0 command\n");
+ return -EIO;
+ }
+
+ if (oob_required)
+ /* switch to main + spare access */
+ denali_mode_main_spare_access(denali);
+ else
+ /* switch to main access only */
+ denali_mode_main_access(denali);
+
+ /* setting up the DMA where ecc_enable is false */
+ irq_status = denali_dma_configuration(denali, DENALI_READ, true,
+ irq_mask, oob_required);
+
+ /* if timeout happen, error out */
+ if (!(irq_status & INTR_STATUS__DMA_CMD_COMP)) {
+ debug("DMA timeout for denali_read_page_raw\n");
+ return -EIO;
+ }
+
+ /* splitting the content to destination buffer holder */
+ memcpy(chip->oob_poi, (denali->buf.dma_buf + mtd->writesize),
+ mtd->oobsize);
+ memcpy(buf, denali->buf.dma_buf, mtd->writesize);
+
+ return 0;
+}
+
+static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf, int oob_required, int page)
+{
+ struct denali_nand_info *denali = mtd_to_denali(mtd);
+ uint32_t irq_status, irq_mask = INTR_STATUS__DMA_CMD_COMP;
+
+ if (denali->page != page) {
+ debug("Missing NAND_CMD_READ0 command\n");
+ return -EIO;
+ }
+
+ if (oob_required)
+ /* switch to main + spare access */
+ denali_mode_main_spare_access(denali);
+ else
+ /* switch to main access only */
+ denali_mode_main_access(denali);
+
+ /* setting up the DMA where ecc_enable is true */
+ irq_status = denali_dma_configuration(denali, DENALI_READ, false,
+ irq_mask, oob_required);
+
+ memcpy(buf, denali->buf.dma_buf, mtd->writesize);
+
+ /* check whether any ECC error */
+ if (irq_status & INTR_STATUS__ECC_UNCOR_ERR) {
+ /* is the ECC cause by erase page, check using read_page_raw */
+ debug(" Uncorrected ECC detected\n");
+ denali_read_page_raw(mtd, chip, buf, oob_required,
+ denali->page);
+
+ if (is_erased(buf, mtd->writesize) == true &&
+ is_erased(chip->oob_poi, mtd->oobsize) == true) {
+ debug(" ECC error cause by erased block\n");
+ /* false alarm, return the 0xFF */
+ } else {
+ return -EIO;
+ }
+ }
+ memcpy(buf, denali->buf.dma_buf, mtd->writesize);
+ return 0;
+}
+
+static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+ int page)
+{
+ read_oob_data(mtd, chip->oob_poi, page);
+
+ return 0;
+}
+
+static uint8_t denali_read_byte(struct mtd_info *mtd)
+{
+ struct denali_nand_info *denali = mtd_to_denali(mtd);
+ uint32_t addr, result;
+
+ addr = (uint32_t)MODE_11 | BANK(denali->flash_bank);
+ index_addr_read_data(denali, addr | 2, &result);
+ return (uint8_t)result & 0xFF;
+}
+
+static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ struct denali_nand_info *denali = mtd_to_denali(mtd);
+ uint32_t i, addr, result;
+
+ /* delay for tR (data transfer from Flash array to data register) */
+ udelay(25);
+
+ /* ensure device completed else additional delay and polling */
+ wait_for_irq(denali, INTR_STATUS__INT_ACT);
+
+ addr = (uint32_t)MODE_11 | BANK(denali->flash_bank);
+ for (i = 0; i < len; i++) {
+ index_addr_read_data(denali, (uint32_t)addr | 2, &result);
+ write_byte_to_buf(denali, result);
+ }
+ memcpy(buf, denali->buf.buf, len);
+}
+
+static void denali_select_chip(struct mtd_info *mtd, int chip)
+{
+ struct denali_nand_info *denali = mtd_to_denali(mtd);
+
+ denali->flash_bank = chip;
+}
+
+static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
+{
+ struct denali_nand_info *denali = mtd_to_denali(mtd);
+ int status = denali->status;
+ denali->status = 0;
+
+ return status;
+}
+
+static void denali_erase(struct mtd_info *mtd, int page)
+{
+ struct denali_nand_info *denali = mtd_to_denali(mtd);
+ uint32_t cmd, irq_status;
+
+ /* clear interrupts */
+ clear_interrupts(denali);
+
+ /* setup page read request for access type */
+ cmd = MODE_10 | BANK(denali->flash_bank) | page;
+ index_addr(denali, cmd, 0x1);
+
+ /* wait for erase to complete or failure to occur */
+ irq_status = wait_for_irq(denali, INTR_STATUS__ERASE_COMP |
+ INTR_STATUS__ERASE_FAIL);
+
+ if (irq_status & INTR_STATUS__ERASE_FAIL ||
+ irq_status & INTR_STATUS__LOCKED_BLK)
+ denali->status = NAND_STATUS_FAIL;
+ else
+ denali->status = 0;
+}
+
+static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col,
+ int page)
+{
+ struct denali_nand_info *denali = mtd_to_denali(mtd);
+ uint32_t addr;
+
+ switch (cmd) {
+ case NAND_CMD_PAGEPROG:
+ break;
+ case NAND_CMD_STATUS:
+ addr = MODE_11 | BANK(denali->flash_bank);
+ index_addr(denali, addr | 0, cmd);
+ break;
+ case NAND_CMD_PARAM:
+ clear_interrupts(denali);
+ case NAND_CMD_READID:
+ reset_buf(denali);
+ /* sometimes ManufactureId read from register is not right
+ * e.g. some of Micron MT29F32G08QAA MLC NAND chips
+ * So here we send READID cmd to NAND insteand
+ * */
+ addr = MODE_11 | BANK(denali->flash_bank);
+ index_addr(denali, addr | 0, cmd);
+ index_addr(denali, addr | 1, col & 0xFF);
+ break;
+ case NAND_CMD_READ0:
+ case NAND_CMD_SEQIN:
+ denali->page = page;
+ break;
+ case NAND_CMD_RESET:
+ reset_bank(denali);
+ break;
+ case NAND_CMD_READOOB:
+ /* TODO: Read OOB data */
+ break;
+ case NAND_CMD_ERASE1:
+ /*
+ * supporting block erase only, not multiblock erase as
+ * it will cross plane and software need complex calculation
+ * to identify the block count for the cross plane
+ */
+ denali_erase(mtd, page);
+ break;
+ case NAND_CMD_ERASE2:
+ /* nothing to do here as it was done during NAND_CMD_ERASE1 */
+ break;
+ case NAND_CMD_UNLOCK1:
+ addr = MODE_10 | BANK(denali->flash_bank) | page;
+ index_addr(denali, addr | 0, DENALI_UNLOCK_START);
+ break;
+ case NAND_CMD_UNLOCK2:
+ addr = MODE_10 | BANK(denali->flash_bank) | page;
+ index_addr(denali, addr | 0, DENALI_UNLOCK_END);
+ break;
+ case NAND_CMD_LOCK:
+ addr = MODE_10 | BANK(denali->flash_bank);
+ index_addr(denali, addr | 0, DENALI_LOCK);
+ break;
+ default:
+ printf(": unsupported command received 0x%x\n", cmd);
+ break;
+ }
+}
+/* end NAND core entry points */
+
+/* Initialization code to bring the device up to a known good state */
+static void denali_hw_init(struct denali_nand_info *denali)
+{
+ /*
+ * tell driver how many bit controller will skip before writing
+ * ECC code in OOB. This is normally used for bad block marker
+ */
+ writel(CONFIG_NAND_DENALI_SPARE_AREA_SKIP_BYTES,
+ denali->flash_reg + SPARE_AREA_SKIP_BYTES);
+ detect_max_banks(denali);
+ denali_nand_reset(denali);
+ writel(0x0F, denali->flash_reg + RB_PIN_ENABLED);
+ writel(CHIP_EN_DONT_CARE__FLAG,
+ denali->flash_reg + CHIP_ENABLE_DONT_CARE);
+ writel(0xffff, denali->flash_reg + SPARE_AREA_MARKER);
+
+ /* Should set value for these registers when init */
+ writel(0, denali->flash_reg + TWO_ROW_ADDR_CYCLES);
+ writel(1, denali->flash_reg + ECC_ENABLE);
+ denali_nand_timing_set(denali);
+ denali_irq_init(denali);
+}
+
+static struct nand_ecclayout nand_oob;
+
+static int denali_nand_init(struct nand_chip *nand)
+{
+ struct denali_nand_info *denali;
+
+ denali = malloc(sizeof(*denali));
+ if (!denali)
+ return -ENOMEM;
+
+ nand->priv = denali;
+
+ denali->flash_reg = (void __iomem *)CONFIG_SYS_NAND_REGS_BASE;
+ denali->flash_mem = (void __iomem *)CONFIG_SYS_NAND_DATA_BASE;
+
+#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT
+ /* check whether flash got BBT table (located at end of flash). As we
+ * use NAND_BBT_NO_OOB, the BBT page will start with
+ * bbt_pattern. We will have mirror pattern too */
+ nand->bbt_options |= NAND_BBT_USE_FLASH;
+ /*
+ * We are using main + spare with ECC support. As BBT need ECC support,
+ * we need to ensure BBT code don't write to OOB for the BBT pattern.
+ * All BBT info will be stored into data area with ECC support.
+ */
+ nand->bbt_options |= NAND_BBT_NO_OOB;
+#endif
+
+ nand->ecc.mode = NAND_ECC_HW;
+ nand->ecc.size = CONFIG_NAND_DENALI_ECC_SIZE;
+ nand->ecc.read_oob = denali_read_oob;
+ nand->ecc.write_oob = denali_write_oob;
+ nand->ecc.read_page = denali_read_page;
+ nand->ecc.read_page_raw = denali_read_page_raw;
+ nand->ecc.write_page = denali_write_page;
+ nand->ecc.write_page_raw = denali_write_page_raw;
+ /*
+ * Tell driver the ecc strength. This register may be already set
+ * correctly. So we read this value out.
+ */
+ nand->ecc.strength = readl(denali->flash_reg + ECC_CORRECTION);
+ switch (nand->ecc.size) {
+ case 512:
+ nand->ecc.bytes = (nand->ecc.strength * 13 + 15) / 16 * 2;
+ break;
+ case 1024:
+ nand->ecc.bytes = (nand->ecc.strength * 14 + 15) / 16 * 2;
+ break;
+ default:
+ pr_err("Unsupported ECC size\n");
+ return -EINVAL;
+ }
+ nand_oob.eccbytes = nand->ecc.bytes;
+ nand->ecc.layout = &nand_oob;
+
+ /* Set address of hardware control function */
+ nand->cmdfunc = denali_cmdfunc;
+ nand->read_byte = denali_read_byte;
+ nand->read_buf = denali_read_buf;
+ nand->select_chip = denali_select_chip;
+ nand->waitfunc = denali_waitfunc;
+ denali_hw_init(denali);
+ return 0;
+}
+
+int board_nand_init(struct nand_chip *chip)
+{
+ return denali_nand_init(chip);
+}
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
new file mode 100644
index 0000000..3277da7
--- /dev/null
+++ b/drivers/mtd/nand/denali.h
@@ -0,0 +1,467 @@
+/*
+ * Copyright (C) 2013-2014 Altera Corporation <www.altera.com>
+ * Copyright (C) 2009-2010, Intel Corporation and its suppliers.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <linux/mtd/nand.h>
+
+#define DEVICE_RESET 0x0
+#define DEVICE_RESET__BANK0 0x0001
+#define DEVICE_RESET__BANK1 0x0002
+#define DEVICE_RESET__BANK2 0x0004
+#define DEVICE_RESET__BANK3 0x0008
+
+#define TRANSFER_SPARE_REG 0x10
+#define TRANSFER_SPARE_REG__FLAG 0x0001
+
+#define LOAD_WAIT_CNT 0x20
+#define LOAD_WAIT_CNT__VALUE 0xffff
+
+#define PROGRAM_WAIT_CNT 0x30
+#define PROGRAM_WAIT_CNT__VALUE 0xffff
+
+#define ERASE_WAIT_CNT 0x40
+#define ERASE_WAIT_CNT__VALUE 0xffff
+
+#define INT_MON_CYCCNT 0x50
+#define INT_MON_CYCCNT__VALUE 0xffff
+
+#define RB_PIN_ENABLED 0x60
+#define RB_PIN_ENABLED__BANK0 0x0001
+#define RB_PIN_ENABLED__BANK1 0x0002
+#define RB_PIN_ENABLED__BANK2 0x0004
+#define RB_PIN_ENABLED__BANK3 0x0008
+
+#define MULTIPLANE_OPERATION 0x70
+#define MULTIPLANE_OPERATION__FLAG 0x0001
+
+#define MULTIPLANE_READ_ENABLE 0x80
+#define MULTIPLANE_READ_ENABLE__FLAG 0x0001
+
+#define COPYBACK_DISABLE 0x90
+#define COPYBACK_DISABLE__FLAG 0x0001
+
+#define CACHE_WRITE_ENABLE 0xa0
+#define CACHE_WRITE_ENABLE__FLAG 0x0001
+
+#define CACHE_READ_ENABLE 0xb0
+#define CACHE_READ_ENABLE__FLAG 0x0001
+
+#define PREFETCH_MODE 0xc0
+#define PREFETCH_MODE__PREFETCH_EN 0x0001
+#define PREFETCH_MODE__PREFETCH_BURST_LENGTH 0xfff0
+
+#define CHIP_ENABLE_DONT_CARE 0xd0
+#define CHIP_EN_DONT_CARE__FLAG 0x01
+
+#define ECC_ENABLE 0xe0
+#define ECC_ENABLE__FLAG 0x0001
+
+#define GLOBAL_INT_ENABLE 0xf0
+#define GLOBAL_INT_EN_FLAG 0x01
+
+#define WE_2_RE 0x100
+#define WE_2_RE__VALUE 0x003f
+
+#define ADDR_2_DATA 0x110
+#define ADDR_2_DATA__VALUE 0x003f
+
+#define RE_2_WE 0x120
+#define RE_2_WE__VALUE 0x003f
+
+#define ACC_CLKS 0x130
+#define ACC_CLKS__VALUE 0x000f
+
+#define NUMBER_OF_PLANES 0x140
+#define NUMBER_OF_PLANES__VALUE 0x0007
+
+#define PAGES_PER_BLOCK 0x150
+#define PAGES_PER_BLOCK__VALUE 0xffff
+
+#define DEVICE_WIDTH 0x160
+#define DEVICE_WIDTH__VALUE 0x0003
+
+#define DEVICE_MAIN_AREA_SIZE 0x170
+#define DEVICE_MAIN_AREA_SIZE__VALUE 0xffff
+
+#define DEVICE_SPARE_AREA_SIZE 0x180
+#define DEVICE_SPARE_AREA_SIZE__VALUE 0xffff
+
+#define TWO_ROW_ADDR_CYCLES 0x190
+#define TWO_ROW_ADDR_CYCLES__FLAG 0x0001
+
+#define MULTIPLANE_ADDR_RESTRICT 0x1a0
+#define MULTIPLANE_ADDR_RESTRICT__FLAG 0x0001
+
+#define ECC_CORRECTION 0x1b0
+#define ECC_CORRECTION__VALUE 0x001f
+
+#define READ_MODE 0x1c0
+#define READ_MODE__VALUE 0x000f
+
+#define WRITE_MODE 0x1d0
+#define WRITE_MODE__VALUE 0x000f
+
+#define COPYBACK_MODE 0x1e0
+#define COPYBACK_MODE__VALUE 0x000f
+
+#define RDWR_EN_LO_CNT 0x1f0
+#define RDWR_EN_LO_CNT__VALUE 0x001f
+
+#define RDWR_EN_HI_CNT 0x200
+#define RDWR_EN_HI_CNT__VALUE 0x001f
+
+#define MAX_RD_DELAY 0x210
+#define MAX_RD_DELAY__VALUE 0x000f
+
+#define CS_SETUP_CNT 0x220
+#define CS_SETUP_CNT__VALUE 0x001f
+
+#define SPARE_AREA_SKIP_BYTES 0x230
+#define SPARE_AREA_SKIP_BYTES__VALUE 0x003f
+
+#define SPARE_AREA_MARKER 0x240
+#define SPARE_AREA_MARKER__VALUE 0xffff
+
+#define DEVICES_CONNECTED 0x250
+#define DEVICES_CONNECTED__VALUE 0x0007
+
+#define DIE_MASK 0x260
+#define DIE_MASK__VALUE 0x00ff
+
+#define FIRST_BLOCK_OF_NEXT_PLANE 0x270
+#define FIRST_BLOCK_OF_NEXT_PLANE__VALUE 0xffff
+
+#define WRITE_PROTECT 0x280
+#define WRITE_PROTECT__FLAG 0x0001
+
+#define RE_2_RE 0x290
+#define RE_2_RE__VALUE 0x003f
+
+#define MANUFACTURER_ID 0x300
+#define MANUFACTURER_ID__VALUE 0x00ff
+
+#define DEVICE_ID 0x310
+#define DEVICE_ID__VALUE 0x00ff
+
+#define DEVICE_PARAM_0 0x320
+#define DEVICE_PARAM_0__VALUE 0x00ff
+
+#define DEVICE_PARAM_1 0x330
+#define DEVICE_PARAM_1__VALUE 0x00ff
+
+#define DEVICE_PARAM_2 0x340
+#define DEVICE_PARAM_2__VALUE 0x00ff
+
+#define LOGICAL_PAGE_DATA_SIZE 0x350
+#define LOGICAL_PAGE_DATA_SIZE__VALUE 0xffff
+
+#define LOGICAL_PAGE_SPARE_SIZE 0x360
+#define LOGICAL_PAGE_SPARE_SIZE__VALUE 0xffff
+
+#define REVISION 0x370
+#define REVISION__VALUE 0xffff
+
+#define ONFI_DEVICE_FEATURES 0x380
+#define ONFI_DEVICE_FEATURES__VALUE 0x003f
+
+#define ONFI_OPTIONAL_COMMANDS 0x390
+#define ONFI_OPTIONAL_COMMANDS__VALUE 0x003f
+
+#define ONFI_TIMING_MODE 0x3a0
+#define ONFI_TIMING_MODE__VALUE 0x003f
+
+#define ONFI_PGM_CACHE_TIMING_MODE 0x3b0
+#define ONFI_PGM_CACHE_TIMING_MODE__VALUE 0x003f
+
+#define ONFI_DEVICE_NO_OF_LUNS 0x3c0
+#define ONFI_DEVICE_NO_OF_LUNS__NO_OF_LUNS 0x00ff
+#define ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE 0x0100
+
+#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L 0x3d0
+#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L__VALUE 0xffff
+
+#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U 0x3e0
+#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U__VALUE 0xffff
+
+#define FEATURES 0x3f0
+#define FEATURES__N_BANKS 0x0003
+#define FEATURES__ECC_MAX_ERR 0x003c
+#define FEATURES__DMA 0x0040
+#define FEATURES__CMD_DMA 0x0080
+#define FEATURES__PARTITION 0x0100
+#define FEATURES__XDMA_SIDEBAND 0x0200
+#define FEATURES__GPREG 0x0400
+#define FEATURES__INDEX_ADDR 0x0800
+
+#define TRANSFER_MODE 0x400
+#define TRANSFER_MODE__VALUE 0x0003
+
+#define INTR_STATUS(__bank) (0x410 + ((__bank) * 0x50))
+#define INTR_EN(__bank) (0x420 + ((__bank) * 0x50))
+
+/*
+ * Some versions of the IP have the ECC fixup handled in hardware. In this
+ * configuration we only get interrupted when the error is uncorrectable.
+ * Unfortunately this bit replaces INTR_STATUS__ECC_TRANSACTION_DONE from the
+ * old IP.
+ */
+#define INTR_STATUS__ECC_UNCOR_ERR 0x0001
+#define INTR_STATUS__ECC_TRANSACTION_DONE 0x0001
+#define INTR_STATUS__ECC_ERR 0x0002
+#define INTR_STATUS__DMA_CMD_COMP 0x0004
+#define INTR_STATUS__TIME_OUT 0x0008
+#define INTR_STATUS__PROGRAM_FAIL 0x0010
+#define INTR_STATUS__ERASE_FAIL 0x0020
+#define INTR_STATUS__LOAD_COMP 0x0040
+#define INTR_STATUS__PROGRAM_COMP 0x0080
+#define INTR_STATUS__ERASE_COMP 0x0100
+#define INTR_STATUS__PIPE_CPYBCK_CMD_COMP 0x0200
+#define INTR_STATUS__LOCKED_BLK 0x0400
+#define INTR_STATUS__UNSUP_CMD 0x0800
+#define INTR_STATUS__INT_ACT 0x1000
+#define INTR_STATUS__RST_COMP 0x2000
+#define INTR_STATUS__PIPE_CMD_ERR 0x4000
+#define INTR_STATUS__PAGE_XFER_INC 0x8000
+
+#define INTR_EN__ECC_TRANSACTION_DONE 0x0001
+#define INTR_EN__ECC_ERR 0x0002
+#define INTR_EN__DMA_CMD_COMP 0x0004
+#define INTR_EN__TIME_OUT 0x0008
+#define INTR_EN__PROGRAM_FAIL 0x0010
+#define INTR_EN__ERASE_FAIL 0x0020
+#define INTR_EN__LOAD_COMP 0x0040
+#define INTR_EN__PROGRAM_COMP 0x0080
+#define INTR_EN__ERASE_COMP 0x0100
+#define INTR_EN__PIPE_CPYBCK_CMD_COMP 0x0200
+#define INTR_EN__LOCKED_BLK 0x0400
+#define INTR_EN__UNSUP_CMD 0x0800
+#define INTR_EN__INT_ACT 0x1000
+#define INTR_EN__RST_COMP 0x2000
+#define INTR_EN__PIPE_CMD_ERR 0x4000
+#define INTR_EN__PAGE_XFER_INC 0x8000
+
+#define PAGE_CNT(__bank) (0x430 + ((__bank) * 0x50))
+#define ERR_PAGE_ADDR(__bank) (0x440 + ((__bank) * 0x50))
+#define ERR_BLOCK_ADDR(__bank) (0x450 + ((__bank) * 0x50))
+
+#define DATA_INTR 0x550
+#define DATA_INTR__WRITE_SPACE_AV 0x0001
+#define DATA_INTR__READ_DATA_AV 0x0002
+
+#define DATA_INTR_EN 0x560
+#define DATA_INTR_EN__WRITE_SPACE_AV 0x0001
+#define DATA_INTR_EN__READ_DATA_AV 0x0002
+
+#define GPREG_0 0x570
+#define GPREG_0__VALUE 0xffff
+
+#define GPREG_1 0x580
+#define GPREG_1__VALUE 0xffff
+
+#define GPREG_2 0x590
+#define GPREG_2__VALUE 0xffff
+
+#define GPREG_3 0x5a0
+#define GPREG_3__VALUE 0xffff
+
+#define ECC_THRESHOLD 0x600
+#define ECC_THRESHOLD__VALUE 0x03ff
+
+#define ECC_ERROR_BLOCK_ADDRESS 0x610
+#define ECC_ERROR_BLOCK_ADDRESS__VALUE 0xffff
+
+#define ECC_ERROR_PAGE_ADDRESS 0x620
+#define ECC_ERROR_PAGE_ADDRESS__VALUE 0x0fff
+#define ECC_ERROR_PAGE_ADDRESS__BANK 0xf000
+
+#define ECC_ERROR_ADDRESS 0x630
+#define ECC_ERROR_ADDRESS__OFFSET 0x0fff
+#define ECC_ERROR_ADDRESS__SECTOR_NR 0xf000
+
+#define ERR_CORRECTION_INFO 0x640
+#define ERR_CORRECTION_INFO__BYTEMASK 0x00ff
+#define ERR_CORRECTION_INFO__DEVICE_NR 0x0f00
+#define ERR_CORRECTION_INFO__ERROR_TYPE 0x4000
+#define ERR_CORRECTION_INFO__LAST_ERR_INFO 0x8000
+
+#define DMA_ENABLE 0x700
+#define DMA_ENABLE__FLAG 0x0001
+
+#define IGNORE_ECC_DONE 0x710
+#define IGNORE_ECC_DONE__FLAG 0x0001
+
+#define DMA_INTR 0x720
+#define DMA_INTR__TARGET_ERROR 0x0001
+#define DMA_INTR__DESC_COMP_CHANNEL0 0x0002
+#define DMA_INTR__DESC_COMP_CHANNEL1 0x0004
+#define DMA_INTR__DESC_COMP_CHANNEL2 0x0008
+#define DMA_INTR__DESC_COMP_CHANNEL3 0x0010
+#define DMA_INTR__MEMCOPY_DESC_COMP 0x0020
+
+#define DMA_INTR_EN 0x730
+#define DMA_INTR_EN__TARGET_ERROR 0x0001
+#define DMA_INTR_EN__DESC_COMP_CHANNEL0 0x0002
+#define DMA_INTR_EN__DESC_COMP_CHANNEL1 0x0004
+#define DMA_INTR_EN__DESC_COMP_CHANNEL2 0x0008
+#define DMA_INTR_EN__DESC_COMP_CHANNEL3 0x0010
+#define DMA_INTR_EN__MEMCOPY_DESC_COMP 0x0020
+
+#define TARGET_ERR_ADDR_LO 0x740
+#define TARGET_ERR_ADDR_LO__VALUE 0xffff
+
+#define TARGET_ERR_ADDR_HI 0x750
+#define TARGET_ERR_ADDR_HI__VALUE 0xffff
+
+#define CHNL_ACTIVE 0x760
+#define CHNL_ACTIVE__CHANNEL0 0x0001
+#define CHNL_ACTIVE__CHANNEL1 0x0002
+#define CHNL_ACTIVE__CHANNEL2 0x0004
+#define CHNL_ACTIVE__CHANNEL3 0x0008
+
+#define ACTIVE_SRC_ID 0x800
+#define ACTIVE_SRC_ID__VALUE 0x00ff
+
+#define PTN_INTR 0x810
+#define PTN_INTR__CONFIG_ERROR 0x0001
+#define PTN_INTR__ACCESS_ERROR_BANK0 0x0002
+#define PTN_INTR__ACCESS_ERROR_BANK1 0x0004
+#define PTN_INTR__ACCESS_ERROR_BANK2 0x0008
+#define PTN_INTR__ACCESS_ERROR_BANK3 0x0010
+#define PTN_INTR__REG_ACCESS_ERROR 0x0020
+
+#define PTN_INTR_EN 0x820
+#define PTN_INTR_EN__CONFIG_ERROR 0x0001
+#define PTN_INTR_EN__ACCESS_ERROR_BANK0 0x0002
+#define PTN_INTR_EN__ACCESS_ERROR_BANK1 0x0004
+#define PTN_INTR_EN__ACCESS_ERROR_BANK2 0x0008
+#define PTN_INTR_EN__ACCESS_ERROR_BANK3 0x0010
+#define PTN_INTR_EN__REG_ACCESS_ERROR 0x0020
+
+#define PERM_SRC_ID(__bank) (0x830 + ((__bank) * 0x40))
+#define PERM_SRC_ID__SRCID 0x00ff
+#define PERM_SRC_ID__DIRECT_ACCESS_ACTIVE 0x0800
+#define PERM_SRC_ID__WRITE_ACTIVE 0x2000
+#define PERM_SRC_ID__READ_ACTIVE 0x4000
+#define PERM_SRC_ID__PARTITION_VALID 0x8000
+
+#define MIN_BLK_ADDR(__bank) (0x840 + ((__bank) * 0x40))
+#define MIN_BLK_ADDR__VALUE 0xffff
+
+#define MAX_BLK_ADDR(__bank) (0x850 + ((__bank) * 0x40))
+#define MAX_BLK_ADDR__VALUE 0xffff
+
+#define MIN_MAX_BANK(__bank) (0x860 + ((__bank) * 0x40))
+#define MIN_MAX_BANK__MIN_VALUE 0x0003
+#define MIN_MAX_BANK__MAX_VALUE 0x000c
+
+/* lld.h */
+#define GOOD_BLOCK 0
+#define DEFECTIVE_BLOCK 1
+#define READ_ERROR 2
+
+#define CLK_X 5
+#define CLK_MULTI 4
+
+/* spectraswconfig.h */
+#define CMD_DMA 0
+
+#define SPECTRA_PARTITION_ID 0
+/**** Block Table and Reserved Block Parameters *****/
+#define SPECTRA_START_BLOCK 3
+#define NUM_FREE_BLOCKS_GATE 30
+
+/* KBV - Updated to LNW scratch register address */
+#define SCRATCH_REG_ADDR CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR
+#define SCRATCH_REG_SIZE 64
+
+#define GLOB_HWCTL_DEFAULT_BLKS 2048
+
+#define CUSTOM_CONF_PARAMS 0
+
+#ifndef _LLD_NAND_
+#define _LLD_NAND_
+
+#define INDEX_CTRL_REG 0x0
+#define INDEX_DATA_REG 0x10
+
+#define MODE_00 0x00000000
+#define MODE_01 0x04000000
+#define MODE_10 0x08000000
+#define MODE_11 0x0C000000
+
+
+#define DATA_TRANSFER_MODE 0
+#define PROTECTION_PER_BLOCK 1
+#define LOAD_WAIT_COUNT 2
+#define PROGRAM_WAIT_COUNT 3
+#define ERASE_WAIT_COUNT 4
+#define INT_MONITOR_CYCLE_COUNT 5
+#define READ_BUSY_PIN_ENABLED 6
+#define MULTIPLANE_OPERATION_SUPPORT 7
+#define PRE_FETCH_MODE 8
+#define CE_DONT_CARE_SUPPORT 9
+#define COPYBACK_SUPPORT 10
+#define CACHE_WRITE_SUPPORT 11
+#define CACHE_READ_SUPPORT 12
+#define NUM_PAGES_IN_BLOCK 13
+#define ECC_ENABLE_SELECT 14
+#define WRITE_ENABLE_2_READ_ENABLE 15
+#define ADDRESS_2_DATA 16
+#define READ_ENABLE_2_WRITE_ENABLE 17
+#define TWO_ROW_ADDRESS_CYCLES 18
+#define MULTIPLANE_ADDRESS_RESTRICT 19
+#define ACC_CLOCKS 20
+#define READ_WRITE_ENABLE_LOW_COUNT 21
+#define READ_WRITE_ENABLE_HIGH_COUNT 22
+
+#define ECC_SECTOR_SIZE 512
+
+#define DENALI_BUF_SIZE (NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE)
+
+struct nand_buf {
+ int head;
+ int tail;
+ /* seprating dma_buf as buf can be used for status read purpose */
+ uint8_t dma_buf[DENALI_BUF_SIZE] __aligned(64);
+ uint8_t buf[DENALI_BUF_SIZE];
+};
+
+#define INTEL_CE4100 1
+#define INTEL_MRST 2
+#define DT 3
+
+struct denali_nand_info {
+ struct mtd_info mtd;
+ struct nand_chip *nand;
+
+ int flash_bank; /* currently selected chip */
+ int status;
+ int platform;
+ struct nand_buf buf;
+ struct device *dev;
+ int total_used_banks;
+ uint32_t block; /* stored for future use */
+ uint32_t page;
+ void __iomem *flash_reg; /* Mapped io reg base address */
+ void __iomem *flash_mem; /* Mapped io reg base address */
+
+ /* elements used by ISR */
+ /*struct completion complete;*/
+
+ uint32_t irq_status;
+ int irq_debug_array[32];
+ int idx;
+ int irq;
+
+ uint32_t devnum; /* represent how many nands connected */
+ uint32_t fwblks; /* represent how many blocks FW used */
+ uint32_t totalblks;
+ uint32_t blksperchip;
+ uint32_t bbtskipbytes;
+ uint32_t max_banks;
+};
+
+#endif /*_LLD_NAND_*/
diff --git a/drivers/mtd/nand/denali_spl.c b/drivers/mtd/nand/denali_spl.c
new file mode 100644
index 0000000..65fdde8
--- /dev/null
+++ b/drivers/mtd/nand/denali_spl.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2014 Panasonic Corporation
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+#include <linux/mtd/nand.h>
+#include "denali.h"
+
+#define SPARE_ACCESS 0x41
+#define MAIN_ACCESS 0x42
+#define PIPELINE_ACCESS 0x2000
+
+#define BANK(x) ((x) << 24)
+
+static void __iomem *denali_flash_mem =
+ (void __iomem *)CONFIG_SYS_NAND_DATA_BASE;
+static void __iomem *denali_flash_reg =
+ (void __iomem *)CONFIG_SYS_NAND_REGS_BASE;
+
+static const int flash_bank;
+static uint8_t page_buffer[NAND_MAX_PAGESIZE];
+static int page_size, oob_size, pages_per_block;
+
+static void index_addr(uint32_t address, uint32_t data)
+{
+ writel(address, denali_flash_mem + INDEX_CTRL_REG);
+ writel(data, denali_flash_mem + INDEX_DATA_REG);
+}
+
+static int wait_for_irq(uint32_t irq_mask)
+{
+ unsigned long timeout = 1000000;
+ uint32_t intr_status;
+
+ do {
+ intr_status = readl(denali_flash_reg + INTR_STATUS(flash_bank));
+
+ if (intr_status & INTR_STATUS__ECC_UNCOR_ERR) {
+ debug("Uncorrected ECC detected\n");
+ return -EIO;
+ }
+
+ if (intr_status & irq_mask)
+ break;
+
+ udelay(1);
+ timeout--;
+ } while (timeout);
+
+ if (!timeout) {
+ debug("Timeout with interrupt status %08x\n", intr_status);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void read_data_from_flash_mem(uint8_t *buf, int len)
+{
+ int i;
+ uint32_t *buf32;
+
+ /* transfer the data from the flash */
+ buf32 = (uint32_t *)buf;
+
+ /*
+ * Let's take care of unaligned access although it rarely happens.
+ * Avoid put_unaligned() for the normal use cases since it leads to
+ * a bit performance regression.
+ */
+ if ((unsigned long)buf32 % 4) {
+ for (i = 0; i < len / 4; i++)
+ put_unaligned(readl(denali_flash_mem + INDEX_DATA_REG),
+ buf32++);
+ } else {
+ for (i = 0; i < len / 4; i++)
+ *buf32++ = readl(denali_flash_mem + INDEX_DATA_REG);
+ }
+
+ if (len % 4) {
+ u32 tmp;
+
+ tmp = cpu_to_le32(readl(denali_flash_mem + INDEX_DATA_REG));
+ buf = (uint8_t *)buf32;
+ for (i = 0; i < len % 4; i++) {
+ *buf++ = tmp;
+ tmp >>= 8;
+ }
+ }
+}
+
+int denali_send_pipeline_cmd(int page, int ecc_en, int access_type)
+{
+ uint32_t addr, cmd;
+ static uint32_t page_count = 1;
+
+ writel(ecc_en, denali_flash_reg + ECC_ENABLE);
+
+ /* clear all bits of intr_status. */
+ writel(0xffff, denali_flash_reg + INTR_STATUS(flash_bank));
+
+ addr = BANK(flash_bank) | page;
+
+ /* setup the acccess type */
+ cmd = MODE_10 | addr;
+ index_addr(cmd, access_type);
+
+ /* setup the pipeline command */
+ index_addr(cmd, PIPELINE_ACCESS | page_count);
+
+ cmd = MODE_01 | addr;
+ writel(cmd, denali_flash_mem + INDEX_CTRL_REG);
+
+ return wait_for_irq(INTR_STATUS__LOAD_COMP);
+}
+
+static int nand_read_oob(void *buf, int page)
+{
+ int ret;
+
+ ret = denali_send_pipeline_cmd(page, 0, SPARE_ACCESS);
+ if (ret < 0)
+ return ret;
+
+ read_data_from_flash_mem(buf, oob_size);
+
+ return 0;
+}
+
+static int nand_read_page(void *buf, int page)
+{
+ int ret;
+
+ ret = denali_send_pipeline_cmd(page, 1, MAIN_ACCESS);
+ if (ret < 0)
+ return ret;
+
+ read_data_from_flash_mem(buf, page_size);
+
+ return 0;
+}
+
+static int nand_block_isbad(int block)
+{
+ int ret;
+
+ ret = nand_read_oob(page_buffer, block * pages_per_block);
+ if (ret < 0)
+ return ret;
+
+ return page_buffer[CONFIG_SYS_NAND_BAD_BLOCK_POS] != 0xff;
+}
+
+/* nand_init() - initialize data to make nand usable by SPL */
+void nand_init(void)
+{
+ /* access to main area */
+ writel(0, denali_flash_reg + TRANSFER_SPARE_REG);
+
+ /*
+ * These registers are expected to be already set by the hardware
+ * or earlier boot code. So we read these values out.
+ */
+ page_size = readl(denali_flash_reg + DEVICE_MAIN_AREA_SIZE);
+ oob_size = readl(denali_flash_reg + DEVICE_SPARE_AREA_SIZE);
+ pages_per_block = readl(denali_flash_reg + PAGES_PER_BLOCK);
+}
+
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
+{
+ int block, page, column, readlen;
+ int ret;
+ int force_bad_block_check = 1;
+
+ page = offs / page_size;
+ column = offs % page_size;
+
+ block = page / pages_per_block;
+ page = page % pages_per_block;
+
+ while (size) {
+ if (force_bad_block_check || page == 0) {
+ ret = nand_block_isbad(block);
+ if (ret < 0)
+ return ret;
+
+ if (ret) {
+ block++;
+ continue;
+ }
+ }
+
+ force_bad_block_check = 0;
+
+ if (unlikely(column || size < page_size)) {
+ /* Partial page read */
+ ret = nand_read_page(page_buffer,
+ block * pages_per_block + page);
+ if (ret < 0)
+ return ret;
+
+ readlen = min(page_size - column, size);
+ memcpy(dst, page_buffer, readlen);
+
+ column = 0;
+ } else {
+ ret = nand_read_page(dst,
+ block * pages_per_block + page);
+ if (ret < 0)
+ return ret;
+
+ readlen = page_size;
+ }
+
+ size -= readlen;
+ dst += readlen;
+ page++;
+ if (page == pages_per_block) {
+ block++;
+ page = 0;
+ }
+ }
+
+ return 0;
+}
+
+void nand_deselect(void) {}
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 7e1e6ec..3372b64 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -37,7 +37,6 @@
#define MAX_BANKS 8
#define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */
-#define FCM_TIMEOUT_MSECS 10 /* Maximum number of mSecs to wait for FCM */
#define LTESR_NAND_MASK (LTESR_FCT | LTESR_PAR | LTESR_CC)
@@ -199,7 +198,8 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
struct fsl_elbc_mtd *priv = chip->priv;
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
fsl_lbc_t *lbc = ctrl->regs;
- long long end_tick;
+ u32 timeo = (CONFIG_SYS_HZ * 10) / 1000;
+ u32 time_start;
u32 ltesr;
/* Setup the FMR[OP] to execute without write protection */
@@ -218,10 +218,10 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
out_be32(&lbc->lsor, priv->bank);
/* wait for FCM complete flag or timeout */
- end_tick = usec2ticks(FCM_TIMEOUT_MSECS * 1000) + get_ticks();
+ time_start = get_timer(0);
ltesr = 0;
- while (end_tick > get_ticks()) {
+ while (get_timer(time_start) < timeo) {
ltesr = in_be32(&lbc->ltesr);
if (ltesr & LTESR_CC)
break;
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
index 2f04c69..81b5070 100644
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -26,8 +26,6 @@
#define MAX_BANKS CONFIG_SYS_FSL_IFC_BANK_COUNT
#define ERR_BYTE 0xFF /* Value returned for read bytes
when read failed */
-#define IFC_TIMEOUT_MSECS 10 /* Maximum number of mSecs to wait for IFC
- NAND Machine */
struct fsl_ifc_ctrl;
@@ -292,7 +290,8 @@ static int fsl_ifc_run_command(struct mtd_info *mtd)
struct fsl_ifc_mtd *priv = chip->priv;
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
struct fsl_ifc *ifc = ctrl->regs;
- long long end_tick;
+ u32 timeo = (CONFIG_SYS_HZ * 10) / 1000;
+ u32 time_start;
u32 eccstat[4];
int i;
@@ -304,9 +303,9 @@ static int fsl_ifc_run_command(struct mtd_info *mtd)
IFC_NAND_SEQ_STRT_FIR_STRT);
/* wait for NAND Machine complete flag or timeout */
- end_tick = usec2ticks(IFC_TIMEOUT_MSECS * 1000) + get_ticks();
+ time_start = get_timer(0);
- while (end_tick > get_ticks()) {
+ while (get_timer(time_start) < timeo) {
ctrl->status = ifc_in32(&ifc->ifc_nand.nand_evter_stat);
if (ctrl->status & IFC_NAND_EVTER_STAT_OPC)
@@ -812,15 +811,16 @@ static int fsl_ifc_sram_init(uint32_t ver)
struct fsl_ifc *ifc = ifc_ctrl->regs;
uint32_t cs = 0, csor = 0, csor_8k = 0, csor_ext = 0;
uint32_t ncfgr = 0;
- long long end_tick;
+ u32 timeo = (CONFIG_SYS_HZ * 10) / 1000;
+ u32 time_start;
if (ver > FSL_IFC_V1_1_0) {
ncfgr = ifc_in32(&ifc->ifc_nand.ncfgr);
ifc_out32(&ifc->ifc_nand.ncfgr, ncfgr | IFC_NAND_SRAM_INIT_EN);
/* wait for SRAM_INIT bit to be clear or timeout */
- end_tick = usec2ticks(IFC_TIMEOUT_MSECS * 1000) + get_ticks();
- while (end_tick > get_ticks()) {
+ time_start = get_timer(0);
+ while (get_timer(time_start) < timeo) {
ifc_ctrl->status =
ifc_in32(&ifc->ifc_nand.nand_evter_stat);
@@ -863,10 +863,9 @@ static int fsl_ifc_sram_init(uint32_t ver)
/* start read seq */
ifc_out32(&ifc->ifc_nand.nandseq_strt, IFC_NAND_SEQ_STRT_FIR_STRT);
- /* wait for NAND Machine complete flag or timeout */
- end_tick = usec2ticks(IFC_TIMEOUT_MSECS * 1000) + get_ticks();
+ time_start = get_timer(0);
- while (end_tick > get_ticks()) {
+ while (get_timer(time_start) < timeo) {
ifc_ctrl->status = ifc_in32(&ifc->ifc_nand.nand_evter_stat);
if (ifc_ctrl->status & IFC_NAND_EVTER_STAT_OPC)
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 7153e3c..0b6e7ee 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -308,8 +308,7 @@ static void ioread16_rep(void *addr, void *buf, int len)
{
int i;
u16 *p = (u16 *) buf;
- len >>= 1;
-
+
for (i = 0; i < len; i++)
p[i] = readw(addr);
}
@@ -318,7 +317,6 @@ static void iowrite16_rep(void *addr, void *buf, int len)
{
int i;
u16 *p = (u16 *) buf;
- len >>= 1;
for (i = 0; i < len; i++)
writew(p[i], addr);
diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c
index a62ef4c..98e0a34 100644
--- a/drivers/mtd/spi/sandbox.c
+++ b/drivers/mtd/spi/sandbox.c
@@ -51,46 +51,7 @@ static const char *sandbox_sf_state_name(enum sandbox_sf_state state)
/* Assume all SPI flashes have 3 byte addresses since they do atm */
#define SF_ADDR_LEN 3
-struct sandbox_spi_flash_erase_commands {
- u8 cmd;
- u32 size;
-};
-#define IDCODE_LEN 5
-#define MAX_ERASE_CMDS 3
-struct sandbox_spi_flash_data {
- const char *name;
- u8 idcode[IDCODE_LEN];
- u32 size;
- const struct sandbox_spi_flash_erase_commands
- erase_cmds[MAX_ERASE_CMDS];
-};
-
-/* Structure describing all the flashes we know how to emulate */
-static const struct sandbox_spi_flash_data sandbox_sf_flashes[] = {
- {
- "M25P16", { 0x20, 0x20, 0x15 }, (2 << 20),
- { /* erase commands */
- { 0xd8, (64 << 10), }, /* sector */
- { 0xc7, (2 << 20), }, /* bulk */
- },
- },
- {
- "W25Q32", { 0xef, 0x40, 0x16 }, (4 << 20),
- { /* erase commands */
- { 0x20, (4 << 10), }, /* 4KB */
- { 0xd8, (64 << 10), }, /* sector */
- { 0xc7, (4 << 20), }, /* bulk */
- },
- },
- {
- "W25Q128", { 0xef, 0x40, 0x18 }, (16 << 20),
- { /* erase commands */
- { 0x20, (4 << 10), }, /* 4KB */
- { 0xd8, (64 << 10), }, /* sector */
- { 0xc7, (16 << 20), }, /* bulk */
- },
- },
-};
+#define IDCODE_LEN 3
/* Used to quickly bulk erase backing store */
static u8 sandbox_sf_0xff[0x1000];
@@ -109,7 +70,8 @@ struct sandbox_spi_flash {
*/
enum sandbox_sf_state state;
uint cmd;
- const void *cmd_data;
+ /* Erase size of current erase command */
+ uint erase_size;
/* Current position in the flash; used when reading/writing/etc... */
uint off;
/* How many address bytes we've consumed */
@@ -117,7 +79,7 @@ struct sandbox_spi_flash {
/* The current flash status (see STAT_XXX defines above) */
u16 status;
/* Data describing the flash we're emulating */
- const struct sandbox_spi_flash_data *data;
+ const struct spi_flash_params *data;
/* The file on disk to serv up data from */
int fd;
};
@@ -127,8 +89,8 @@ static int sandbox_sf_setup(void **priv, const char *spec)
/* spec = idcode:file */
struct sandbox_spi_flash *sbsf;
const char *file;
- size_t i, len, idname_len;
- const struct sandbox_spi_flash_data *data;
+ size_t len, idname_len;
+ const struct spi_flash_params *data;
file = strchr(spec, ':');
if (!file) {
@@ -138,15 +100,14 @@ static int sandbox_sf_setup(void **priv, const char *spec)
idname_len = file - spec;
++file;
- for (i = 0; i < ARRAY_SIZE(sandbox_sf_flashes); ++i) {
- data = &sandbox_sf_flashes[i];
+ for (data = spi_flash_params_table; data->name; data++) {
len = strlen(data->name);
if (idname_len != len)
continue;
if (!memcmp(spec, data->name, len))
break;
}
- if (i == ARRAY_SIZE(sandbox_sf_flashes)) {
+ if (!data->name) {
printf("sandbox_sf: unknown flash '%*s'\n", (int)idname_len,
spec);
goto error;
@@ -223,7 +184,6 @@ static int sandbox_sf_process_cmd(struct sandbox_spi_flash *sbsf, const u8 *rx,
sbsf->pad_addr_bytes = 1;
case CMD_READ_ARRAY_SLOW:
case CMD_PAGE_PROGRAM:
- state_addr:
sbsf->state = SF_ADDR;
break;
case CMD_WRITE_DISABLE:
@@ -241,24 +201,25 @@ static int sandbox_sf_process_cmd(struct sandbox_spi_flash *sbsf, const u8 *rx,
sbsf->status |= STAT_WEL;
break;
default: {
- size_t i;
-
- /* handle erase commands first */
- for (i = 0; i < MAX_ERASE_CMDS; ++i) {
- const struct sandbox_spi_flash_erase_commands *
- erase_cmd = &sbsf->data->erase_cmds[i];
-
- if (erase_cmd->cmd == 0x00)
- continue;
- if (sbsf->cmd != erase_cmd->cmd)
- continue;
-
- sbsf->cmd_data = erase_cmd;
- goto state_addr;
+ int flags = sbsf->data->flags;
+
+ /* we only support erase here */
+ if (sbsf->cmd == CMD_ERASE_CHIP) {
+ sbsf->erase_size = sbsf->data->sector_size *
+ sbsf->data->nr_sectors;
+ } else if (sbsf->cmd == CMD_ERASE_4K && (flags & SECT_4K)) {
+ sbsf->erase_size = 4 << 10;
+ } else if (sbsf->cmd == CMD_ERASE_32K && (flags & SECT_32K)) {
+ sbsf->erase_size = 32 << 10;
+ } else if (sbsf->cmd == CMD_ERASE_64K &&
+ !(flags & (SECT_4K | SECT_32K))) {
+ sbsf->erase_size = 64 << 10;
+ } else {
+ debug(" cmd unknown: %#x\n", sbsf->cmd);
+ return 1;
}
-
- debug(" cmd unknown: %#x\n", sbsf->cmd);
- return 1;
+ sbsf->state = SF_ADDR;
+ break;
}
}
@@ -309,11 +270,14 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx,
u8 id;
debug(" id: off:%u tx:", sbsf->off);
- if (sbsf->off < IDCODE_LEN)
- id = sbsf->data->idcode[sbsf->off];
- else
+ if (sbsf->off < IDCODE_LEN) {
+ /* Extract correct byte from ID 0x00aabbcc */
+ id = sbsf->data->jedec >>
+ (8 * (IDCODE_LEN - 1 - sbsf->off));
+ } else {
id = 0;
- debug("%02x\n", id);
+ }
+ debug("%d %02x\n", sbsf->off, id);
tx[pos++] = id;
++sbsf->off;
break;
@@ -406,24 +370,22 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx,
break;
case SF_ERASE:
case_sf_erase: {
- const struct sandbox_spi_flash_erase_commands *
- erase_cmd = sbsf->cmd_data;
-
if (!(sbsf->status & STAT_WEL)) {
puts("sandbox_sf: write enable not set before erase\n");
goto done;
}
/* verify address is aligned */
- if (sbsf->off & (erase_cmd->size - 1)) {
+ if (sbsf->off & (sbsf->erase_size - 1)) {
debug(" sector erase: cmd:%#x needs align:%#x, but we got %#x\n",
- erase_cmd->cmd, erase_cmd->size,
+ sbsf->cmd, sbsf->erase_size,
sbsf->off);
sbsf->status &= ~STAT_WEL;
goto done;
}
- debug(" sector erase addr: %u\n", sbsf->off);
+ debug(" sector erase addr: %u, size: %u\n", sbsf->off,
+ sbsf->erase_size);
cnt = bytes - pos;
sandbox_spi_tristate(&tx[pos], cnt);
@@ -433,7 +395,7 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx,
* TODO(vapier@gentoo.org): latch WIP in status, and
* delay before clearing it ?
*/
- ret = sandbox_erase_part(sbsf, erase_cmd->size);
+ ret = sandbox_erase_part(sbsf, sbsf->erase_size);
sbsf->status &= ~STAT_WEL;
if (ret) {
debug("sandbox_sf: Erase failed\n");
diff --git a/drivers/mtd/spi/sf_params.c b/drivers/mtd/spi/sf_params.c
index ac886fd..453edf0 100644
--- a/drivers/mtd/spi/sf_params.c
+++ b/drivers/mtd/spi/sf_params.c
@@ -68,9 +68,12 @@ const struct spi_flash_params spi_flash_params_table[] = {
{"M25P40", 0x202013, 0x0, 64 * 1024, 8, 0, 0},
{"M25P80", 0x202014, 0x0, 64 * 1024, 16, 0, 0},
{"M25P16", 0x202015, 0x0, 64 * 1024, 32, 0, 0},
+ {"M25PE16", 0x208015, 0x1000, 64 * 1024, 32, 0, 0},
+ {"M25PX16", 0x207115, 0x1000, 64 * 1024, 32, RD_EXTN, 0},
{"M25P32", 0x202016, 0x0, 64 * 1024, 64, 0, 0},
{"M25P64", 0x202017, 0x0, 64 * 1024, 128, 0, 0},
{"M25P128", 0x202018, 0x0, 256 * 1024, 64, 0, 0},
+ {"M25PX64", 0x207117, 0x0, 64 * 1024, 128, 0, SECT_4K},
{"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K},
{"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K},
{"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128, RD_FULL, WR_QPP | SECT_4K},
@@ -116,6 +119,7 @@ const struct spi_flash_params spi_flash_params_table[] = {
{"W25Q64DW", 0xef6017, 0x0, 64 * 1024, 128, RD_FULL, WR_QPP | SECT_4K},
{"W25Q128FW", 0xef6018, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP | SECT_4K},
#endif
+ {}, /* Empty entry to terminate the list */
/*
* Note:
* Below paired flash devices has similar spi_flash params.
diff --git a/drivers/mtd/spi/spi_spl_load.c b/drivers/mtd/spi/spi_spl_load.c
index 1954b7e..59cca0f 100644
--- a/drivers/mtd/spi/spi_spl_load.c
+++ b/drivers/mtd/spi/spi_spl_load.c
@@ -56,8 +56,10 @@ void spl_spi_load_image(void)
* Load U-Boot image from SPI flash into RAM
*/
- flash = spi_flash_probe(CONFIG_SPL_SPI_BUS, CONFIG_SPL_SPI_CS,
- CONFIG_SF_DEFAULT_SPEED, SPI_MODE_3);
+ flash = spi_flash_probe(CONFIG_SF_DEFAULT_BUS,
+ CONFIG_SF_DEFAULT_CS,
+ CONFIG_SF_DEFAULT_SPEED,
+ CONFIG_SF_DEFAULT_MODE);
if (!flash) {
puts("SPI probe failed.\n");
hang();
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/net/Kconfig
diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c
index 0eba57c..6e8765c 100644
--- a/drivers/net/e1000.c
+++ b/drivers/net/e1000.c
@@ -5362,7 +5362,9 @@ e1000_initialize(bd_t * bis)
hw->autoneg_failed = 0;
hw->autoneg = 1;
hw->get_link_status = true;
+#ifndef CONFIG_E1000_NO_NVM
hw->eeprom_semaphore_present = true;
+#endif
hw->hw_addr = pci_map_bar(devno, PCI_BASE_ADDRESS_0,
PCI_REGION_MEM);
hw->mac_type = e1000_undefined;
diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c
index 4cefda4..549d648 100644
--- a/drivers/net/fec_mxc.c
+++ b/drivers/net/fec_mxc.c
@@ -28,6 +28,14 @@ DECLARE_GLOBAL_DATA_PTR;
*/
#define FEC_XFER_TIMEOUT 5000
+/*
+ * The standard 32-byte DMA alignment does not work on mx6solox, which requires
+ * 64-byte alignment in the DMA RX FEC buffer.
+ * Introduce the FEC_DMA_RX_MINALIGN which can cover mx6solox needs and also
+ * satisfies the alignment on other SoCs (32-bytes)
+ */
+#define FEC_DMA_RX_MINALIGN 64
+
#ifndef CONFIG_MII
#error "CONFIG_MII has to be defined!"
#endif
@@ -711,13 +719,37 @@ static int fec_send(struct eth_device *dev, void *packet, int length)
break;
}
- if (!timeout)
+ if (!timeout) {
ret = -EINVAL;
+ goto out;
+ }
- invalidate_dcache_range(addr, addr + size);
- if (readw(&fec->tbd_base[fec->tbd_index].status) & FEC_TBD_READY)
+ /*
+ * The TDAR bit is cleared when the descriptors are all out from TX
+ * but on mx6solox we noticed that the READY bit is still not cleared
+ * right after TDAR.
+ * These are two distinct signals, and in IC simulation, we found that
+ * TDAR always gets cleared prior than the READY bit of last BD becomes
+ * cleared.
+ * In mx6solox, we use a later version of FEC IP. It looks like that
+ * this intrinsic behaviour of TDAR bit has changed in this newer FEC
+ * version.
+ *
+ * Fix this by polling the READY bit of BD after the TDAR polling,
+ * which covers the mx6solox case and does not harm the other SoCs.
+ */
+ timeout = FEC_XFER_TIMEOUT;
+ while (--timeout) {
+ invalidate_dcache_range(addr, addr + size);
+ if (!(readw(&fec->tbd_base[fec->tbd_index].status) &
+ FEC_TBD_READY))
+ break;
+ }
+
+ if (!timeout)
ret = -EINVAL;
+out:
debug("fec_send: status 0x%x index %d ret %i\n",
readw(&fec->tbd_base[fec->tbd_index].status),
fec->tbd_index, ret);
@@ -881,9 +913,9 @@ static int fec_alloc_descs(struct fec_priv *fec)
/* Allocate RX buffers. */
/* Maximum RX buffer size. */
- size = roundup(FEC_MAX_PKT_SIZE, ARCH_DMA_MINALIGN);
+ size = roundup(FEC_MAX_PKT_SIZE, FEC_DMA_RX_MINALIGN);
for (i = 0; i < FEC_RBD_NUM; i++) {
- data = memalign(ARCH_DMA_MINALIGN, size);
+ data = memalign(FEC_DMA_RX_MINALIGN, size);
if (!data) {
printf("%s: error allocating rxbuf %d\n", __func__, i);
goto err_ring;
diff --git a/drivers/net/fm/t1040.c b/drivers/net/fm/t1040.c
index bcc871d..4cce46d 100644
--- a/drivers/net/fm/t1040.c
+++ b/drivers/net/fm/t1040.c
@@ -49,8 +49,6 @@ phy_interface_t fman_port_enet_if(enum fm_port port)
else if ((rcwsr13 & FSL_CORENET_RCWSR13_EC2) ==
FSL_CORENET_RCWSR13_EC2_FM1_DTSEC5_MII)
return PHY_INTERFACE_MODE_MII;
- else
- return PHY_INTERFACE_MODE_NONE;
}
switch (port) {
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/pci/Kconfig
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 4fd9c53..28859f3 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -648,6 +648,10 @@ int pci_hose_scan_bus(struct pci_controller *hose, int bus)
pci_hose_read_config_word(hose, dev, PCI_DEVICE_ID, &device);
pci_hose_read_config_word(hose, dev, PCI_CLASS_DEVICE, &class);
+#ifdef CONFIG_PCI_FIXUP_DEV
+ board_pci_fixup_dev(hose, dev, vendor, device, class);
+#endif
+
#ifdef CONFIG_PCI_SCAN_SHOW
indent++;
diff --git a/drivers/pci/pcie_imx.c b/drivers/pci/pcie_imx.c
index a3982c4..fd7e4d4 100644
--- a/drivers/pci/pcie_imx.c
+++ b/drivers/pci/pcie_imx.c
@@ -23,13 +23,20 @@
#define PCI_ACCESS_READ 0
#define PCI_ACCESS_WRITE 1
+#ifdef CONFIG_MX6SX
+#define MX6_DBI_ADDR 0x08ffc000
+#define MX6_IO_ADDR 0x08000000
+#define MX6_MEM_ADDR 0x08100000
+#define MX6_ROOT_ADDR 0x08f00000
+#else
#define MX6_DBI_ADDR 0x01ffc000
-#define MX6_DBI_SIZE 0x4000
#define MX6_IO_ADDR 0x01000000
-#define MX6_IO_SIZE 0x100000
#define MX6_MEM_ADDR 0x01100000
-#define MX6_MEM_SIZE 0xe00000
#define MX6_ROOT_ADDR 0x01f00000
+#endif
+#define MX6_DBI_SIZE 0x4000
+#define MX6_IO_SIZE 0x100000
+#define MX6_MEM_SIZE 0xe00000
#define MX6_ROOT_SIZE 0xfc000
/* PCIe Port Logic registers (memory-mapped) */
@@ -57,6 +64,8 @@
#define PHY_RX_OVRD_IN_LO_RX_DATA_EN (1 << 5)
#define PHY_RX_OVRD_IN_LO_RX_PLL_EN (1 << 3)
+#define PCIE_PHY_PUP_REQ (1 << 7)
+
/* iATU registers */
#define PCIE_ATU_VIEWPORT 0x900
#define PCIE_ATU_REGION_INBOUND (0x1 << 31)
@@ -421,9 +430,19 @@ static int imx_pcie_write_config(struct pci_controller *hose, pci_dev_t d,
static int imx6_pcie_assert_core_reset(void)
{
struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
-
+#if defined(CONFIG_MX6SX)
+ struct gpc *gpc_regs = (struct gpc *)GPC_BASE_ADDR;
+
+ /* SSP_EN is not used on MX6SX anymore */
+ setbits_le32(&iomuxc_regs->gpr[12], IOMUXC_GPR12_TEST_POWERDOWN);
+ /* Force PCIe PHY reset */
+ setbits_le32(&iomuxc_regs->gpr[5], IOMUXC_GPR5_PCIE_BTNRST);
+ /* Power up PCIe PHY */
+ setbits_le32(&gpc_regs->cntr, PCIE_PHY_PUP_REQ);
+#else
setbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_TEST_POWERDOWN);
clrbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_REF_SSP_EN);
+#endif
return 0;
}
@@ -441,6 +460,12 @@ static int imx6_pcie_init_phy(void)
IOMUXC_GPR12_LOS_LEVEL_MASK,
IOMUXC_GPR12_LOS_LEVEL_9);
+#ifdef CONFIG_MX6SX
+ clrsetbits_le32(&iomuxc_regs->gpr[12],
+ IOMUXC_GPR12_RX_EQ_MASK,
+ IOMUXC_GPR12_RX_EQ_2);
+#endif
+
writel((0x0 << IOMUXC_GPR8_PCS_TX_DEEMPH_GEN1_OFFSET) |
(0x0 << IOMUXC_GPR8_PCS_TX_DEEMPH_GEN2_3P5DB_OFFSET) |
(20 << IOMUXC_GPR8_PCS_TX_DEEMPH_GEN2_6DB_OFFSET) |
@@ -517,9 +542,16 @@ static int imx6_pcie_deassert_core_reset(void)
*/
mdelay(50);
+#if defined(CONFIG_MX6SX)
+ /* SSP_EN is not used on MX6SX anymore */
+ clrbits_le32(&iomuxc_regs->gpr[12], IOMUXC_GPR12_TEST_POWERDOWN);
+ /* Clear PCIe PHY reset bit */
+ clrbits_le32(&iomuxc_regs->gpr[5], IOMUXC_GPR5_PCIE_BTNRST);
+#else
/* Enable PCIe */
clrbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_TEST_POWERDOWN);
setbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_REF_SSP_EN);
+#endif
imx6_pcie_toggle_reset();
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/pcmcia/Kconfig
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/power/Kconfig
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/rtc/Kconfig
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/serial/Kconfig
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 853a8c6..b4f299b 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_FSL_LPUART) += serial_lpuart.o
obj-$(CONFIG_MXS_AUART) += mxs_auart.o
obj-$(CONFIG_ARC_SERIAL) += serial_arc.o
obj-$(CONFIG_TEGRA_SERIAL) += serial_tegra.o
+obj-$(CONFIG_UNIPHIER_SERIAL) += serial_uniphier.o
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_USB_TTY) += usbtty.o
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c
index d04104e..1ac943f 100644
--- a/drivers/serial/serial-uclass.c
+++ b/drivers/serial/serial-uclass.c
@@ -25,6 +25,7 @@ struct udevice *cur_dev __attribute__ ((section(".data")));
static void serial_find_console_or_panic(void)
{
+#ifdef CONFIG_OF_CONTROL
int node;
/* Check for a chosen console */
@@ -44,7 +45,7 @@ static void serial_find_console_or_panic(void)
return;
cur_dev = NULL;
}
-
+#endif
/*
* Failing that, get the device with sequence number 0, or in extremis
* just the first serial device we can find. But we insist on having
diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c
index bbe60af..82fbbd9 100644
--- a/drivers/serial/serial.c
+++ b/drivers/serial/serial.c
@@ -157,6 +157,7 @@ serial_initfunc(sh_serial_initialize);
serial_initfunc(arm_dcc_initialize);
serial_initfunc(mxs_auart_initialize);
serial_initfunc(arc_serial_initialize);
+serial_initfunc(uniphier_serial_initialize);
/**
* serial_register() - Register serial driver with serial driver core
@@ -250,6 +251,7 @@ void serial_initialize(void)
arm_dcc_initialize();
mxs_auart_initialize();
arc_serial_initialize();
+ uniphier_serial_initialize();
serial_assign(default_serial_console()->name);
}
diff --git a/drivers/serial/serial_lpuart.c b/drivers/serial/serial_lpuart.c
index b0c6f6f..63fc388 100644
--- a/drivers/serial/serial_lpuart.c
+++ b/drivers/serial/serial_lpuart.c
@@ -14,8 +14,13 @@
#define US1_TDRE (1 << 7)
#define US1_RDRF (1 << 5)
+#define US1_OR (1 << 3)
#define UC2_TE (1 << 3)
#define UC2_RE (1 << 2)
+#define CFIFO_TXFLUSH (1 << 7)
+#define CFIFO_RXFLUSH (1 << 6)
+#define SFIFO_RXOF (1 << 2)
+#define SFIFO_RXUF (1 << 0)
#define STAT_LBKDIF (1 << 31)
#define STAT_RXEDGIF (1 << 30)
@@ -62,14 +67,10 @@ static void lpuart_serial_setbrg(void)
static int lpuart_serial_getc(void)
{
- u8 status;
-
- while (!(__raw_readb(&base->us1) & US1_RDRF))
+ while (!(__raw_readb(&base->us1) & (US1_RDRF | US1_OR)))
WATCHDOG_RESET();
- status = __raw_readb(&base->us1);
- status |= US1_RDRF;
- __raw_writeb(status, &base->us1);
+ barrier();
return __raw_readb(&base->ud);
}
@@ -112,6 +113,12 @@ static int lpuart_serial_init(void)
__raw_writeb(0, &base->umodem);
__raw_writeb(0, &base->uc1);
+ /* Disable FIFO and flush buffer */
+ __raw_writeb(0x0, &base->upfifo);
+ __raw_writeb(0x0, &base->utwfifo);
+ __raw_writeb(0x1, &base->urwfifo);
+ __raw_writeb(CFIFO_TXFLUSH | CFIFO_RXFLUSH, &base->ucfifo);
+
/* provide data bits, parity, stop bit, etc */
serial_setbrg();
diff --git a/drivers/serial/serial_uniphier.c b/drivers/serial/serial_uniphier.c
new file mode 100644
index 0000000..f8c9d92
--- /dev/null
+++ b/drivers/serial/serial_uniphier.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2012-2014 Panasonic Corporation
+ * Author: Masahiro Yamada <yamada.m@jp.panasonic.com>
+ *
+ * Based on serial_ns16550.c
+ * (C) Copyright 2000
+ * Rob Taylor, Flying Pig Systems. robt@flyingpig.com.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <serial.h>
+
+#define UART_REG(x) \
+ u8 x; \
+ u8 postpad_##x[3];
+
+/*
+ * Note: Register map is slightly different from that of 16550.
+ */
+struct uniphier_serial {
+ UART_REG(rbr); /* 0x00 */
+ UART_REG(ier); /* 0x04 */
+ UART_REG(iir); /* 0x08 */
+ UART_REG(fcr); /* 0x0c */
+ u8 mcr; /* 0x10 */
+ u8 lcr;
+ u16 __postpad;
+ UART_REG(lsr); /* 0x14 */
+ UART_REG(msr); /* 0x18 */
+ u32 __none1;
+ u32 __none2;
+ u16 dlr;
+ u16 __postpad2;
+};
+
+#define thr rbr
+
+/*
+ * These are the definitions for the Line Control Register
+ */
+#define UART_LCR_WLS_8 0x03 /* 8 bit character length */
+
+/*
+ * These are the definitions for the Line Status Register
+ */
+#define UART_LSR_DR 0x01 /* Data ready */
+#define UART_LSR_THRE 0x20 /* Xmit holding register empty */
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void uniphier_serial_init(struct uniphier_serial *port)
+{
+ const unsigned int mode_x_div = 16;
+ unsigned int divisor;
+
+ writeb(UART_LCR_WLS_8, &port->lcr);
+
+ divisor = DIV_ROUND_CLOSEST(CONFIG_SYS_UNIPHIER_UART_CLK,
+ mode_x_div * gd->baudrate);
+
+ writew(divisor, &port->dlr);
+}
+
+static void uniphier_serial_setbrg(struct uniphier_serial *port)
+{
+ uniphier_serial_init(port);
+}
+
+static int uniphier_serial_tstc(struct uniphier_serial *port)
+{
+ return (readb(&port->lsr) & UART_LSR_DR) != 0;
+}
+
+static int uniphier_serial_getc(struct uniphier_serial *port)
+{
+ while (!uniphier_serial_tstc(port))
+ ;
+
+ return readb(&port->rbr);
+}
+
+static void uniphier_serial_putc(struct uniphier_serial *port, const char c)
+{
+ if (c == '\n')
+ uniphier_serial_putc(port, '\r');
+
+ while (!(readb(&port->lsr) & UART_LSR_THRE))
+ ;
+
+ writeb(c, &port->thr);
+}
+
+static struct uniphier_serial *serial_ports[4] = {
+#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE0
+ (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE0,
+#else
+ NULL,
+#endif
+#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE1
+ (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE1,
+#else
+ NULL,
+#endif
+#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE2
+ (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE2,
+#else
+ NULL,
+#endif
+#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE3
+ (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE3,
+#else
+ NULL,
+#endif
+};
+
+/* Multi serial device functions */
+#define DECLARE_ESERIAL_FUNCTIONS(port) \
+ static int eserial##port##_init(void) \
+ { \
+ uniphier_serial_init(serial_ports[port]); \
+ return 0 ; \
+ } \
+ static void eserial##port##_setbrg(void) \
+ { \
+ uniphier_serial_setbrg(serial_ports[port]); \
+ } \
+ static int eserial##port##_getc(void) \
+ { \
+ return uniphier_serial_getc(serial_ports[port]); \
+ } \
+ static int eserial##port##_tstc(void) \
+ { \
+ return uniphier_serial_tstc(serial_ports[port]); \
+ } \
+ static void eserial##port##_putc(const char c) \
+ { \
+ uniphier_serial_putc(serial_ports[port], c); \
+ }
+
+/* Serial device descriptor */
+#define INIT_ESERIAL_STRUCTURE(port, __name) { \
+ .name = __name, \
+ .start = eserial##port##_init, \
+ .stop = NULL, \
+ .setbrg = eserial##port##_setbrg, \
+ .getc = eserial##port##_getc, \
+ .tstc = eserial##port##_tstc, \
+ .putc = eserial##port##_putc, \
+ .puts = default_serial_puts, \
+}
+
+#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE0)
+DECLARE_ESERIAL_FUNCTIONS(0);
+struct serial_device uniphier_serial0_device =
+ INIT_ESERIAL_STRUCTURE(0, "ttyS0");
+#endif
+#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE1)
+DECLARE_ESERIAL_FUNCTIONS(1);
+struct serial_device uniphier_serial1_device =
+ INIT_ESERIAL_STRUCTURE(1, "ttyS1");
+#endif
+#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE2)
+DECLARE_ESERIAL_FUNCTIONS(2);
+struct serial_device uniphier_serial2_device =
+ INIT_ESERIAL_STRUCTURE(2, "ttyS2");
+#endif
+#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE3)
+DECLARE_ESERIAL_FUNCTIONS(3);
+struct serial_device uniphier_serial3_device =
+ INIT_ESERIAL_STRUCTURE(3, "ttyS3");
+#endif
+
+__weak struct serial_device *default_serial_console(void)
+{
+#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE0)
+ return &uniphier_serial0_device;
+#elif defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE1)
+ return &uniphier_serial1_device;
+#elif defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE2)
+ return &uniphier_serial2_device;
+#elif defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE3)
+ return &uniphier_serial3_device;
+#else
+#error "No uniphier serial ports configured."
+#endif
+}
+
+void uniphier_serial_initialize(void)
+{
+#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE0)
+ serial_register(&uniphier_serial0_device);
+#endif
+#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE1)
+ serial_register(&uniphier_serial1_device);
+#endif
+#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE2)
+ serial_register(&uniphier_serial2_device);
+#endif
+#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE3)
+ serial_register(&uniphier_serial3_device);
+#endif
+}
diff --git a/drivers/serial/usbtty.c b/drivers/serial/usbtty.c
index b030526..7fb0b92 100644
--- a/drivers/serial/usbtty.c
+++ b/drivers/serial/usbtty.c
@@ -475,7 +475,7 @@ static void __usbtty_puts (const char *str, int len)
if (space) {
write_buffer (&usbtty_output);
- n = MIN (space, MIN (len, maxlen));
+ n = min(space, min(len, maxlen));
buf_push (&usbtty_output, str, n);
str += n;
@@ -882,7 +882,7 @@ static int write_buffer (circbuf_t * buf)
space_avail =
current_urb->buffer_length -
current_urb->actual_length;
- popnum = MIN (space_avail, buf->size);
+ popnum = min(space_avail, buf->size);
if (popnum == 0)
break;
diff --git a/drivers/sound/Kconfig b/drivers/sound/Kconfig
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/sound/Kconfig
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/spi/Kconfig
diff --git a/drivers/spi/kirkwood_spi.c b/drivers/spi/kirkwood_spi.c
index 942a208..3d58bcc 100644
--- a/drivers/spi/kirkwood_spi.c
+++ b/drivers/spi/kirkwood_spi.c
@@ -18,7 +18,7 @@
static struct kwspi_registers *spireg = (struct kwspi_registers *)KW_SPI_BASE;
-u32 cs_spi_mpp_back[2];
+static u32 cs_spi_mpp_back[2];
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int mode)
@@ -37,7 +37,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
if (!slave)
return NULL;
- writel(~KWSPI_CSN_ACT | KWSPI_SMEMRDY, &spireg->ctrl);
+ writel(KWSPI_SMEMRDY, &spireg->ctrl);
/* calculate spi clock prescaller using max_hz */
data = ((CONFIG_SYS_TCLK / 2) / max_hz) + 0x10;
@@ -46,7 +46,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
/* program spi clock prescaller using max_hz */
writel(KWSPI_ADRLEN_3BYTE | data, &spireg->cfg);
- debug("data = 0x%08x \n", data);
+ debug("data = 0x%08x\n", data);
writel(KWSPI_SMEMRDIRQ, &spireg->irq_cause);
writel(KWSPI_IRQMASK, &spireg->irq_mask);
@@ -100,7 +100,6 @@ int spi_claim_bus(struct spi_slave *slave)
/* set new spi mpp and save current mpp config */
kirkwood_mpp_conf(spi_mpp_config, spi_mpp_backup);
-
#endif
return board_spi_claim_bus(slave);
@@ -127,7 +126,7 @@ void spi_release_bus(struct spi_slave *slave)
*/
int spi_cs_is_valid(unsigned int bus, unsigned int cs)
{
- return (bus == 0 && (cs == 0 || cs == 1));
+ return bus == 0 && (cs == 0 || cs == 1);
}
#endif
@@ -137,12 +136,12 @@ void spi_init(void)
void spi_cs_activate(struct spi_slave *slave)
{
- writel(readl(&spireg->ctrl) | KWSPI_IRQUNMASK, &spireg->ctrl);
+ setbits_le32(&spireg->ctrl, KWSPI_CSN_ACT);
}
void spi_cs_deactivate(struct spi_slave *slave)
{
- writel(readl(&spireg->ctrl) & KWSPI_IRQMASK, &spireg->ctrl);
+ clrbits_le32(&spireg->ctrl, KWSPI_CSN_ACT);
}
int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
@@ -161,8 +160,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
* handle data in 8-bit chunks
* TBD: 2byte xfer mode to be enabled
*/
- writel(((readl(&spireg->cfg) & ~KWSPI_XFERLEN_MASK) |
- KWSPI_XFERLEN_1BYTE), &spireg->cfg);
+ clrsetbits_le32(&spireg->cfg, KWSPI_XFERLEN_MASK, KWSPI_XFERLEN_1BYTE);
while (bitlen > 4) {
debug("loopstart bitlen %d\n", bitlen);
@@ -170,9 +168,9 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
/* Shift data so it's msb-justified */
if (dout)
- tmpdout = *(u32 *) dout & 0x0ff;
+ tmpdout = *(u32 *)dout & 0xff;
- writel(~KWSPI_SMEMRDIRQ, &spireg->irq_cause);
+ clrbits_le32(&spireg->irq_cause, KWSPI_SMEMRDIRQ);
writel(tmpdout, &spireg->dout); /* Write the data out */
debug("*** spi_xfer: ... %08x written, bitlen %d\n",
tmpdout, bitlen);
@@ -186,12 +184,11 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
if (readl(&spireg->irq_cause) & KWSPI_SMEMRDIRQ) {
isread = 1;
tmpdin = readl(&spireg->din);
- debug
- ("spi_xfer: din %p..%08x read\n",
- din, tmpdin);
+ debug("spi_xfer: din %p..%08x read\n",
+ din, tmpdin);
if (din) {
- *((u8 *) din) = (u8) tmpdin;
+ *((u8 *)din) = (u8)tmpdin;
din += 1;
}
if (dout)
diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c
index 2d5f385..026f680 100644
--- a/drivers/spi/mxc_spi.c
+++ b/drivers/spi/mxc_spi.c
@@ -25,6 +25,11 @@ static unsigned long spi_bases[] = {
MXC_SPI_BASE_ADDRESSES
};
+__weak int board_spi_cs_gpio(unsigned bus, unsigned cs)
+{
+ return -1;
+}
+
#define OUT MXC_GPIO_DIRECTION_OUT
#define reg_read readl
@@ -371,31 +376,30 @@ void spi_init(void)
{
}
-static int decode_cs(struct mxc_spi_slave *mxcs, unsigned int cs)
+/*
+ * Some SPI devices require active chip-select over multiple
+ * transactions, we achieve this using a GPIO. Still, the SPI
+ * controller has to be configured to use one of its own chipselects.
+ * To use this feature you have to implement board_spi_cs_gpio() to assign
+ * a gpio value for each cs (-1 if cs doesn't need to use gpio).
+ * You must use some unused on this SPI controller cs between 0 and 3.
+ */
+static int setup_cs_gpio(struct mxc_spi_slave *mxcs,
+ unsigned int bus, unsigned int cs)
{
int ret;
- /*
- * Some SPI devices require active chip-select over multiple
- * transactions, we achieve this using a GPIO. Still, the SPI
- * controller has to be configured to use one of its own chipselects.
- * To use this feature you have to call spi_setup_slave() with
- * cs = internal_cs | (gpio << 8), and you have to use some unused
- * on this SPI controller cs between 0 and 3.
- */
- if (cs > 3) {
- mxcs->gpio = cs >> 8;
- cs &= 3;
- ret = gpio_direction_output(mxcs->gpio, !(mxcs->ss_pol));
- if (ret) {
- printf("mxc_spi: cannot setup gpio %d\n", mxcs->gpio);
- return -EINVAL;
- }
- } else {
- mxcs->gpio = -1;
+ mxcs->gpio = board_spi_cs_gpio(bus, cs);
+ if (mxcs->gpio == -1)
+ return 0;
+
+ ret = gpio_direction_output(mxcs->gpio, !(mxcs->ss_pol));
+ if (ret) {
+ printf("mxc_spi: cannot setup gpio %d\n", mxcs->gpio);
+ return -EINVAL;
}
- return cs;
+ return 0;
}
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
@@ -415,14 +419,12 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
mxcs->ss_pol = (mode & SPI_CS_HIGH) ? 1 : 0;
- ret = decode_cs(mxcs, cs);
+ ret = setup_cs_gpio(mxcs, bus, cs);
if (ret < 0) {
free(mxcs);
return NULL;
}
- cs = ret;
-
mxcs->base = spi_bases[bus];
ret = spi_cfg_mxc(mxcs, cs, max_hz, mode);
diff --git a/drivers/tpm/Kconfig b/drivers/tpm/Kconfig
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/tpm/Kconfig
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/usb/Kconfig
diff --git a/drivers/usb/eth/smsc95xx.c b/drivers/usb/eth/smsc95xx.c
index 7a7a676..6bca34d 100644
--- a/drivers/usb/eth/smsc95xx.c
+++ b/drivers/usb/eth/smsc95xx.c
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2011 The Chromium OS Authors.
* Copyright (C) 2009 NVIDIA, Corporation
+ * Copyright (C) 2007-2008 SMSC (Steve Glendinning)
*
* SPDX-License-Identifier: GPL-2.0+
*/
diff --git a/drivers/usb/gadget/designware_udc.c b/drivers/usb/gadget/designware_udc.c
index b7c1038..3559400 100644
--- a/drivers/usb/gadget/designware_udc.c
+++ b/drivers/usb/gadget/designware_udc.c
@@ -269,7 +269,7 @@ static void dw_write_noniso_tx_fifo(struct usb_endpoint_instance
UDCDBGA("urb->buffer %p, buffer_length %d, actual_length %d",
urb->buffer, urb->buffer_length, urb->actual_length);
- last = MIN(urb->actual_length - endpoint->sent,
+ last = min(urb->actual_length - endpoint->sent,
endpoint->tx_packetSize);
if (last) {
@@ -285,7 +285,7 @@ static void dw_write_noniso_tx_fifo(struct usb_endpoint_instance
align = ((ulong)cp % sizeof(int));
if (align)
- last = MIN(last, sizeof(int) - align);
+ last = min(last, sizeof(int) - align);
UDCDBGA("endpoint->sent %d, tx_packetSize %d, last %d",
endpoint->sent, endpoint->tx_packetSize, last);
diff --git a/drivers/usb/gadget/ep0.c b/drivers/usb/gadget/ep0.c
index b321488..4ba2f3d 100644
--- a/drivers/usb/gadget/ep0.c
+++ b/drivers/usb/gadget/ep0.c
@@ -315,7 +315,7 @@ static int ep0_get_descriptor (struct usb_device_instance *device,
/*copy_config(urb, &report_descriptor->bData[0], report_descriptor->wLength, max); */
if (max - urb->actual_length > 0) {
int length =
- MIN (report_descriptor->wLength,
+ min(report_descriptor->wLength,
max - urb->actual_length);
memcpy (urb->buffer + urb->actual_length,
&report_descriptor->bData[0], length);
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
index 7a1acb9..38c0965 100644
--- a/drivers/usb/gadget/f_fastboot.c
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -10,6 +10,7 @@
*
* SPDX-License-Identifier: GPL-2.0+
*/
+#include <config.h>
#include <common.h>
#include <errno.h>
#include <malloc.h>
@@ -19,6 +20,9 @@
#include <linux/compiler.h>
#include <version.h>
#include <g_dnl.h>
+#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
+#include <fb_mmc.h>
+#endif
#define FASTBOOT_VERSION "0.4"
@@ -38,7 +42,7 @@
struct f_fastboot {
struct usb_function usb_function;
- /* IN/OUT EP's and correspoinding requests */
+ /* IN/OUT EP's and corresponding requests */
struct usb_ep *in_ep, *out_ep;
struct usb_request *in_req, *out_req;
};
@@ -290,7 +294,7 @@ static int fastboot_add(struct usb_configuration *c)
}
DECLARE_GADGET_BIND_CALLBACK(usb_dnl_fastboot, fastboot_add);
-int fastboot_tx_write(const char *buffer, unsigned int buffer_size)
+static int fastboot_tx_write(const char *buffer, unsigned int buffer_size)
{
struct usb_request *in_req = fastboot_func->in_req;
int ret;
@@ -338,6 +342,7 @@ static void cb_getvar(struct usb_ep *ep, struct usb_request *req)
strsep(&cmd, ":");
if (!cmd) {
+ error("missing variable\n");
fastboot_tx_write_str("FAILmissing var");
return;
}
@@ -358,6 +363,7 @@ static void cb_getvar(struct usb_ep *ep, struct usb_request *req)
else
strcpy(response, "FAILValue not set");
} else {
+ error("unknown variable: %s\n", cmd);
strcpy(response, "FAILVariable not implemented");
}
fastboot_tx_write_str(response);
@@ -469,6 +475,28 @@ static void cb_boot(struct usb_ep *ep, struct usb_request *req)
fastboot_tx_write_str("OKAY");
}
+#ifdef CONFIG_FASTBOOT_FLASH
+static void cb_flash(struct usb_ep *ep, struct usb_request *req)
+{
+ char *cmd = req->buf;
+ char response[RESPONSE_LEN];
+
+ strsep(&cmd, ":");
+ if (!cmd) {
+ error("missing partition name\n");
+ fastboot_tx_write_str("FAILmissing partition name");
+ return;
+ }
+
+ strcpy(response, "FAILno flash device defined");
+#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
+ fb_mmc_flash_write(cmd, (void *)CONFIG_USB_FASTBOOT_BUF_ADDR,
+ download_bytes, response);
+#endif
+ fastboot_tx_write_str(response);
+}
+#endif
+
struct cmd_dispatch_info {
char *cmd;
void (*cb)(struct usb_ep *ep, struct usb_request *req);
@@ -488,6 +516,12 @@ static const struct cmd_dispatch_info cmd_dispatch_info[] = {
.cmd = "boot",
.cb = cb_boot,
},
+#ifdef CONFIG_FASTBOOT_FLASH
+ {
+ .cmd = "flash",
+ .cb = cb_flash,
+ },
+#endif
};
static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
@@ -503,10 +537,12 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
}
}
- if (!func_cb)
+ if (!func_cb) {
+ error("unknown command: %s\n", cmdbuf);
fastboot_tx_write_str("FAILunknown command");
- else
+ } else {
func_cb(ep, req);
+ }
if (req->status == 0) {
*cmdbuf = '\0';
diff --git a/drivers/usb/gadget/mpc8xx_udc.c b/drivers/usb/gadget/mpc8xx_udc.c
index 7f72972..b3e178a 100644
--- a/drivers/usb/gadget/mpc8xx_udc.c
+++ b/drivers/usb/gadget/mpc8xx_udc.c
@@ -897,7 +897,7 @@ static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi)
pkt_len = urb->actual_length - epi->sent;
if (pkt_len > epi->tx_packetSize || pkt_len > EP_MAX_PKT) {
- pkt_len = MIN (epi->tx_packetSize, EP_MAX_PKT);
+ pkt_len = min(epi->tx_packetSize, EP_MAX_PKT);
}
for (x = 0; x < pkt_len; x++) {
@@ -942,7 +942,7 @@ static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi)
/* TX ACK : USB 2.0 8.7.2, Toggle PID, Advance TX */
epi->sent += pkt_len;
- epi->last = MIN (urb->actual_length - epi->sent, epi->tx_packetSize);
+ epi->last = min(urb->actual_length - epi->sent, epi->tx_packetSize);
TOGGLE_TX_PID (ep_ref[ep].pid);
if (epi->sent >= epi->tx_urb->actual_length) {
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index 733558d..efd5c7f 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -65,7 +65,7 @@ static int udc_write_urb(struct usb_endpoint_instance *endpoint)
if (!urb || !urb->actual_length)
return -1;
- n = MIN(urb->actual_length - endpoint->sent, endpoint->tx_packetSize);
+ n = min(urb->actual_length - endpoint->sent, endpoint->tx_packetSize);
if (n <= 0)
return -1;
diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index 9ffe501..9a8f004 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -40,7 +40,11 @@ int ehci_hcd_init(int index, enum usb_init_type init,
}
/* Enable USB Host clock */
+#ifdef CPU_HAS_PCR
+ at91_periph_clk_enable(ATMEL_ID_UHPHS);
+#else
writel(1 << ATMEL_ID_UHPHS, &pmc->pcer);
+#endif
*hccr = (struct ehci_hccr *)ATMEL_BASE_EHCI;
*hcor = (struct ehci_hcor *)((uint32_t)*hccr +
@@ -55,7 +59,11 @@ int ehci_hcd_stop(int index)
ulong start_time, tmp_time;
/* Disable USB Host Clock */
+#ifdef CPU_HAS_PCR
+ at91_periph_clk_disable(ATMEL_ID_UHPHS);
+#else
writel(1 << ATMEL_ID_UHPHS, &pmc->pcdr);
+#endif
start_time = get_timer(0);
/* Disable UTMI PLL */
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index c24505e..820e2e5 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -38,8 +38,8 @@ int usb_cpu_init(void)
#endif
/* Enable USB host clock. */
-#ifdef CONFIG_SAMA5D3
- writel(1 << (ATMEL_ID_UHP - 32), &pmc->pcer1);
+#ifdef CPU_HAS_PCR
+ at91_periph_clk_enable(ATMEL_ID_UHP);
#else
writel(1 << ATMEL_ID_UHP, &pmc->pcer);
#endif
@@ -58,8 +58,8 @@ int usb_cpu_stop(void)
at91_pmc_t *pmc = (at91_pmc_t *)ATMEL_BASE_PMC;
/* Disable USB host clock. */
-#ifdef CONFIG_SAMA5D3
- writel(1 << (ATMEL_ID_UHP - 32), &pmc->pcdr1);
+#ifdef CPU_HAS_PCR
+ at91_periph_clk_disable(ATMEL_ID_UHP);
#else
writel(1 << ATMEL_ID_UHP, &pmc->pcdr);
#endif
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/video/Kconfig
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/watchdog/Kconfig