diff options
Diffstat (limited to 'drivers')
139 files changed, 5501 insertions, 2269 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index 4ac823d962e..e9fbadd13d5 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -40,6 +40,8 @@ source "drivers/fpga/Kconfig" source "drivers/gpio/Kconfig" +source "drivers/hwspinlock/Kconfig" + source "drivers/i2c/Kconfig" source "drivers/input/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 55de10926ef..c425831b584 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -113,4 +113,5 @@ obj-$(CONFIG_W1) += w1/ obj-$(CONFIG_W1_EEPROM) += w1-eeprom/ obj-$(CONFIG_MACH_PIC32) += ddr/microchip/ +obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock/ endif diff --git a/drivers/bootcount/Kconfig b/drivers/bootcount/Kconfig index 67033637c0d..b7c29f2fd30 100644 --- a/drivers/bootcount/Kconfig +++ b/drivers/bootcount/Kconfig @@ -70,8 +70,36 @@ config BOOTCOUNT_AT91 bool "Boot counter for Atmel AT91SAM9XE" depends on AT91SAM9XE +config DM_BOOTCOUNT + bool "Boot counter in a device-model device" + help + Enables reading/writing the bootcount in a device-model based + backing store. If an entry in /chosen/u-boot,bootcount-device + exists, this will be the preferred bootcount device; otherwise + the first available bootcount device will be used. + endchoice +if DM_BOOTCOUNT + +menu "Backing stores for device-model backed bootcount" +config DM_BOOTCOUNT_RTC + bool "Support RTC devices as a backing store for bootcount" + depends on DM_RTC + help + Enabled reading/writing the bootcount in a DM RTC device. + The wrapper device is to be specified with the compatible string + 'u-boot,bootcount-rtc' and the 'rtc'-property (a phandle pointing + to the underlying RTC device) and an optional 'offset' property + are supported. + + Accesses to the backing store are performed using the write16 + and read16 ops of DM RTC devices. + +endmenu + +endif + config BOOTCOUNT_BOOTLIMIT int "Maximum number of reboot cycles allowed" default 0 diff --git a/drivers/bootcount/Makefile b/drivers/bootcount/Makefile index 68bc006b753..f9841d86156 100644 --- a/drivers/bootcount/Makefile +++ b/drivers/bootcount/Makefile @@ -7,3 +7,6 @@ obj-$(CONFIG_BOOTCOUNT_RAM) += bootcount_ram.o obj-$(CONFIG_BOOTCOUNT_ENV) += bootcount_env.o obj-$(CONFIG_BOOTCOUNT_I2C) += bootcount_i2c.o obj-$(CONFIG_BOOTCOUNT_EXT) += bootcount_ext.o + +obj-$(CONFIG_DM_BOOTCOUNT) += bootcount-uclass.o +obj-$(CONFIG_DM_BOOTCOUNT_RTC) += rtc.o diff --git a/drivers/bootcount/bootcount-uclass.c b/drivers/bootcount/bootcount-uclass.c new file mode 100644 index 00000000000..0689db7a5bc --- /dev/null +++ b/drivers/bootcount/bootcount-uclass.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2018 Theobroma Systems Design und Consulting GmbH + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <bootcount.h> + +int dm_bootcount_get(struct udevice *dev, u32 *bootcount) +{ + struct bootcount_ops *ops = bootcount_get_ops(dev); + + assert(ops); + if (!ops->get) + return -ENOSYS; + return ops->get(dev, bootcount); +} + +int dm_bootcount_set(struct udevice *dev, const u32 bootcount) +{ + struct bootcount_ops *ops = bootcount_get_ops(dev); + + assert(ops); + if (!ops->set) + return -ENOSYS; + return ops->set(dev, bootcount); +} + +/* Now implement the generic default functions */ +void bootcount_store(ulong val) +{ + struct udevice *dev = NULL; + ofnode node; + const char *propname = "u-boot,bootcount-device"; + int ret = -ENODEV; + + /* + * If there's a preferred bootcount device selected by the user (by + * setting '/chosen/u-boot,bootcount-device' in the DTS), try to use + * it if available. + */ + node = ofnode_get_chosen_node(propname); + if (ofnode_valid(node)) + ret = uclass_get_device_by_ofnode(UCLASS_BOOTCOUNT, node, &dev); + + /* If there was no user-selected device, use the first available one */ + if (ret) + ret = uclass_get_device(UCLASS_BOOTCOUNT, 0, &dev); + + if (dev) + ret = dm_bootcount_set(dev, val); + + if (ret) + pr_debug("%s: failed to store 0x%lx\n", __func__, val); +} + +ulong bootcount_load(void) +{ + struct udevice *dev = NULL; + ofnode node; + const char *propname = "u-boot,bootcount-device"; + int ret = -ENODEV; + u32 val; + + /* + * If there's a preferred bootcount device selected by the user (by + * setting '/chosen/u-boot,bootcount-device' in the DTS), try to use + * it if available. + */ + node = ofnode_get_chosen_node(propname); + if (ofnode_valid(node)) + ret = uclass_get_device_by_ofnode(UCLASS_BOOTCOUNT, node, &dev); + + /* If there was no user-selected device, use the first available one */ + if (ret) + ret = uclass_get_device(UCLASS_BOOTCOUNT, 0, &dev); + + if (dev) + ret = dm_bootcount_get(dev, &val); + + if (ret) + pr_debug("%s: failed to load bootcount\n", __func__); + + /* Return the 0, if the call to dm_bootcount_get failed */ + return ret ? 0 : val; +} + +UCLASS_DRIVER(bootcount) = { + .name = "bootcount", + .id = UCLASS_BOOTCOUNT, +}; diff --git a/drivers/bootcount/rtc.c b/drivers/bootcount/rtc.c new file mode 100644 index 00000000000..db89fa3a358 --- /dev/null +++ b/drivers/bootcount/rtc.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2018 Theobroma Systems Design und Consulting GmbH + */ + +#include <common.h> +#include <bootcount.h> +#include <dm.h> +#include <rtc.h> + +static const u8 bootcount_magic = 0xbc; + +struct bootcount_rtc_priv { + struct udevice *rtc; + u32 offset; +}; + +static int bootcount_rtc_set(struct udevice *dev, const u32 a) +{ + struct bootcount_rtc_priv *priv = dev_get_priv(dev); + const u16 val = bootcount_magic << 8 | (a & 0xff); + + if (rtc_write16(priv->rtc, priv->offset, val) < 0) { + debug("%s: rtc_write16 failed\n", __func__); + return -EIO; + } + + return 0; +} + +static int bootcount_rtc_get(struct udevice *dev, u32 *a) +{ + struct bootcount_rtc_priv *priv = dev_get_priv(dev); + u16 val; + + if (rtc_read16(priv->rtc, priv->offset, &val) < 0) { + debug("%s: rtc_write16 failed\n", __func__); + return -EIO; + } + + if (val >> 8 == bootcount_magic) { + *a = val & 0xff; + return 0; + } + + debug("%s: bootcount magic does not match on %04x\n", __func__, val); + return -EIO; +} + +static int bootcount_rtc_probe(struct udevice *dev) +{ + struct ofnode_phandle_args phandle_args; + struct bootcount_rtc_priv *priv = dev_get_priv(dev); + struct udevice *rtc; + + if (dev_read_phandle_with_args(dev, "rtc", NULL, 0, 0, &phandle_args)) { + debug("%s: rtc backing device not specified\n", dev->name); + return -ENOENT; + } + + if (uclass_get_device_by_ofnode(UCLASS_RTC, phandle_args.node, &rtc)) { + debug("%s: could not get backing device\n", dev->name); + return -ENODEV; + } + + priv->rtc = rtc; + priv->offset = dev_read_u32_default(dev, "offset", 0); + + return 0; +} + +static const struct bootcount_ops bootcount_rtc_ops = { + .get = bootcount_rtc_get, + .set = bootcount_rtc_set, +}; + +static const struct udevice_id bootcount_rtc_ids[] = { + { .compatible = "u-boot,bootcount-rtc" }, + { } +}; + +U_BOOT_DRIVER(bootcount_rtc) = { + .name = "bootcount-rtc", + .id = UCLASS_BOOTCOUNT, + .priv_auto_alloc_size = sizeof(struct bootcount_rtc_priv), + .probe = bootcount_rtc_probe, + .of_match = bootcount_rtc_ids, + .ops = &bootcount_rtc_ops, +}; diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index 04b369aa5a1..6d7a5140065 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -243,6 +243,10 @@ int clk_set_defaults(struct udevice *dev) { int ret; + /* If this not in SPL and pre-reloc state, don't take any action. */ + if (!(IS_ENABLED(CONFIG_SPL_BUILD) || (gd->flags & GD_FLG_RELOC))) + return 0; + debug("%s(%s)\n", __func__, dev_read_name(dev)); ret = clk_set_default_parents(dev); diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index 6a8c7b754fa..b7c5d34fe06 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -104,6 +104,7 @@ #define RCC_MP_APB2ENSETR 0XA08 #define RCC_MP_APB3ENSETR 0xA10 #define RCC_MP_AHB2ENSETR 0xA18 +#define RCC_MP_AHB3ENSETR 0xA20 #define RCC_MP_AHB4ENSETR 0xA28 /* used for most of SELR register */ @@ -534,6 +535,8 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { STM32MP1_CLK_SET_CLR(RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL), + STM32MP1_CLK_SET_CLR(RCC_MP_AHB3ENSETR, 11, HSEM, _UNKNOWN_SEL), + STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL), diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig index e8ba20ca82d..046b87a3337 100644 --- a/drivers/core/Kconfig +++ b/drivers/core/Kconfig @@ -57,13 +57,21 @@ config DM_DEVICE_REMOVE default y help We can save some code space by dropping support for removing a - device. This is not normally required in SPL, so by default this - option is disabled for SPL. + device. Note that this may have undesirable results in the USB subsystem as it causes unplugged devices to linger around in the dm-tree, and it causes USB host controllers to not be stopped when booting the OS. +config SPL_DM_DEVICE_REMOVE + bool "Support device removal in SPL" + depends on SPL_DM + default n + help + We can save some code space by dropping support for removing a + device. This is not normally required in SPL, so by default this + option is disabled for SPL. + config DM_STDIO bool "Support stdio registration" depends on DM diff --git a/drivers/core/device.c b/drivers/core/device.c index 836bcadced5..0d15e5062b6 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -70,7 +70,8 @@ static int device_bind_common(struct udevice *parent, const struct driver *drv, dev->seq = -1; dev->req_seq = -1; - if (CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(DM_SEQ_ALIAS)) { + if (CONFIG_IS_ENABLED(DM_SEQ_ALIAS) && + (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS)) { /* * Some devices, such as a SPI bus, I2C bus and serial ports * are numbered using aliases. @@ -78,10 +79,11 @@ static int device_bind_common(struct udevice *parent, const struct driver *drv, * This is just a 'requested' sequence, and will be * resolved (and ->seq updated) when the device is probed. */ - if (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS) { - if (uc->uc_drv->name && ofnode_valid(node)) { + if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) { + if (uc->uc_drv->name && ofnode_valid(node)) dev_read_alias_seq(dev, &dev->req_seq); - } + } else { + dev->req_seq = uclass_find_next_free_req_seq(drv->id); } } diff --git a/drivers/core/fdtaddr.c b/drivers/core/fdtaddr.c index bfd9580050c..e113f1dd39c 100644 --- a/drivers/core/fdtaddr.c +++ b/drivers/core/fdtaddr.c @@ -146,6 +146,16 @@ void *devfdt_remap_addr_index(struct udevice *dev, int index) return map_physmem(addr, 0, MAP_NOCACHE); } +void *devfdt_remap_addr_name(struct udevice *dev, const char *name) +{ + fdt_addr_t addr = devfdt_get_addr_name(dev, name); + + if (addr == FDT_ADDR_T_NONE) + return NULL; + + return map_physmem(addr, 0, MAP_NOCACHE); +} + void *devfdt_remap_addr(struct udevice *dev) { return devfdt_remap_addr_index(dev, 0); diff --git a/drivers/core/read.c b/drivers/core/read.c index 96766c7876a..cdd78be03e2 100644 --- a/drivers/core/read.c +++ b/drivers/core/read.c @@ -69,6 +69,26 @@ void *dev_remap_addr_index(struct udevice *dev, int index) return map_physmem(addr, 0, MAP_NOCACHE); } +fdt_addr_t dev_read_addr_name(struct udevice *dev, const char *name) +{ + int index = dev_read_stringlist_search(dev, "reg-names", name); + + if (index < 0) + return FDT_ADDR_T_NONE; + else + return dev_read_addr_index(dev, index); +} + +void *dev_remap_addr_name(struct udevice *dev, const char *name) +{ + fdt_addr_t addr = dev_read_addr_name(dev, name); + + if (addr == FDT_ADDR_T_NONE) + return NULL; + + return map_physmem(addr, 0, MAP_NOCACHE); +} + fdt_addr_t dev_read_addr(struct udevice *dev) { return dev_read_addr_index(dev, 0); diff --git a/drivers/core/root.c b/drivers/core/root.c index 4ce55f9cc89..e6ec7faf379 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -187,6 +187,7 @@ int dm_uninit(void) { device_remove(dm_root(), DM_REMOVE_NORMAL); device_unbind(dm_root()); + gd->dm_root = NULL; return 0; } diff --git a/drivers/core/syscon-uclass.c b/drivers/core/syscon-uclass.c index 303e166a69c..661cf61d62a 100644 --- a/drivers/core/syscon-uclass.c +++ b/drivers/core/syscon-uclass.c @@ -53,6 +53,29 @@ static int syscon_pre_probe(struct udevice *dev) #endif } +struct regmap *syscon_regmap_lookup_by_phandle(struct udevice *dev, + const char *name) +{ + struct udevice *syscon; + struct regmap *r; + int err; + + err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, + name, &syscon); + if (err) { + dev_dbg(dev, "unable to find syscon device\n"); + return ERR_PTR(err); + } + + r = syscon_get_regmap(syscon); + if (!r) { + dev_dbg(dev, "unable to find regmap\n"); + return ERR_PTR(-ENODEV); + } + + return r; +} + int syscon_get_by_driver_data(ulong driver_data, struct udevice **devp) { struct udevice *dev; diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 9766aeabd19..a622f079410 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -269,6 +269,30 @@ int uclass_find_device_by_name(enum uclass_id id, const char *name, return -ENODEV; } +#if !CONFIG_IS_ENABLED(OF_CONTROL) || CONFIG_IS_ENABLED(OF_PLATDATA) +int uclass_find_next_free_req_seq(enum uclass_id id) +{ + struct uclass *uc; + struct udevice *dev; + int ret; + int max = -1; + + ret = uclass_get(id, &uc); + if (ret) + return ret; + + list_for_each_entry(dev, &uc->dev_head, uclass_node) { + if ((dev->req_seq != -1) && (dev->req_seq > max)) + max = dev->req_seq; + } + + if (max == -1) + return 0; + + return max + 1; +} +#endif + int uclass_find_device_by_seq(enum uclass_id id, int seq_or_req_seq, bool find_req_seq, struct udevice **devp) { diff --git a/drivers/ddr/marvell/a38x/ddr3_debug.c b/drivers/ddr/marvell/a38x/ddr3_debug.c index 1eac0bcd2b2..f5fc964d6f8 100644 --- a/drivers/ddr/marvell/a38x/ddr3_debug.c +++ b/drivers/ddr/marvell/a38x/ddr3_debug.c @@ -4,6 +4,8 @@ */ #include "ddr3_init.h" +#include "mv_ddr_training_db.h" +#include "mv_ddr_regs.h" u8 is_reg_dump = 0; u8 debug_pbs = DEBUG_LEVEL_ERROR; @@ -83,7 +85,7 @@ void ddr3_hws_set_log_level(enum ddr_lib_debug_block block, u8 level) #endif /* SILENT_LIB */ #if defined(DDR_VIEWER_TOOL) -static char *convert_freq(enum hws_ddr_freq freq); +static char *convert_freq(enum mv_ddr_freq freq); #if defined(EXCLUDE_SWITCH_DEBUG) u32 ctrl_sweepres[ADLL_LENGTH][MAX_INTERFACE_NUM][MAX_BUS_NUM]; u32 ctrl_adll[MAX_CS_NUM * MAX_INTERFACE_NUM * MAX_BUS_NUM]; @@ -177,23 +179,6 @@ int ddr3_tip_init_config_func(u32 dev_num, } /* - * Read training result table - */ -int hws_ddr3_tip_read_training_result( - u32 dev_num, enum hws_result result[MAX_STAGE_LIMIT][MAX_INTERFACE_NUM]) -{ - if (result == NULL) - return MV_BAD_PARAM; - - memcpy(result, training_result, - sizeof(enum hws_result) * - MAX_STAGE_LIMIT * - MAX_INTERFACE_NUM); - - return MV_OK; -} - -/* * Get training result info pointer */ enum hws_result *ddr3_tip_get_result_ptr(u32 stage) @@ -218,50 +203,50 @@ int ddr3_tip_get_device_info(u32 dev_num, struct ddr3_device_info *info_ptr) /* * Convert freq to character string */ -static char *convert_freq(enum hws_ddr_freq freq) +static char *convert_freq(enum mv_ddr_freq freq) { switch (freq) { - case DDR_FREQ_LOW_FREQ: - return "DDR_FREQ_LOW_FREQ"; + case MV_DDR_FREQ_LOW_FREQ: + return "MV_DDR_FREQ_LOW_FREQ"; - case DDR_FREQ_400: + case MV_DDR_FREQ_400: return "400"; - case DDR_FREQ_533: + case MV_DDR_FREQ_533: return "533"; - case DDR_FREQ_667: + case MV_DDR_FREQ_667: return "667"; - case DDR_FREQ_800: + case MV_DDR_FREQ_800: return "800"; - case DDR_FREQ_933: + case MV_DDR_FREQ_933: return "933"; - case DDR_FREQ_1066: + case MV_DDR_FREQ_1066: return "1066"; - case DDR_FREQ_311: + case MV_DDR_FREQ_311: return "311"; - case DDR_FREQ_333: + case MV_DDR_FREQ_333: return "333"; - case DDR_FREQ_467: + case MV_DDR_FREQ_467: return "467"; - case DDR_FREQ_850: + case MV_DDR_FREQ_850: return "850"; - case DDR_FREQ_900: + case MV_DDR_FREQ_900: return "900"; - case DDR_FREQ_360: - return "DDR_FREQ_360"; + case MV_DDR_FREQ_360: + return "MV_DDR_FREQ_360"; - case DDR_FREQ_1000: - return "DDR_FREQ_1000"; + case MV_DDR_FREQ_1000: + return "MV_DDR_FREQ_1000"; default: return "Unknown Frequency"; @@ -364,7 +349,7 @@ int ddr3_tip_print_log(u32 dev_num, u32 mem_addr) if ((is_validate_window_per_if != 0) || (is_validate_window_per_pup != 0)) { u32 is_pup_log = 0; - enum hws_ddr_freq freq; + enum mv_ddr_freq freq; freq = tm->interface_params[first_active_if].memory_freq; @@ -528,7 +513,7 @@ int ddr3_tip_print_stability_log(u32 dev_num) u8 if_id = 0, csindex = 0, bus_id = 0, idx = 0; u32 reg_data; u32 read_data[MAX_INTERFACE_NUM]; - u32 max_cs = ddr3_tip_max_cs_get(dev_num); + unsigned int max_cs = mv_ddr_cs_num_get(); struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); /* Title print */ @@ -844,8 +829,6 @@ u32 xsb_test_table[][8] = { 0xffffffff, 0xffffffff} }; -static int ddr3_tip_access_atr(u32 dev_num, u32 flag_id, u32 value, u32 **ptr); - int ddr3_tip_print_adll(void) { u32 bus_cnt = 0, if_id, data_p1, data_p2, ui_data3, dev_num = 0; @@ -877,353 +860,6 @@ int ddr3_tip_print_adll(void) return MV_OK; } -/* - * Set attribute value - */ -int ddr3_tip_set_atr(u32 dev_num, u32 flag_id, u32 value) -{ - int ret; - u32 *ptr_flag = NULL; - - ret = ddr3_tip_access_atr(dev_num, flag_id, value, &ptr_flag); - if (ptr_flag != NULL) { - printf("ddr3_tip_set_atr Flag ID 0x%x value is set to 0x%x (was 0x%x)\n", - flag_id, value, *ptr_flag); - *ptr_flag = value; - } else { - printf("ddr3_tip_set_atr Flag ID 0x%x value is set to 0x%x\n", - flag_id, value); - } - - return ret; -} - -/* - * Access attribute - */ -static int ddr3_tip_access_atr(u32 dev_num, u32 flag_id, u32 value, u32 **ptr) -{ - u32 tmp_val = 0, if_id = 0, pup_id = 0; - struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); - - *ptr = NULL; - - switch (flag_id) { - case 0: - *ptr = (u32 *)&(tm->if_act_mask); - break; - - case 0x1: - *ptr = (u32 *)&mask_tune_func; - break; - - case 0x2: - low_freq = (enum hws_ddr_freq)value; - break; - - case 0x3: - medium_freq = (enum hws_ddr_freq)value; - break; - - case 0x4: - *ptr = (u32 *)&generic_init_controller; - break; - - case 0x8: - *ptr = (u32 *)&start_xsb_offset; - break; - - case 0x20: - *ptr = (u32 *)&is_rl_old; - break; - - case 0x21: - *ptr = (u32 *)&is_freq_old; - break; - - case 0x23: - *ptr = (u32 *)&is_dfs_disabled; - break; - - case 0x24: - *ptr = (u32 *)&is_pll_before_init; - break; - - case 0x25: - *ptr = (u32 *)&is_adll_calib_before_init; - break; - case 0x28: - *ptr = (u32 *)&is_tune_result; - break; - - case 0x29: - *ptr = (u32 *)&is_validate_window_per_if; - break; - - case 0x2a: - *ptr = (u32 *)&is_validate_window_per_pup; - break; - - case 0x30: - *ptr = (u32 *)&sweep_cnt; - break; - - case 0x31: - *ptr = (u32 *)&is_bist_reset_bit; - break; - - case 0x32: - *ptr = (u32 *)&is_dfs_in_init; - break; - - case 0x33: - *ptr = (u32 *)&g_zpodt_data; - break; - - case 0x34: - *ptr = (u32 *)&g_znodt_data; - break; - - case 0x35: - break; - - case 0x36: - *ptr = (u32 *)&(freq_val[DDR_FREQ_LOW_FREQ]); - break; - - case 0x37: - *ptr = (u32 *)&start_pattern; - break; - - case 0x38: - *ptr = (u32 *)&end_pattern; - break; - - case 0x39: - *ptr = (u32 *)&phy_reg0_val; - break; - - case 0x4a: - *ptr = (u32 *)&phy_reg1_val; - break; - - case 0x4b: - *ptr = (u32 *)&phy_reg2_val; - break; - - case 0x4c: - *ptr = (u32 *)&phy_reg3_val; - break; - - case 0x4e: - sweep_pattern = (enum hws_pattern)value; - break; - - case 0x51: - *ptr = (u32 *)&g_znri_data; - break; - - case 0x52: - *ptr = (u32 *)&g_zpri_data; - break; - - case 0x53: - *ptr = (u32 *)&finger_test; - break; - - case 0x54: - *ptr = (u32 *)&n_finger_start; - break; - - case 0x55: - *ptr = (u32 *)&n_finger_end; - break; - - case 0x56: - *ptr = (u32 *)&p_finger_start; - break; - - case 0x57: - *ptr = (u32 *)&p_finger_end; - break; - - case 0x58: - *ptr = (u32 *)&p_finger_step; - break; - - case 0x59: - *ptr = (u32 *)&n_finger_step; - break; - - case 0x5a: - *ptr = (u32 *)&g_znri_ctrl; - break; - - case 0x5b: - *ptr = (u32 *)&g_zpri_ctrl; - break; - - case 0x5c: - *ptr = (u32 *)&is_reg_dump; - break; - - case 0x5d: - *ptr = (u32 *)&vref_init_val; - break; - - case 0x5e: - *ptr = (u32 *)&mode_2t; - break; - - case 0x5f: - *ptr = (u32 *)&xsb_validate_type; - break; - - case 0x60: - *ptr = (u32 *)&xsb_validation_base_address; - break; - - case 0x67: - *ptr = (u32 *)&activate_select_before_run_alg; - break; - - case 0x68: - *ptr = (u32 *)&activate_deselect_after_run_alg; - break; - - case 0x69: - *ptr = (u32 *)&odt_additional; - break; - - case 0x70: - *ptr = (u32 *)&debug_mode; - break; - - case 0x71: - pbs_pattern = (enum hws_pattern)value; - break; - - case 0x72: - *ptr = (u32 *)&delay_enable; - break; - - case 0x73: - *ptr = (u32 *)&ck_delay; - break; - - case 0x75: - *ptr = (u32 *)&ca_delay; - break; - - case 0x100: - *ptr = (u32 *)&debug_dunit; - break; - - case 0x101: - debug_acc = (int)value; - break; - - case 0x102: - debug_training = (u8)value; - break; - - case 0x103: - debug_training_bist = (u8)value; - break; - - case 0x104: - debug_centralization = (u8)value; - break; - - case 0x105: - debug_training_ip = (u8)value; - break; - - case 0x106: - debug_leveling = (u8)value; - break; - - case 0x107: - debug_pbs = (u8)value; - break; - - case 0x108: - debug_training_static = (u8)value; - break; - - case 0x109: - debug_training_access = (u8)value; - break; - - - case 0x112: - *ptr = &start_pattern; - break; - - case 0x113: - *ptr = &end_pattern; - break; - - default: - if ((flag_id >= 0x200) && (flag_id < 0x210)) { - if_id = flag_id - 0x200; - *ptr = (u32 *)&(tm->interface_params - [if_id].memory_freq); - } else if ((flag_id >= 0x210) && (flag_id < 0x220)) { - if_id = flag_id - 0x210; - *ptr = (u32 *)&(tm->interface_params - [if_id].speed_bin_index); - } else if ((flag_id >= 0x220) && (flag_id < 0x230)) { - if_id = flag_id - 0x220; - *ptr = (u32 *)&(tm->interface_params - [if_id].bus_width); - } else if ((flag_id >= 0x230) && (flag_id < 0x240)) { - if_id = flag_id - 0x230; - *ptr = (u32 *)&(tm->interface_params - [if_id].memory_size); - } else if ((flag_id >= 0x240) && (flag_id < 0x250)) { - if_id = flag_id - 0x240; - *ptr = (u32 *)&(tm->interface_params - [if_id].cas_l); - } else if ((flag_id >= 0x250) && (flag_id < 0x260)) { - if_id = flag_id - 0x250; - *ptr = (u32 *)&(tm->interface_params - [if_id].cas_wl); - } else if ((flag_id >= 0x270) && (flag_id < 0x2cf)) { - if_id = (flag_id - 0x270) / MAX_BUS_NUM; - pup_id = (flag_id - 0x270) % MAX_BUS_NUM; - *ptr = (u32 *)&(tm->interface_params[if_id]. - as_bus_params[pup_id].is_ck_swap); - } else if ((flag_id >= 0x2d0) && (flag_id < 0x32f)) { - if_id = (flag_id - 0x2d0) / MAX_BUS_NUM; - pup_id = (flag_id - 0x2d0) % MAX_BUS_NUM; - *ptr = (u32 *)&(tm->interface_params[if_id]. - as_bus_params[pup_id].is_dqs_swap); - } else if ((flag_id >= 0x330) && (flag_id < 0x38f)) { - if_id = (flag_id - 0x330) / MAX_BUS_NUM; - pup_id = (flag_id - 0x330) % MAX_BUS_NUM; - *ptr = (u32 *)&(tm->interface_params[if_id]. - as_bus_params[pup_id].cs_bitmask); - } else if ((flag_id >= 0x390) && (flag_id < 0x3ef)) { - if_id = (flag_id - 0x390) / MAX_BUS_NUM; - pup_id = (flag_id - 0x390) % MAX_BUS_NUM; - *ptr = (u32 *)&(tm->interface_params - [if_id].as_bus_params - [pup_id].mirror_enable_bitmask); - } else if ((flag_id >= 0x500) && (flag_id <= 0x50f)) { - tmp_val = flag_id - 0x320; - *ptr = (u32 *)&(clamp_tbl[tmp_val]); - } else { - DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, - ("flag_id out of boundary %d\n", - flag_id)); - return MV_BAD_PARAM; - } - } - - return MV_OK; -} - #endif /* EXCLUDE_SWITCH_DEBUG */ #if defined(DDR_VIEWER_TOOL) @@ -1315,7 +951,7 @@ int ddr3_tip_run_sweep_test(int dev_num, u32 repeat_num, u32 direction, u32 reg; enum hws_access_type pup_access; u32 cs; - u32 max_cs = ddr3_tip_max_cs_get(dev_num); + unsigned int max_cs = mv_ddr_cs_num_get(); u32 octets_per_if_num = ddr3_tip_dev_attr_get(dev_num, MV_ATTR_OCTET_PER_INTERFACE); struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); @@ -1462,7 +1098,7 @@ int ddr3_tip_run_leveling_sweep_test(int dev_num, u32 repeat_num, u32 reg; enum hws_access_type pup_access; u32 cs; - u32 max_cs = ddr3_tip_max_cs_get(dev_num); + unsigned int max_cs = mv_ddr_cs_num_get(); u32 octets_per_if_num = ddr3_tip_dev_attr_get(dev_num, MV_ATTR_OCTET_PER_INTERFACE); struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); diff --git a/drivers/ddr/marvell/a38x/ddr3_init.c b/drivers/ddr/marvell/a38x/ddr3_init.c index 27dbf4f44b9..22c8f9ca54e 100644 --- a/drivers/ddr/marvell/a38x/ddr3_init.c +++ b/drivers/ddr/marvell/a38x/ddr3_init.c @@ -6,18 +6,6 @@ #include "ddr3_init.h" #include "mv_ddr_common.h" -/* - * Translates topology map definitions to real memory size in bits - * (per values in ddr3_training_ip_def.h) - */ -u32 mem_size[] = { - ADDR_SIZE_512MB, - ADDR_SIZE_1GB, - ADDR_SIZE_2GB, - ADDR_SIZE_4GB, - ADDR_SIZE_8GB -}; - static char *ddr_type = "DDR3"; /* @@ -37,8 +25,6 @@ static int mv_ddr_training_params_set(u8 dev_num); */ int ddr3_init(void) { - struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); - u32 octets_per_if_num; int status; int is_manual_cal_done; @@ -55,7 +41,7 @@ int ddr3_init(void) mv_ddr_early_init(); - if (mv_ddr_topology_map_update() == NULL) { + if (mv_ddr_topology_map_update()) { printf("mv_ddr: failed to update topology\n"); return MV_FAIL; } @@ -68,7 +54,6 @@ int ddr3_init(void) if (MV_OK != status) return status; - mv_ddr_mc_config(); is_manual_cal_done = mv_ddr_manual_cal_do(); @@ -101,76 +86,14 @@ int ddr3_init(void) mv_ddr_post_training_fixup(); - octets_per_if_num = ddr3_tip_dev_attr_get(0, MV_ATTR_OCTET_PER_INTERFACE); - if (ddr3_if_ecc_enabled()) { - if (MV_DDR_IS_64BIT_DRAM_MODE(tm->bus_act_mask) || - MV_DDR_IS_32BIT_IN_64BIT_DRAM_MODE(tm->bus_act_mask, octets_per_if_num)) - mv_ddr_mem_scrubbing(); - else - ddr3_new_tip_ecc_scrub(); - } + if (mv_ddr_is_ecc_ena()) + mv_ddr_mem_scrubbing(); printf("mv_ddr: completed successfully\n"); return MV_OK; } -uint64_t mv_ddr_get_memory_size_per_cs_in_bits(void) -{ - uint64_t memory_size_per_cs; - - u32 bus_cnt, num_of_active_bus = 0; - u32 num_of_sub_phys_per_ddr_unit = 0; - - struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); - - u32 octets_per_if_num = ddr3_tip_dev_attr_get(DEV_NUM_0, MV_ATTR_OCTET_PER_INTERFACE); - - /* count the number of active bus */ - for (bus_cnt = 0; bus_cnt < octets_per_if_num - 1/* ignore ecc octet */; bus_cnt++) { - VALIDATE_BUS_ACTIVE(tm->bus_act_mask, bus_cnt); - num_of_active_bus++; - } - - /* calculate number of sub-phys per ddr unit */ - if (tm->interface_params[0].bus_width/* supports only single interface */ == MV_DDR_DEV_WIDTH_16BIT) - num_of_sub_phys_per_ddr_unit = TWO_SUB_PHYS; - if (tm->interface_params[0].bus_width/* supports only single interface */ == MV_DDR_DEV_WIDTH_8BIT) - num_of_sub_phys_per_ddr_unit = SINGLE_SUB_PHY; - - /* calculate dram size per cs */ - memory_size_per_cs = (uint64_t)mem_size[tm->interface_params[0].memory_size] * (uint64_t)num_of_active_bus - / (uint64_t)num_of_sub_phys_per_ddr_unit * (uint64_t)MV_DDR_NUM_BITS_IN_BYTE; - - return memory_size_per_cs; -} - -uint64_t mv_ddr_get_total_memory_size_in_bits(void) -{ - uint64_t total_memory_size = 0; - uint64_t memory_size_per_cs = 0; - - /* get the number of cs */ - u32 max_cs = ddr3_tip_max_cs_get(DEV_NUM_0); - - memory_size_per_cs = mv_ddr_get_memory_size_per_cs_in_bits(); - total_memory_size = (uint64_t)max_cs * memory_size_per_cs; - - return total_memory_size; -} - -int ddr3_if_ecc_enabled(void) -{ - struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); - - if (DDR3_IS_ECC_PUP4_MODE(tm->bus_act_mask) || - DDR3_IS_ECC_PUP3_MODE(tm->bus_act_mask) || - DDR3_IS_ECC_PUP8_MODE(tm->bus_act_mask)) - return 1; - else - return 0; -} - /* * Name: mv_ddr_training_params_set * Desc: @@ -182,15 +105,9 @@ static int mv_ddr_training_params_set(u8 dev_num) { struct tune_train_params params; int status; - struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); - u32 if_id; u32 cs_num; - CHECK_STATUS(ddr3_tip_get_first_active_if - (dev_num, tm->if_act_mask, - &if_id)); - - CHECK_STATUS(calc_cs_num(dev_num, if_id, &cs_num)); + cs_num = mv_ddr_cs_num_get(); /* NOTE: do not remove any field initilization */ params.ck_delay = TUNE_TRAINING_PARAMS_CK_DELAY; diff --git a/drivers/ddr/marvell/a38x/ddr3_init.h b/drivers/ddr/marvell/a38x/ddr3_init.h index 382bd922f21..055516b67e9 100644 --- a/drivers/ddr/marvell/a38x/ddr3_init.h +++ b/drivers/ddr/marvell/a38x/ddr3_init.h @@ -7,9 +7,7 @@ #define _DDR3_INIT_H #include "ddr_ml_wrapper.h" -#if defined(CONFIG_ARMADA_38X) || defined(CONFIG_ARMADA_39X) #include "mv_ddr_plat.h" -#endif #include "seq_exec.h" #include "ddr3_logging_def.h" @@ -32,14 +30,8 @@ return status; \ } -#define GET_MAX_VALUE(x, y) \ - ((x) > (y)) ? (x) : (y) - #define SUB_VERSION 0 -/* max number of devices supported by driver */ -#define MAX_DEVICE_NUM 1 - enum log_level { MV_LOG_LEVEL_0, MV_LOG_LEVEL_1, @@ -47,24 +39,26 @@ enum log_level { MV_LOG_LEVEL_3 }; +/* TODO: consider to move to misl phy driver */ +#define MISL_PHY_DRV_P_OFFS 0x7 +#define MISL_PHY_DRV_N_OFFS 0x0 +#define MISL_PHY_ODT_P_OFFS 0x6 +#define MISL_PHY_ODT_N_OFFS 0x0 + /* Globals */ extern u8 debug_training, debug_calibration, debug_ddr4_centralization, debug_tap_tuning, debug_dm_tuning; extern u8 is_reg_dump; extern u8 generic_init_controller; -/* list of allowed frequency listed in order of enum hws_ddr_freq */ -extern u32 freq_val[DDR_FREQ_LAST]; +/* list of allowed frequency listed in order of enum mv_ddr_freq */ extern u32 is_pll_old; -extern struct cl_val_per_freq cas_latency_table[]; extern struct pattern_info pattern_table[]; -extern struct cl_val_per_freq cas_write_latency_table[]; extern u8 debug_centralization, debug_training_ip, debug_training_bist, debug_pbs, debug_training_static, debug_leveling; extern struct hws_tip_config_func_db config_func_info[]; extern u8 twr_mask_table[]; extern u8 cl_mask_table[]; extern u8 cwl_mask_table[]; -extern u16 rfc_table[]; extern u32 speed_bin_table_t_rc[]; extern u32 speed_bin_table_t_rcd_t_rp[]; @@ -90,10 +84,10 @@ extern u32 mask_tune_func; extern u32 rl_version; extern int rl_mid_freq_wa; extern u8 calibration_update_control; /* 2 external only, 1 is internal only */ -extern enum hws_ddr_freq medium_freq; +extern enum mv_ddr_freq medium_freq; extern enum hws_result training_result[MAX_STAGE_LIMIT][MAX_INTERFACE_NUM]; -extern enum hws_ddr_freq low_freq; +extern enum mv_ddr_freq low_freq; extern enum auto_tune_stage training_stage; extern u32 is_pll_before_init; extern u32 is_adll_calib_before_init; @@ -120,7 +114,7 @@ extern u32 odt_additional; extern u32 debug_mode; extern u32 debug_dunit; extern u32 clamp_tbl[]; -extern u32 freq_mask[MAX_DEVICE_NUM][DDR_FREQ_LAST]; +extern u32 freq_mask[MAX_DEVICE_NUM][MV_DDR_FREQ_LAST]; extern u32 maxt_poll_tries; extern u32 is_bist_reset_bit; @@ -139,7 +133,6 @@ extern u16 mask_results_dq_reg_map[]; extern u32 target_freq; extern u32 dfs_low_freq; -extern u32 mem_size[]; extern u32 nominal_avs; extern u32 extension_avs; @@ -154,13 +147,8 @@ int mv_ddr_early_init(void); int mv_ddr_early_init2(void); int ddr3_silicon_post_init(void); int ddr3_post_run_alg(void); -int ddr3_if_ecc_enabled(void); void ddr3_new_tip_ecc_scrub(void); -void mv_ddr_ver_print(void); -struct mv_ddr_topology_map *mv_ddr_topology_map_get(void); - -int ddr3_if_ecc_enabled(void); int ddr3_tip_reg_write(u32 dev_num, u32 reg_addr, u32 data); int ddr3_tip_reg_read(u32 dev_num, u32 reg_addr, u32 *data, u32 reg_mask); int ddr3_silicon_get_ddr_target_freq(u32 *ddr_freq); @@ -185,15 +173,20 @@ void get_target_freq(u32 freq_mode, u32 *ddr_freq, u32 *hclk_ps); void ddr3_fast_path_static_cs_size_config(u32 cs_ena); u32 mv_board_id_index_get(u32 board_id); void ddr3_set_log_level(u32 n_log_level); -int calc_cs_num(u32 dev_num, u32 if_id, u32 *cs_num); int hws_ddr3_cs_base_adr_calc(u32 if_id, u32 cs, u32 *cs_base_addr); int ddr3_tip_print_pbs_result(u32 dev_num, u32 cs_num, enum pbs_dir pbs_mode); int ddr3_tip_clean_pbs_result(u32 dev_num, enum pbs_dir pbs_mode); - -u32 mv_ddr_init_freq_get(void); void mv_ddr_mc_config(void); int mv_ddr_mc_init(void); void mv_ddr_set_calib_controller(void); +/* TODO: consider to move to misl phy driver */ +unsigned int mv_ddr_misl_phy_drv_data_p_get(void); +unsigned int mv_ddr_misl_phy_drv_data_n_get(void); +unsigned int mv_ddr_misl_phy_drv_ctrl_p_get(void); +unsigned int mv_ddr_misl_phy_drv_ctrl_n_get(void); +unsigned int mv_ddr_misl_phy_odt_p_get(void); +unsigned int mv_ddr_misl_phy_odt_n_get(void); + #endif /* _DDR3_INIT_H */ diff --git a/drivers/ddr/marvell/a38x/ddr3_topology_def.h b/drivers/ddr/marvell/a38x/ddr3_topology_def.h deleted file mode 100644 index 1963bae3e62..00000000000 --- a/drivers/ddr/marvell/a38x/ddr3_topology_def.h +++ /dev/null @@ -1,78 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) Marvell International Ltd. and its affiliates - */ - -#ifndef _DDR3_TOPOLOGY_DEF_H -#define _DDR3_TOPOLOGY_DEF_H - -#define DEV_NUM_0 0 - -/* TOPOLOGY */ -enum hws_speed_bin { - SPEED_BIN_DDR_800D, - SPEED_BIN_DDR_800E, - SPEED_BIN_DDR_1066E, - SPEED_BIN_DDR_1066F, - SPEED_BIN_DDR_1066G, - SPEED_BIN_DDR_1333F, - SPEED_BIN_DDR_1333G, - SPEED_BIN_DDR_1333H, - SPEED_BIN_DDR_1333J, - SPEED_BIN_DDR_1600G, - SPEED_BIN_DDR_1600H, - SPEED_BIN_DDR_1600J, - SPEED_BIN_DDR_1600K, - SPEED_BIN_DDR_1866J, - SPEED_BIN_DDR_1866K, - SPEED_BIN_DDR_1866L, - SPEED_BIN_DDR_1866M, - SPEED_BIN_DDR_2133K, - SPEED_BIN_DDR_2133L, - SPEED_BIN_DDR_2133M, - SPEED_BIN_DDR_2133N, - - SPEED_BIN_DDR_1333H_EXT, - SPEED_BIN_DDR_1600K_EXT, - SPEED_BIN_DDR_1866M_EXT -}; - -enum hws_ddr_freq { - DDR_FREQ_LOW_FREQ, - DDR_FREQ_400, - DDR_FREQ_533, - DDR_FREQ_667, - DDR_FREQ_800, - DDR_FREQ_933, - DDR_FREQ_1066, - DDR_FREQ_311, - DDR_FREQ_333, - DDR_FREQ_467, - DDR_FREQ_850, - DDR_FREQ_600, - DDR_FREQ_300, - DDR_FREQ_900, - DDR_FREQ_360, - DDR_FREQ_1000, - DDR_FREQ_LAST, - DDR_FREQ_SAR -}; - -enum speed_bin_table_elements { - SPEED_BIN_TRCD, - SPEED_BIN_TRP, - SPEED_BIN_TRAS, - SPEED_BIN_TRC, - SPEED_BIN_TRRD1K, - SPEED_BIN_TRRD2K, - SPEED_BIN_TPD, - SPEED_BIN_TFAW1K, - SPEED_BIN_TFAW2K, - SPEED_BIN_TWTR, - SPEED_BIN_TRTP, - SPEED_BIN_TWR, - SPEED_BIN_TMOD, - SPEED_BIN_TXPDLL -}; - -#endif /* _DDR3_TOPOLOGY_DEF_H */ diff --git a/drivers/ddr/marvell/a38x/ddr3_training.c b/drivers/ddr/marvell/a38x/ddr3_training.c index 799c5ba089a..c7be700d641 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training.c +++ b/drivers/ddr/marvell/a38x/ddr3_training.c @@ -5,6 +5,8 @@ #include "ddr3_init.h" #include "mv_ddr_common.h" +#include "mv_ddr_training_db.h" +#include "mv_ddr_regs.h" #define GET_CS_FROM_MASK(mask) (cs_mask2_num[mask]) #define CS_CBE_VALUE(cs_num) (cs_cbe_reg[cs_num]) @@ -14,8 +16,8 @@ u32 phy_reg0_val = 0; u32 phy_reg1_val = 8; u32 phy_reg2_val = 0; u32 phy_reg3_val = PARAM_UNDEFINED; -enum hws_ddr_freq low_freq = DDR_FREQ_LOW_FREQ; -enum hws_ddr_freq medium_freq; +enum mv_ddr_freq low_freq = MV_DDR_FREQ_LOW_FREQ; +enum mv_ddr_freq medium_freq; u32 debug_dunit = 0; u32 odt_additional = 1; u32 *dq_map_table = NULL; @@ -97,36 +99,9 @@ static int odt_test(u32 dev_num, enum hws_algo_type algo_type); #endif int adll_calibration(u32 dev_num, enum hws_access_type access_type, - u32 if_id, enum hws_ddr_freq frequency); + u32 if_id, enum mv_ddr_freq frequency); static int ddr3_tip_set_timing(u32 dev_num, enum hws_access_type access_type, - u32 if_id, enum hws_ddr_freq frequency); - -static struct page_element page_tbl[] = { - /* - * 8bits 16 bits - * page-size(K) page-size(K) mask - */ - { 1, 2, 2}, - /* 512M */ - { 1, 2, 3}, - /* 1G */ - { 1, 2, 0}, - /* 2G */ - { 1, 2, 4}, - /* 4G */ - { 2, 2, 5}, - /* 8G */ - {0, 0, 0}, /* TODO: placeholder for 16-Mbit die capacity */ - {0, 0, 0}, /* TODO: placeholder for 32-Mbit die capacity */ - {0, 0, 0}, /* TODO: placeholder for 12-Mbit die capacity */ - {0, 0, 0} /* TODO: placeholder for 24-Mbit die capacity */ - -}; - -struct page_element *mv_ddr_page_tbl_get(void) -{ - return &page_tbl[0]; -} + u32 if_id, enum mv_ddr_freq frequency); static u8 mem_size_config[MV_DDR_DIE_CAP_LAST] = { 0x2, /* 512Mbit */ @@ -204,7 +179,52 @@ struct mv_ddr_mr_data mr_data[] = { {MRS3_CMD, MR3_REG} }; -static int ddr3_tip_pad_inv(u32 dev_num, u32 if_id); +/* inverse pads */ +static int ddr3_tip_pad_inv(void) +{ + u32 sphy, data; + u32 sphy_max = ddr3_tip_dev_attr_get(0, MV_ATTR_OCTET_PER_INTERFACE); + u32 ck_swap_ctrl_sphy; + struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); + + for (sphy = 0; sphy < sphy_max; sphy++) { + VALIDATE_BUS_ACTIVE(tm->bus_act_mask, sphy); + if (tm->interface_params[0]. + as_bus_params[sphy].is_dqs_swap == 1) { + data = (INVERT_PAD << INV_PAD4_OFFS | + INVERT_PAD << INV_PAD5_OFFS); + /* dqs swap */ + ddr3_tip_bus_read_modify_write(0, ACCESS_TYPE_UNICAST, + 0, sphy, + DDR_PHY_DATA, + PHY_CTRL_PHY_REG, + data, data); + } + + if (tm->interface_params[0].as_bus_params[sphy]. + is_ck_swap == 1 && sphy == 0) { +/* TODO: move this code to per platform one */ +#if defined(CONFIG_ARMADA_38X) || defined(CONFIG_ARMADA_39X) + /* clock swap for both cs0 and cs1 */ + data = (INVERT_PAD << INV_PAD2_OFFS | + INVERT_PAD << INV_PAD6_OFFS | + INVERT_PAD << INV_PAD4_OFFS | + INVERT_PAD << INV_PAD5_OFFS); + ck_swap_ctrl_sphy = CK_SWAP_CTRL_PHY_NUM; + ddr3_tip_bus_read_modify_write(0, ACCESS_TYPE_UNICAST, + 0, ck_swap_ctrl_sphy, + DDR_PHY_CONTROL, + PHY_CTRL_PHY_REG, + data, data); +#else /* !CONFIG_ARMADA_38X && !CONFIG_ARMADA_39X && !A70X0 && !A80X0 && !A3900 */ +#pragma message "unknown platform to configure ddr clock swap" +#endif + } + } + + return MV_OK; +} + static int ddr3_tip_rank_control(u32 dev_num, u32 if_id); /* @@ -244,6 +264,7 @@ int ddr3_tip_tune_training_params(u32 dev_num, if (params->g_rtt_park != PARAM_UNDEFINED) g_rtt_park = params->g_rtt_park; + DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("DGL parameters: 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n", g_zpri_data, g_znri_data, g_zpri_ctrl, g_znri_ctrl, g_zpodt_data, g_znodt_data, @@ -309,44 +330,6 @@ int ddr3_tip_configure_cs(u32 dev_num, u32 if_id, u32 cs_num, u32 enable) } /* - * Calculate number of CS - */ -int calc_cs_num(u32 dev_num, u32 if_id, u32 *cs_num) -{ - u32 cs; - u32 bus_cnt; - u32 cs_count; - u32 cs_bitmask; - u32 curr_cs_num = 0; - u32 octets_per_if_num = ddr3_tip_dev_attr_get(dev_num, MV_ATTR_OCTET_PER_INTERFACE); - struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); - - for (bus_cnt = 0; bus_cnt < octets_per_if_num; bus_cnt++) { - VALIDATE_BUS_ACTIVE(tm->bus_act_mask, bus_cnt); - cs_count = 0; - cs_bitmask = tm->interface_params[if_id]. - as_bus_params[bus_cnt].cs_bitmask; - for (cs = 0; cs < MAX_CS_NUM; cs++) { - if ((cs_bitmask >> cs) & 1) - cs_count++; - } - - if (curr_cs_num == 0) { - curr_cs_num = cs_count; - } else if (cs_count != curr_cs_num) { - DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, - ("CS number is different per bus (IF %d BUS %d cs_num %d curr_cs_num %d)\n", - if_id, bus_cnt, cs_count, - curr_cs_num)); - return MV_NOT_SUPPORTED; - } - } - *cs_num = curr_cs_num; - - return MV_OK; -} - -/* * Init Controller Flow */ int hws_ddr3_tip_init_controller(u32 dev_num, struct init_cntr_param *init_cntr_prm) @@ -356,7 +339,7 @@ int hws_ddr3_tip_init_controller(u32 dev_num, struct init_cntr_param *init_cntr_ u32 t_ckclk = 0, t_wr = 0, t2t = 0; u32 data_value = 0, cs_cnt = 0, mem_mask = 0, bus_index = 0; - enum hws_speed_bin speed_bin_index = SPEED_BIN_DDR_2133N; + enum mv_ddr_speed_bin speed_bin_index = SPEED_BIN_DDR_2133N; u32 cs_mask = 0; u32 cl_value = 0, cwl_val = 0; u32 bus_cnt = 0, adll_tap = 0; @@ -364,8 +347,8 @@ int hws_ddr3_tip_init_controller(u32 dev_num, struct init_cntr_param *init_cntr_ u32 data_read[MAX_INTERFACE_NUM]; u32 octets_per_if_num = ddr3_tip_dev_attr_get(dev_num, MV_ATTR_OCTET_PER_INTERFACE); struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); - enum hws_ddr_freq freq = tm->interface_params[0].memory_freq; enum mv_ddr_timing timing; + enum mv_ddr_freq freq = tm->interface_params[0].memory_freq; DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE, ("Init_controller, do_mrs_phy=%d, is_ctrl64_bit=%d\n", @@ -403,7 +386,7 @@ int hws_ddr3_tip_init_controller(u32 dev_num, struct init_cntr_param *init_cntr_ speed_bin_index; /* t_ckclk is external clock */ - t_ckclk = (MEGA / freq_val[freq]); + t_ckclk = (MEGA / mv_ddr_freq_get(freq)); if (MV_DDR_IS_HALF_BUS_DRAM_MODE(tm->bus_act_mask, octets_per_if_num)) data_value = (0x4000 | 0 | 0x1000000) & ~(1 << 26); @@ -508,7 +491,7 @@ int hws_ddr3_tip_init_controller(u32 dev_num, struct init_cntr_param *init_cntr_ * configure them both: The Bust_width it\92s the * Memory Bus width \96 x8 or x16 */ - for (cs_cnt = 0; cs_cnt < NUM_OF_CS; cs_cnt++) { + for (cs_cnt = 0; cs_cnt < MAX_CS_NUM; cs_cnt++) { ddr3_tip_configure_cs(dev_num, if_id, cs_cnt, ((cs_mask & (1 << cs_cnt)) ? 1 : 0)); @@ -534,7 +517,7 @@ int hws_ddr3_tip_init_controller(u32 dev_num, struct init_cntr_param *init_cntr_ ("cl_value 0x%x cwl_val 0x%x\n", cl_value, cwl_val)); - t_wr = time_to_nclk(speed_bin_table + t_wr = time_to_nclk(mv_ddr_speed_bin_timing_get (speed_bin_index, SPEED_BIN_TWR), t_ckclk); @@ -612,8 +595,7 @@ int hws_ddr3_tip_init_controller(u32 dev_num, struct init_cntr_param *init_cntr_ t2t = (timing == MV_DDR_TIM_2T) ? 1 : 0; } else { /* calculate number of CS (per interface) */ - CHECK_STATUS(calc_cs_num - (dev_num, if_id, &cs_num)); + cs_num = mv_ddr_cs_num_get(); t2t = (cs_num == 1) ? 0 : 1; } @@ -666,9 +648,8 @@ int hws_ddr3_tip_init_controller(u32 dev_num, struct init_cntr_param *init_cntr_ VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id); CHECK_STATUS(ddr3_tip_rank_control(dev_num, if_id)); - if (init_cntr_prm->do_mrs_phy) { - CHECK_STATUS(ddr3_tip_pad_inv(dev_num, if_id)); - } + if (init_cntr_prm->do_mrs_phy) + ddr3_tip_pad_inv(); /* Pad calibration control - disable */ CHECK_STATUS(ddr3_tip_if_write @@ -682,7 +663,7 @@ int hws_ddr3_tip_init_controller(u32 dev_num, struct init_cntr_param *init_cntr_ if (delay_enable != 0) { - adll_tap = MEGA / (freq_val[freq] * 64); + adll_tap = MEGA / (mv_ddr_freq_get(freq) * 64); ddr3_tip_cmd_addr_init_delay(dev_num, adll_tap); } @@ -788,48 +769,6 @@ static int ddr3_tip_rank_control(u32 dev_num, u32 if_id) } /* - * PAD Inverse Flow - */ -static int ddr3_tip_pad_inv(u32 dev_num, u32 if_id) -{ - u32 bus_cnt, data_value, ck_swap_pup_ctrl; - u32 octets_per_if_num = ddr3_tip_dev_attr_get(dev_num, MV_ATTR_OCTET_PER_INTERFACE); - struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); - - for (bus_cnt = 0; bus_cnt < octets_per_if_num; bus_cnt++) { - VALIDATE_BUS_ACTIVE(tm->bus_act_mask, bus_cnt); - if (tm->interface_params[if_id]. - as_bus_params[bus_cnt].is_dqs_swap == 1) { - /* dqs swap */ - ddr3_tip_bus_read_modify_write(dev_num, ACCESS_TYPE_UNICAST, - if_id, bus_cnt, - DDR_PHY_DATA, - PHY_CTRL_PHY_REG, 0xc0, - 0xc0); - } - - if (tm->interface_params[if_id]. - as_bus_params[bus_cnt].is_ck_swap == 1) { - if (bus_cnt <= 1) - data_value = 0x5 << 2; - else - data_value = 0xa << 2; - - /* mask equals data */ - /* ck swap pup is only control pup #0 ! */ - ck_swap_pup_ctrl = 0; - ddr3_tip_bus_read_modify_write(dev_num, ACCESS_TYPE_UNICAST, - if_id, ck_swap_pup_ctrl, - DDR_PHY_CONTROL, - PHY_CTRL_PHY_REG, - data_value, data_value); - } - } - - return MV_OK; -} - -/* * Algorithm Parameters Validation */ int ddr3_tip_validate_algo_var(u32 value, u32 fail_value, char *var_name) @@ -1182,7 +1121,7 @@ int ddr3_tip_bus_read_modify_write(u32 dev_num, enum hws_access_type access_type * ADLL Calibration */ int adll_calibration(u32 dev_num, enum hws_access_type access_type, - u32 if_id, enum hws_ddr_freq frequency) + u32 if_id, enum mv_ddr_freq frequency) { struct hws_tip_freq_config_info freq_config_info; u32 bus_cnt = 0; @@ -1229,7 +1168,7 @@ int adll_calibration(u32 dev_num, enum hws_access_type access_type, CHECK_STATUS(ddr3_tip_if_write (dev_num, access_type, if_id, DRAM_PHY_CFG_REG, 0, (0x80000000 | 0x40000000))); - mdelay(100 / (freq_val[frequency] / freq_val[DDR_FREQ_LOW_FREQ])); + mdelay(100 / (mv_ddr_freq_get(frequency)) / mv_ddr_freq_get(MV_DDR_FREQ_LOW_FREQ)); CHECK_STATUS(ddr3_tip_if_write (dev_num, access_type, if_id, DRAM_PHY_CFG_REG, (0x80000000 | 0x40000000), (0x80000000 | 0x40000000))); @@ -1255,7 +1194,7 @@ int adll_calibration(u32 dev_num, enum hws_access_type access_type, } int ddr3_tip_freq_set(u32 dev_num, enum hws_access_type access_type, - u32 if_id, enum hws_ddr_freq frequency) + u32 if_id, enum mv_ddr_freq frequency) { u32 cl_value = 0, cwl_value = 0, mem_mask = 0, val = 0, bus_cnt = 0, t_wr = 0, t_ckclk = 0, @@ -1263,7 +1202,7 @@ int ddr3_tip_freq_set(u32 dev_num, enum hws_access_type access_type, u32 end_if, start_if; u32 bus_index = 0; int is_dll_off = 0; - enum hws_speed_bin speed_bin_index = 0; + enum mv_ddr_speed_bin speed_bin_index = 0; struct hws_tip_freq_config_info freq_config_info; enum hws_result *flow_result = training_result[training_stage]; u32 adll_tap = 0; @@ -1274,12 +1213,13 @@ int ddr3_tip_freq_set(u32 dev_num, enum hws_access_type access_type, struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); unsigned int tclk; enum mv_ddr_timing timing = tm->interface_params[if_id].timing; + u32 freq = mv_ddr_freq_get(frequency); DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE, ("dev %d access %d IF %d freq %d\n", dev_num, access_type, if_id, frequency)); - if (frequency == DDR_FREQ_LOW_FREQ) + if (frequency == MV_DDR_FREQ_LOW_FREQ) is_dll_off = 1; if (access_type == ACCESS_TYPE_MULTICAST) { start_if = 0; @@ -1318,7 +1258,7 @@ int ddr3_tip_freq_set(u32 dev_num, enum hws_access_type access_type, cwl_value = tm->interface_params[if_id].cas_wl; } else if (tm->cfg_src == MV_DDR_CFG_SPD) { - tclk = 1000000 / freq_val[frequency]; + tclk = 1000000 / freq; cl_value = mv_ddr_cl_calc(tm->timing_data[MV_DDR_TAA_MIN], tclk); if (cl_value == 0) { printf("mv_ddr: unsupported cas latency value found\n"); @@ -1330,11 +1270,8 @@ int ddr3_tip_freq_set(u32 dev_num, enum hws_access_type access_type, return MV_FAIL; } } else { - cl_value = - cas_latency_table[speed_bin_index].cl_val[frequency]; - cwl_value = - cas_write_latency_table[speed_bin_index]. - cl_val[frequency]; + cl_value = mv_ddr_cl_val_get(speed_bin_index, frequency); + cwl_value = mv_ddr_cwl_val_get(speed_bin_index, frequency); } DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE, @@ -1342,11 +1279,9 @@ int ddr3_tip_freq_set(u32 dev_num, enum hws_access_type access_type, dev_num, access_type, if_id, frequency, speed_bin_index)); - for (cnt_id = 0; cnt_id < DDR_FREQ_LAST; cnt_id++) { + for (cnt_id = 0; cnt_id < MV_DDR_FREQ_LAST; cnt_id++) { DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE, - ("%d ", - cas_latency_table[speed_bin_index]. - cl_val[cnt_id])); + ("%d ", mv_ddr_cl_val_get(speed_bin_index, cnt_id))); } DEBUG_TRAINING_IP(DEBUG_LEVEL_TRACE, ("\n")); @@ -1420,7 +1355,7 @@ int ddr3_tip_freq_set(u32 dev_num, enum hws_access_type access_type, t2t = (timing == MV_DDR_TIM_2T) ? 1 : 0; } else { /* Calculate number of CS per interface */ - CHECK_STATUS(calc_cs_num(dev_num, if_id, &cs_num)); + cs_num = mv_ddr_cs_num_get(); t2t = (cs_num == 1) ? 0 : 1; } @@ -1455,8 +1390,8 @@ int ddr3_tip_freq_set(u32 dev_num, enum hws_access_type access_type, (dev_num, access_type, if_id, DFS_REG, (cwl_mask_table[cwl_value] << 12), 0x7000)); - t_ckclk = (MEGA / freq_val[frequency]); - t_wr = time_to_nclk(speed_bin_table + t_ckclk = (MEGA / freq); + t_wr = time_to_nclk(mv_ddr_speed_bin_timing_get (speed_bin_index, SPEED_BIN_TWR), t_ckclk); @@ -1517,7 +1452,7 @@ int ddr3_tip_freq_set(u32 dev_num, enum hws_access_type access_type, (dev_num, access_type, if_id, DRAM_PHY_CFG_REG, 0, (0x80000000 | 0x40000000))); - mdelay(100 / (freq_val[frequency] / freq_val[DDR_FREQ_LOW_FREQ])); + mdelay(100 / (freq / mv_ddr_freq_get(MV_DDR_FREQ_LOW_FREQ))); CHECK_STATUS(ddr3_tip_if_write (dev_num, access_type, if_id, DRAM_PHY_CFG_REG, (0x80000000 | 0x40000000), @@ -1544,7 +1479,7 @@ int ddr3_tip_freq_set(u32 dev_num, enum hws_access_type access_type, /* Set proper timing params before existing Self-Refresh */ ddr3_tip_set_timing(dev_num, access_type, if_id, frequency); if (delay_enable != 0) { - adll_tap = (is_dll_off == 1) ? 1000 : (MEGA / (freq_val[frequency] * 64)); + adll_tap = (is_dll_off == 1) ? 1000 : (MEGA / (freq * 64)); ddr3_tip_cmd_addr_init_delay(dev_num, adll_tap); } @@ -1682,7 +1617,7 @@ static int ddr3_tip_write_odt(u32 dev_num, enum hws_access_type access_type, * Set Timing values for training */ static int ddr3_tip_set_timing(u32 dev_num, enum hws_access_type access_type, - u32 if_id, enum hws_ddr_freq frequency) + u32 if_id, enum mv_ddr_freq frequency) { u32 t_ckclk = 0, t_ras = 0; u32 t_rcd = 0, t_rp = 0, t_wr = 0, t_wtr = 0, t_rrd = 0, t_rtp = 0, @@ -1690,66 +1625,63 @@ static int ddr3_tip_set_timing(u32 dev_num, enum hws_access_type access_type, t_r2w_w2r = 0x3, t_r2w_w2r_high = 0x1, t_w2w = 0x3; u32 refresh_interval_cnt, t_hclk, t_refi, t_faw, t_pd, t_xpdll; u32 val = 0, page_size = 0, mask = 0; - enum hws_speed_bin speed_bin_index; + enum mv_ddr_speed_bin speed_bin_index; enum mv_ddr_die_capacity memory_size = MV_DDR_DIE_CAP_2GBIT; struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); - struct page_element *page_param = mv_ddr_page_tbl_get(); + u32 freq = mv_ddr_freq_get(frequency); speed_bin_index = tm->interface_params[if_id].speed_bin_index; memory_size = tm->interface_params[if_id].memory_size; - page_size = - (tm->interface_params[if_id].bus_width == - MV_DDR_DEV_WIDTH_8BIT) ? page_param[memory_size]. - page_size_8bit : page_param[memory_size].page_size_16bit; - t_ckclk = (MEGA / freq_val[frequency]); + page_size = mv_ddr_page_size_get(tm->interface_params[if_id].bus_width, memory_size); + t_ckclk = (MEGA / freq); /* HCLK in[ps] */ - t_hclk = MEGA / (freq_val[frequency] / config_func_info[dev_num].tip_get_clock_ratio(frequency)); + t_hclk = MEGA / (freq / config_func_info[dev_num].tip_get_clock_ratio(frequency)); t_refi = (tm->interface_params[if_id].interface_temp == MV_DDR_TEMP_HIGH) ? TREFI_HIGH : TREFI_LOW; t_refi *= 1000; /* psec */ refresh_interval_cnt = t_refi / t_hclk; /* no units */ if (page_size == 1) { - t_faw = speed_bin_table(speed_bin_index, SPEED_BIN_TFAW1K); + t_faw = mv_ddr_speed_bin_timing_get(speed_bin_index, SPEED_BIN_TFAW1K); t_faw = time_to_nclk(t_faw, t_ckclk); t_faw = GET_MAX_VALUE(20, t_faw); } else { /* page size =2, we do not support page size 0.5k */ - t_faw = speed_bin_table(speed_bin_index, SPEED_BIN_TFAW2K); + t_faw = mv_ddr_speed_bin_timing_get(speed_bin_index, SPEED_BIN_TFAW2K); t_faw = time_to_nclk(t_faw, t_ckclk); t_faw = GET_MAX_VALUE(28, t_faw); } - t_pd = GET_MAX_VALUE(t_ckclk * 3, speed_bin_table(speed_bin_index, SPEED_BIN_TPD)); + t_pd = GET_MAX_VALUE(t_ckclk * 3, mv_ddr_speed_bin_timing_get(speed_bin_index, SPEED_BIN_TPD)); t_pd = time_to_nclk(t_pd, t_ckclk); - t_xpdll = GET_MAX_VALUE(t_ckclk * 10, speed_bin_table(speed_bin_index, SPEED_BIN_TXPDLL)); + t_xpdll = GET_MAX_VALUE(t_ckclk * 10, mv_ddr_speed_bin_timing_get(speed_bin_index, SPEED_BIN_TXPDLL)); t_xpdll = time_to_nclk(t_xpdll, t_ckclk); - t_rrd = (page_size == 1) ? speed_bin_table(speed_bin_index, + t_rrd = (page_size == 1) ? mv_ddr_speed_bin_timing_get(speed_bin_index, SPEED_BIN_TRRD1K) : - speed_bin_table(speed_bin_index, SPEED_BIN_TRRD2K); + mv_ddr_speed_bin_timing_get(speed_bin_index, SPEED_BIN_TRRD2K); t_rrd = GET_MAX_VALUE(t_ckclk * 4, t_rrd); - t_rtp = GET_MAX_VALUE(t_ckclk * 4, speed_bin_table(speed_bin_index, + t_rtp = GET_MAX_VALUE(t_ckclk * 4, mv_ddr_speed_bin_timing_get(speed_bin_index, SPEED_BIN_TRTP)); t_mod = GET_MAX_VALUE(t_ckclk * 12, 15000); - t_wtr = GET_MAX_VALUE(t_ckclk * 4, speed_bin_table(speed_bin_index, + t_wtr = GET_MAX_VALUE(t_ckclk * 4, mv_ddr_speed_bin_timing_get(speed_bin_index, SPEED_BIN_TWTR)); - t_ras = time_to_nclk(speed_bin_table(speed_bin_index, + t_ras = time_to_nclk(mv_ddr_speed_bin_timing_get(speed_bin_index, SPEED_BIN_TRAS), t_ckclk); - t_rcd = time_to_nclk(speed_bin_table(speed_bin_index, + t_rcd = time_to_nclk(mv_ddr_speed_bin_timing_get(speed_bin_index, SPEED_BIN_TRCD), t_ckclk); - t_rp = time_to_nclk(speed_bin_table(speed_bin_index, + t_rp = time_to_nclk(mv_ddr_speed_bin_timing_get(speed_bin_index, SPEED_BIN_TRP), t_ckclk); - t_wr = time_to_nclk(speed_bin_table(speed_bin_index, + t_wr = time_to_nclk(mv_ddr_speed_bin_timing_get(speed_bin_index, SPEED_BIN_TWR), t_ckclk); t_wtr = time_to_nclk(t_wtr, t_ckclk); t_rrd = time_to_nclk(t_rrd, t_ckclk); t_rtp = time_to_nclk(t_rtp, t_ckclk); - t_rfc = time_to_nclk(rfc_table[memory_size] * 1000, t_ckclk); + t_rfc = time_to_nclk(mv_ddr_rfc_get(memory_size) * 1000, t_ckclk); t_mod = time_to_nclk(t_mod, t_ckclk); /* SDRAM Timing Low */ @@ -1827,68 +1759,6 @@ static int ddr3_tip_set_timing(u32 dev_num, enum hws_access_type access_type, /* - * Mode Read - */ -int hws_ddr3_tip_mode_read(u32 dev_num, struct mode_info *mode_info) -{ - u32 ret; - - ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, - MR0_REG, mode_info->reg_mr0, MASK_ALL_BITS); - if (ret != MV_OK) - return ret; - - ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, - MR1_REG, mode_info->reg_mr1, MASK_ALL_BITS); - if (ret != MV_OK) - return ret; - - ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, - MR2_REG, mode_info->reg_mr2, MASK_ALL_BITS); - if (ret != MV_OK) - return ret; - - ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, - MR3_REG, mode_info->reg_mr2, MASK_ALL_BITS); - if (ret != MV_OK) - return ret; - - ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, - RD_DATA_SMPL_DLYS_REG, mode_info->read_data_sample, - MASK_ALL_BITS); - if (ret != MV_OK) - return ret; - - ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, - RD_DATA_RDY_DLYS_REG, mode_info->read_data_ready, - MASK_ALL_BITS); - if (ret != MV_OK) - return ret; - - return MV_OK; -} - -/* - * Get first active IF - */ -int ddr3_tip_get_first_active_if(u8 dev_num, u32 interface_mask, - u32 *interface_id) -{ - u32 if_id; - struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); - - for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { - VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id); - if (interface_mask & (1 << if_id)) { - *interface_id = if_id; - break; - } - } - - return MV_OK; -} - -/* * Write CS Result */ int ddr3_tip_write_cs_result(u32 dev_num, u32 offset) @@ -2139,9 +2009,10 @@ static int ddr3_tip_ddr3_training_main_flow(u32 dev_num) int ret = MV_OK; int adll_bypass_flag = 0; u32 if_id; - u32 max_cs = ddr3_tip_max_cs_get(dev_num); + unsigned int max_cs = mv_ddr_cs_num_get(); struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); - enum hws_ddr_freq freq = tm->interface_params[0].memory_freq; + enum mv_ddr_freq freq = tm->interface_params[0].memory_freq; + unsigned int *freq_tbl = mv_ddr_freq_tbl_get(); #ifdef DDR_VIEWER_TOOL if (debug_training == DEBUG_LEVEL_TRACE) { @@ -2157,7 +2028,7 @@ static int ddr3_tip_ddr3_training_main_flow(u32 dev_num) /* Set to 0 after each loop to avoid illegal value may be used */ effective_cs = 0; - freq_val[DDR_FREQ_LOW_FREQ] = dfs_low_freq; + freq_tbl[MV_DDR_FREQ_LOW_FREQ] = dfs_low_freq; if (is_pll_before_init != 0) { for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) { @@ -2220,7 +2091,7 @@ static int ddr3_tip_ddr3_training_main_flow(u32 dev_num) DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("SET_LOW_FREQ_MASK_BIT %d\n", - freq_val[low_freq])); + freq_tbl[low_freq])); ret = ddr3_tip_freq_set(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, low_freq); if (is_reg_dump != 0) @@ -2281,7 +2152,7 @@ static int ddr3_tip_ddr3_training_main_flow(u32 dev_num) training_stage = SET_MEDIUM_FREQ; DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("SET_MEDIUM_FREQ_MASK_BIT %d\n", - freq_val[medium_freq])); + freq_tbl[medium_freq])); ret = ddr3_tip_freq_set(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, medium_freq); @@ -2299,7 +2170,7 @@ static int ddr3_tip_ddr3_training_main_flow(u32 dev_num) training_stage = WRITE_LEVELING; DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("WRITE_LEVELING_MASK_BIT\n")); - if ((rl_mid_freq_wa == 0) || (freq_val[medium_freq] == 533)) { + if ((rl_mid_freq_wa == 0) || (freq_tbl[medium_freq] == 533)) { ret = ddr3_tip_dynamic_write_leveling(dev_num, 0); } else { /* Use old WL */ @@ -2341,7 +2212,7 @@ static int ddr3_tip_ddr3_training_main_flow(u32 dev_num) training_stage = READ_LEVELING; DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("READ_LEVELING_MASK_BIT\n")); - if ((rl_mid_freq_wa == 0) || (freq_val[medium_freq] == 533)) { + if ((rl_mid_freq_wa == 0) || (freq_tbl[medium_freq] == 533)) { ret = ddr3_tip_dynamic_read_leveling(dev_num, medium_freq); } else { /* Use old RL */ @@ -2417,19 +2288,13 @@ static int ddr3_tip_ddr3_training_main_flow(u32 dev_num) training_stage = SET_TARGET_FREQ; DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("SET_TARGET_FREQ_MASK_BIT %d\n", - freq_val[tm-> + freq_tbl[tm-> interface_params[first_active_if]. memory_freq])); ret = ddr3_tip_freq_set(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, tm->interface_params[first_active_if]. memory_freq); -#if defined(A70X0) || defined(A80X0) - if (apn806_rev_id_get() == APN806_REV_ID_A0) { - reg_write(0x6f812c, extension_avs); - reg_write(0x6f8130, nominal_avs); - } -#endif /* #if defined(A70X0) || defined(A80X0) */ if (is_reg_dump != 0) ddr3_tip_reg_dump(dev_num); if (ret != MV_OK) { @@ -2892,3 +2757,140 @@ int hws_ddr3_cs_base_adr_calc(u32 if_id, u32 cs, u32 *cs_base_addr) return MV_OK; } + +/* TODO: consider to move to misl phy driver */ +enum { + MISL_PHY_DRV_OHM_30 = 0xf, + MISL_PHY_DRV_OHM_48 = 0xa, + MISL_PHY_DRV_OHM_80 = 0x6, + MISL_PHY_DRV_OHM_120 = 0x4 +}; + +enum { + MISL_PHY_ODT_OHM_60 = 0x8, + MISL_PHY_ODT_OHM_80 = 0x6, + MISL_PHY_ODT_OHM_120 = 0x4, + MISL_PHY_ODT_OHM_240 = 0x2 +}; + +static unsigned int mv_ddr_misl_phy_drv_calc(unsigned int cfg) +{ + unsigned int val; + + switch (cfg) { + case MV_DDR_OHM_30: + val = MISL_PHY_DRV_OHM_30; + break; + case MV_DDR_OHM_48: + val = MISL_PHY_DRV_OHM_48; + break; + case MV_DDR_OHM_80: + val = MISL_PHY_DRV_OHM_80; + break; + case MV_DDR_OHM_120: + val = MISL_PHY_DRV_OHM_120; + break; + default: + val = PARAM_UNDEFINED; + } + + return val; +} + +static unsigned int mv_ddr_misl_phy_odt_calc(unsigned int cfg) +{ + unsigned int val; + + switch (cfg) { + case MV_DDR_OHM_60: + val = MISL_PHY_ODT_OHM_60; + break; + case MV_DDR_OHM_80: + val = MISL_PHY_ODT_OHM_80; + break; + case MV_DDR_OHM_120: + val = MISL_PHY_ODT_OHM_120; + break; + case MV_DDR_OHM_240: + val = MISL_PHY_ODT_OHM_240; + break; + default: + val = PARAM_UNDEFINED; + } + + return val; +} + +unsigned int mv_ddr_misl_phy_drv_data_p_get(void) +{ + struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); + unsigned int drv_data_p = mv_ddr_misl_phy_drv_calc(tm->edata.phy_edata.drv_data_p); + + if (drv_data_p == PARAM_UNDEFINED) + printf("error: %s: unsupported drv_data_p parameter found\n", __func__); + + return drv_data_p; +} + +unsigned int mv_ddr_misl_phy_drv_data_n_get(void) +{ + struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); + unsigned int drv_data_n = mv_ddr_misl_phy_drv_calc(tm->edata.phy_edata.drv_data_n); + + if (drv_data_n == PARAM_UNDEFINED) + printf("error: %s: unsupported drv_data_n parameter found\n", __func__); + + return drv_data_n; +} + +unsigned int mv_ddr_misl_phy_drv_ctrl_p_get(void) +{ + struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); + unsigned int drv_ctrl_p = mv_ddr_misl_phy_drv_calc(tm->edata.phy_edata.drv_ctrl_p); + + if (drv_ctrl_p == PARAM_UNDEFINED) + printf("error: %s: unsupported drv_ctrl_p parameter found\n", __func__); + + return drv_ctrl_p; +} + +unsigned int mv_ddr_misl_phy_drv_ctrl_n_get(void) +{ + struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); + unsigned int drv_ctrl_n = mv_ddr_misl_phy_drv_calc(tm->edata.phy_edata.drv_ctrl_n); + + if (drv_ctrl_n == PARAM_UNDEFINED) + printf("error: %s: unsupported drv_ctrl_n parameter found\n", __func__); + + return drv_ctrl_n; +} + +unsigned int mv_ddr_misl_phy_odt_p_get(void) +{ + struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); + unsigned int cs_num = mv_ddr_cs_num_get(); + unsigned int odt_p = PARAM_UNDEFINED; + + if (cs_num > 0 && cs_num <= MAX_CS_NUM) + odt_p = mv_ddr_misl_phy_odt_calc(tm->edata.phy_edata.odt_p[cs_num - 1]); + + if (odt_p == PARAM_UNDEFINED) + printf("error: %s: unsupported odt_p parameter found\n", __func__); + + return odt_p; +} + +unsigned int mv_ddr_misl_phy_odt_n_get(void) +{ + struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); + unsigned int cs_num = mv_ddr_cs_num_get(); + unsigned int odt_n = PARAM_UNDEFINED; + + if (cs_num > 0 && cs_num <= MAX_CS_NUM) + odt_n = mv_ddr_misl_phy_odt_calc(tm->edata.phy_edata.odt_n[cs_num - 1]); + + if (odt_n == PARAM_UNDEFINED) + printf("error: %s: unsupported odt_n parameter found\n", __func__); + + return odt_n; +} diff --git a/drivers/ddr/marvell/a38x/ddr3_training_bist.c b/drivers/ddr/marvell/a38x/ddr3_training_bist.c index e29b1713f9a..d388a172918 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training_bist.c +++ b/drivers/ddr/marvell/a38x/ddr3_training_bist.c @@ -4,6 +4,7 @@ */ #include "ddr3_init.h" +#include "mv_ddr_regs.h" static u32 bist_offset = 32; enum hws_pattern sweep_pattern = PATTERN_KILLER_DQ0; diff --git a/drivers/ddr/marvell/a38x/ddr3_training_centralization.c b/drivers/ddr/marvell/a38x/ddr3_training_centralization.c index 03e5c9fdcea..648b37ef6f7 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training_centralization.c +++ b/drivers/ddr/marvell/a38x/ddr3_training_centralization.c @@ -4,6 +4,7 @@ */ #include "ddr3_init.h" +#include "mv_ddr_regs.h" #define VALIDATE_WIN_LENGTH(e1, e2, maxsize) \ (((e2) + 1 > (e1) + (u8)MIN_WINDOW_SIZE) && \ @@ -698,6 +699,8 @@ int ddr3_tip_print_centralization_result(u32 dev_num) u32 octets_per_if_num = ddr3_tip_dev_attr_get(dev_num, MV_ATTR_OCTET_PER_INTERFACE); struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); + dev_num = dev_num; + printf("Centralization Results\n"); printf("I/F0 Result[0 - success 1-fail 2 - state_2 3 - state_3] ...\n"); for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) { diff --git a/drivers/ddr/marvell/a38x/ddr3_training_db.c b/drivers/ddr/marvell/a38x/ddr3_training_db.c index c0089f67f27..111a8586c6e 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training_db.c +++ b/drivers/ddr/marvell/a38x/ddr3_training_db.c @@ -3,11 +3,16 @@ * Copyright (C) Marvell International Ltd. and its affiliates */ -#include "ddr3_init.h" +#include "ddr_ml_wrapper.h" + +#include "ddr3_training_ip_flow.h" +#include "mv_ddr_topology.h" +#include "mv_ddr_training_db.h" +#include "ddr3_training_ip_db.h" /* Device attributes structures */ -enum mv_ddr_dev_attribute ddr_dev_attributes[MAX_DEVICE_NUM][MV_ATTR_LAST]; -int ddr_dev_attr_init_done[MAX_DEVICE_NUM] = { 0 }; +enum mv_ddr_dev_attribute ddr_dev_attributes[MV_ATTR_LAST]; +int ddr_dev_attr_init_done = 0; static inline u32 pattern_table_get_killer_word16(u8 dqs, u8 index); static inline u32 pattern_table_get_sso_word(u8 sso, u8 index); @@ -20,28 +25,38 @@ static inline u32 pattern_table_get_sso_xtalk_free_word16(u8 bit, u8 index); static inline u32 pattern_table_get_isi_word(u8 index); static inline u32 pattern_table_get_isi_word16(u8 index); -/* List of allowed frequency listed in order of enum hws_ddr_freq */ -u32 freq_val[DDR_FREQ_LAST] = { - 0, /*DDR_FREQ_LOW_FREQ */ - 400, /*DDR_FREQ_400, */ - 533, /*DDR_FREQ_533, */ - 666, /*DDR_FREQ_667, */ - 800, /*DDR_FREQ_800, */ - 933, /*DDR_FREQ_933, */ - 1066, /*DDR_FREQ_1066, */ - 311, /*DDR_FREQ_311, */ - 333, /*DDR_FREQ_333, */ - 467, /*DDR_FREQ_467, */ - 850, /*DDR_FREQ_850, */ - 600, /*DDR_FREQ_600 */ - 300, /*DDR_FREQ_300 */ - 900, /*DDR_FREQ_900 */ - 360, /*DDR_FREQ_360 */ - 1000 /*DDR_FREQ_1000 */ +/* List of allowed frequency listed in order of enum mv_ddr_freq */ +static unsigned int freq_val[MV_DDR_FREQ_LAST] = { + 0, /*MV_DDR_FREQ_LOW_FREQ */ + 400, /*MV_DDR_FREQ_400, */ + 533, /*MV_DDR_FREQ_533, */ + 666, /*MV_DDR_FREQ_667, */ + 800, /*MV_DDR_FREQ_800, */ + 933, /*MV_DDR_FREQ_933, */ + 1066, /*MV_DDR_FREQ_1066, */ + 311, /*MV_DDR_FREQ_311, */ + 333, /*MV_DDR_FREQ_333, */ + 467, /*MV_DDR_FREQ_467, */ + 850, /*MV_DDR_FREQ_850, */ + 600, /*MV_DDR_FREQ_600 */ + 300, /*MV_DDR_FREQ_300 */ + 900, /*MV_DDR_FREQ_900 */ + 360, /*MV_DDR_FREQ_360 */ + 1000 /*MV_DDR_FREQ_1000 */ }; -/* Table for CL values per frequency for each speed bin index */ -struct cl_val_per_freq cas_latency_table[] = { +unsigned int *mv_ddr_freq_tbl_get(void) +{ + return &freq_val[0]; +} + +u32 mv_ddr_freq_get(enum mv_ddr_freq freq) +{ + return freq_val[freq]; +} + +/* cas latency values per frequency for each speed bin index */ +static struct mv_ddr_cl_val_per_freq cl_table[] = { /* * 400M 667M 933M 311M 467M 600M 360 * 100M 533M 800M 1066M 333M 850M 900 @@ -97,8 +112,13 @@ struct cl_val_per_freq cas_latency_table[] = { { {6, 6, 7, 9, 11, 13, 0, 6, 6, 7, 13, 9, 6, 13, 6, 13} }, }; -/* Table for CWL values per speedbin index */ -struct cl_val_per_freq cas_write_latency_table[] = { +u32 mv_ddr_cl_val_get(u32 index, u32 freq) +{ + return cl_table[index].cl_val[freq]; +} + +/* cas write latency values per frequency for each speed bin index */ +static struct mv_ddr_cl_val_per_freq cwl_table[] = { /* * 400M 667M 933M 311M 467M 600M 360 * 100M 533M 800M 1066M 333M 850M 900 @@ -154,6 +174,11 @@ struct cl_val_per_freq cas_write_latency_table[] = { { {5, 5, 6, 7, 8, 9, 0, 5, 5, 6, 9, 7, 5, 9, 5, 9} }, }; +u32 mv_ddr_cwl_val_get(u32 index, u32 freq) +{ + return cwl_table[index].cl_val[freq]; +} + u8 twr_mask_table[] = { 10, 10, @@ -213,18 +238,23 @@ u8 cwl_mask_table[] = { }; /* RFC values (in ns) */ -u16 rfc_table[] = { - 90, /* 512M */ - 110, /* 1G */ - 160, /* 2G */ - 260, /* 4G */ - 350, /* 8G */ - 0, /* TODO: placeholder for 16-Mbit dev width */ - 0, /* TODO: placeholder for 32-Mbit dev width */ - 0, /* TODO: placeholder for 12-Mbit dev width */ - 0 /* TODO: placeholder for 24-Mbit dev width */ +static unsigned int rfc_table[] = { + 90, /* 512M */ + 110, /* 1G */ + 160, /* 2G */ + 260, /* 4G */ + 350, /* 8G */ + 0, /* TODO: placeholder for 16-Mbit dev width */ + 0, /* TODO: placeholder for 32-Mbit dev width */ + 0, /* TODO: placeholder for 12-Mbit dev width */ + 0 /* TODO: placeholder for 24-Mbit dev width */ }; +u32 mv_ddr_rfc_get(u32 mem) +{ + return rfc_table[mem]; +} + u32 speed_bin_table_t_rc[] = { 50000, 52500, @@ -358,8 +388,29 @@ static u8 pattern_vref_pattern_table_map[] = { 0xfe }; +static struct mv_ddr_page_element page_tbl[] = { + /* 8-bit, 16-bit page size */ + {MV_DDR_PAGE_SIZE_1K, MV_DDR_PAGE_SIZE_2K}, /* 512M */ + {MV_DDR_PAGE_SIZE_1K, MV_DDR_PAGE_SIZE_2K}, /* 1G */ + {MV_DDR_PAGE_SIZE_1K, MV_DDR_PAGE_SIZE_2K}, /* 2G */ + {MV_DDR_PAGE_SIZE_1K, MV_DDR_PAGE_SIZE_2K}, /* 4G */ + {MV_DDR_PAGE_SIZE_2K, MV_DDR_PAGE_SIZE_2K}, /* 8G */ + {0, 0}, /* TODO: placeholder for 16-Mbit die capacity */ + {0, 0}, /* TODO: placeholder for 32-Mbit die capacity */ + {0, 0}, /* TODO: placeholder for 12-Mbit die capacity */ + {0, 0} /* TODO: placeholder for 24-Mbit die capacity */ +}; + +u32 mv_ddr_page_size_get(enum mv_ddr_dev_width bus_width, enum mv_ddr_die_capacity mem_size) +{ + if (bus_width == MV_DDR_DEV_WIDTH_8BIT) + return page_tbl[mem_size].page_size_8bit; + else + return page_tbl[mem_size].page_size_16bit; +} + /* Return speed Bin value for selected index and t* element */ -u32 speed_bin_table(u8 index, enum speed_bin_table_elements element) +unsigned int mv_ddr_speed_bin_timing_get(enum mv_ddr_speed_bin index, enum mv_ddr_speed_bin_timing element) { u32 result = 0; @@ -384,19 +435,19 @@ u32 speed_bin_table(u8 index, enum speed_bin_table_elements element) result = speed_bin_table_t_rc[index]; break; case SPEED_BIN_TRRD1K: - if (index < SPEED_BIN_DDR_800E) + if (index <= SPEED_BIN_DDR_800E) result = 10000; - else if (index < SPEED_BIN_DDR_1066G) + else if (index <= SPEED_BIN_DDR_1066G) result = 7500; - else if (index < SPEED_BIN_DDR_1600K) + else if (index <= SPEED_BIN_DDR_1600K) result = 6000; else result = 5000; break; case SPEED_BIN_TRRD2K: - if (index < SPEED_BIN_DDR_1066G) + if (index <= SPEED_BIN_DDR_1066G) result = 10000; - else if (index < SPEED_BIN_DDR_1600K) + else if (index <= SPEED_BIN_DDR_1600K) result = 7500; else result = 6000; @@ -410,23 +461,23 @@ u32 speed_bin_table(u8 index, enum speed_bin_table_elements element) result = 5000; break; case SPEED_BIN_TFAW1K: - if (index < SPEED_BIN_DDR_800E) + if (index <= SPEED_BIN_DDR_800E) result = 40000; - else if (index < SPEED_BIN_DDR_1066G) + else if (index <= SPEED_BIN_DDR_1066G) result = 37500; - else if (index < SPEED_BIN_DDR_1600K) + else if (index <= SPEED_BIN_DDR_1600K) result = 30000; - else if (index < SPEED_BIN_DDR_1866M) + else if (index <= SPEED_BIN_DDR_1866M) result = 27000; else result = 25000; break; case SPEED_BIN_TFAW2K: - if (index < SPEED_BIN_DDR_1066G) + if (index <= SPEED_BIN_DDR_1066G) result = 50000; - else if (index < SPEED_BIN_DDR_1333J) + else if (index <= SPEED_BIN_DDR_1333J) result = 45000; - else if (index < SPEED_BIN_DDR_1600K) + else if (index <= SPEED_BIN_DDR_1600K) result = 40000; else result = 35000; @@ -446,6 +497,9 @@ u32 speed_bin_table(u8 index, enum speed_bin_table_elements element) case SPEED_BIN_TXPDLL: result = 24000; break; + case SPEED_BIN_TXSDLL: + result = 512; + break; default: break; } @@ -608,7 +662,7 @@ static inline u32 pattern_table_get_static_pbs_word(u8 index) u32 pattern_table_get_word(u32 dev_num, enum hws_pattern type, u8 index) { - u32 pattern; + u32 pattern = 0; struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); if (DDR3_IS_16BIT_DRAM_MODE(tm->bus_act_mask) == 0) { @@ -696,8 +750,8 @@ u32 pattern_table_get_word(u32 dev_num, enum hws_pattern type, u8 index) pattern = pattern_table_get_isi_word(index); break; default: - DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, ("Error: %s: pattern type [%d] not supported\n", - __func__, (int)type)); + printf("error: %s: unsupported pattern type [%d] found\n", + __func__, (int)type); pattern = 0; break; } @@ -779,8 +833,8 @@ u32 pattern_table_get_word(u32 dev_num, enum hws_pattern type, u8 index) pattern = pattern_table_get_isi_word16(index); break; default: - DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, ("Error: %s: pattern type [%d] not supported\n", - __func__, (int)type)); + printf("error: %s: unsupported pattern type [%d] found\n", + __func__, (int)type); pattern = 0; break; } @@ -795,23 +849,23 @@ void ddr3_tip_dev_attr_init(u32 dev_num) u32 attr_id; for (attr_id = 0; attr_id < MV_ATTR_LAST; attr_id++) - ddr_dev_attributes[dev_num][attr_id] = 0xFF; + ddr_dev_attributes[attr_id] = 0xFF; - ddr_dev_attr_init_done[dev_num] = 1; + ddr_dev_attr_init_done = 1; } u32 ddr3_tip_dev_attr_get(u32 dev_num, enum mv_ddr_dev_attribute attr_id) { - if (ddr_dev_attr_init_done[dev_num] == 0) + if (ddr_dev_attr_init_done == 0) ddr3_tip_dev_attr_init(dev_num); - return ddr_dev_attributes[dev_num][attr_id]; + return ddr_dev_attributes[attr_id]; } void ddr3_tip_dev_attr_set(u32 dev_num, enum mv_ddr_dev_attribute attr_id, u32 value) { - if (ddr_dev_attr_init_done[dev_num] == 0) + if (ddr_dev_attr_init_done == 0) ddr3_tip_dev_attr_init(dev_num); - ddr_dev_attributes[dev_num][attr_id] = value; + ddr_dev_attributes[attr_id] = value; } diff --git a/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.c b/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.c index 6b8aae83d75..db0f8ad7fb5 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.c +++ b/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.c @@ -4,6 +4,7 @@ */ #include "ddr3_init.h" +#include "mv_ddr_regs.h" #define VREF_INITIAL_STEP 3 #define VREF_SECOND_STEP 1 diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip.h b/drivers/ddr/marvell/a38x/ddr3_training_ip.h index 531103c1abd..056c21497c8 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training_ip.h +++ b/drivers/ddr/marvell/a38x/ddr3_training_ip.h @@ -6,12 +6,8 @@ #ifndef _DDR3_TRAINING_IP_H_ #define _DDR3_TRAINING_IP_H_ -#include "ddr3_training_ip_def.h" #include "ddr_topology_def.h" -#include "ddr_training_ip_db.h" -#define MAX_CS_NUM 4 -#define MAX_TOTAL_BUS_NUM (MAX_INTERFACE_NUM * MAX_BUS_NUM) #define TIP_ENG_LOCK 0x02000000 #define TIP_TX_DLL_RANGE_MAX 64 @@ -112,40 +108,11 @@ struct pattern_info { u8 pattern_len; }; -/* CL value for each frequency */ -struct cl_val_per_freq { - u8 cl_val[DDR_FREQ_LAST]; -}; - struct cs_element { u8 cs_num; u8 num_of_cs; }; -struct mode_info { - /* 32 bits representing MRS bits */ - u32 reg_mr0[MAX_INTERFACE_NUM]; - u32 reg_mr1[MAX_INTERFACE_NUM]; - u32 reg_mr2[MAX_INTERFACE_NUM]; - u32 reg_m_r3[MAX_INTERFACE_NUM]; - /* - * Each element in array represent read_data_sample register delay for - * a specific interface. - * Each register, 4 bits[0+CS*8 to 4+CS*8] represent Number of DDR - * cycles from read command until data is ready to be fetched from - * the PHY, when accessing CS. - */ - u32 read_data_sample[MAX_INTERFACE_NUM]; - /* - * Each element in array represent read_data_sample register delay for - * a specific interface. - * Each register, 4 bits[0+CS*8 to 4+CS*8] represent the total delay - * from read command until opening the read mask, when accessing CS. - * This field defines the delay in DDR cycles granularity. - */ - u32 read_data_ready[MAX_INTERFACE_NUM]; -}; - struct hws_tip_freq_config_info { u8 is_supported; u8 bw_per_freq; @@ -173,12 +140,7 @@ int hws_ddr3_tip_init_controller(u32 dev_num, int hws_ddr3_tip_load_topology_map(u32 dev_num, struct mv_ddr_topology_map *topology); int hws_ddr3_tip_run_alg(u32 dev_num, enum hws_algo_type algo_type); -int hws_ddr3_tip_mode_read(u32 dev_num, struct mode_info *mode_info); -int hws_ddr3_tip_read_training_result(u32 dev_num, - enum hws_result result[MAX_STAGE_LIMIT][MAX_INTERFACE_NUM]); int ddr3_tip_is_pup_lock(u32 *pup_buf, enum hws_training_result read_mode); u8 ddr3_tip_get_buf_min(u8 *buf_ptr); u8 ddr3_tip_get_buf_max(u8 *buf_ptr); -uint64_t mv_ddr_get_memory_size_per_cs_in_bits(void); -uint64_t mv_ddr_get_total_memory_size_in_bits(void); #endif /* _DDR3_TRAINING_IP_H_ */ diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_def.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_def.h index 2318ceba292..2a68669f36c 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training_ip_def.h +++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_def.h @@ -75,32 +75,6 @@ #define GET_RESULT_STATE(res) (res) #define SET_RESULT_STATE(res, state) (res = state) -#define _1K 0x00000400 -#define _4K 0x00001000 -#define _8K 0x00002000 -#define _16K 0x00004000 -#define _32K 0x00008000 -#define _64K 0x00010000 -#define _128K 0x00020000 -#define _256K 0x00040000 -#define _512K 0x00080000 - -#define _1M 0x00100000 -#define _2M 0x00200000 -#define _4M 0x00400000 -#define _8M 0x00800000 -#define _16M 0x01000000 -#define _32M 0x02000000 -#define _64M 0x04000000 -#define _128M 0x08000000 -#define _256M 0x10000000 -#define _512M 0x20000000 - -#define _1G 0x40000000 -#define _2G 0x80000000 -#define _4G 0x100000000 -#define _8G 0x200000000 - #define ADDR_SIZE_512MB 0x04000000 #define ADDR_SIZE_1GB 0x08000000 #define ADDR_SIZE_2GB 0x10000000 @@ -126,11 +100,6 @@ enum hws_search_dir { HWS_SEARCH_DIR_LIMIT }; -enum hws_page_size { - PAGE_SIZE_1K, - PAGE_SIZE_2K -}; - enum hws_operation { OPERATION_READ = 0, OPERATION_WRITE = 1 diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.c b/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.c index 334c2906fdb..74417d61b4c 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.c +++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.c @@ -4,6 +4,8 @@ */ #include "ddr3_init.h" +#include "mv_ddr_regs.h" +#include "ddr_training_ip_db.h" #define PATTERN_1 0x55555555 #define PATTERN_2 0xaaaaaaaa diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.h index 8fbcff50bb2..2d40e68db86 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.h +++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.h @@ -8,6 +8,7 @@ #include "ddr3_training_ip_def.h" #include "ddr3_training_ip_flow.h" +#include "ddr3_training_ip_pbs.h" #define EDGE_1 0 #define EDGE_2 1 diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_flow.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_flow.h index 6a9ef35f643..ab152cb455e 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training_ip_flow.h +++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_flow.h @@ -7,71 +7,17 @@ #define _DDR3_TRAINING_IP_FLOW_H_ #include "ddr3_training_ip.h" -#include "ddr3_training_ip_pbs.h" -#include "mv_ddr_regs.h" +#include "ddr3_training_ip_db.h" #define KILLER_PATTERN_LENGTH 32 #define EXT_ACCESS_BURST_LENGTH 8 -#define IS_ACTIVE(mask, id) \ - ((mask) & (1 << (id))) - -#define VALIDATE_ACTIVE(mask, id) \ - { \ - if (IS_ACTIVE(mask, id) == 0) \ - continue; \ - } - -#define IS_IF_ACTIVE(if_mask, if_id) \ - ((if_mask) & (1 << (if_id))) - -#define VALIDATE_IF_ACTIVE(mask, id) \ - { \ - if (IS_IF_ACTIVE(mask, id) == 0) \ - continue; \ - } - -#define IS_BUS_ACTIVE(if_mask , if_id) \ - (((if_mask) >> (if_id)) & 1) - -#define VALIDATE_BUS_ACTIVE(mask, id) \ - { \ - if (IS_BUS_ACTIVE(mask, id) == 0) \ - continue; \ - } - -#define DDR3_IS_ECC_PUP3_MODE(if_mask) \ - (((if_mask) == BUS_MASK_16BIT_ECC_PUP3) ? 1 : 0) - -#define DDR3_IS_ECC_PUP4_MODE(if_mask) \ - ((if_mask == BUS_MASK_32BIT_ECC || if_mask == BUS_MASK_16BIT_ECC) ? 1 : 0) - -#define DDR3_IS_16BIT_DRAM_MODE(mask) \ - ((mask == BUS_MASK_16BIT || mask == BUS_MASK_16BIT_ECC || mask == BUS_MASK_16BIT_ECC_PUP3) ? 1 : 0) - -#define DDR3_IS_ECC_PUP8_MODE(if_mask) \ - ((if_mask == MV_DDR_32BIT_ECC_PUP8_BUS_MASK || if_mask == MV_DDR_64BIT_ECC_PUP8_BUS_MASK) ? 1 : 0) - -#define MV_DDR_IS_64BIT_DRAM_MODE(mask) \ - ((((mask) & MV_DDR_64BIT_BUS_MASK) == MV_DDR_64BIT_BUS_MASK) || \ - (((mask) & MV_DDR_64BIT_ECC_PUP8_BUS_MASK) == MV_DDR_64BIT_ECC_PUP8_BUS_MASK) ? 1 : 0) - -#define MV_DDR_IS_32BIT_IN_64BIT_DRAM_MODE(mask, octets_per_if_num/* FIXME: get from ATF */) \ - ((octets_per_if_num == 9/* FIXME: get from ATF */) && \ - ((mask == BUS_MASK_32BIT) || \ - (mask == MV_DDR_32BIT_ECC_PUP8_BUS_MASK)) ? 1 : 0) - -#define MV_DDR_IS_HALF_BUS_DRAM_MODE(mask, octets_per_if_num/* FIXME: get from ATF */) \ - (MV_DDR_IS_32BIT_IN_64BIT_DRAM_MODE(mask, octets_per_if_num) || DDR3_IS_16BIT_DRAM_MODE(mask)) - #define ECC_READ_BUS_0 0 #define ECC_PHY_ACCESS_3 3 #define ECC_PHY_ACCESS_4 4 #define ECC_PHY_ACCESS_8 8 -#define MEGA 1000000 #define BUS_WIDTH_IN_BITS 8 #define MAX_POLLING_ITERATIONS 1000000 -#define NUM_OF_CS 4 #define ADLL_LENGTH 32 #define GP_RSVD0_REG 0x182e0 @@ -92,8 +38,6 @@ */ /* nsec */ -#define TREFI_LOW 7800 -#define TREFI_HIGH 3900 #define AUTO_ZQC_TIMING 15384 enum mr_number { @@ -114,20 +58,11 @@ struct write_supp_result { int is_pup_fail; }; -struct page_element { - enum hws_page_size page_size_8bit; - /* page size in 8 bits bus width */ - enum hws_page_size page_size_16bit; - /* page size in 16 bits bus width */ - u32 ui_page_mask; - /* Mask used in register */ -}; - int ddr3_tip_write_leveling_static_config(u32 dev_num, u32 if_id, - enum hws_ddr_freq frequency, + enum mv_ddr_freq frequency, u32 *round_trip_delay_arr); int ddr3_tip_read_leveling_static_config(u32 dev_num, u32 if_id, - enum hws_ddr_freq frequency, + enum mv_ddr_freq frequency, u32 *total_round_trip_delay_arr); int ddr3_tip_if_write(u32 dev_num, enum hws_access_type interface_access, u32 if_id, u32 reg_addr, u32 data_value, u32 mask); @@ -149,7 +84,7 @@ int ddr3_tip_bus_write(u32 dev_num, enum hws_access_type e_interface_access, enum hws_ddr_phy e_phy_type, u32 reg_addr, u32 data_value); int ddr3_tip_freq_set(u32 dev_num, enum hws_access_type e_access, u32 if_id, - enum hws_ddr_freq memory_freq); + enum mv_ddr_freq memory_freq); int ddr3_tip_adjust_dqs(u32 dev_num); int ddr3_tip_init_controller(u32 dev_num); int ddr3_tip_ext_read(u32 dev_num, u32 if_id, u32 reg_addr, @@ -174,22 +109,12 @@ int ddr3_tip_configure_odpg(u32 dev_num, enum hws_access_type access_type, u32 tx_burst_size, u32 rx_phases, u32 delay_between_burst, u32 rd_mode, u32 cs_num, u32 addr_stress_jump, u32 single_pattern); -int ddr3_tip_set_atr(u32 dev_num, u32 flag_id, u32 value); int ddr3_tip_write_mrs_cmd(u32 dev_num, u32 *cs_mask_arr, enum mr_number mr_num, u32 data, u32 mask); int ddr3_tip_write_cs_result(u32 dev_num, u32 offset); -int ddr3_tip_get_first_active_if(u8 dev_num, u32 interface_mask, u32 *if_id); int ddr3_tip_reset_fifo_ptr(u32 dev_num); -int ddr3_tip_read_pup_value(u32 dev_num, - u32 pup_values[MAX_INTERFACE_NUM * MAX_BUS_NUM], - int reg_addr, u32 mask); -int ddr3_tip_read_adll_value(u32 dev_num, - u32 pup_values[MAX_INTERFACE_NUM * MAX_BUS_NUM], - u32 reg_addr, u32 mask); -int ddr3_tip_write_adll_value(u32 dev_num, - u32 pup_values[MAX_INTERFACE_NUM * MAX_BUS_NUM], - u32 reg_addr); -int ddr3_tip_tune_training_params(u32 dev_num, - struct tune_train_params *params); -struct page_element *mv_ddr_page_tbl_get(void); +int ddr3_tip_read_pup_value(u32 dev_num, u32 pup_values[], int reg_addr, u32 mask); +int ddr3_tip_read_adll_value(u32 dev_num, u32 pup_values[], u32 reg_addr, u32 mask); +int ddr3_tip_write_adll_value(u32 dev_num, u32 pup_values[], u32 reg_addr); +int ddr3_tip_tune_training_params(u32 dev_num, struct tune_train_params *params); #endif /* _DDR3_TRAINING_IP_FLOW_H_ */ diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_prv_if.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_prv_if.h index f614d688c91..2df592e1b02 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training_ip_prv_if.h +++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_prv_if.h @@ -28,15 +28,15 @@ typedef int (*HWS_TIP_DUNIT_REG_WRITE_FUNC_PTR)( u8 dev_num, enum hws_access_type interface_access, u32 if_id, u32 offset, u32 data, u32 mask); typedef int (*HWS_TIP_GET_FREQ_CONFIG_INFO)( - u8 dev_num, enum hws_ddr_freq freq, + u8 dev_num, enum mv_ddr_freq freq, struct hws_tip_freq_config_info *freq_config_info); typedef int (*HWS_TIP_GET_DEVICE_INFO)( u8 dev_num, struct ddr3_device_info *info_ptr); typedef int (*HWS_GET_CS_CONFIG_FUNC_PTR)( u8 dev_num, u32 cs_mask, struct hws_cs_config_info *cs_info); typedef int (*HWS_SET_FREQ_DIVIDER_FUNC_PTR)( - u8 dev_num, u32 if_id, enum hws_ddr_freq freq); -typedef int (*HWS_GET_INIT_FREQ)(u8 dev_num, enum hws_ddr_freq *freq); + u8 dev_num, u32 if_id, enum mv_ddr_freq freq); +typedef int (*HWS_GET_INIT_FREQ)(u8 dev_num, enum mv_ddr_freq *freq); typedef int (*HWS_TRAINING_IP_IF_WRITE_FUNC_PTR)( u32 dev_num, enum hws_access_type access_type, u32 dunit_id, u32 reg_addr, u32 data, u32 mask); @@ -54,7 +54,7 @@ typedef int (*HWS_TRAINING_IP_ALGO_RUN_FUNC_PTR)( u32 dev_num, enum hws_algo_type algo_type); typedef int (*HWS_TRAINING_IP_SET_FREQ_FUNC_PTR)( u32 dev_num, enum hws_access_type access_type, u32 if_id, - enum hws_ddr_freq frequency); + enum mv_ddr_freq frequency); typedef int (*HWS_TRAINING_IP_INIT_CONTROLLER_FUNC_PTR)( u32 dev_num, struct init_cntr_param *init_cntr_prm); typedef int (*HWS_TRAINING_IP_PBS_RX_FUNC_PTR)(u32 dev_num); @@ -64,7 +64,7 @@ typedef int (*HWS_TRAINING_IP_SELECT_CONTROLLER_FUNC_PTR)( typedef int (*HWS_TRAINING_IP_TOPOLOGY_MAP_LOAD_FUNC_PTR)( u32 dev_num, struct mv_ddr_topology_map *tm); typedef int (*HWS_TRAINING_IP_STATIC_CONFIG_FUNC_PTR)( - u32 dev_num, enum hws_ddr_freq frequency, + u32 dev_num, enum mv_ddr_freq frequency, enum hws_static_config_type static_config_type, u32 if_id); typedef int (*HWS_TRAINING_IP_EXTERNAL_READ_PTR)( u32 dev_num, u32 if_id, u32 ddr_addr, u32 num_bursts, u32 *data); diff --git a/drivers/ddr/marvell/a38x/ddr3_training_leveling.c b/drivers/ddr/marvell/a38x/ddr3_training_leveling.c index 6248ffc3fb3..7f7df6794a9 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training_leveling.c +++ b/drivers/ddr/marvell/a38x/ddr3_training_leveling.c @@ -4,6 +4,9 @@ */ #include "ddr3_init.h" +#include "mv_ddr_training_db.h" +#include "ddr_training_ip_db.h" +#include "mv_ddr_regs.h" #define WL_ITERATION_NUM 10 @@ -24,33 +27,6 @@ static int ddr3_tip_wl_supp_align_phase_shift(u32 dev_num, u32 if_id, static int ddr3_tip_xsb_compare_test(u32 dev_num, u32 if_id, u32 bus_id, u32 edge_offset); -u32 ddr3_tip_max_cs_get(u32 dev_num) -{ - u32 c_cs, if_id, bus_id; - static u32 max_cs; - struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); - u32 octets_per_if_num = ddr3_tip_dev_attr_get(dev_num, MV_ATTR_OCTET_PER_INTERFACE); - - if (!max_cs) { - CHECK_STATUS(ddr3_tip_get_first_active_if((u8)dev_num, - tm->if_act_mask, - &if_id)); - for (bus_id = 0; bus_id < octets_per_if_num; bus_id++) { - VALIDATE_BUS_ACTIVE(tm->bus_act_mask, bus_id); - break; - } - - for (c_cs = 0; c_cs < NUM_OF_CS; c_cs++) { - VALIDATE_ACTIVE(tm-> - interface_params[if_id].as_bus_params[bus_id]. - cs_bitmask, c_cs); - max_cs++; - } - } - - return max_cs; -} - enum { PASS, FAIL @@ -61,20 +37,20 @@ Dynamic read leveling int ddr3_tip_dynamic_read_leveling(u32 dev_num, u32 freq) { u32 data, mask; - u32 max_cs = ddr3_tip_max_cs_get(dev_num); + unsigned int max_cs = mv_ddr_cs_num_get(); u32 bus_num, if_id, cl_val; - enum hws_speed_bin speed_bin_index; + enum mv_ddr_speed_bin speed_bin_index; /* save current CS value */ u32 cs_enable_reg_val[MAX_INTERFACE_NUM] = { 0 }; int is_any_pup_fail = 0; u32 data_read[MAX_INTERFACE_NUM + 1] = { 0 }; - u8 rl_values[NUM_OF_CS][MAX_BUS_NUM][MAX_INTERFACE_NUM]; + u8 rl_values[MAX_CS_NUM][MAX_BUS_NUM][MAX_INTERFACE_NUM]; struct pattern_info *pattern_table = ddr3_tip_get_pattern_table(); u16 *mask_results_pup_reg_map = ddr3_tip_get_mask_results_pup_reg_map(); u32 octets_per_if_num = ddr3_tip_dev_attr_get(dev_num, MV_ATTR_OCTET_PER_INTERFACE); struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); - for (effective_cs = 0; effective_cs < NUM_OF_CS; effective_cs++) + for (effective_cs = 0; effective_cs < MAX_CS_NUM; effective_cs++) for (bus_num = 0; bus_num < MAX_BUS_NUM; bus_num++) for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) rl_values[effective_cs][bus_num][if_id] = 0; @@ -143,8 +119,7 @@ int ddr3_tip_dynamic_read_leveling(u32 dev_num, u32 freq) VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id); speed_bin_index = tm->interface_params[if_id].speed_bin_index; - cl_val = - cas_latency_table[speed_bin_index].cl_val[freq]; + cl_val = mv_ddr_cl_val_get(speed_bin_index, freq); data = (cl_val << 17) | (0x3 << 25); mask = (0xff << 9) | (0x1f << 17) | (0x3 << 25); CHECK_STATUS(ddr3_tip_if_write @@ -340,7 +315,7 @@ int ddr3_tip_dynamic_read_leveling(u32 dev_num, u32 freq) int ddr3_tip_legacy_dynamic_write_leveling(u32 dev_num) { u32 c_cs, if_id, cs_mask = 0; - u32 max_cs = ddr3_tip_max_cs_get(dev_num); + unsigned int max_cs = mv_ddr_cs_num_get(); struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); /* @@ -381,7 +356,7 @@ int ddr3_tip_legacy_dynamic_write_leveling(u32 dev_num) int ddr3_tip_legacy_dynamic_read_leveling(u32 dev_num) { u32 c_cs, if_id, cs_mask = 0; - u32 max_cs = ddr3_tip_max_cs_get(dev_num); + unsigned int max_cs = mv_ddr_cs_num_get(); struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); /* @@ -426,7 +401,7 @@ int ddr3_tip_dynamic_per_bit_read_leveling(u32 dev_num, u32 freq) u32 curr_numb, curr_min_delay; int adll_array[3] = { 0, -0xa, 0x14 }; u32 phyreg3_arr[MAX_INTERFACE_NUM][MAX_BUS_NUM]; - enum hws_speed_bin speed_bin_index; + enum mv_ddr_speed_bin speed_bin_index; int is_any_pup_fail = 0; int break_loop = 0; u32 cs_enable_reg_val[MAX_INTERFACE_NUM]; /* save current CS value */ @@ -516,8 +491,7 @@ int ddr3_tip_dynamic_per_bit_read_leveling(u32 dev_num, u32 freq) VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id); speed_bin_index = tm->interface_params[if_id].speed_bin_index; - cl_val = - cas_latency_table[speed_bin_index].cl_val[freq]; + cl_val = mv_ddr_cl_val_get(speed_bin_index, freq); data = (cl_val << 17) | (0x3 << 25); mask = (0xff << 9) | (0x1f << 17) | (0x3 << 25); CHECK_STATUS(ddr3_tip_if_write @@ -839,10 +813,10 @@ int ddr3_tip_dynamic_write_leveling(u32 dev_num, int phase_remove) u32 res_values[MAX_INTERFACE_NUM * MAX_BUS_NUM] = { 0 }; u32 test_res = 0; /* 0 - success for all pup */ u32 data_read[MAX_INTERFACE_NUM]; - u8 wl_values[NUM_OF_CS][MAX_BUS_NUM][MAX_INTERFACE_NUM]; + u8 wl_values[MAX_CS_NUM][MAX_BUS_NUM][MAX_INTERFACE_NUM]; u16 *mask_results_pup_reg_map = ddr3_tip_get_mask_results_pup_reg_map(); u32 cs_mask0[MAX_INTERFACE_NUM] = { 0 }; - u32 max_cs = ddr3_tip_max_cs_get(dev_num); + unsigned int max_cs = mv_ddr_cs_num_get(); u32 octets_per_if_num = ddr3_tip_dev_attr_get(dev_num, MV_ATTR_OCTET_PER_INTERFACE); struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); @@ -1694,9 +1668,11 @@ enum rl_dqs_burst_state { RL_INSIDE, RL_BEHIND }; + + int mv_ddr_rl_dqs_burst(u32 dev_num, u32 if_id, u32 freq) { - enum rl_dqs_burst_state rl_state[NUM_OF_CS][MAX_BUS_NUM][MAX_INTERFACE_NUM] = { { {0} } }; + enum rl_dqs_burst_state rl_state[MAX_CS_NUM][MAX_BUS_NUM][MAX_INTERFACE_NUM] = { { {0} } }; enum hws_ddr_phy subphy_type = DDR_PHY_DATA; struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); int cl_val = tm->interface_params[0].cas_l; @@ -1707,17 +1683,18 @@ int mv_ddr_rl_dqs_burst(u32 dev_num, u32 if_id, u32 freq) int init_pass_lock_num; int phase_delta; int min_phase, max_phase; - u32 max_cs = ddr3_tip_max_cs_get(dev_num); - u32 rl_values[NUM_OF_CS][MAX_BUS_NUM][MAX_INTERFACE_NUM] = { { {0} } }; - u32 rl_min_values[NUM_OF_CS][MAX_BUS_NUM][MAX_INTERFACE_NUM] = { { {0} } }; - u32 rl_max_values[NUM_OF_CS][MAX_BUS_NUM][MAX_INTERFACE_NUM] = { { {0} } }; - u32 rl_val, rl_min_val[NUM_OF_CS], rl_max_val[NUM_OF_CS]; + unsigned int max_cs = mv_ddr_cs_num_get(); + u32 rl_values[MAX_CS_NUM][MAX_BUS_NUM][MAX_INTERFACE_NUM] = { { {0} } }; + u32 rl_min_values[MAX_CS_NUM][MAX_BUS_NUM][MAX_INTERFACE_NUM] = { { {0} } }; + u32 rl_max_values[MAX_CS_NUM][MAX_BUS_NUM][MAX_INTERFACE_NUM] = { { {0} } }; + u32 rl_val, rl_min_val[MAX_CS_NUM], rl_max_val[MAX_CS_NUM]; u32 reg_val_low, reg_val_high; - u32 reg_val, reg_mask; + u32 reg_val, reg_mask; uintptr_t test_addr = TEST_ADDR; + /* initialization */ - if (ddr3_if_ecc_enabled()) { + if (mv_ddr_is_ecc_ena()) { ddr3_tip_if_read(dev_num, ACCESS_TYPE_UNICAST, if_id, TRAINING_SW_2_REG, ®_val, MASK_ALL_BITS); reg_mask = (TRAINING_ECC_MUX_MASK << TRAINING_ECC_MUX_OFFS) | @@ -1753,6 +1730,7 @@ int mv_ddr_rl_dqs_burst(u32 dev_num, u32 if_id, u32 freq) /* search for dqs edges per subphy */ if_id = 0; for (effective_cs = 0; effective_cs < max_cs; effective_cs++) { + pass_lock_num = init_pass_lock_num; ddr3_tip_if_write(0, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE, ODPG_DATA_CTRL_REG, effective_cs << ODPG_DATA_CS_OFFS, @@ -1972,6 +1950,7 @@ int mv_ddr_rl_dqs_burst(u32 dev_num, u32 if_id, u32 freq) CHECK_STATUS(ddr3_tip_write_additional_odt_setting(dev_num, if_id)); } + /* reset read fifo assertion */ ddr3_tip_if_write(dev_num, ACCESS_TYPE_MULTICAST, if_id, SDRAM_CFG_REG, DATA_PUP_RD_RESET_ENA << DATA_PUP_RD_RESET_OFFS, diff --git a/drivers/ddr/marvell/a38x/ddr3_training_leveling.h b/drivers/ddr/marvell/a38x/ddr3_training_leveling.h index 96d945a33d6..6719fb83f51 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training_leveling.h +++ b/drivers/ddr/marvell/a38x/ddr3_training_leveling.h @@ -11,6 +11,5 @@ int ddr3_tip_print_wl_supp_result(u32 dev_num); int ddr3_tip_calc_cs_mask(u32 dev_num, u32 if_id, u32 effective_cs, u32 *cs_mask); -u32 ddr3_tip_max_cs_get(u32 dev_num); #endif /* _DDR3_TRAINING_LEVELING_H_ */ diff --git a/drivers/ddr/marvell/a38x/ddr3_training_pbs.c b/drivers/ddr/marvell/a38x/ddr3_training_pbs.c index 0511026afbe..b7dfebd93cc 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training_pbs.c +++ b/drivers/ddr/marvell/a38x/ddr3_training_pbs.c @@ -4,6 +4,9 @@ */ #include "ddr3_init.h" +#include "mv_ddr_training_db.h" +#include "mv_ddr_common.h" +#include "mv_ddr_regs.h" #define TYPICAL_PBS_VALUE 12 @@ -33,7 +36,7 @@ static u8 pup_state[MAX_INTERFACE_NUM][MAX_BUS_NUM]; int ddr3_tip_pbs(u32 dev_num, enum pbs_dir pbs_mode) { u32 res0[MAX_INTERFACE_NUM]; - int adll_tap = MEGA / freq_val[medium_freq] / 64; + int adll_tap = MEGA / mv_ddr_freq_get(medium_freq) / 64; int pad_num = 0; enum hws_search_dir search_dir = (pbs_mode == PBS_RX_MODE) ? HWS_HIGH2LOW : HWS_LOW2HIGH; @@ -921,7 +924,7 @@ int ddr3_tip_pbs_tx(u32 uidev_num) int ddr3_tip_print_all_pbs_result(u32 dev_num) { u32 curr_cs; - u32 max_cs = ddr3_tip_max_cs_get(dev_num); + unsigned int max_cs = mv_ddr_cs_num_get(); for (curr_cs = 0; curr_cs < max_cs; curr_cs++) { ddr3_tip_print_pbs_result(dev_num, curr_cs, PBS_RX_MODE); diff --git a/drivers/ddr/marvell/a38x/ddr_topology_def.h b/drivers/ddr/marvell/a38x/ddr_topology_def.h index 812224909ae..e6fe8a04289 100644 --- a/drivers/ddr/marvell/a38x/ddr_topology_def.h +++ b/drivers/ddr/marvell/a38x/ddr_topology_def.h @@ -7,16 +7,13 @@ #define _DDR_TOPOLOGY_DEF_H #include "ddr3_training_ip_def.h" -#include "ddr3_topology_def.h" - -#if defined(CONFIG_ARMADA_38X) || defined(CONFIG_ARMADA_39X) -#include "mv_ddr_plat.h" -#endif - #include "mv_ddr_topology.h" #include "mv_ddr_spd.h" #include "ddr3_logging_def.h" +#define MV_DDR_MAX_BUS_NUM 9 +#define MV_DDR_MAX_IFACE_NUM 1 + struct bus_params { /* Chip Select (CS) bitmask (bits 0-CS0, bit 1- CS1 ...) */ u8 cs_bitmask; @@ -36,10 +33,10 @@ struct bus_params { struct if_params { /* bus configuration */ - struct bus_params as_bus_params[MAX_BUS_NUM]; + struct bus_params as_bus_params[MV_DDR_MAX_BUS_NUM]; /* Speed Bin Table */ - enum hws_speed_bin speed_bin_index; + enum mv_ddr_speed_bin speed_bin_index; /* sdram device width */ enum mv_ddr_dev_width bus_width; @@ -48,7 +45,7 @@ struct if_params { enum mv_ddr_die_capacity memory_size; /* The DDR frequency for each interfaces */ - enum hws_ddr_freq memory_freq; + enum mv_ddr_freq memory_freq; /* * delay CAS Write Latency @@ -69,6 +66,37 @@ struct if_params { enum mv_ddr_timing timing; }; +/* memory electrical configuration */ +struct mv_ddr_mem_edata { + enum mv_ddr_rtt_nom_park_evalue rtt_nom; + enum mv_ddr_rtt_nom_park_evalue rtt_park[MAX_CS_NUM]; + enum mv_ddr_rtt_wr_evalue rtt_wr[MAX_CS_NUM]; + enum mv_ddr_dic_evalue dic; +}; + +/* phy electrical configuration */ +struct mv_ddr_phy_edata { + enum mv_ddr_ohm_evalue drv_data_p; + enum mv_ddr_ohm_evalue drv_data_n; + enum mv_ddr_ohm_evalue drv_ctrl_p; + enum mv_ddr_ohm_evalue drv_ctrl_n; + enum mv_ddr_ohm_evalue odt_p[MAX_CS_NUM]; + enum mv_ddr_ohm_evalue odt_n[MAX_CS_NUM]; +}; + +/* mac electrical configuration */ +struct mv_ddr_mac_edata { + enum mv_ddr_odt_cfg_evalue odt_cfg_pat; + enum mv_ddr_odt_cfg_evalue odt_cfg_wr; + enum mv_ddr_odt_cfg_evalue odt_cfg_rd; +}; + +struct mv_ddr_edata { + struct mv_ddr_mem_edata mem_edata; + struct mv_ddr_phy_edata phy_edata; + struct mv_ddr_mac_edata mac_edata; +}; + struct mv_ddr_topology_map { /* debug level configuration */ enum mv_ddr_debug_level debug_level; @@ -77,7 +105,7 @@ struct mv_ddr_topology_map { u8 if_act_mask; /* Controller configuration per interface */ - struct if_params interface_params[MAX_INTERFACE_NUM]; + struct if_params interface_params[MV_DDR_MAX_IFACE_NUM]; /* Bit mask for active buses */ u16 bus_act_mask; @@ -90,8 +118,67 @@ struct mv_ddr_topology_map { /* timing parameters */ unsigned int timing_data[MV_DDR_TDATA_LAST]; + + /* electrical configuration */ + struct mv_ddr_edata edata; + + /* electrical parameters */ + unsigned int electrical_data[MV_DDR_EDATA_LAST]; +}; + +enum mv_ddr_iface_mode { + MV_DDR_RAR_ENA, + MV_DDR_RAR_DIS, }; +enum mv_ddr_iface_state { + MV_DDR_IFACE_NRDY, /* not ready */ + MV_DDR_IFACE_INIT, /* init'd */ + MV_DDR_IFACE_RDY, /* ready */ + MV_DDR_IFACE_DNE /* does not exist */ +}; + +enum mv_ddr_validation { + MV_DDR_VAL_DIS, + MV_DDR_VAL_RX, + MV_DDR_VAL_TX, + MV_DDR_VAL_RX_TX +}; + +struct mv_ddr_iface { + /* base addr of ap ddr interface belongs to */ + unsigned int ap_base; + + /* ddr interface id */ + unsigned int id; + + /* ddr interface state */ + enum mv_ddr_iface_state state; + + /* ddr interface mode (rar enabled/disabled) */ + enum mv_ddr_iface_mode iface_mode; + + /* ddr interface base address */ + unsigned long long iface_base_addr; + + /* ddr interface size - ddr flow will update this parameter */ + unsigned long long iface_byte_size; + + /* ddr i2c spd data address */ + unsigned int spd_data_addr; + + /* ddr i2c spd page 0 select address */ + unsigned int spd_page_sel_addr; + + /* ddr interface validation mode */ + enum mv_ddr_validation validation; + + /* ddr interface topology map */ + struct mv_ddr_topology_map tm; +}; + +struct mv_ddr_iface *mv_ddr_iface_get(void); + /* DDR3 training global configuration parameters */ struct tune_train_params { u32 ck_delay; diff --git a/drivers/ddr/marvell/a38x/ddr_training_ip_db.h b/drivers/ddr/marvell/a38x/ddr_training_ip_db.h index e7de5aef0ca..f1b4d8efc0e 100644 --- a/drivers/ddr/marvell/a38x/ddr_training_ip_db.h +++ b/drivers/ddr/marvell/a38x/ddr_training_ip_db.h @@ -6,10 +6,8 @@ #ifndef _DDR_TRAINING_IP_DB_H_ #define _DDR_TRAINING_IP_DB_H_ -#include "ddr_topology_def.h" #include "ddr3_training_ip_db.h" -u32 speed_bin_table(u8 index, enum speed_bin_table_elements element); u32 pattern_table_get_word(u32 dev_num, enum hws_pattern type, u8 index); #endif /* _DDR3_TRAINING_IP_DB_H_ */ diff --git a/drivers/ddr/marvell/a38x/dram_if.h b/drivers/ddr/marvell/a38x/dram_if.h new file mode 100644 index 00000000000..4d0846489b9 --- /dev/null +++ b/drivers/ddr/marvell/a38x/dram_if.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2016 Marvell International Ltd. + */ + +#ifndef _DRAM_IF_H_ +#define _DRAM_IF_H_ + +/* TODO: update atf to this new prototype */ +int dram_init(void); +void dram_mmap_config(void); +unsigned long long dram_iface_mem_sz_get(void); +#endif /* _DRAM_IF_H_ */ diff --git a/drivers/ddr/marvell/a38x/mv_ddr_build_message.c b/drivers/ddr/marvell/a38x/mv_ddr_build_message.c index 2b49b77f730..cc6234fd406 100644 --- a/drivers/ddr/marvell/a38x/mv_ddr_build_message.c +++ b/drivers/ddr/marvell/a38x/mv_ddr_build_message.c @@ -1,3 +1,3 @@ // SPDX-License-Identifier: GPL-2.0 const char mv_ddr_build_message[] = ""; -const char mv_ddr_version_string[] = "mv_ddr: mv_ddr-armada-17.10.4"; +const char mv_ddr_version_string[] = "mv_ddr: mv_ddr-armada-18.09.2"; diff --git a/drivers/ddr/marvell/a38x/mv_ddr_common.h b/drivers/ddr/marvell/a38x/mv_ddr_common.h index c71ff442edd..321a390c0d3 100644 --- a/drivers/ddr/marvell/a38x/mv_ddr_common.h +++ b/drivers/ddr/marvell/a38x/mv_ddr_common.h @@ -9,10 +9,44 @@ extern const char mv_ddr_build_message[]; extern const char mv_ddr_version_string[]; -#define MV_DDR_NUM_BITS_IN_BYTE 8 -#define MV_DDR_MEGA_BITS (1024 * 1024) +#define _1K 0x00000400 +#define _4K 0x00001000 +#define _8K 0x00002000 +#define _16K 0x00004000 +#define _32K 0x00008000 +#define _64K 0x00010000 +#define _128K 0x00020000 +#define _256K 0x00040000 +#define _512K 0x00080000 + +#define _1M 0x00100000 +#define _2M 0x00200000 +#define _4M 0x00400000 +#define _8M 0x00800000 +#define _16M 0x01000000 +#define _32M 0x02000000 +#define _64M 0x04000000 +#define _128M 0x08000000 +#define _256M 0x10000000 +#define _512M 0x20000000 + +#define _1G 0x40000000 +#define _2G 0x80000000 +#define _4G 0x100000000 +#define _8G 0x200000000 +#define _16G 0x400000000 +#define _32G 0x800000000 +#define _64G 0x1000000000 +#define _128G 0x2000000000 + +#define MEGA 1000000 +#define MV_DDR_MEGABYTE (1024 * 1024) #define MV_DDR_32_BITS_MASK 0xffffffff +#define GET_MAX_VALUE(x, y) \ + (((x) > (y)) ? (x) : (y)) + +void mv_ddr_ver_print(void); unsigned int ceil_div(unsigned int x, unsigned int y); unsigned int time_to_nclk(unsigned int t, unsigned int tclk); int round_div(unsigned int dividend, unsigned int divisor, unsigned int *quotient); diff --git a/drivers/ddr/marvell/a38x/mv_ddr_plat.c b/drivers/ddr/marvell/a38x/mv_ddr_plat.c index 2f318cb9ea7..cc7942d0ba3 100644 --- a/drivers/ddr/marvell/a38x/mv_ddr_plat.c +++ b/drivers/ddr/marvell/a38x/mv_ddr_plat.c @@ -4,7 +4,8 @@ */ #include "ddr3_init.h" - +#include "mv_ddr_training_db.h" +#include "mv_ddr_regs.h" #include "mv_ddr_sys_env_lib.h" #define DDR_INTERFACES_NUM 1 @@ -58,42 +59,42 @@ static struct dlb_config *sys_env_dlb_config_ptr_get(void) return &ddr3_dlb_config_table[0]; } -static u8 a38x_bw_per_freq[DDR_FREQ_LAST] = { - 0x3, /* DDR_FREQ_100 */ - 0x4, /* DDR_FREQ_400 */ - 0x4, /* DDR_FREQ_533 */ - 0x5, /* DDR_FREQ_667 */ - 0x5, /* DDR_FREQ_800 */ - 0x5, /* DDR_FREQ_933 */ - 0x5, /* DDR_FREQ_1066 */ - 0x3, /* DDR_FREQ_311 */ - 0x3, /* DDR_FREQ_333 */ - 0x4, /* DDR_FREQ_467 */ - 0x5, /* DDR_FREQ_850 */ - 0x5, /* DDR_FREQ_600 */ - 0x3, /* DDR_FREQ_300 */ - 0x5, /* DDR_FREQ_900 */ - 0x3, /* DDR_FREQ_360 */ - 0x5 /* DDR_FREQ_1000 */ +static u8 a38x_bw_per_freq[MV_DDR_FREQ_LAST] = { + 0x3, /* MV_DDR_FREQ_100 */ + 0x4, /* MV_DDR_FREQ_400 */ + 0x4, /* MV_DDR_FREQ_533 */ + 0x5, /* MV_DDR_FREQ_667 */ + 0x5, /* MV_DDR_FREQ_800 */ + 0x5, /* MV_DDR_FREQ_933 */ + 0x5, /* MV_DDR_FREQ_1066 */ + 0x3, /* MV_DDR_FREQ_311 */ + 0x3, /* MV_DDR_FREQ_333 */ + 0x4, /* MV_DDR_FREQ_467 */ + 0x5, /* MV_DDR_FREQ_850 */ + 0x5, /* MV_DDR_FREQ_600 */ + 0x3, /* MV_DDR_FREQ_300 */ + 0x5, /* MV_DDR_FREQ_900 */ + 0x3, /* MV_DDR_FREQ_360 */ + 0x5 /* MV_DDR_FREQ_1000 */ }; -static u8 a38x_rate_per_freq[DDR_FREQ_LAST] = { - 0x1, /* DDR_FREQ_100 */ - 0x2, /* DDR_FREQ_400 */ - 0x2, /* DDR_FREQ_533 */ - 0x2, /* DDR_FREQ_667 */ - 0x2, /* DDR_FREQ_800 */ - 0x3, /* DDR_FREQ_933 */ - 0x3, /* DDR_FREQ_1066 */ - 0x1, /* DDR_FREQ_311 */ - 0x1, /* DDR_FREQ_333 */ - 0x2, /* DDR_FREQ_467 */ - 0x2, /* DDR_FREQ_850 */ - 0x2, /* DDR_FREQ_600 */ - 0x1, /* DDR_FREQ_300 */ - 0x2, /* DDR_FREQ_900 */ - 0x1, /* DDR_FREQ_360 */ - 0x2 /* DDR_FREQ_1000 */ +static u8 a38x_rate_per_freq[MV_DDR_FREQ_LAST] = { + 0x1, /* MV_DDR_FREQ_100 */ + 0x2, /* MV_DDR_FREQ_400 */ + 0x2, /* MV_DDR_FREQ_533 */ + 0x2, /* MV_DDR_FREQ_667 */ + 0x2, /* MV_DDR_FREQ_800 */ + 0x3, /* MV_DDR_FREQ_933 */ + 0x3, /* MV_DDR_FREQ_1066 */ + 0x1, /* MV_DDR_FREQ_311 */ + 0x1, /* MV_DDR_FREQ_333 */ + 0x2, /* MV_DDR_FREQ_467 */ + 0x2, /* MV_DDR_FREQ_850 */ + 0x2, /* MV_DDR_FREQ_600 */ + 0x1, /* MV_DDR_FREQ_300 */ + 0x2, /* MV_DDR_FREQ_900 */ + 0x1, /* MV_DDR_FREQ_360 */ + 0x2 /* MV_DDR_FREQ_1000 */ }; static u16 a38x_vco_freq_per_sar_ref_clk_25_mhz[] = { @@ -177,10 +178,11 @@ static u32 dq_bit_map_2_phy_pin[] = { void mv_ddr_mem_scrubbing(void) { + ddr3_new_tip_ecc_scrub(); } static int ddr3_tip_a38x_set_divider(u8 dev_num, u32 if_id, - enum hws_ddr_freq freq); + enum mv_ddr_freq freq); /* * Read temperature TJ value @@ -219,7 +221,7 @@ static u32 ddr3_ctrl_get_junc_temp(u8 dev_num) * Notes: * Returns: MV_OK if success, other error code if fail. */ -static int ddr3_tip_a38x_get_freq_config(u8 dev_num, enum hws_ddr_freq freq, +static int ddr3_tip_a38x_get_freq_config(u8 dev_num, enum mv_ddr_freq freq, struct hws_tip_freq_config_info *freq_config_info) { @@ -377,13 +379,13 @@ static int ddr3_tip_a38x_select_ddr_controller(u8 dev_num, int enable) static u8 ddr3_tip_clock_mode(u32 frequency) { - if ((frequency == DDR_FREQ_LOW_FREQ) || (freq_val[frequency] <= 400)) + if ((frequency == MV_DDR_FREQ_LOW_FREQ) || (mv_ddr_freq_get(frequency) <= 400)) return 1; return 2; } -static int mv_ddr_sar_freq_get(int dev_num, enum hws_ddr_freq *freq) +static int mv_ddr_sar_freq_get(int dev_num, enum mv_ddr_freq *freq) { u32 reg, ref_clk_satr; @@ -402,7 +404,7 @@ static int mv_ddr_sar_freq_get(int dev_num, enum hws_ddr_freq *freq) reg)); /* fallthrough */ case 0x0: - *freq = DDR_FREQ_333; + *freq = MV_DDR_FREQ_333; break; case 0x3: DEBUG_TRAINING_ACCESS(DEBUG_LEVEL_ERROR, @@ -410,7 +412,7 @@ static int mv_ddr_sar_freq_get(int dev_num, enum hws_ddr_freq *freq) reg)); /* fallthrough */ case 0x2: - *freq = DDR_FREQ_400; + *freq = MV_DDR_FREQ_400; break; case 0xd: DEBUG_TRAINING_ACCESS(DEBUG_LEVEL_ERROR, @@ -418,10 +420,10 @@ static int mv_ddr_sar_freq_get(int dev_num, enum hws_ddr_freq *freq) reg)); /* fallthrough */ case 0x4: - *freq = DDR_FREQ_533; + *freq = MV_DDR_FREQ_533; break; case 0x6: - *freq = DDR_FREQ_600; + *freq = MV_DDR_FREQ_600; break; case 0x11: case 0x14: @@ -430,7 +432,7 @@ static int mv_ddr_sar_freq_get(int dev_num, enum hws_ddr_freq *freq) reg)); /* fallthrough */ case 0x8: - *freq = DDR_FREQ_667; + *freq = MV_DDR_FREQ_667; break; case 0x15: case 0x1b: @@ -439,16 +441,16 @@ static int mv_ddr_sar_freq_get(int dev_num, enum hws_ddr_freq *freq) reg)); /* fallthrough */ case 0xc: - *freq = DDR_FREQ_800; + *freq = MV_DDR_FREQ_800; break; case 0x10: - *freq = DDR_FREQ_933; + *freq = MV_DDR_FREQ_933; break; case 0x12: - *freq = DDR_FREQ_900; + *freq = MV_DDR_FREQ_900; break; case 0x13: - *freq = DDR_FREQ_933; + *freq = MV_DDR_FREQ_933; break; default: *freq = 0; @@ -457,16 +459,16 @@ static int mv_ddr_sar_freq_get(int dev_num, enum hws_ddr_freq *freq) } else { /* REFCLK 40MHz case */ switch (reg) { case 0x3: - *freq = DDR_FREQ_400; + *freq = MV_DDR_FREQ_400; break; case 0x5: - *freq = DDR_FREQ_533; + *freq = MV_DDR_FREQ_533; break; case 0xb: - *freq = DDR_FREQ_800; + *freq = MV_DDR_FREQ_800; break; case 0x1e: - *freq = DDR_FREQ_900; + *freq = MV_DDR_FREQ_900; break; default: *freq = 0; @@ -477,7 +479,7 @@ static int mv_ddr_sar_freq_get(int dev_num, enum hws_ddr_freq *freq) return MV_OK; } -static int ddr3_tip_a38x_get_medium_freq(int dev_num, enum hws_ddr_freq *freq) +static int ddr3_tip_a38x_get_medium_freq(int dev_num, enum mv_ddr_freq *freq) { u32 reg, ref_clk_satr; @@ -493,37 +495,37 @@ static int ddr3_tip_a38x_get_medium_freq(int dev_num, enum hws_ddr_freq *freq) case 0x0: case 0x1: /* Medium is same as TF to run PBS in this freq */ - *freq = DDR_FREQ_333; + *freq = MV_DDR_FREQ_333; break; case 0x2: case 0x3: /* Medium is same as TF to run PBS in this freq */ - *freq = DDR_FREQ_400; + *freq = MV_DDR_FREQ_400; break; case 0x4: case 0xd: /* Medium is same as TF to run PBS in this freq */ - *freq = DDR_FREQ_533; + *freq = MV_DDR_FREQ_533; break; case 0x8: case 0x10: case 0x11: case 0x14: - *freq = DDR_FREQ_333; + *freq = MV_DDR_FREQ_333; break; case 0xc: case 0x15: case 0x1b: - *freq = DDR_FREQ_400; + *freq = MV_DDR_FREQ_400; break; case 0x6: - *freq = DDR_FREQ_300; + *freq = MV_DDR_FREQ_300; break; case 0x12: - *freq = DDR_FREQ_360; + *freq = MV_DDR_FREQ_360; break; case 0x13: - *freq = DDR_FREQ_400; + *freq = MV_DDR_FREQ_400; break; default: *freq = 0; @@ -533,17 +535,17 @@ static int ddr3_tip_a38x_get_medium_freq(int dev_num, enum hws_ddr_freq *freq) switch (reg) { case 0x3: /* Medium is same as TF to run PBS in this freq */ - *freq = DDR_FREQ_400; + *freq = MV_DDR_FREQ_400; break; case 0x5: /* Medium is same as TF to run PBS in this freq */ - *freq = DDR_FREQ_533; + *freq = MV_DDR_FREQ_533; break; case 0xb: - *freq = DDR_FREQ_400; + *freq = MV_DDR_FREQ_400; break; case 0x1e: - *freq = DDR_FREQ_360; + *freq = MV_DDR_FREQ_360; break; default: *freq = 0; @@ -682,7 +684,7 @@ static int mv_ddr_sw_db_init(u32 dev_num, u32 board_id) static int mv_ddr_training_mask_set(void) { struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); - enum hws_ddr_freq ddr_freq = tm->interface_params[0].memory_freq; + enum mv_ddr_freq ddr_freq = tm->interface_params[0].memory_freq; mask_tune_func = (SET_LOW_FREQ_MASK_BIT | LOAD_PATTERN_MASK_BIT | @@ -699,7 +701,7 @@ static int mv_ddr_training_mask_set(void) CENTRALIZATION_TX_MASK_BIT); rl_mid_freq_wa = 1; - if ((ddr_freq == DDR_FREQ_333) || (ddr_freq == DDR_FREQ_400)) { + if ((ddr_freq == MV_DDR_FREQ_333) || (ddr_freq == MV_DDR_FREQ_400)) { mask_tune_func = (WRITE_LEVELING_MASK_BIT | LOAD_PATTERN_2_MASK_BIT | WRITE_LEVELING_SUPP_MASK_BIT | @@ -712,7 +714,7 @@ static int mv_ddr_training_mask_set(void) } /* Supplementary not supported for ECC modes */ - if (1 == ddr3_if_ecc_enabled()) { + if (mv_ddr_is_ecc_ena()) { mask_tune_func &= ~WRITE_LEVELING_SUPP_TF_MASK_BIT; mask_tune_func &= ~WRITE_LEVELING_SUPP_MASK_BIT; mask_tune_func &= ~PBS_TX_MASK_BIT; @@ -734,11 +736,12 @@ void mv_ddr_set_calib_controller(void) } static int ddr3_tip_a38x_set_divider(u8 dev_num, u32 if_id, - enum hws_ddr_freq frequency) + enum mv_ddr_freq frequency) { u32 divider = 0; u32 sar_val, ref_clk_satr; u32 async_val; + u32 freq = mv_ddr_freq_get(frequency); if (if_id != 0) { DEBUG_TRAINING_ACCESS(DEBUG_LEVEL_ERROR, @@ -755,11 +758,11 @@ static int ddr3_tip_a38x_set_divider(u8 dev_num, u32 if_id, ref_clk_satr = reg_read(DEVICE_SAMPLE_AT_RESET2_REG); if (((ref_clk_satr >> DEVICE_SAMPLE_AT_RESET2_REG_REFCLK_OFFSET) & 0x1) == DEVICE_SAMPLE_AT_RESET2_REG_REFCLK_25MHZ) - divider = a38x_vco_freq_per_sar_ref_clk_25_mhz[sar_val] / freq_val[frequency]; + divider = a38x_vco_freq_per_sar_ref_clk_25_mhz[sar_val] / freq; else - divider = a38x_vco_freq_per_sar_ref_clk_40_mhz[sar_val] / freq_val[frequency]; + divider = a38x_vco_freq_per_sar_ref_clk_40_mhz[sar_val] / freq; - if ((async_mode_at_tf == 1) && (freq_val[frequency] > 400)) { + if ((async_mode_at_tf == 1) && (freq > 400)) { /* Set async mode */ dunit_write(0x20220, 0x1000, 0x1000); dunit_write(0xe42f4, 0x200, 0x200); @@ -769,42 +772,38 @@ static int ddr3_tip_a38x_set_divider(u8 dev_num, u32 if_id, /* Set KNL values */ switch (frequency) { -#ifdef CONFIG_DDR3 - case DDR_FREQ_467: + case MV_DDR_FREQ_467: async_val = 0x806f012; break; - case DDR_FREQ_533: + case MV_DDR_FREQ_533: async_val = 0x807f012; break; - case DDR_FREQ_600: + case MV_DDR_FREQ_600: async_val = 0x805f00a; break; -#endif - case DDR_FREQ_667: + case MV_DDR_FREQ_667: async_val = 0x809f012; break; - case DDR_FREQ_800: + case MV_DDR_FREQ_800: async_val = 0x807f00a; break; -#ifdef CONFIG_DDR3 - case DDR_FREQ_850: + case MV_DDR_FREQ_850: async_val = 0x80cb012; break; -#endif - case DDR_FREQ_900: + case MV_DDR_FREQ_900: async_val = 0x80d7012; break; - case DDR_FREQ_933: + case MV_DDR_FREQ_933: async_val = 0x80df012; break; - case DDR_FREQ_1000: + case MV_DDR_FREQ_1000: async_val = 0x80ef012; break; - case DDR_FREQ_1066: + case MV_DDR_FREQ_1066: async_val = 0x80ff012; break; default: - /* set DDR_FREQ_667 as default */ + /* set MV_DDR_FREQ_667 as default */ async_val = 0x809f012; } dunit_write(0xe42f0, 0xffffffff, async_val); @@ -890,7 +889,7 @@ int mv_ddr_early_init(void) mv_ddr_sw_db_init(0, 0); - if (tm->interface_params[0].memory_freq != DDR_FREQ_SAR) + if (tm->interface_params[0].memory_freq != MV_DDR_FREQ_SAR) async_mode_at_tf = 1; return MV_OK; @@ -934,7 +933,7 @@ int ddr3_silicon_post_init(void) u32 mv_ddr_init_freq_get(void) { - enum hws_ddr_freq freq; + enum mv_ddr_freq freq; mv_ddr_sar_freq_get(0, &freq); diff --git a/drivers/ddr/marvell/a38x/mv_ddr_plat.h b/drivers/ddr/marvell/a38x/mv_ddr_plat.h index 9c5fdecd934..281d4c23013 100644 --- a/drivers/ddr/marvell/a38x/mv_ddr_plat.h +++ b/drivers/ddr/marvell/a38x/mv_ddr_plat.h @@ -6,6 +6,7 @@ #ifndef _MV_DDR_PLAT_H #define _MV_DDR_PLAT_H +#define MAX_DEVICE_NUM 1 #define MAX_INTERFACE_NUM 1 #define MAX_BUS_NUM 5 #define DDR_IF_CTRL_SUBPHYS_NUM 3 @@ -121,6 +122,9 @@ #define DLB_QUEUE_MAP_REG 0x1784 #define DLB_SPLIT_REG 0x1788 +/* ck swap control subphy number */ +#define CK_SWAP_CTRL_PHY_NUM 2 + /* Subphy result control per byte registers */ #define RESULT_CONTROL_BYTE_PUP_0_REG 0x1830 #define RESULT_CONTROL_BYTE_PUP_1_REG 0x1834 @@ -221,7 +225,7 @@ extern u16 odt_intercept[]; int mv_ddr_pre_training_soc_config(const char *ddr_type); int mv_ddr_post_training_soc_config(const char *ddr_type); void mv_ddr_mem_scrubbing(void); - +u32 mv_ddr_init_freq_get(void); void mv_ddr_odpg_enable(void); void mv_ddr_odpg_disable(void); void mv_ddr_odpg_done_clr(void); @@ -233,4 +237,5 @@ int mv_ddr_pre_training_fixup(void); int mv_ddr_post_training_fixup(void); int mv_ddr_manual_cal_do(void); int ddr3_calc_mem_cs_size(u32 cs, uint64_t *cs_size); + #endif /* _MV_DDR_PLAT_H */ diff --git a/drivers/ddr/marvell/a38x/mv_ddr_regs.h b/drivers/ddr/marvell/a38x/mv_ddr_regs.h index ceda204a498..cf2a6c92e80 100644 --- a/drivers/ddr/marvell/a38x/mv_ddr_regs.h +++ b/drivers/ddr/marvell/a38x/mv_ddr_regs.h @@ -134,6 +134,7 @@ #define SDRAM_OP_CMD_CS_BASE 8 #define SDRAM_OP_CMD_CS_OFFS(cs) (SDRAM_OP_CMD_CS_BASE + (cs)) #define SDRAM_OP_CMD_CS_MASK 0x1 +#define SDRAM_OP_CMD_ALL_CS_MASK 0xf enum { CMD_NORMAL, CMD_PRECHARGE, @@ -270,6 +271,10 @@ enum { #define ZQC_CFG_REG 0x15e4 #define DRAM_PHY_CFG_REG 0x15ec #define ODPG_CTRL_CTRL_REG 0x1600 +#define ODPG_CTRL_AUTO_REFRESH_OFFS 21 +#define ODPG_CTRL_AUTO_REFRESH_MASK 0x1 +#define ODPG_CTRL_AUTO_REFRESH_DIS 1 +#define ODPG_CTRL_AUTO_REFRESH_ENA 0 #define ODPG_DATA_CTRL_REG 0x1630 #define ODPG_WRBUF_WR_CTRL_OFFS 0 @@ -406,6 +411,20 @@ enum { #define CRX_PHY_REG(cs) (CRX_PHY_BASE + (cs) * 0x4) #define PHY_CTRL_PHY_REG 0x90 +#define INV_PAD0_OFFS 2 +#define INV_PAD1_OFFS 3 +#define INV_PAD2_OFFS 4 +#define INV_PAD3_OFFS 5 +#define INV_PAD4_OFFS 6 +#define INV_PAD5_OFFS 7 +#define INV_PAD6_OFFS 8 +#define INV_PAD7_OFFS 9 +#define INV_PAD8_OFFS 10 +#define INV_PAD9_OFFS 11 +#define INV_PAD10_OFFS 12 +#define INV_PAD_MASK 0x1 +#define INVERT_PAD 1 + #define ADLL_CFG0_PHY_REG 0x92 #define ADLL_CFG1_PHY_REG 0x93 #define ADLL_CFG2_PHY_REG 0x94 diff --git a/drivers/ddr/marvell/a38x/mv_ddr_spd.c b/drivers/ddr/marvell/a38x/mv_ddr_spd.c index e9e7f18098b..04dbfe94d66 100644 --- a/drivers/ddr/marvell/a38x/mv_ddr_spd.c +++ b/drivers/ddr/marvell/a38x/mv_ddr_spd.c @@ -81,9 +81,6 @@ int mv_ddr_spd_timing_calc(union mv_ddr_spd_data *spd_data, unsigned int timing_ timing_data[MV_DDR_TWR_MIN] = (spd_data->byte_fields.byte_42 + (spd_data->byte_fields.byte_41.bit_fields.t_wr_min_msn << MV_DDR_SPD_MSB_OFFS)) * MV_DDR_SPD_DATA_MTB; - /* FIXME: wa: set twr to a default value, if it's unset on spd */ - if (timing_data[MV_DDR_TWR_MIN] == 0) - timing_data[MV_DDR_TWR_MIN] = 15000; /* t rcd min, ps */ calc_val = spd_data->byte_fields.byte_25 * MV_DDR_SPD_DATA_MTB + @@ -127,6 +124,13 @@ int mv_ddr_spd_timing_calc(union mv_ddr_spd_data *spd_data, unsigned int timing_ return 1; timing_data[MV_DDR_TRRD_L_MIN] = calc_val; + /* t ccd l min, ps */ + calc_val = spd_data->byte_fields.byte_40 * MV_DDR_SPD_DATA_MTB + + (signed char)spd_data->byte_fields.byte_117 * MV_DDR_SPD_DATA_FTB; + if (calc_val < 0) + return 1; + timing_data[MV_DDR_TCCD_L_MIN] = calc_val; + /* t faw min, ps */ timing_data[MV_DDR_TFAW_MIN] = (spd_data->byte_fields.byte_37 + (spd_data->byte_fields.byte_36.bit_fields.t_faw_min_msn << MV_DDR_SPD_MSB_OFFS)) * @@ -136,17 +140,11 @@ int mv_ddr_spd_timing_calc(union mv_ddr_spd_data *spd_data, unsigned int timing_ timing_data[MV_DDR_TWTR_S_MIN] = (spd_data->byte_fields.byte_44 + (spd_data->byte_fields.byte_43.bit_fields.t_wtr_s_min_msn << MV_DDR_SPD_MSB_OFFS)) * MV_DDR_SPD_DATA_MTB; - /* FIXME: wa: set twtr_s to a default value, if it's unset on spd */ - if (timing_data[MV_DDR_TWTR_S_MIN] == 0) - timing_data[MV_DDR_TWTR_S_MIN] = 2500; /* t wtr l min, ps */ timing_data[MV_DDR_TWTR_L_MIN] = (spd_data->byte_fields.byte_45 + (spd_data->byte_fields.byte_43.bit_fields.t_wtr_l_min_msn << MV_DDR_SPD_MSB_OFFS)) * MV_DDR_SPD_DATA_MTB; - /* FIXME: wa: set twtr_l to a default value, if it's unset on spd */ - if (timing_data[MV_DDR_TWTR_L_MIN] == 0) - timing_data[MV_DDR_TWTR_L_MIN] = 7500; return 0; } diff --git a/drivers/ddr/marvell/a38x/mv_ddr_topology.c b/drivers/ddr/marvell/a38x/mv_ddr_topology.c index f56ce067707..ef3b658a789 100644 --- a/drivers/ddr/marvell/a38x/mv_ddr_topology.c +++ b/drivers/ddr/marvell/a38x/mv_ddr_topology.c @@ -2,15 +2,16 @@ /* * Copyright (C) Marvell International Ltd. and its affiliates */ +#include "ddr_ml_wrapper.h" +#include "mv_ddr_plat.h" #include "mv_ddr_topology.h" #include "mv_ddr_common.h" #include "mv_ddr_spd.h" -#include "ddr3_init.h" #include "ddr_topology_def.h" #include "ddr3_training_ip_db.h" #include "ddr3_training_ip.h" - +#include "mv_ddr_training_db.h" unsigned int mv_ddr_cl_calc(unsigned int taa_min, unsigned int tclk) { @@ -32,54 +33,57 @@ unsigned int mv_ddr_cwl_calc(unsigned int tclk) cwl = 11; else if (tclk >= 833) cwl = 12; + else if (tclk >= 750) + cwl = 14; + else if (tclk >= 625) + cwl = 16; else cwl = 0; return cwl; } -struct mv_ddr_topology_map *mv_ddr_topology_map_update(void) +int mv_ddr_topology_map_update(void) { struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); + struct if_params *iface_params = &(tm->interface_params[0]); unsigned int octets_per_if_num = ddr3_tip_dev_attr_get(0, MV_ATTR_OCTET_PER_INTERFACE); - enum hws_speed_bin speed_bin_index; - enum hws_ddr_freq freq = DDR_FREQ_LAST; + enum mv_ddr_speed_bin speed_bin_index; + enum mv_ddr_freq freq = MV_DDR_FREQ_LAST; unsigned int tclk; unsigned char val = 0; int i; - - if (tm->interface_params[0].memory_freq == DDR_FREQ_SAR) - tm->interface_params[0].memory_freq = mv_ddr_init_freq_get(); + if (iface_params->memory_freq == MV_DDR_FREQ_SAR) + iface_params->memory_freq = mv_ddr_init_freq_get(); if (tm->cfg_src == MV_DDR_CFG_SPD) { /* check dram device type */ val = mv_ddr_spd_dev_type_get(&tm->spd_data); if (val != MV_DDR_SPD_DEV_TYPE_DDR4) { printf("mv_ddr: unsupported dram device type found\n"); - return NULL; + return -1; } /* update topology map with timing data */ if (mv_ddr_spd_timing_calc(&tm->spd_data, tm->timing_data) > 0) { printf("mv_ddr: negative timing data found\n"); - return NULL; + return -1; } /* update device width in topology map */ - tm->interface_params[0].bus_width = mv_ddr_spd_dev_width_get(&tm->spd_data); + iface_params->bus_width = mv_ddr_spd_dev_width_get(&tm->spd_data); /* update die capacity in topology map */ - tm->interface_params[0].memory_size = mv_ddr_spd_die_capacity_get(&tm->spd_data); + iface_params->memory_size = mv_ddr_spd_die_capacity_get(&tm->spd_data); /* update bus bit mask in topology map */ tm->bus_act_mask = mv_ddr_bus_bit_mask_get(); /* update cs bit mask in topology map */ val = mv_ddr_spd_cs_bit_mask_get(&tm->spd_data); - for (i = 0; i < octets_per_if_num; i++) { - tm->interface_params[0].as_bus_params[i].cs_bitmask = val; - } + for (i = 0; i < octets_per_if_num; i++) + iface_params->as_bus_params[i].cs_bitmask = val; /* check dram module type */ val = mv_ddr_spd_module_type_get(&tm->spd_data); @@ -93,48 +97,44 @@ struct mv_ddr_topology_map *mv_ddr_topology_map_update(void) break; default: printf("mv_ddr: unsupported dram module type found\n"); - return NULL; + return -1; } /* update mirror bit mask in topology map */ val = mv_ddr_spd_mem_mirror_get(&tm->spd_data); - for (i = 0; i < octets_per_if_num; i++) { - tm->interface_params[0].as_bus_params[i].mirror_enable_bitmask = val << 1; - } + for (i = 0; i < octets_per_if_num; i++) + iface_params->as_bus_params[i].mirror_enable_bitmask = val << 1; - tclk = 1000000 / freq_val[tm->interface_params[0].memory_freq]; + tclk = 1000000 / mv_ddr_freq_get(iface_params->memory_freq); /* update cas write latency (cwl) */ val = mv_ddr_cwl_calc(tclk); if (val == 0) { printf("mv_ddr: unsupported cas write latency value found\n"); - return NULL; + return -1; } - tm->interface_params[0].cas_wl = val; + iface_params->cas_wl = val; /* update cas latency (cl) */ mv_ddr_spd_supported_cls_calc(&tm->spd_data); val = mv_ddr_cl_calc(tm->timing_data[MV_DDR_TAA_MIN], tclk); if (val == 0) { printf("mv_ddr: unsupported cas latency value found\n"); - return NULL; + return -1; } - tm->interface_params[0].cas_l = val; + iface_params->cas_l = val; } else if (tm->cfg_src == MV_DDR_CFG_DEFAULT) { /* set cas and cas-write latencies per speed bin, if they unset */ - speed_bin_index = tm->interface_params[0].speed_bin_index; - freq = tm->interface_params[0].memory_freq; + speed_bin_index = iface_params->speed_bin_index; + freq = iface_params->memory_freq; - if (tm->interface_params[0].cas_l == 0) - tm->interface_params[0].cas_l = - cas_latency_table[speed_bin_index].cl_val[freq]; + if (iface_params->cas_l == 0) + iface_params->cas_l = mv_ddr_cl_val_get(speed_bin_index, freq); - if (tm->interface_params[0].cas_wl == 0) - tm->interface_params[0].cas_wl = - cas_write_latency_table[speed_bin_index].cl_val[freq]; + if (iface_params->cas_wl == 0) + iface_params->cas_wl = mv_ddr_cwl_val_get(speed_bin_index, freq); } - - return tm; + return 0; } unsigned short mv_ddr_bus_bit_mask_get(void) @@ -195,3 +195,150 @@ unsigned int mv_ddr_if_bus_width_get(void) return bus_width; } + +unsigned int mv_ddr_cs_num_get(void) +{ + unsigned int cs_num = 0; + unsigned int cs, sphy; + struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); + struct if_params *iface_params = &(tm->interface_params[0]); + unsigned int sphy_max = ddr3_tip_dev_attr_get(0, MV_ATTR_OCTET_PER_INTERFACE); + + for (sphy = 0; sphy < sphy_max; sphy++) { + VALIDATE_BUS_ACTIVE(tm->bus_act_mask, sphy); + break; + } + + for (cs = 0; cs < MAX_CS_NUM; cs++) { + VALIDATE_ACTIVE(iface_params->as_bus_params[sphy].cs_bitmask, cs); + cs_num++; + } + + return cs_num; +} + +int mv_ddr_is_ecc_ena(void) +{ + struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); + + if (DDR3_IS_ECC_PUP4_MODE(tm->bus_act_mask) || + DDR3_IS_ECC_PUP3_MODE(tm->bus_act_mask) || + DDR3_IS_ECC_PUP8_MODE(tm->bus_act_mask)) + return 1; + else + return 0; +} + +/* translate topology map definition to real memory size in bits */ +static unsigned int mem_size[] = { + ADDR_SIZE_512MB, + ADDR_SIZE_1GB, + ADDR_SIZE_2GB, + ADDR_SIZE_4GB, + ADDR_SIZE_8GB + /* TODO: add capacity up to 256GB */ +}; + +unsigned long long mv_ddr_mem_sz_per_cs_get(void) +{ + unsigned long long mem_sz_per_cs; + unsigned int i, sphys, sphys_per_dunit; + unsigned int sphy_max = ddr3_tip_dev_attr_get(0, MV_ATTR_OCTET_PER_INTERFACE); + struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); + struct if_params *iface_params = &(tm->interface_params[0]); + + /* calc number of active subphys excl. ecc one */ + for (i = 0, sphys = 0; i < sphy_max - 1; i++) { + VALIDATE_BUS_ACTIVE(tm->bus_act_mask, i); + sphys++; + } + + /* calc number of subphys per ddr unit */ + if (iface_params->bus_width == MV_DDR_DEV_WIDTH_8BIT) + sphys_per_dunit = MV_DDR_ONE_SPHY_PER_DUNIT; + else if (iface_params->bus_width == MV_DDR_DEV_WIDTH_16BIT) + sphys_per_dunit = MV_DDR_TWO_SPHY_PER_DUNIT; + else { + printf("mv_ddr: unsupported bus width type found\n"); + return 0; + } + + /* calc dram size per cs */ + mem_sz_per_cs = (unsigned long long)mem_size[iface_params->memory_size] * + (unsigned long long)sphys / + (unsigned long long)sphys_per_dunit; + + return mem_sz_per_cs; +} + +unsigned long long mv_ddr_mem_sz_get(void) +{ + unsigned long long tot_mem_sz = 0; + unsigned long long mem_sz_per_cs = 0; + unsigned long long max_cs = mv_ddr_cs_num_get(); + + mem_sz_per_cs = mv_ddr_mem_sz_per_cs_get(); + tot_mem_sz = max_cs * mem_sz_per_cs; + + return tot_mem_sz; +} + +unsigned int mv_ddr_rtt_nom_get(void) +{ + struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); + unsigned int rtt_nom = tm->edata.mem_edata.rtt_nom; + + if (rtt_nom >= MV_DDR_RTT_NOM_PARK_RZQ_LAST) { + printf("error: %s: unsupported rtt_nom parameter found\n", __func__); + rtt_nom = PARAM_UNDEFINED; + } + + return rtt_nom; +} + +unsigned int mv_ddr_rtt_park_get(void) +{ + struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); + unsigned int cs_num = mv_ddr_cs_num_get(); + unsigned int rtt_park = MV_DDR_RTT_NOM_PARK_RZQ_LAST; + + if (cs_num > 0 && cs_num <= MAX_CS_NUM) + rtt_park = tm->edata.mem_edata.rtt_park[cs_num - 1]; + + if (rtt_park >= MV_DDR_RTT_NOM_PARK_RZQ_LAST) { + printf("error: %s: unsupported rtt_park parameter found\n", __func__); + rtt_park = PARAM_UNDEFINED; + } + + return rtt_park; +} + +unsigned int mv_ddr_rtt_wr_get(void) +{ + struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); + unsigned int cs_num = mv_ddr_cs_num_get(); + unsigned int rtt_wr = MV_DDR_RTT_WR_RZQ_LAST; + + if (cs_num > 0 && cs_num <= MAX_CS_NUM) + rtt_wr = tm->edata.mem_edata.rtt_wr[cs_num - 1]; + + if (rtt_wr >= MV_DDR_RTT_WR_RZQ_LAST) { + printf("error: %s: unsupported rtt_wr parameter found\n", __func__); + rtt_wr = PARAM_UNDEFINED; + } + + return rtt_wr; +} + +unsigned int mv_ddr_dic_get(void) +{ + struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); + unsigned int dic = tm->edata.mem_edata.dic; + + if (dic >= MV_DDR_DIC_RZQ_LAST) { + printf("error: %s: unsupported dic parameter found\n", __func__); + dic = PARAM_UNDEFINED; + } + + return dic; +} diff --git a/drivers/ddr/marvell/a38x/mv_ddr_topology.h b/drivers/ddr/marvell/a38x/mv_ddr_topology.h index 7bef2d1e0e8..766f25db573 100644 --- a/drivers/ddr/marvell/a38x/mv_ddr_topology.h +++ b/drivers/ddr/marvell/a38x/mv_ddr_topology.h @@ -6,6 +6,75 @@ #ifndef _MV_DDR_TOPOLOGY_H #define _MV_DDR_TOPOLOGY_H +#define MAX_CS_NUM 4 + +enum mv_ddr_speed_bin { + SPEED_BIN_DDR_800D, + SPEED_BIN_DDR_800E, + SPEED_BIN_DDR_1066E, + SPEED_BIN_DDR_1066F, + SPEED_BIN_DDR_1066G, + SPEED_BIN_DDR_1333F, + SPEED_BIN_DDR_1333G, + SPEED_BIN_DDR_1333H, + SPEED_BIN_DDR_1333J, + SPEED_BIN_DDR_1600G, + SPEED_BIN_DDR_1600H, + SPEED_BIN_DDR_1600J, + SPEED_BIN_DDR_1600K, + SPEED_BIN_DDR_1866J, + SPEED_BIN_DDR_1866K, + SPEED_BIN_DDR_1866L, + SPEED_BIN_DDR_1866M, + SPEED_BIN_DDR_2133K, + SPEED_BIN_DDR_2133L, + SPEED_BIN_DDR_2133M, + SPEED_BIN_DDR_2133N, + + SPEED_BIN_DDR_1333H_EXT, + SPEED_BIN_DDR_1600K_EXT, + SPEED_BIN_DDR_1866M_EXT +}; + +enum mv_ddr_freq { + MV_DDR_FREQ_LOW_FREQ, + MV_DDR_FREQ_400, + MV_DDR_FREQ_533, + MV_DDR_FREQ_667, + MV_DDR_FREQ_800, + MV_DDR_FREQ_933, + MV_DDR_FREQ_1066, + MV_DDR_FREQ_311, + MV_DDR_FREQ_333, + MV_DDR_FREQ_467, + MV_DDR_FREQ_850, + MV_DDR_FREQ_600, + MV_DDR_FREQ_300, + MV_DDR_FREQ_900, + MV_DDR_FREQ_360, + MV_DDR_FREQ_1000, + MV_DDR_FREQ_LAST, + MV_DDR_FREQ_SAR +}; + +enum mv_ddr_speed_bin_timing { + SPEED_BIN_TRCD, + SPEED_BIN_TRP, + SPEED_BIN_TRAS, + SPEED_BIN_TRC, + SPEED_BIN_TRRD1K, + SPEED_BIN_TRRD2K, + SPEED_BIN_TPD, + SPEED_BIN_TFAW1K, + SPEED_BIN_TFAW2K, + SPEED_BIN_TWTR, + SPEED_BIN_TRTP, + SPEED_BIN_TWR, + SPEED_BIN_TMOD, + SPEED_BIN_TXPDLL, + SPEED_BIN_TXSDLL +}; + /* ddr bus masks */ #define BUS_MASK_32BIT 0xf #define BUS_MASK_32BIT_ECC 0x1f @@ -16,6 +85,12 @@ #define MV_DDR_64BIT_ECC_PUP8_BUS_MASK 0x1ff #define MV_DDR_32BIT_ECC_PUP8_BUS_MASK 0x10f +#define MV_DDR_CS_BITMASK_1CS 0x1 +#define MV_DDR_CS_BITMASK_2CS 0x3 + +#define MV_DDR_ONE_SPHY_PER_DUNIT 1 +#define MV_DDR_TWO_SPHY_PER_DUNIT 2 + /* source of ddr configuration data */ enum mv_ddr_cfg_src { MV_DDR_CFG_DEFAULT, /* based on data in mv_ddr_topology_map structure */ @@ -25,11 +100,6 @@ enum mv_ddr_cfg_src { MV_DDR_CFG_LAST }; -enum mv_ddr_num_of_sub_phys_per_ddr_unit { - SINGLE_SUB_PHY = 1, - TWO_SUB_PHYS = 2 -}; - enum mv_ddr_temperature { MV_DDR_TEMP_LOW, MV_DDR_TEMP_NORMAL, @@ -53,12 +123,78 @@ enum mv_ddr_timing_data { MV_DDR_TRAS_MIN, /* min active to precharge delay time (t ras min) */ MV_DDR_TRRD_S_MIN, /* min activate to activate delay time (t rrd_s min), diff bank group */ MV_DDR_TRRD_L_MIN, /* min activate to activate delay time (t rrd_l min), same bank group */ + MV_DDR_TCCD_L_MIN, /* min cas to cas delay time (t ccd_l min), same bank group */ MV_DDR_TFAW_MIN, /* min four activate window delay time (t faw min) */ MV_DDR_TWTR_S_MIN, /* min write to read time (t wtr s min), diff bank group */ MV_DDR_TWTR_L_MIN, /* min write to read time (t wtr l min), same bank group */ MV_DDR_TDATA_LAST }; +enum mv_ddr_electrical_data { + MV_DDR_CK_DLY, + MV_DDR_PHY_REG3, + MV_DDR_ZPRI_DATA, + MV_DDR_ZNRI_DATA, + MV_DDR_ZPRI_CTRL, + MV_DDR_ZNRI_CTRL, + MV_DDR_ZPODT_DATA, + MV_DDR_ZNODT_DATA, + MV_DDR_ZPODT_CTRL, + MV_DDR_ZNODT_CTRL, + MV_DDR_DIC, + MV_DDR_ODT_CFG, + MV_DDR_RTT_NOM, + MV_DDR_RTT_WR, + MV_DDR_RTT_PARK, + MV_DDR_EDATA_LAST +}; + +/* memory electrical configuration values */ +enum mv_ddr_rtt_nom_park_evalue { + MV_DDR_RTT_NOM_PARK_RZQ_DISABLE, + MV_DDR_RTT_NOM_PARK_RZQ_DIV4, /* 60-Ohm; RZQ = 240-Ohm */ + MV_DDR_RTT_NOM_PARK_RZQ_DIV2, /* 120-Ohm; RZQ = 240-Ohm */ + MV_DDR_RTT_NOM_PARK_RZQ_DIV6, /* 40-Ohm; RZQ = 240-Ohm */ + MV_DDR_RTT_NOM_PARK_RZQ_DIV1, /* 240-Ohm; RZQ = 240-Ohm */ + MV_DDR_RTT_NOM_PARK_RZQ_DIV5, /* 48-Ohm; RZQ = 240-Ohm */ + MV_DDR_RTT_NOM_PARK_RZQ_DIV3, /* 80-Ohm; RZQ = 240-Ohm */ + MV_DDR_RTT_NOM_PARK_RZQ_DIV7, /* 34-Ohm; RZQ = 240-Ohm */ + MV_DDR_RTT_NOM_PARK_RZQ_LAST +}; + +enum mv_ddr_rtt_wr_evalue { + MV_DDR_RTT_WR_DYN_ODT_OFF, + MV_DDR_RTT_WR_RZQ_DIV2, /* 120-Ohm; RZQ = 240-Ohm */ + MV_DDR_RTT_WR_RZQ_DIV1, /* 240-Ohm; RZQ = 240-Ohm */ + MV_DDR_RTT_WR_HIZ, + MV_DDR_RTT_WR_RZQ_DIV3, /* 80-Ohm; RZQ = 240-Ohm */ + MV_DDR_RTT_WR_RZQ_LAST +}; + +enum mv_ddr_dic_evalue { + MV_DDR_DIC_RZQ_DIV7, /* 34-Ohm; RZQ = 240-Ohm */ + MV_DDR_DIC_RZQ_DIV5, /* 48-Ohm; RZQ = 240-Ohm */ + MV_DDR_DIC_RZQ_LAST +}; + +/* phy electrical configuration values */ +enum mv_ddr_ohm_evalue { + MV_DDR_OHM_30 = 30, + MV_DDR_OHM_48 = 48, + MV_DDR_OHM_60 = 60, + MV_DDR_OHM_80 = 80, + MV_DDR_OHM_120 = 120, + MV_DDR_OHM_240 = 240, + MV_DDR_OHM_LAST +}; + +/* mac electrical configuration values */ +enum mv_ddr_odt_cfg_evalue { + MV_DDR_ODT_CFG_NORMAL, + MV_DDR_ODT_CFG_ALWAYS_ON, + MV_DDR_ODT_CFG_LAST +}; + enum mv_ddr_dev_width { /* sdram device width */ MV_DDR_DEV_WIDTH_4BIT, MV_DDR_DEV_WIDTH_8BIT, @@ -119,11 +255,75 @@ enum mv_ddr_die_count { MV_DDR_DIE_CNT_LAST }; +#define IS_ACTIVE(mask, id) \ + ((mask) & (1 << (id))) + +#define VALIDATE_ACTIVE(mask, id) \ + { \ + if (IS_ACTIVE(mask, id) == 0) \ + continue; \ + } + +#define IS_IF_ACTIVE(if_mask, if_id) \ + ((if_mask) & (1 << (if_id))) + +#define VALIDATE_IF_ACTIVE(mask, id) \ + { \ + if (IS_IF_ACTIVE(mask, id) == 0) \ + continue; \ + } + +#define IS_BUS_ACTIVE(if_mask , if_id) \ + (((if_mask) >> (if_id)) & 1) + +#define VALIDATE_BUS_ACTIVE(mask, id) \ + { \ + if (IS_BUS_ACTIVE(mask, id) == 0) \ + continue; \ + } + +#define DDR3_IS_ECC_PUP3_MODE(if_mask) \ + (((if_mask) == BUS_MASK_16BIT_ECC_PUP3) ? 1 : 0) + +#define DDR3_IS_ECC_PUP4_MODE(if_mask) \ + (((if_mask) == BUS_MASK_32BIT_ECC || \ + (if_mask) == BUS_MASK_16BIT_ECC) ? 1 : 0) + +#define DDR3_IS_16BIT_DRAM_MODE(mask) \ + (((mask) == BUS_MASK_16BIT || \ + (mask) == BUS_MASK_16BIT_ECC || \ + (mask) == BUS_MASK_16BIT_ECC_PUP3) ? 1 : 0) + +#define DDR3_IS_ECC_PUP8_MODE(if_mask) \ + (((if_mask) == MV_DDR_32BIT_ECC_PUP8_BUS_MASK || \ + (if_mask) == MV_DDR_64BIT_ECC_PUP8_BUS_MASK) ? 1 : 0) + +#define MV_DDR_IS_64BIT_DRAM_MODE(mask) \ + ((((mask) & MV_DDR_64BIT_BUS_MASK) == MV_DDR_64BIT_BUS_MASK) || \ + (((mask) & MV_DDR_64BIT_ECC_PUP8_BUS_MASK) == MV_DDR_64BIT_ECC_PUP8_BUS_MASK) ? 1 : 0) + +#define MV_DDR_IS_32BIT_IN_64BIT_DRAM_MODE(mask, sphys) \ + (((sphys) == 9) && \ + (((mask) == BUS_MASK_32BIT) || \ + ((mask) == MV_DDR_32BIT_ECC_PUP8_BUS_MASK)) ? 1 : 0) + +#define MV_DDR_IS_HALF_BUS_DRAM_MODE(mask, sphys) \ + (MV_DDR_IS_32BIT_IN_64BIT_DRAM_MODE(mask, sphys) || \ + DDR3_IS_16BIT_DRAM_MODE(mask)) + +struct mv_ddr_topology_map *mv_ddr_topology_map_get(void); unsigned int mv_ddr_cl_calc(unsigned int taa_min, unsigned int tclk); unsigned int mv_ddr_cwl_calc(unsigned int tclk); -struct mv_ddr_topology_map *mv_ddr_topology_map_update(void); -struct dram_config *mv_ddr_dram_config_update(void); +int mv_ddr_topology_map_update(void); unsigned short mv_ddr_bus_bit_mask_get(void); unsigned int mv_ddr_if_bus_width_get(void); +unsigned int mv_ddr_cs_num_get(void); +int mv_ddr_is_ecc_ena(void); +unsigned long long mv_ddr_mem_sz_per_cs_get(void); +unsigned long long mv_ddr_mem_sz_get(void); +unsigned int mv_ddr_rtt_nom_get(void); +unsigned int mv_ddr_rtt_park_get(void); +unsigned int mv_ddr_rtt_wr_get(void); +unsigned int mv_ddr_dic_get(void); #endif /* _MV_DDR_TOPOLOGY_H */ diff --git a/drivers/ddr/marvell/a38x/mv_ddr_training_db.h b/drivers/ddr/marvell/a38x/mv_ddr_training_db.h new file mode 100644 index 00000000000..838be4574d9 --- /dev/null +++ b/drivers/ddr/marvell/a38x/mv_ddr_training_db.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018 Marvell International Ltd. + */ + +#ifndef _MV_DDR_TRAINING_DB_H +#define _MV_DDR_TRAINING_DB_H + +#include "mv_ddr_topology.h" + +/* in ns */ +#define TREFI_LOW 7800 +#define TREFI_HIGH 3900 + +enum mv_ddr_page_size { + MV_DDR_PAGE_SIZE_1K = 1, + MV_DDR_PAGE_SIZE_2K +}; + +struct mv_ddr_page_element { + /* 8-bit bus width page size */ + enum mv_ddr_page_size page_size_8bit; + /* 16-bit bus width page size */ + enum mv_ddr_page_size page_size_16bit; +}; + +/* cas latency value per frequency */ +struct mv_ddr_cl_val_per_freq { + unsigned int cl_val[MV_DDR_FREQ_LAST]; +}; + +u32 mv_ddr_rfc_get(u32 mem); +unsigned int *mv_ddr_freq_tbl_get(void); +u32 mv_ddr_freq_get(enum mv_ddr_freq freq); +u32 mv_ddr_page_size_get(enum mv_ddr_dev_width bus_width, enum mv_ddr_die_capacity mem_size); +unsigned int mv_ddr_speed_bin_timing_get(enum mv_ddr_speed_bin index, enum mv_ddr_speed_bin_timing element); +u32 mv_ddr_cl_val_get(u32 index, u32 freq); +u32 mv_ddr_cwl_val_get(u32 index, u32 freq); + +#endif /* _MV_DDR_TRAINING_DB_H */ diff --git a/drivers/ddr/marvell/a38x/xor.c b/drivers/ddr/marvell/a38x/xor.c index f859596d895..5fb9e216d38 100644 --- a/drivers/ddr/marvell/a38x/xor.c +++ b/drivers/ddr/marvell/a38x/xor.c @@ -4,6 +4,7 @@ */ #include "ddr3_init.h" +#include "mv_ddr_common.h" #include "xor_regs.h" /* defines */ @@ -339,16 +340,17 @@ void ddr3_new_tip_ecc_scrub(void) { u32 cs_c, max_cs; u32 cs_ena = 0; - u32 dev_num = 0; uint64_t total_mem_size, cs_mem_size = 0; printf("DDR Training Sequence - Start scrubbing\n"); - max_cs = ddr3_tip_max_cs_get(dev_num); + max_cs = mv_ddr_cs_num_get(); for (cs_c = 0; cs_c < max_cs; cs_c++) cs_ena |= 1 << cs_c; - /* assume that all CS have same size */ +#if defined(CONFIG_ARMADA_38X) || defined(CONFIG_ARMADA_39X) + /* all chip-selects are of same size */ ddr3_calc_mem_cs_size(0, &cs_mem_size); +#endif mv_sys_xor_init(max_cs, cs_ena, cs_mem_size, 0); total_mem_size = max_cs * cs_mem_size; diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 4ee6afad35e..8a4162eccdb 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -12,6 +12,20 @@ config DMA buses that is used to transfer data to and from memory. The uclass interface is defined in include/dma.h. +config DMA_CHANNELS + bool "Enable DMA channels support" + depends on DMA + help + Enable channels support for DMA. Some DMA controllers have multiple + channels which can either transfer data to/from different devices. + +config SANDBOX_DMA + bool "Enable the sandbox DMA test driver" + depends on DMA && DMA_CHANNELS && SANDBOX + help + Enable support for a test DMA uclass implementation. It stimulates + DMA transfer by simple copying data between channels. + config TI_EDMA3 bool "TI EDMA3 driver" help diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 4eaef8ac651..aff31f986a1 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_DMA) += dma-uclass.o obj-$(CONFIG_FSLDMAFEC) += MCD_tasksInit.o MCD_dmaApi.o MCD_tasks.o obj-$(CONFIG_APBH_DMA) += apbh_dma.o obj-$(CONFIG_FSL_DMA) += fsl_dma.o +obj-$(CONFIG_SANDBOX_DMA) += sandbox-dma-test.o obj-$(CONFIG_TI_KSNAV) += keystone_nav.o keystone_nav_cfg.o obj-$(CONFIG_TI_EDMA3) += ti-edma3.o obj-$(CONFIG_DMA_LPC32XX) += lpc32xx_dma.o diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c index a33f7d52dac..9c961cf1e2c 100644 --- a/drivers/dma/dma-uclass.c +++ b/drivers/dma/dma-uclass.c @@ -2,19 +2,192 @@ /* * Direct Memory Access U-Class driver * - * (C) Copyright 2015 - * Texas Instruments Incorporated, <www.ti.com> + * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com> + * Copyright (C) 2015 - 2018 Texas Instruments Incorporated <www.ti.com> + * Written by Mugunthan V N <mugunthanvnm@ti.com> * * Author: Mugunthan V N <mugunthanvnm@ti.com> */ #include <common.h> -#include <dma.h> #include <dm.h> -#include <dm/uclass-internal.h> -#include <dm/device-internal.h> +#include <dm/read.h> +#include <dma-uclass.h> +#include <dt-structs.h> #include <errno.h> +#ifdef CONFIG_DMA_CHANNELS +static inline struct dma_ops *dma_dev_ops(struct udevice *dev) +{ + return (struct dma_ops *)dev->driver->ops; +} + +# if CONFIG_IS_ENABLED(OF_CONTROL) +static int dma_of_xlate_default(struct dma *dma, + struct ofnode_phandle_args *args) +{ + debug("%s(dma=%p)\n", __func__, dma); + + if (args->args_count > 1) { + pr_err("Invaild args_count: %d\n", args->args_count); + return -EINVAL; + } + + if (args->args_count) + dma->id = args->args[0]; + else + dma->id = 0; + + return 0; +} + +int dma_get_by_index(struct udevice *dev, int index, struct dma *dma) +{ + int ret; + struct ofnode_phandle_args args; + struct udevice *dev_dma; + const struct dma_ops *ops; + + debug("%s(dev=%p, index=%d, dma=%p)\n", __func__, dev, index, dma); + + assert(dma); + dma->dev = NULL; + + ret = dev_read_phandle_with_args(dev, "dmas", "#dma-cells", 0, index, + &args); + if (ret) { + pr_err("%s: dev_read_phandle_with_args failed: err=%d\n", + __func__, ret); + return ret; + } + + ret = uclass_get_device_by_ofnode(UCLASS_DMA, args.node, &dev_dma); + if (ret) { + pr_err("%s: uclass_get_device_by_ofnode failed: err=%d\n", + __func__, ret); + return ret; + } + + dma->dev = dev_dma; + + ops = dma_dev_ops(dev_dma); + + if (ops->of_xlate) + ret = ops->of_xlate(dma, &args); + else + ret = dma_of_xlate_default(dma, &args); + if (ret) { + pr_err("of_xlate() failed: %d\n", ret); + return ret; + } + + return dma_request(dev_dma, dma); +} + +int dma_get_by_name(struct udevice *dev, const char *name, struct dma *dma) +{ + int index; + + debug("%s(dev=%p, name=%s, dma=%p)\n", __func__, dev, name, dma); + dma->dev = NULL; + + index = dev_read_stringlist_search(dev, "dma-names", name); + if (index < 0) { + pr_err("dev_read_stringlist_search() failed: %d\n", index); + return index; + } + + return dma_get_by_index(dev, index, dma); +} +# endif /* OF_CONTROL */ + +int dma_request(struct udevice *dev, struct dma *dma) +{ + struct dma_ops *ops = dma_dev_ops(dev); + + debug("%s(dev=%p, dma=%p)\n", __func__, dev, dma); + + dma->dev = dev; + + if (!ops->request) + return 0; + + return ops->request(dma); +} + +int dma_free(struct dma *dma) +{ + struct dma_ops *ops = dma_dev_ops(dma->dev); + + debug("%s(dma=%p)\n", __func__, dma); + + if (!ops->free) + return 0; + + return ops->free(dma); +} + +int dma_enable(struct dma *dma) +{ + struct dma_ops *ops = dma_dev_ops(dma->dev); + + debug("%s(dma=%p)\n", __func__, dma); + + if (!ops->enable) + return -ENOSYS; + + return ops->enable(dma); +} + +int dma_disable(struct dma *dma) +{ + struct dma_ops *ops = dma_dev_ops(dma->dev); + + debug("%s(dma=%p)\n", __func__, dma); + + if (!ops->disable) + return -ENOSYS; + + return ops->disable(dma); +} + +int dma_prepare_rcv_buf(struct dma *dma, void *dst, size_t size) +{ + struct dma_ops *ops = dma_dev_ops(dma->dev); + + debug("%s(dma=%p)\n", __func__, dma); + + if (!ops->prepare_rcv_buf) + return -1; + + return ops->prepare_rcv_buf(dma, dst, size); +} + +int dma_receive(struct dma *dma, void **dst, void *metadata) +{ + struct dma_ops *ops = dma_dev_ops(dma->dev); + + debug("%s(dma=%p)\n", __func__, dma); + + if (!ops->receive) + return -ENOSYS; + + return ops->receive(dma, dst, metadata); +} + +int dma_send(struct dma *dma, void *src, size_t len, void *metadata) +{ + struct dma_ops *ops = dma_dev_ops(dma->dev); + + debug("%s(dma=%p)\n", __func__, dma); + + if (!ops->send) + return -ENOSYS; + + return ops->send(dma, src, len, metadata); +} +#endif /* CONFIG_DMA_CHANNELS */ + int dma_get_device(u32 transfer_type, struct udevice **devp) { struct udevice *dev; diff --git a/drivers/dma/sandbox-dma-test.c b/drivers/dma/sandbox-dma-test.c new file mode 100644 index 00000000000..8fcef1863e2 --- /dev/null +++ b/drivers/dma/sandbox-dma-test.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Direct Memory Access U-Class Simulation driver + * + * Copyright (C) 2018 Texas Instruments Incorporated <www.ti.com> + * + * Author: Grygorii Strashko <grygorii.strashko@ti.com> + */ + +#include <common.h> +#include <dm.h> +#include <dm/read.h> +#include <dma-uclass.h> +#include <dt-structs.h> +#include <errno.h> + +#define SANDBOX_DMA_CH_CNT 3 +#define SANDBOX_DMA_BUF_SIZE 1024 + +struct sandbox_dma_chan { + struct sandbox_dma_dev *ud; + char name[20]; + u32 id; + enum dma_direction dir; + bool in_use; + bool enabled; +}; + +struct sandbox_dma_dev { + struct device *dev; + u32 ch_count; + struct sandbox_dma_chan channels[SANDBOX_DMA_CH_CNT]; + uchar buf[SANDBOX_DMA_BUF_SIZE]; + uchar *buf_rx; + size_t data_len; + u32 meta; +}; + +static int sandbox_dma_transfer(struct udevice *dev, int direction, + void *dst, void *src, size_t len) +{ + memcpy(dst, src, len); + + return 0; +} + +static int sandbox_dma_of_xlate(struct dma *dma, + struct ofnode_phandle_args *args) +{ + struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); + struct sandbox_dma_chan *uc; + + debug("%s(dma id=%u)\n", __func__, args->args[0]); + + if (args->args[0] >= SANDBOX_DMA_CH_CNT) + return -EINVAL; + + dma->id = args->args[0]; + + uc = &ud->channels[dma->id]; + + if (dma->id == 1) + uc->dir = DMA_MEM_TO_DEV; + else if (dma->id == 2) + uc->dir = DMA_DEV_TO_MEM; + else + uc->dir = DMA_MEM_TO_MEM; + debug("%s(dma id=%lu dir=%d)\n", __func__, dma->id, uc->dir); + + return 0; +} + +static int sandbox_dma_request(struct dma *dma) +{ + struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); + struct sandbox_dma_chan *uc; + + if (dma->id >= SANDBOX_DMA_CH_CNT) + return -EINVAL; + + uc = &ud->channels[dma->id]; + if (uc->in_use) + return -EBUSY; + + uc->in_use = true; + debug("%s(dma id=%lu in_use=%d)\n", __func__, dma->id, uc->in_use); + + return 0; +} + +static int sandbox_dma_free(struct dma *dma) +{ + struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); + struct sandbox_dma_chan *uc; + + if (dma->id >= SANDBOX_DMA_CH_CNT) + return -EINVAL; + + uc = &ud->channels[dma->id]; + if (!uc->in_use) + return -EINVAL; + + uc->in_use = false; + ud->buf_rx = NULL; + ud->data_len = 0; + debug("%s(dma id=%lu in_use=%d)\n", __func__, dma->id, uc->in_use); + + return 0; +} + +static int sandbox_dma_enable(struct dma *dma) +{ + struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); + struct sandbox_dma_chan *uc; + + if (dma->id >= SANDBOX_DMA_CH_CNT) + return -EINVAL; + + uc = &ud->channels[dma->id]; + if (!uc->in_use) + return -EINVAL; + if (uc->enabled) + return -EINVAL; + + uc->enabled = true; + debug("%s(dma id=%lu enabled=%d)\n", __func__, dma->id, uc->enabled); + + return 0; +} + +static int sandbox_dma_disable(struct dma *dma) +{ + struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); + struct sandbox_dma_chan *uc; + + if (dma->id >= SANDBOX_DMA_CH_CNT) + return -EINVAL; + + uc = &ud->channels[dma->id]; + if (!uc->in_use) + return -EINVAL; + if (!uc->enabled) + return -EINVAL; + + uc->enabled = false; + debug("%s(dma id=%lu enabled=%d)\n", __func__, dma->id, uc->enabled); + + return 0; +} + +static int sandbox_dma_send(struct dma *dma, + void *src, size_t len, void *metadata) +{ + struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); + struct sandbox_dma_chan *uc; + + if (dma->id >= SANDBOX_DMA_CH_CNT) + return -EINVAL; + if (!src || !metadata) + return -EINVAL; + + debug("%s(dma id=%lu)\n", __func__, dma->id); + + uc = &ud->channels[dma->id]; + if (uc->dir != DMA_MEM_TO_DEV) + return -EINVAL; + if (!uc->in_use) + return -EINVAL; + if (!uc->enabled) + return -EINVAL; + if (len >= SANDBOX_DMA_BUF_SIZE) + return -EINVAL; + + memcpy(ud->buf, src, len); + ud->data_len = len; + ud->meta = *((u32 *)metadata); + + debug("%s(dma id=%lu len=%zu meta=%08x)\n", + __func__, dma->id, len, ud->meta); + + return 0; +} + +static int sandbox_dma_receive(struct dma *dma, void **dst, void *metadata) +{ + struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); + struct sandbox_dma_chan *uc; + + if (dma->id >= SANDBOX_DMA_CH_CNT) + return -EINVAL; + if (!dst || !metadata) + return -EINVAL; + + uc = &ud->channels[dma->id]; + if (uc->dir != DMA_DEV_TO_MEM) + return -EINVAL; + if (!uc->in_use) + return -EINVAL; + if (!uc->enabled) + return -EINVAL; + if (!ud->data_len) + return 0; + + if (ud->buf_rx) { + memcpy(ud->buf_rx, ud->buf, ud->data_len); + *dst = ud->buf_rx; + } else { + memcpy(*dst, ud->buf, ud->data_len); + } + + *((u32 *)metadata) = ud->meta; + + debug("%s(dma id=%lu len=%zu meta=%08x %p)\n", + __func__, dma->id, ud->data_len, ud->meta, *dst); + + return ud->data_len; +} + +static int sandbox_dma_prepare_rcv_buf(struct dma *dma, void *dst, size_t size) +{ + struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); + + ud->buf_rx = dst; + + return 0; +} + +static const struct dma_ops sandbox_dma_ops = { + .transfer = sandbox_dma_transfer, + .of_xlate = sandbox_dma_of_xlate, + .request = sandbox_dma_request, + .free = sandbox_dma_free, + .enable = sandbox_dma_enable, + .disable = sandbox_dma_disable, + .send = sandbox_dma_send, + .receive = sandbox_dma_receive, + .prepare_rcv_buf = sandbox_dma_prepare_rcv_buf, +}; + +static int sandbox_dma_probe(struct udevice *dev) +{ + struct dma_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct sandbox_dma_dev *ud = dev_get_priv(dev); + int i, ret = 0; + + uc_priv->supported = DMA_SUPPORTS_MEM_TO_MEM | + DMA_SUPPORTS_MEM_TO_DEV | + DMA_SUPPORTS_DEV_TO_MEM; + + ud->ch_count = SANDBOX_DMA_CH_CNT; + ud->buf_rx = NULL; + ud->meta = 0; + ud->data_len = 0; + + pr_err("Number of channels: %u\n", ud->ch_count); + + for (i = 0; i < ud->ch_count; i++) { + struct sandbox_dma_chan *uc = &ud->channels[i]; + + uc->ud = ud; + uc->id = i; + sprintf(uc->name, "DMA chan%d\n", i); + uc->in_use = false; + uc->enabled = false; + } + + return ret; +} + +static const struct udevice_id sandbox_dma_ids[] = { + { .compatible = "sandbox,dma" }, + { } +}; + +U_BOOT_DRIVER(sandbox_dma) = { + .name = "sandbox-dma", + .id = UCLASS_DMA, + .of_match = sandbox_dma_ids, + .ops = &sandbox_dma_ops, + .probe = sandbox_dma_probe, + .priv_auto_alloc_size = sizeof(struct sandbox_dma_dev), +}; diff --git a/drivers/dma/ti-edma3.c b/drivers/dma/ti-edma3.c index 2131e10a408..7e11b13e45c 100644 --- a/drivers/dma/ti-edma3.c +++ b/drivers/dma/ti-edma3.c @@ -11,7 +11,7 @@ #include <asm/io.h> #include <common.h> #include <dm.h> -#include <dma.h> +#include <dma-uclass.h> #include <asm/omap_common.h> #include <asm/ti-common/ti-edma3.h> diff --git a/drivers/gpio/stm32f7_gpio.c b/drivers/gpio/stm32f7_gpio.c index a690c437ebc..f160b4e6895 100644 --- a/drivers/gpio/stm32f7_gpio.c +++ b/drivers/gpio/stm32f7_gpio.c @@ -15,17 +15,45 @@ #include <linux/errno.h> #include <linux/io.h> -#define STM32_GPIOS_PER_BANK 16 #define MODE_BITS(gpio_pin) (gpio_pin * 2) #define MODE_BITS_MASK 3 #define BSRR_BIT(gpio_pin, value) BIT(gpio_pin + (value ? 0 : 16)) +/* + * convert gpio offset to gpio index taking into account gpio holes + * into gpio bank + */ +int stm32_offset_to_index(struct udevice *dev, unsigned int offset) +{ + struct stm32_gpio_priv *priv = dev_get_priv(dev); + int idx = 0; + int i; + + for (i = 0; i < STM32_GPIOS_PER_BANK; i++) { + if (priv->gpio_range & BIT(i)) { + if (idx == offset) + return idx; + idx++; + } + } + /* shouldn't happen */ + return -EINVAL; +} + static int stm32_gpio_direction_input(struct udevice *dev, unsigned offset) { struct stm32_gpio_priv *priv = dev_get_priv(dev); struct stm32_gpio_regs *regs = priv->regs; - int bits_index = MODE_BITS(offset); - int mask = MODE_BITS_MASK << bits_index; + int bits_index; + int mask; + int idx; + + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; + + bits_index = MODE_BITS(idx); + mask = MODE_BITS_MASK << bits_index; clrsetbits_le32(®s->moder, mask, STM32_GPIO_MODE_IN << bits_index); @@ -37,12 +65,20 @@ static int stm32_gpio_direction_output(struct udevice *dev, unsigned offset, { struct stm32_gpio_priv *priv = dev_get_priv(dev); struct stm32_gpio_regs *regs = priv->regs; - int bits_index = MODE_BITS(offset); - int mask = MODE_BITS_MASK << bits_index; + int bits_index; + int mask; + int idx; + + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; + + bits_index = MODE_BITS(idx); + mask = MODE_BITS_MASK << bits_index; clrsetbits_le32(®s->moder, mask, STM32_GPIO_MODE_OUT << bits_index); - writel(BSRR_BIT(offset, value), ®s->bsrr); + writel(BSRR_BIT(idx, value), ®s->bsrr); return 0; } @@ -51,16 +87,26 @@ static int stm32_gpio_get_value(struct udevice *dev, unsigned offset) { struct stm32_gpio_priv *priv = dev_get_priv(dev); struct stm32_gpio_regs *regs = priv->regs; + int idx; + + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; - return readl(®s->idr) & BIT(offset) ? 1 : 0; + return readl(®s->idr) & BIT(idx) ? 1 : 0; } static int stm32_gpio_set_value(struct udevice *dev, unsigned offset, int value) { struct stm32_gpio_priv *priv = dev_get_priv(dev); struct stm32_gpio_regs *regs = priv->regs; + int idx; + + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; - writel(BSRR_BIT(offset, value), ®s->bsrr); + writel(BSRR_BIT(idx, value), ®s->bsrr); return 0; } @@ -69,10 +115,18 @@ static int stm32_gpio_get_function(struct udevice *dev, unsigned int offset) { struct stm32_gpio_priv *priv = dev_get_priv(dev); struct stm32_gpio_regs *regs = priv->regs; - int bits_index = MODE_BITS(offset); - int mask = MODE_BITS_MASK << bits_index; + int bits_index; + int mask; + int idx; u32 mode; + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; + + bits_index = MODE_BITS(idx); + mask = MODE_BITS_MASK << bits_index; + mode = (readl(®s->moder) & mask) >> bits_index; if (mode == STM32_GPIO_MODE_OUT) return GPIOF_OUTPUT; @@ -96,8 +150,12 @@ static int gpio_stm32_probe(struct udevice *dev) { struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct ofnode_phandle_args args; + struct clk clk; fdt_addr_t addr; const char *name; + int ret; + int i; addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) @@ -108,14 +166,25 @@ static int gpio_stm32_probe(struct udevice *dev) if (!name) return -EINVAL; uc_priv->bank_name = name; - uc_priv->gpio_count = dev_read_u32_default(dev, "ngpios", - STM32_GPIOS_PER_BANK); - debug("%s, addr = 0x%p, bank_name = %s\n", __func__, (u32 *)priv->regs, - uc_priv->bank_name); -#ifdef CONFIG_CLK - struct clk clk; - int ret; + i = 0; + ret = dev_read_phandle_with_args(dev, "gpio-ranges", + NULL, 3, i, &args); + + while (ret != -ENOENT) { + priv->gpio_range |= GENMASK(args.args[2] + args.args[0] - 1, + args.args[0]); + + uc_priv->gpio_count += args.args[2]; + + ret = dev_read_phandle_with_args(dev, "gpio-ranges", NULL, 3, + ++i, &args); + } + + dev_dbg(dev, "addr = 0x%p bank_name = %s gpio_count = %d gpio_range = 0x%x\n", + (u32 *)priv->regs, uc_priv->bank_name, uc_priv->gpio_count, + priv->gpio_range); + ret = clk_get_by_index(dev, 0, &clk); if (ret < 0) return ret; @@ -127,7 +196,6 @@ static int gpio_stm32_probe(struct udevice *dev) return ret; } debug("clock enabled for device %s\n", dev->name); -#endif return 0; } diff --git a/drivers/hwspinlock/Kconfig b/drivers/hwspinlock/Kconfig new file mode 100644 index 00000000000..96d4f5d6ca3 --- /dev/null +++ b/drivers/hwspinlock/Kconfig @@ -0,0 +1,24 @@ +menu "Hardware Spinlock Support" + +config DM_HWSPINLOCK + bool "Enable U-Boot hardware spinlock support" + help + This option enables U-Boot hardware spinlock support + +config HWSPINLOCK_SANDBOX + bool "Enable Hardware Spinlock support for Sandbox" + depends on SANDBOX && DM_HWSPINLOCK + help + Enable hardware spinlock support in Sandbox. This is a dummy device that + can be probed and support all the methods of HWSPINLOCK, but does not + really do anything. + +config HWSPINLOCK_STM32 + bool "Enable Hardware Spinlock support for STM32" + depends on ARCH_STM32MP && DM_HWSPINLOCK + help + Enable hardware spinlock support in STM32MP. Hardware spinlocks are + hardware mutex which provide a synchronisation mechanism for the + various processors on the SoC. + +endmenu diff --git a/drivers/hwspinlock/Makefile b/drivers/hwspinlock/Makefile new file mode 100644 index 00000000000..289b12a2566 --- /dev/null +++ b/drivers/hwspinlock/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +# +# Copyright (C) 2018, STMicroelectronics - All Rights Reserved + +obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock-uclass.o +obj-$(CONFIG_HWSPINLOCK_SANDBOX) += sandbox_hwspinlock.o +obj-$(CONFIG_HWSPINLOCK_STM32) += stm32_hwspinlock.o diff --git a/drivers/hwspinlock/hwspinlock-uclass.c b/drivers/hwspinlock/hwspinlock-uclass.c new file mode 100644 index 00000000000..195f079707c --- /dev/null +++ b/drivers/hwspinlock/hwspinlock-uclass.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <hwspinlock.h> +#include <dm/device-internal.h> + +static inline const struct hwspinlock_ops * +hwspinlock_dev_ops(struct udevice *dev) +{ + return (const struct hwspinlock_ops *)dev->driver->ops; +} + +static int hwspinlock_of_xlate_default(struct hwspinlock *hws, + struct ofnode_phandle_args *args) +{ + if (args->args_count > 1) { + debug("Invaild args_count: %d\n", args->args_count); + return -EINVAL; + } + + if (args->args_count) + hws->id = args->args[0]; + else + hws->id = 0; + + return 0; +} + +int hwspinlock_get_by_index(struct udevice *dev, int index, + struct hwspinlock *hws) +{ + int ret; + struct ofnode_phandle_args args; + struct udevice *dev_hws; + const struct hwspinlock_ops *ops; + + assert(hws); + hws->dev = NULL; + + ret = dev_read_phandle_with_args(dev, "hwlocks", "#hwlock-cells", 1, + index, &args); + if (ret) { + dev_dbg(dev, "%s: dev_read_phandle_with_args: err=%d\n", + __func__, ret); + return ret; + } + + ret = uclass_get_device_by_ofnode(UCLASS_HWSPINLOCK, + args.node, &dev_hws); + if (ret) { + dev_dbg(dev, + "%s: uclass_get_device_by_of_offset failed: err=%d\n", + __func__, ret); + return ret; + } + + hws->dev = dev_hws; + + ops = hwspinlock_dev_ops(dev_hws); + + if (ops->of_xlate) + ret = ops->of_xlate(hws, &args); + else + ret = hwspinlock_of_xlate_default(hws, &args); + if (ret) + dev_dbg(dev, "of_xlate() failed: %d\n", ret); + + return ret; +} + +int hwspinlock_lock_timeout(struct hwspinlock *hws, unsigned int timeout) +{ + const struct hwspinlock_ops *ops; + ulong start; + int ret; + + assert(hws); + + if (!hws->dev) + return -EINVAL; + + ops = hwspinlock_dev_ops(hws->dev); + if (!ops->lock) + return -ENOSYS; + + start = get_timer(0); + do { + ret = ops->lock(hws->dev, hws->id); + if (!ret) + return ret; + + if (ops->relax) + ops->relax(hws->dev); + } while (get_timer(start) < timeout); + + return -ETIMEDOUT; +} + +int hwspinlock_unlock(struct hwspinlock *hws) +{ + const struct hwspinlock_ops *ops; + + assert(hws); + + if (!hws->dev) + return -EINVAL; + + ops = hwspinlock_dev_ops(hws->dev); + if (!ops->unlock) + return -ENOSYS; + + return ops->unlock(hws->dev, hws->id); +} + +static int hwspinlock_post_bind(struct udevice *dev) +{ +#if defined(CONFIG_NEEDS_MANUAL_RELOC) + struct hwspinlock_ops *ops = device_get_ops(dev); + static int reloc_done; + + if (!reloc_done) { + if (ops->lock) + ops->lock += gd->reloc_off; + if (ops->unlock) + ops->unlock += gd->reloc_off; + if (ops->relax) + ops->relax += gd->reloc_off; + + reloc_done++; + } +#endif + return 0; +} + +UCLASS_DRIVER(hwspinlock) = { + .id = UCLASS_HWSPINLOCK, + .name = "hwspinlock", + .post_bind = hwspinlock_post_bind, +}; diff --git a/drivers/hwspinlock/sandbox_hwspinlock.c b/drivers/hwspinlock/sandbox_hwspinlock.c new file mode 100644 index 00000000000..be920f5f99d --- /dev/null +++ b/drivers/hwspinlock/sandbox_hwspinlock.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include <common.h> +#include <dm.h> +#include <hwspinlock.h> +#include <asm/state.h> + +static int sandbox_lock(struct udevice *dev, int index) +{ + struct sandbox_state *state = state_get_current(); + + if (index != 0) + return -1; + + if (state->hwspinlock) + return -1; + + state->hwspinlock = true; + + return 0; +} + +static int sandbox_unlock(struct udevice *dev, int index) +{ + struct sandbox_state *state = state_get_current(); + + if (index != 0) + return -1; + + if (!state->hwspinlock) + return -1; + + state->hwspinlock = false; + + return 0; +} + +static const struct hwspinlock_ops sandbox_hwspinlock_ops = { + .lock = sandbox_lock, + .unlock = sandbox_unlock, +}; + +static const struct udevice_id sandbox_hwspinlock_ids[] = { + { .compatible = "sandbox,hwspinlock" }, + {} +}; + +U_BOOT_DRIVER(hwspinlock_sandbox) = { + .name = "hwspinlock_sandbox", + .id = UCLASS_HWSPINLOCK, + .of_match = sandbox_hwspinlock_ids, + .ops = &sandbox_hwspinlock_ops, +}; diff --git a/drivers/hwspinlock/stm32_hwspinlock.c b/drivers/hwspinlock/stm32_hwspinlock.c new file mode 100644 index 00000000000..a32bde4906d --- /dev/null +++ b/drivers/hwspinlock/stm32_hwspinlock.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <hwspinlock.h> +#include <asm/io.h> + +#define STM32_MUTEX_COREID BIT(8) +#define STM32_MUTEX_LOCK_BIT BIT(31) +#define STM32_MUTEX_NUM_LOCKS 32 + +struct stm32mp1_hws_priv { + fdt_addr_t base; +}; + +static int stm32mp1_lock(struct udevice *dev, int index) +{ + struct stm32mp1_hws_priv *priv = dev_get_priv(dev); + u32 status; + + if (index >= STM32_MUTEX_NUM_LOCKS) + return -EINVAL; + + status = readl(priv->base + index * sizeof(u32)); + if (status == (STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID)) + return -EBUSY; + + writel(STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID, + priv->base + index * sizeof(u32)); + + status = readl(priv->base + index * sizeof(u32)); + if (status != (STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID)) + return -EINVAL; + + return 0; +} + +static int stm32mp1_unlock(struct udevice *dev, int index) +{ + struct stm32mp1_hws_priv *priv = dev_get_priv(dev); + + if (index >= STM32_MUTEX_NUM_LOCKS) + return -EINVAL; + + writel(STM32_MUTEX_COREID, priv->base + index * sizeof(u32)); + + return 0; +} + +static int stm32mp1_hwspinlock_probe(struct udevice *dev) +{ + struct stm32mp1_hws_priv *priv = dev_get_priv(dev); + struct clk clk; + int ret; + + priv->base = dev_read_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) + return -EINVAL; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return ret; + + ret = clk_enable(&clk); + if (ret) + clk_free(&clk); + + return ret; +} + +static const struct hwspinlock_ops stm32mp1_hwspinlock_ops = { + .lock = stm32mp1_lock, + .unlock = stm32mp1_unlock, +}; + +static const struct udevice_id stm32mp1_hwspinlock_ids[] = { + { .compatible = "st,stm32-hwspinlock" }, + {} +}; + +U_BOOT_DRIVER(hwspinlock_stm32mp1) = { + .name = "hwspinlock_stm32mp1", + .id = UCLASS_HWSPINLOCK, + .of_match = stm32mp1_hwspinlock_ids, + .ops = &stm32mp1_hwspinlock_ops, + .probe = stm32mp1_hwspinlock_probe, + .priv_auto_alloc_size = sizeof(struct stm32mp1_hws_priv), +}; diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c index c5a3c4e2016..975318e5f25 100644 --- a/drivers/i2c/i2c-uclass.c +++ b/drivers/i2c/i2c-uclass.c @@ -347,6 +347,17 @@ int i2c_get_chip_for_busnum(int busnum, int chip_addr, uint offset_len, debug("Cannot find I2C bus %d\n", busnum); return ret; } + + /* detect the presence of the chip on the bus */ + ret = i2c_probe_chip(bus, chip_addr, 0); + debug("%s: bus='%s', address %02x, ret=%d\n", __func__, bus->name, + chip_addr, ret); + if (ret) { + debug("Cannot detect I2C chip %02x on bus %d\n", chip_addr, + busnum); + return ret; + } + ret = i2c_get_chip(bus, chip_addr, offset_len, devp); if (ret) { debug("Cannot find I2C chip %02x on bus %d\n", chip_addr, diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c index 51f923752c3..4b93e02bbe8 100644 --- a/drivers/i2c/omap24xx_i2c.c +++ b/drivers/i2c/omap24xx_i2c.c @@ -42,8 +42,18 @@ #include <dm.h> #include <i2c.h> -#include <asm/arch/i2c.h> #include <asm/io.h> +#include <asm/omap_i2c.h> + +/* + * Provide access to architecture-specific I2C header files for platforms + * that are NOT yet solely relying on CONFIG_DM_I2C, CONFIG_OF_CONTROL, and + * the defaults provided in 'omap24xx_i2c.h' for all U-Boot stages where I2C + * access is desired. + */ +#ifndef CONFIG_ARCH_K3 +#include <asm/arch/i2c.h> +#endif #include "omap24xx_i2c.h" @@ -52,14 +62,107 @@ /* Absolutely safe for status update at 100 kHz I2C: */ #define I2C_WAIT 200 +enum { + OMAP_I2C_REV_REG = 0, /* Only on IP V1 (OMAP34XX) */ + OMAP_I2C_IE_REG, /* Only on IP V1 (OMAP34XX) */ + OMAP_I2C_STAT_REG, + OMAP_I2C_WE_REG, + OMAP_I2C_SYSS_REG, + OMAP_I2C_BUF_REG, + OMAP_I2C_CNT_REG, + OMAP_I2C_DATA_REG, + OMAP_I2C_SYSC_REG, + OMAP_I2C_CON_REG, + OMAP_I2C_OA_REG, + OMAP_I2C_SA_REG, + OMAP_I2C_PSC_REG, + OMAP_I2C_SCLL_REG, + OMAP_I2C_SCLH_REG, + OMAP_I2C_SYSTEST_REG, + OMAP_I2C_BUFSTAT_REG, + /* Only on IP V2 (OMAP4430, etc.) */ + OMAP_I2C_IP_V2_REVNB_LO, + OMAP_I2C_IP_V2_REVNB_HI, + OMAP_I2C_IP_V2_IRQSTATUS_RAW, + OMAP_I2C_IP_V2_IRQENABLE_SET, + OMAP_I2C_IP_V2_IRQENABLE_CLR, +}; + +static const u8 __maybe_unused reg_map_ip_v1[] = { + [OMAP_I2C_REV_REG] = 0x00, + [OMAP_I2C_IE_REG] = 0x04, + [OMAP_I2C_STAT_REG] = 0x08, + [OMAP_I2C_WE_REG] = 0x0c, + [OMAP_I2C_SYSS_REG] = 0x10, + [OMAP_I2C_BUF_REG] = 0x14, + [OMAP_I2C_CNT_REG] = 0x18, + [OMAP_I2C_DATA_REG] = 0x1c, + [OMAP_I2C_SYSC_REG] = 0x20, + [OMAP_I2C_CON_REG] = 0x24, + [OMAP_I2C_OA_REG] = 0x28, + [OMAP_I2C_SA_REG] = 0x2c, + [OMAP_I2C_PSC_REG] = 0x30, + [OMAP_I2C_SCLL_REG] = 0x34, + [OMAP_I2C_SCLH_REG] = 0x38, + [OMAP_I2C_SYSTEST_REG] = 0x3c, + [OMAP_I2C_BUFSTAT_REG] = 0x40, +}; + +static const u8 __maybe_unused reg_map_ip_v2[] = { + [OMAP_I2C_STAT_REG] = 0x28, + [OMAP_I2C_WE_REG] = 0x34, + [OMAP_I2C_SYSS_REG] = 0x90, + [OMAP_I2C_BUF_REG] = 0x94, + [OMAP_I2C_CNT_REG] = 0x98, + [OMAP_I2C_DATA_REG] = 0x9c, + [OMAP_I2C_SYSC_REG] = 0x10, + [OMAP_I2C_CON_REG] = 0xa4, + [OMAP_I2C_OA_REG] = 0xa8, + [OMAP_I2C_SA_REG] = 0xac, + [OMAP_I2C_PSC_REG] = 0xb0, + [OMAP_I2C_SCLL_REG] = 0xb4, + [OMAP_I2C_SCLH_REG] = 0xb8, + [OMAP_I2C_SYSTEST_REG] = 0xbc, + [OMAP_I2C_BUFSTAT_REG] = 0xc0, + [OMAP_I2C_IP_V2_REVNB_LO] = 0x00, + [OMAP_I2C_IP_V2_REVNB_HI] = 0x04, + [OMAP_I2C_IP_V2_IRQSTATUS_RAW] = 0x24, + [OMAP_I2C_IP_V2_IRQENABLE_SET] = 0x2c, + [OMAP_I2C_IP_V2_IRQENABLE_CLR] = 0x30, +}; + struct omap_i2c { struct udevice *clk; + int ip_rev; struct i2c *regs; unsigned int speed; int waitdelay; int clk_id; }; +static inline const u8 *omap_i2c_get_ip_reg_map(int ip_rev) +{ + switch (ip_rev) { + case OMAP_I2C_REV_V1: + return reg_map_ip_v1; + case OMAP_I2C_REV_V2: + /* Fall through... */ + default: + return reg_map_ip_v2; + } +} + +static inline void omap_i2c_write_reg(void __iomem *base, int ip_rev, + u16 val, int reg) +{ + writew(val, base + omap_i2c_get_ip_reg_map(ip_rev)[reg]); +} + +static inline u16 omap_i2c_read_reg(void __iomem *base, int ip_rev, int reg) +{ + return readw(base + omap_i2c_get_ip_reg_map(ip_rev)[reg]); +} + static int omap24_i2c_findpsc(u32 *pscl, u32 *psch, uint speed) { unsigned long internal_clk = 0, fclk; @@ -114,29 +217,31 @@ static int omap24_i2c_findpsc(u32 *pscl, u32 *psch, uint speed) * Wait for the bus to be free by checking the Bus Busy (BB) * bit to become clear */ -static int wait_for_bb(struct i2c *i2c_base, int waitdelay) +static int wait_for_bb(void __iomem *i2c_base, int ip_rev, int waitdelay) { int timeout = I2C_TIMEOUT; + int irq_stat_reg; u16 stat; - writew(0xFFFF, &i2c_base->stat); /* clear current interrupts...*/ -#if defined(CONFIG_OMAP34XX) - while ((stat = readw(&i2c_base->stat) & I2C_STAT_BB) && timeout--) { -#else - /* Read RAW status */ - while ((stat = readw(&i2c_base->irqstatus_raw) & + irq_stat_reg = (ip_rev == OMAP_I2C_REV_V1) ? + OMAP_I2C_STAT_REG : OMAP_I2C_IP_V2_IRQSTATUS_RAW; + + /* clear current interrupts */ + omap_i2c_write_reg(i2c_base, ip_rev, 0xFFFF, OMAP_I2C_STAT_REG); + + while ((stat = omap_i2c_read_reg(i2c_base, ip_rev, irq_stat_reg) & I2C_STAT_BB) && timeout--) { -#endif - writew(stat, &i2c_base->stat); + omap_i2c_write_reg(i2c_base, ip_rev, stat, OMAP_I2C_STAT_REG); udelay(waitdelay); } if (timeout <= 0) { - printf("Timed out in wait_for_bb: status=%04x\n", - stat); + printf("Timed out in %s: status=%04x\n", __func__, stat); return 1; } - writew(0xFFFF, &i2c_base->stat); /* clear delayed stuff*/ + + /* clear delayed stuff */ + omap_i2c_write_reg(i2c_base, ip_rev, 0xFFFF, OMAP_I2C_STAT_REG); return 0; } @@ -144,40 +249,37 @@ static int wait_for_bb(struct i2c *i2c_base, int waitdelay) * Wait for the I2C controller to complete current action * and update status */ -static u16 wait_for_event(struct i2c *i2c_base, int waitdelay) +static u16 wait_for_event(void __iomem *i2c_base, int ip_rev, int waitdelay) { u16 status; int timeout = I2C_TIMEOUT; + int irq_stat_reg; + irq_stat_reg = (ip_rev == OMAP_I2C_REV_V1) ? + OMAP_I2C_STAT_REG : OMAP_I2C_IP_V2_IRQSTATUS_RAW; do { udelay(waitdelay); -#if defined(CONFIG_OMAP34XX) - status = readw(&i2c_base->stat); -#else - /* Read RAW status */ - status = readw(&i2c_base->irqstatus_raw); -#endif + status = omap_i2c_read_reg(i2c_base, ip_rev, irq_stat_reg); } while (!(status & (I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY | I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK | I2C_STAT_AL)) && timeout--); if (timeout <= 0) { - printf("Timed out in wait_for_event: status=%04x\n", - status); + printf("Timed out in %s: status=%04x\n", __func__, status); /* * If status is still 0 here, probably the bus pads have * not been configured for I2C, and/or pull-ups are missing. */ printf("Check if pads/pull-ups of bus are properly configured\n"); - writew(0xFFFF, &i2c_base->stat); + omap_i2c_write_reg(i2c_base, ip_rev, 0xFFFF, OMAP_I2C_STAT_REG); status = 0; } return status; } -static void flush_fifo(struct i2c *i2c_base) +static void flush_fifo(void __iomem *i2c_base, int ip_rev) { u16 stat; @@ -186,17 +288,18 @@ static void flush_fifo(struct i2c *i2c_base) * you get a bus error */ while (1) { - stat = readw(&i2c_base->stat); + stat = omap_i2c_read_reg(i2c_base, ip_rev, OMAP_I2C_STAT_REG); if (stat == I2C_STAT_RRDY) { - readb(&i2c_base->data); - writew(I2C_STAT_RRDY, &i2c_base->stat); + omap_i2c_read_reg(i2c_base, ip_rev, OMAP_I2C_DATA_REG); + omap_i2c_write_reg(i2c_base, ip_rev, + I2C_STAT_RRDY, OMAP_I2C_STAT_REG); udelay(1000); } else break; } } -static int __omap24_i2c_setspeed(struct i2c *i2c_base, uint speed, +static int __omap24_i2c_setspeed(void __iomem *i2c_base, int ip_rev, uint speed, int *waitdelay) { int psc, fsscll = 0, fssclh = 0; @@ -248,79 +351,89 @@ static int __omap24_i2c_setspeed(struct i2c *i2c_base, uint speed, } } - *waitdelay = (10000000 / speed) * 2; /* wait for 20 clkperiods */ - writew(0, &i2c_base->con); - writew(psc, &i2c_base->psc); - writew(scll, &i2c_base->scll); - writew(sclh, &i2c_base->sclh); - writew(I2C_CON_EN, &i2c_base->con); - writew(0xFFFF, &i2c_base->stat); /* clear all pending status */ + /* wait for 20 clkperiods */ + *waitdelay = (10000000 / speed) * 2; + + omap_i2c_write_reg(i2c_base, ip_rev, 0, OMAP_I2C_CON_REG); + omap_i2c_write_reg(i2c_base, ip_rev, psc, OMAP_I2C_PSC_REG); + omap_i2c_write_reg(i2c_base, ip_rev, scll, OMAP_I2C_SCLL_REG); + omap_i2c_write_reg(i2c_base, ip_rev, sclh, OMAP_I2C_SCLH_REG); + omap_i2c_write_reg(i2c_base, ip_rev, I2C_CON_EN, OMAP_I2C_CON_REG); + + /* clear all pending status */ + omap_i2c_write_reg(i2c_base, ip_rev, 0xFFFF, OMAP_I2C_STAT_REG); return 0; } -static void omap24_i2c_deblock(struct i2c *i2c_base) +static void omap24_i2c_deblock(void __iomem *i2c_base, int ip_rev) { int i; u16 systest; u16 orgsystest; /* set test mode ST_EN = 1 */ - orgsystest = readw(&i2c_base->systest); + orgsystest = omap_i2c_read_reg(i2c_base, ip_rev, OMAP_I2C_SYSTEST_REG); systest = orgsystest; + /* enable testmode */ systest |= I2C_SYSTEST_ST_EN; - writew(systest, &i2c_base->systest); + omap_i2c_write_reg(i2c_base, ip_rev, systest, OMAP_I2C_SYSTEST_REG); systest &= ~I2C_SYSTEST_TMODE_MASK; systest |= 3 << I2C_SYSTEST_TMODE_SHIFT; - writew(systest, &i2c_base->systest); + omap_i2c_write_reg(i2c_base, ip_rev, systest, OMAP_I2C_SYSTEST_REG); /* set SCL, SDA = 1 */ systest |= I2C_SYSTEST_SCL_O | I2C_SYSTEST_SDA_O; - writew(systest, &i2c_base->systest); + omap_i2c_write_reg(i2c_base, ip_rev, systest, OMAP_I2C_SYSTEST_REG); udelay(10); /* toggle scl 9 clocks */ for (i = 0; i < 9; i++) { /* SCL = 0 */ systest &= ~I2C_SYSTEST_SCL_O; - writew(systest, &i2c_base->systest); + omap_i2c_write_reg(i2c_base, ip_rev, + systest, OMAP_I2C_SYSTEST_REG); udelay(10); /* SCL = 1 */ systest |= I2C_SYSTEST_SCL_O; - writew(systest, &i2c_base->systest); + omap_i2c_write_reg(i2c_base, ip_rev, + systest, OMAP_I2C_SYSTEST_REG); udelay(10); } /* send stop */ systest &= ~I2C_SYSTEST_SDA_O; - writew(systest, &i2c_base->systest); + omap_i2c_write_reg(i2c_base, ip_rev, systest, OMAP_I2C_SYSTEST_REG); udelay(10); systest |= I2C_SYSTEST_SCL_O | I2C_SYSTEST_SDA_O; - writew(systest, &i2c_base->systest); + omap_i2c_write_reg(i2c_base, ip_rev, systest, OMAP_I2C_SYSTEST_REG); udelay(10); /* restore original mode */ - writew(orgsystest, &i2c_base->systest); + omap_i2c_write_reg(i2c_base, ip_rev, orgsystest, OMAP_I2C_SYSTEST_REG); } -static void __omap24_i2c_init(struct i2c *i2c_base, int speed, int slaveadd, - int *waitdelay) +static void __omap24_i2c_init(void __iomem *i2c_base, int ip_rev, int speed, + int slaveadd, int *waitdelay) { int timeout = I2C_TIMEOUT; int deblock = 1; retry: - if (readw(&i2c_base->con) & I2C_CON_EN) { - writew(0, &i2c_base->con); + if (omap_i2c_read_reg(i2c_base, ip_rev, OMAP_I2C_CON_REG) & + I2C_CON_EN) { + omap_i2c_write_reg(i2c_base, ip_rev, 0, OMAP_I2C_CON_REG); udelay(50000); } - writew(0x2, &i2c_base->sysc); /* for ES2 after soft reset */ + /* for ES2 after soft reset */ + omap_i2c_write_reg(i2c_base, ip_rev, 0x2, OMAP_I2C_SYSC_REG); udelay(1000); - writew(I2C_CON_EN, &i2c_base->con); - while (!(readw(&i2c_base->syss) & I2C_SYSS_RDONE) && timeout--) { + omap_i2c_write_reg(i2c_base, ip_rev, I2C_CON_EN, OMAP_I2C_CON_REG); + while (!(omap_i2c_read_reg(i2c_base, ip_rev, OMAP_I2C_SYSS_REG) & + I2C_SYSS_RDONE) && timeout--) { if (timeout <= 0) { puts("ERROR: Timeout in soft-reset\n"); return; @@ -328,30 +441,33 @@ retry: udelay(1000); } - if (0 != __omap24_i2c_setspeed(i2c_base, speed, waitdelay)) { + if (__omap24_i2c_setspeed(i2c_base, ip_rev, speed, waitdelay)) { printf("ERROR: failed to setup I2C bus-speed!\n"); return; } /* own address */ - writew(slaveadd, &i2c_base->oa); + omap_i2c_write_reg(i2c_base, ip_rev, slaveadd, OMAP_I2C_OA_REG); + + if (ip_rev == OMAP_I2C_REV_V1) { + /* + * Have to enable interrupts for OMAP2/3, these IPs don't have + * an 'irqstatus_raw' register and we shall have to poll 'stat' + */ + omap_i2c_write_reg(i2c_base, ip_rev, I2C_IE_XRDY_IE | + I2C_IE_RRDY_IE | I2C_IE_ARDY_IE | + I2C_IE_NACK_IE | I2C_IE_AL_IE, + OMAP_I2C_IE_REG); + } -#if defined(CONFIG_OMAP34XX) - /* - * Have to enable interrupts for OMAP2/3, these IPs don't have - * an 'irqstatus_raw' register and we shall have to poll 'stat' - */ - writew(I2C_IE_XRDY_IE | I2C_IE_RRDY_IE | I2C_IE_ARDY_IE | - I2C_IE_NACK_IE | I2C_IE_AL_IE, &i2c_base->ie); -#endif udelay(1000); - flush_fifo(i2c_base); - writew(0xFFFF, &i2c_base->stat); + flush_fifo(i2c_base, ip_rev); + omap_i2c_write_reg(i2c_base, ip_rev, 0xFFFF, OMAP_I2C_STAT_REG); /* Handle possible failed I2C state */ - if (wait_for_bb(i2c_base, *waitdelay)) + if (wait_for_bb(i2c_base, ip_rev, *waitdelay)) if (deblock == 1) { - omap24_i2c_deblock(i2c_base); + omap24_i2c_deblock(i2c_base, ip_rev); deblock = 0; goto retry; } @@ -361,25 +477,28 @@ retry: * i2c_probe: Use write access. Allows to identify addresses that are * write-only (like the config register of dual-port EEPROMs) */ -static int __omap24_i2c_probe(struct i2c *i2c_base, int waitdelay, uchar chip) +static int __omap24_i2c_probe(void __iomem *i2c_base, int ip_rev, int waitdelay, + uchar chip) { u16 status; int res = 1; /* default = fail */ - if (chip == readw(&i2c_base->oa)) + if (chip == omap_i2c_read_reg(i2c_base, ip_rev, OMAP_I2C_OA_REG)) return res; /* Wait until bus is free */ - if (wait_for_bb(i2c_base, waitdelay)) + if (wait_for_bb(i2c_base, ip_rev, waitdelay)) return res; /* No data transfer, slave addr only */ - writew(chip, &i2c_base->sa); + omap_i2c_write_reg(i2c_base, ip_rev, chip, OMAP_I2C_SA_REG); + /* Stop bit needed here */ - writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | - I2C_CON_STP, &i2c_base->con); + omap_i2c_write_reg(i2c_base, ip_rev, I2C_CON_EN | I2C_CON_MST | + I2C_CON_STT | I2C_CON_TRX | I2C_CON_STP, + OMAP_I2C_CON_REG); - status = wait_for_event(i2c_base, waitdelay); + status = wait_for_event(i2c_base, ip_rev, waitdelay); if ((status & ~I2C_STAT_XRDY) == 0 || (status & I2C_STAT_AL)) { /* @@ -400,14 +519,17 @@ static int __omap24_i2c_probe(struct i2c *i2c_base, int waitdelay, uchar chip) res = 0; /* Device found */ udelay(waitdelay);/* Required by AM335X in SPL */ /* Abort transfer (force idle state) */ - writew(I2C_CON_MST | I2C_CON_TRX, &i2c_base->con); /* Reset */ + omap_i2c_write_reg(i2c_base, ip_rev, I2C_CON_MST | I2C_CON_TRX, + OMAP_I2C_CON_REG); /* Reset */ udelay(1000); - writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_TRX | - I2C_CON_STP, &i2c_base->con); /* STP */ + omap_i2c_write_reg(i2c_base, ip_rev, I2C_CON_EN | I2C_CON_MST | + I2C_CON_TRX | I2C_CON_STP, + OMAP_I2C_CON_REG); /* STP */ } + pr_exit: - flush_fifo(i2c_base); - writew(0xFFFF, &i2c_base->stat); + flush_fifo(i2c_base, ip_rev); + omap_i2c_write_reg(i2c_base, ip_rev, 0xFFFF, OMAP_I2C_STAT_REG); return res; } @@ -424,8 +546,9 @@ pr_exit: * or that do not need a register address at all (such as some clock * distributors). */ -static int __omap24_i2c_read(struct i2c *i2c_base, int waitdelay, uchar chip, - uint addr, int alen, uchar *buffer, int len) +static int __omap24_i2c_read(void __iomem *i2c_base, int ip_rev, int waitdelay, + uchar chip, uint addr, int alen, uchar *buffer, + int len) { int i2c_error = 0; u16 status; @@ -434,10 +557,12 @@ static int __omap24_i2c_read(struct i2c *i2c_base, int waitdelay, uchar chip, puts("I2C read: addr len < 0\n"); return 1; } + if (len < 0) { puts("I2C read: data len < 0\n"); return 1; } + if (buffer == NULL) { puts("I2C read: NULL pointer passed\n"); return 1; @@ -471,28 +596,29 @@ static int __omap24_i2c_read(struct i2c *i2c_base, int waitdelay, uchar chip, #endif /* Wait until bus not busy */ - if (wait_for_bb(i2c_base, waitdelay)) + if (wait_for_bb(i2c_base, ip_rev, waitdelay)) return 1; /* Zero, one or two bytes reg address (offset) */ - writew(alen, &i2c_base->cnt); + omap_i2c_write_reg(i2c_base, ip_rev, alen, OMAP_I2C_CNT_REG); /* Set slave address */ - writew(chip, &i2c_base->sa); + omap_i2c_write_reg(i2c_base, ip_rev, chip, OMAP_I2C_SA_REG); if (alen) { /* Must write reg offset first */ #ifdef CONFIG_I2C_REPEATED_START /* No stop bit, use Repeated Start (Sr) */ - writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | - I2C_CON_TRX, &i2c_base->con); + omap_i2c_write_reg(i2c_base, ip_rev, I2C_CON_EN | I2C_CON_MST | + I2C_CON_STT | I2C_CON_TRX, OMAP_I2C_CON_REG); #else /* Stop - Start (P-S) */ - writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP | - I2C_CON_TRX, &i2c_base->con); + omap_i2c_write_reg(i2c_base, ip_rev, I2C_CON_EN | I2C_CON_MST | + I2C_CON_STT | I2C_CON_STP | I2C_CON_TRX, + OMAP_I2C_CON_REG); #endif /* Send register offset */ while (1) { - status = wait_for_event(i2c_base, waitdelay); + status = wait_for_event(i2c_base, ip_rev, waitdelay); /* Try to identify bus that is not padconf'd for I2C */ if (status == I2C_STAT_XRDY) { i2c_error = 2; @@ -508,31 +634,37 @@ static int __omap24_i2c_read(struct i2c *i2c_base, int waitdelay, uchar chip, } if (alen) { if (status & I2C_STAT_XRDY) { + u8 addr_byte; alen--; - /* Do we have to use byte access? */ - writeb((addr >> (8 * alen)) & 0xff, - &i2c_base->data); - writew(I2C_STAT_XRDY, &i2c_base->stat); + addr_byte = (addr >> (8 * alen)) & 0xff; + omap_i2c_write_reg(i2c_base, ip_rev, + addr_byte, + OMAP_I2C_DATA_REG); + omap_i2c_write_reg(i2c_base, ip_rev, + I2C_STAT_XRDY, + OMAP_I2C_STAT_REG); } } if (status & I2C_STAT_ARDY) { - writew(I2C_STAT_ARDY, &i2c_base->stat); + omap_i2c_write_reg(i2c_base, ip_rev, + I2C_STAT_ARDY, + OMAP_I2C_STAT_REG); break; } } } + /* Set slave address */ - writew(chip, &i2c_base->sa); + omap_i2c_write_reg(i2c_base, ip_rev, chip, OMAP_I2C_SA_REG); /* Read len bytes from slave */ - writew(len, &i2c_base->cnt); + omap_i2c_write_reg(i2c_base, ip_rev, len, OMAP_I2C_CNT_REG); /* Need stop bit here */ - writew(I2C_CON_EN | I2C_CON_MST | - I2C_CON_STT | I2C_CON_STP, - &i2c_base->con); + omap_i2c_write_reg(i2c_base, ip_rev, I2C_CON_EN | I2C_CON_MST | + I2C_CON_STT | I2C_CON_STP, OMAP_I2C_CON_REG); /* Receive data */ while (1) { - status = wait_for_event(i2c_base, waitdelay); + status = wait_for_event(i2c_base, ip_rev, waitdelay); /* * Try to identify bus that is not padconf'd for I2C. This * state could be left over from previous transactions if @@ -549,24 +681,28 @@ static int __omap24_i2c_read(struct i2c *i2c_base, int waitdelay, uchar chip, goto rd_exit; } if (status & I2C_STAT_RRDY) { - *buffer++ = readb(&i2c_base->data); - writew(I2C_STAT_RRDY, &i2c_base->stat); + *buffer++ = omap_i2c_read_reg(i2c_base, ip_rev, + OMAP_I2C_DATA_REG); + omap_i2c_write_reg(i2c_base, ip_rev, + I2C_STAT_RRDY, OMAP_I2C_STAT_REG); } if (status & I2C_STAT_ARDY) { - writew(I2C_STAT_ARDY, &i2c_base->stat); + omap_i2c_write_reg(i2c_base, ip_rev, + I2C_STAT_ARDY, OMAP_I2C_STAT_REG); break; } } rd_exit: - flush_fifo(i2c_base); - writew(0xFFFF, &i2c_base->stat); + flush_fifo(i2c_base, ip_rev); + omap_i2c_write_reg(i2c_base, ip_rev, 0xFFFF, OMAP_I2C_STAT_REG); return i2c_error; } /* i2c_write: Address (reg offset) may be 0, 1 or 2 bytes long. */ -static int __omap24_i2c_write(struct i2c *i2c_base, int waitdelay, uchar chip, - uint addr, int alen, uchar *buffer, int len) +static int __omap24_i2c_write(void __iomem *i2c_base, int ip_rev, int waitdelay, + uchar chip, uint addr, int alen, uchar *buffer, + int len) { int i; u16 status; @@ -617,20 +753,21 @@ static int __omap24_i2c_write(struct i2c *i2c_base, int waitdelay, uchar chip, #endif /* Wait until bus not busy */ - if (wait_for_bb(i2c_base, waitdelay)) + if (wait_for_bb(i2c_base, ip_rev, waitdelay)) return 1; /* Start address phase - will write regoffset + len bytes data */ - writew(alen + len, &i2c_base->cnt); + omap_i2c_write_reg(i2c_base, ip_rev, alen + len, OMAP_I2C_CNT_REG); /* Set slave address */ - writew(chip, &i2c_base->sa); + omap_i2c_write_reg(i2c_base, ip_rev, chip, OMAP_I2C_SA_REG); /* Stop bit needed here */ - writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | - I2C_CON_STP, &i2c_base->con); + omap_i2c_write_reg(i2c_base, ip_rev, I2C_CON_EN | I2C_CON_MST | + I2C_CON_STT | I2C_CON_TRX | I2C_CON_STP, + OMAP_I2C_CON_REG); while (alen) { /* Must write reg offset (one or two bytes) */ - status = wait_for_event(i2c_base, waitdelay); + status = wait_for_event(i2c_base, ip_rev, waitdelay); /* Try to identify bus that is not padconf'd for I2C */ if (status == I2C_STAT_XRDY) { i2c_error = 2; @@ -646,8 +783,11 @@ static int __omap24_i2c_write(struct i2c *i2c_base, int waitdelay, uchar chip, } if (status & I2C_STAT_XRDY) { alen--; - writeb((addr >> (8 * alen)) & 0xff, &i2c_base->data); - writew(I2C_STAT_XRDY, &i2c_base->stat); + omap_i2c_write_reg(i2c_base, ip_rev, + (addr >> (8 * alen)) & 0xff, + OMAP_I2C_DATA_REG); + omap_i2c_write_reg(i2c_base, ip_rev, + I2C_STAT_XRDY, OMAP_I2C_STAT_REG); } else { i2c_error = 1; printf("i2c_write: bus not ready for addr Tx (status=0x%x)\n", @@ -655,9 +795,10 @@ static int __omap24_i2c_write(struct i2c *i2c_base, int waitdelay, uchar chip, goto wr_exit; } } + /* Address phase is over, now write data */ for (i = 0; i < len; i++) { - status = wait_for_event(i2c_base, waitdelay); + status = wait_for_event(i2c_base, ip_rev, waitdelay); if (status == 0 || (status & I2C_STAT_NACK)) { i2c_error = 1; printf("i2c_write: error waiting for data ACK (status=0x%x)\n", @@ -665,8 +806,10 @@ static int __omap24_i2c_write(struct i2c *i2c_base, int waitdelay, uchar chip, goto wr_exit; } if (status & I2C_STAT_XRDY) { - writeb(buffer[i], &i2c_base->data); - writew(I2C_STAT_XRDY, &i2c_base->stat); + omap_i2c_write_reg(i2c_base, ip_rev, + buffer[i], OMAP_I2C_DATA_REG); + omap_i2c_write_reg(i2c_base, ip_rev, + I2C_STAT_XRDY, OMAP_I2C_STAT_REG); } else { i2c_error = 1; printf("i2c_write: bus not ready for data Tx (i=%d)\n", @@ -674,19 +817,20 @@ static int __omap24_i2c_write(struct i2c *i2c_base, int waitdelay, uchar chip, goto wr_exit; } } + /* * poll ARDY bit for making sure that last byte really has been * transferred on the bus. */ do { - status = wait_for_event(i2c_base, waitdelay); + status = wait_for_event(i2c_base, ip_rev, waitdelay); } while (!(status & I2C_STAT_ARDY) && timeout--); if (timeout <= 0) printf("i2c_write: timed out writig last byte!\n"); wr_exit: - flush_fifo(i2c_base); - writew(0xFFFF, &i2c_base->stat); + flush_fifo(i2c_base, ip_rev); + omap_i2c_write_reg(i2c_base, ip_rev, 0xFFFF, OMAP_I2C_STAT_REG); return i2c_error; } @@ -695,26 +839,26 @@ wr_exit: * The legacy I2C functions. These need to get removed once * all users of this driver are converted to DM. */ -static struct i2c *omap24_get_base(struct i2c_adapter *adap) +static void __iomem *omap24_get_base(struct i2c_adapter *adap) { switch (adap->hwadapnr) { case 0: - return (struct i2c *)I2C_BASE1; + return (void __iomem *)I2C_BASE1; break; case 1: - return (struct i2c *)I2C_BASE2; + return (void __iomem *)I2C_BASE2; break; #if (CONFIG_SYS_I2C_BUS_MAX > 2) case 2: - return (struct i2c *)I2C_BASE3; + return (void __iomem *)I2C_BASE3; break; #if (CONFIG_SYS_I2C_BUS_MAX > 3) case 3: - return (struct i2c *)I2C_BASE4; + return (void __iomem *)I2C_BASE4; break; #if (CONFIG_SYS_I2C_BUS_MAX > 4) case 4: - return (struct i2c *)I2C_BASE5; + return (void __iomem *)I2C_BASE5; break; #endif #endif @@ -723,35 +867,46 @@ static struct i2c *omap24_get_base(struct i2c_adapter *adap) printf("wrong hwadapnr: %d\n", adap->hwadapnr); break; } + return NULL; } +static int omap24_get_ip_rev(void) +{ +#ifdef CONFIG_OMAP34XX + return OMAP_I2C_REV_V1; +#else + return OMAP_I2C_REV_V2; +#endif +} static int omap24_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr, int alen, uchar *buffer, int len) { - struct i2c *i2c_base = omap24_get_base(adap); + void __iomem *i2c_base = omap24_get_base(adap); + int ip_rev = omap24_get_ip_rev(); - return __omap24_i2c_read(i2c_base, adap->waitdelay, chip, addr, + return __omap24_i2c_read(i2c_base, ip_rev, adap->waitdelay, chip, addr, alen, buffer, len); } - static int omap24_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr, int alen, uchar *buffer, int len) { - struct i2c *i2c_base = omap24_get_base(adap); + void __iomem *i2c_base = omap24_get_base(adap); + int ip_rev = omap24_get_ip_rev(); - return __omap24_i2c_write(i2c_base, adap->waitdelay, chip, addr, + return __omap24_i2c_write(i2c_base, ip_rev, adap->waitdelay, chip, addr, alen, buffer, len); } static uint omap24_i2c_setspeed(struct i2c_adapter *adap, uint speed) { - struct i2c *i2c_base = omap24_get_base(adap); + void __iomem *i2c_base = omap24_get_base(adap); + int ip_rev = omap24_get_ip_rev(); int ret; - ret = __omap24_i2c_setspeed(i2c_base, speed, &adap->waitdelay); + ret = __omap24_i2c_setspeed(i2c_base, ip_rev, speed, &adap->waitdelay); if (ret) { pr_err("%s: set i2c speed failed\n", __func__); return ret; @@ -764,16 +919,19 @@ static uint omap24_i2c_setspeed(struct i2c_adapter *adap, uint speed) static void omap24_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd) { - struct i2c *i2c_base = omap24_get_base(adap); + void __iomem *i2c_base = omap24_get_base(adap); + int ip_rev = omap24_get_ip_rev(); - return __omap24_i2c_init(i2c_base, speed, slaveadd, &adap->waitdelay); + return __omap24_i2c_init(i2c_base, ip_rev, speed, slaveadd, + &adap->waitdelay); } static int omap24_i2c_probe(struct i2c_adapter *adap, uchar chip) { - struct i2c *i2c_base = omap24_get_base(adap); + void __iomem *i2c_base = omap24_get_base(adap); + int ip_rev = omap24_get_ip_rev(); - return __omap24_i2c_probe(i2c_base, adap->waitdelay, chip); + return __omap24_i2c_probe(i2c_base, ip_rev, adap->waitdelay, chip); } #if !defined(CONFIG_SYS_OMAP24_I2C_SPEED1) @@ -793,6 +951,7 @@ U_BOOT_I2C_ADAP_COMPLETE(omap24_1, omap24_i2c_init, omap24_i2c_probe, CONFIG_SYS_OMAP24_I2C_SPEED1, CONFIG_SYS_OMAP24_I2C_SLAVE1, 1) + #if (CONFIG_SYS_I2C_BUS_MAX > 2) #if !defined(CONFIG_SYS_OMAP24_I2C_SPEED2) #define CONFIG_SYS_OMAP24_I2C_SPEED2 CONFIG_SYS_OMAP24_I2C_SPEED @@ -847,11 +1006,13 @@ static int omap_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs) for (; nmsgs > 0; nmsgs--, msg++) { debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len); if (msg->flags & I2C_M_RD) { - ret = __omap24_i2c_read(priv->regs, priv->waitdelay, + ret = __omap24_i2c_read(priv->regs, priv->ip_rev, + priv->waitdelay, msg->addr, 0, 0, msg->buf, msg->len); } else { - ret = __omap24_i2c_write(priv->regs, priv->waitdelay, + ret = __omap24_i2c_write(priv->regs, priv->ip_rev, + priv->waitdelay, msg->addr, 0, 0, msg->buf, msg->len); } @@ -870,7 +1031,8 @@ static int omap_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) priv->speed = speed; - return __omap24_i2c_setspeed(priv->regs, speed, &priv->waitdelay); + return __omap24_i2c_setspeed(priv->regs, priv->ip_rev, speed, + &priv->waitdelay); } static int omap_i2c_probe_chip(struct udevice *bus, uint chip_addr, @@ -878,14 +1040,22 @@ static int omap_i2c_probe_chip(struct udevice *bus, uint chip_addr, { struct omap_i2c *priv = dev_get_priv(bus); - return __omap24_i2c_probe(priv->regs, priv->waitdelay, chip_addr); + return __omap24_i2c_probe(priv->regs, priv->ip_rev, priv->waitdelay, + chip_addr); } static int omap_i2c_probe(struct udevice *bus) { struct omap_i2c *priv = dev_get_priv(bus); + struct omap_i2c_platdata *plat = dev_get_platdata(bus); - __omap24_i2c_init(priv->regs, priv->speed, 0, &priv->waitdelay); + priv->speed = plat->speed; + priv->regs = map_physmem(plat->base, sizeof(void *), + MAP_NOCACHE); + priv->ip_rev = plat->ip_rev; + + __omap24_i2c_init(priv->regs, priv->ip_rev, priv->speed, 0, + &priv->waitdelay); return 0; } @@ -893,18 +1063,18 @@ static int omap_i2c_probe(struct udevice *bus) #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) static int omap_i2c_ofdata_to_platdata(struct udevice *bus) { - struct omap_i2c *priv = dev_get_priv(bus); + struct omap_i2c_platdata *plat = dev_get_platdata(bus); - priv->regs = map_physmem(devfdt_get_addr(bus), sizeof(void *), - MAP_NOCACHE); - priv->speed = CONFIG_SYS_OMAP24_I2C_SPEED; + plat->base = devfdt_get_addr(bus); + plat->speed = dev_read_u32_default(bus, "clock-frequency", 100000); + plat->ip_rev = dev_get_driver_data(bus); return 0; } static const struct udevice_id omap_i2c_ids[] = { - { .compatible = "ti,omap3-i2c" }, - { .compatible = "ti,omap4-i2c" }, + { .compatible = "ti,omap3-i2c", .data = OMAP_I2C_REV_V1 }, + { .compatible = "ti,omap4-i2c", .data = OMAP_I2C_REV_V2 }, { } }; #endif @@ -921,6 +1091,7 @@ U_BOOT_DRIVER(i2c_omap) = { #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) .of_match = omap_i2c_ids, .ofdata_to_platdata = omap_i2c_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct omap_i2c_platdata), #endif .probe = omap_i2c_probe, .priv_auto_alloc_size = sizeof(struct omap_i2c), diff --git a/drivers/input/i8042.c b/drivers/input/i8042.c index 5678f8e3cfb..9a5dc46207c 100644 --- a/drivers/input/i8042.c +++ b/drivers/input/i8042.c @@ -167,19 +167,8 @@ static int kbd_controller_present(void) return in8(I8042_STS_REG) != 0xff; } -/* - * Implement a weak default function for boards that optionally - * need to skip the i8042 initialization. - * - * TODO(sjg@chromium.org): Use device tree for this? - */ -int __weak board_i8042_skip(void) -{ - /* As default, don't skip */ - return 0; -} - -void i8042_flush(void) +/** Flush all buffer from keyboard controller to host*/ +static void i8042_flush(void) { int timeout; @@ -202,7 +191,13 @@ void i8042_flush(void) } } -int i8042_disable(void) +/** + * Disables the keyboard so that key strokes no longer generate scancodes to + * the host. + * + * @return 0 if ok, -1 if keyboard input was found while disabling + */ +static int i8042_disable(void) { if (kbd_input_empty() == 0) return -1; @@ -266,7 +261,7 @@ static int i8042_start(struct udevice *dev) char *penv; int ret; - if (!kbd_controller_present() || board_i8042_skip()) { + if (!kbd_controller_present()) { debug("i8042 keyboard controller is not present\n"); return -ENOENT; } @@ -294,6 +289,15 @@ static int i8042_start(struct udevice *dev) return 0; } +static int i8042_kbd_remove(struct udevice *dev) +{ + if (i8042_disable()) + log_debug("i8042_disable() failed. fine, continue.\n"); + i8042_flush(); + + return 0; +} + /** * Set up the i8042 keyboard. This is called by the stdio device handler * @@ -348,6 +352,7 @@ U_BOOT_DRIVER(i8042_kbd) = { .id = UCLASS_KEYBOARD, .of_match = i8042_kbd_ids, .probe = i8042_kbd_probe, + .remove = i8042_kbd_remove, .ops = &i8042_kbd_ops, .priv_auto_alloc_size = sizeof(struct i8042_kbd_priv), }; diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index 2dcdb3d8d61..565de040fe9 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -420,7 +420,7 @@ int cros_ec_read_id(struct udevice *dev, char *id, int maxlen) ret = ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0, (uint8_t **)&r, sizeof(*r)); if (ret != sizeof(*r)) { - log_err("Got rc %d, expected %d\n", ret, sizeof(*r)); + log_err("Got rc %d, expected %u\n", ret, (uint)sizeof(*r)); return -1; } @@ -1466,7 +1466,7 @@ int cros_ec_set_lid_shutdown_mask(struct udevice *dev, int enable) if (ret < 0) return ret; - // Set lid close event state in the EC SMI event mask + /* Set lid close event state in the EC SMI event mask */ if (enable) mask |= EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_CLOSED); else diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c index 429f1a9b269..4fcb2d96f51 100644 --- a/drivers/misc/cros_ec_sandbox.c +++ b/drivers/misc/cros_ec_sandbox.c @@ -313,13 +313,15 @@ static int process_cmd(struct ec_state *ec, switch (req->op) { case EC_VBNV_CONTEXT_OP_READ: + /* TODO(sjg@chromium.org): Support full-size context */ memcpy(resp->block, ec->vbnv_context, - sizeof(resp->block)); - len = sizeof(*resp); + EC_VBNV_BLOCK_SIZE); + len = 16; break; case EC_VBNV_CONTEXT_OP_WRITE: - memcpy(ec->vbnv_context, resp->block, - sizeof(resp->block)); + /* TODO(sjg@chromium.org): Support full-size context */ + memcpy(ec->vbnv_context, req->block, + EC_VBNV_BLOCK_SIZE); len = 0; break; default: diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index d6b9cdc9922..f5c821e308c 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1289,6 +1289,10 @@ static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode) ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); int speed; + /* SD version 1.00 and 1.01 does not support CMD 6 */ + if (mmc->version == SD_VERSION_1_0) + return 0; + switch (mode) { case SD_LEGACY: speed = UHS_SDR12_BUS_SPEED; diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c index a9d95fbd747..4f57990d9c4 100644 --- a/drivers/mmc/mmc_spi.c +++ b/drivers/mmc/mmc_spi.c @@ -10,7 +10,7 @@ #include <part.h> #include <mmc.h> #include <spi.h> -#include <crc.h> +#include <u-boot/crc.h> #include <linux/crc7.h> #include <asm/byteorder.h> diff --git a/drivers/mtd/mtd_uboot.c b/drivers/mtd/mtd_uboot.c index 5ca560c9687..d638f700d04 100644 --- a/drivers/mtd/mtd_uboot.c +++ b/drivers/mtd/mtd_uboot.c @@ -13,6 +13,29 @@ #define MTD_NAME_MAX_LEN 20 +void board_mtdparts_default(const char **mtdids, const char **mtdparts); + +static const char *get_mtdids(void) +{ + __maybe_unused const char *mtdparts = NULL; + const char *mtdids = env_get("mtdids"); + + if (mtdids) + return mtdids; + +#if defined(CONFIG_SYS_MTDPARTS_RUNTIME) + board_mtdparts_default(&mtdids, &mtdparts); +#elif defined(MTDIDS_DEFAULT) + mtdids = MTDIDS_DEFAULT; +#elif defined(CONFIG_MTDIDS_DEFAULT) + mtdids = CONFIG_MTDIDS_DEFAULT; +#endif + + if (mtdids) + env_set("mtdids", mtdids); + + return mtdids; +} /** * mtd_search_alternate_name - Search an alternate name for @mtdname thanks to @@ -34,7 +57,7 @@ int mtd_search_alternate_name(const char *mtdname, char *altname, const char *mtdids, *equal, *comma, *dev_id, *mtd_id; int dev_id_len, mtd_id_len; - mtdids = env_get("mtdids"); + mtdids = get_mtdids(); if (!mtdids) return -EINVAL; @@ -92,30 +115,6 @@ static void mtd_probe_uclass_mtd_devs(void) { } #endif #if defined(CONFIG_MTD_PARTITIONS) -extern void board_mtdparts_default(const char **mtdids, - const char **mtdparts); - -static const char *get_mtdids(void) -{ - __maybe_unused const char *mtdparts = NULL; - const char *mtdids = env_get("mtdids"); - - if (mtdids) - return mtdids; - -#if defined(CONFIG_SYS_MTDPARTS_RUNTIME) - board_mtdparts_default(&mtdids, &mtdparts); -#elif defined(MTDIDS_DEFAULT) - mtdids = MTDIDS_DEFAULT; -#elif defined(CONFIG_MTDIDS_DEFAULT) - mtdids = CONFIG_MTDIDS_DEFAULT; -#endif - - if (mtdids) - env_set("mtdids", mtdids); - - return mtdids; -} #define MTDPARTS_MAXLEN 512 @@ -150,20 +149,74 @@ static const char *get_mtdparts(void) return mtdparts; } +static int mtd_del_parts(struct mtd_info *mtd, bool quiet) +{ + int ret; + + if (!mtd_has_partitions(mtd)) + return 0; + + /* do not delete partitions if they are in use. */ + if (mtd_partitions_used(mtd)) { + if (!quiet) + printf("\"%s\" partitions still in use, can't delete them\n", + mtd->name); + return -EACCES; + } + + ret = del_mtd_partitions(mtd); + if (ret) + return ret; + + return 1; +} + +static bool mtd_del_all_parts_failed; + +static void mtd_del_all_parts(void) +{ + struct mtd_info *mtd; + int ret = 0; + + mtd_del_all_parts_failed = false; + + /* + * It is not safe to remove entries from the mtd_for_each_device loop + * as it uses idr indexes and the partitions removal is done in bulk + * (all partitions of one device at the same time), so break and + * iterate from start each time a new partition is found and deleted. + */ + do { + mtd_for_each_device(mtd) { + ret = mtd_del_parts(mtd, false); + if (ret > 0) + break; + else if (ret < 0) + mtd_del_all_parts_failed = true; + } + } while (ret > 0); +} + int mtd_probe_devices(void) { static char *old_mtdparts; static char *old_mtdids; const char *mtdparts = get_mtdparts(); const char *mtdids = get_mtdids(); - bool remaining_partitions = true; + const char *mtdparts_next = mtdparts; struct mtd_info *mtd; mtd_probe_uclass_mtd_devs(); - /* Check if mtdparts/mtdids changed since last call, otherwise: exit */ + /* + * Check if mtdparts/mtdids changed, if the MTD dev list was updated + * or if our previous attempt to delete existing partititions failed. + * In any of these cases we want to update the partitions, otherwise, + * everything is up-to-date and we can return 0 directly. + */ if ((!mtdparts && !old_mtdparts && !mtdids && !old_mtdids) || (mtdparts && old_mtdparts && mtdids && old_mtdids && + !mtd_dev_list_updated() && !mtd_del_all_parts_failed && !strcmp(mtdparts, old_mtdparts) && !strcmp(mtdids, old_mtdids))) return 0; @@ -174,55 +227,55 @@ int mtd_probe_devices(void) old_mtdparts = strdup(mtdparts); old_mtdids = strdup(mtdids); - /* If at least one partition is still in use, do not delete anything */ - mtd_for_each_device(mtd) { - if (mtd->usecount) { - printf("Partition \"%s\" already in use, aborting\n", - mtd->name); - return -EACCES; - } - } + /* + * Remove all old parts. Note that partition removal can fail in case + * one of the partition is still being used by an MTD user, so this + * does not guarantee that all old partitions are gone. + */ + mtd_del_all_parts(); /* - * Everything looks clear, remove all partitions. It is not safe to - * remove entries from the mtd_for_each_device loop as it uses idr - * indexes and the partitions removal is done in bulk (all partitions of - * one device at the same time), so break and iterate from start each - * time a new partition is found and deleted. + * Call mtd_dev_list_updated() to clear updates generated by our own + * parts removal loop. */ - while (remaining_partitions) { - remaining_partitions = false; - mtd_for_each_device(mtd) { - if (!mtd_is_partition(mtd) && mtd_has_partitions(mtd)) { - del_mtd_partitions(mtd); - remaining_partitions = true; - break; - } - } - } + mtd_dev_list_updated(); /* If either mtdparts or mtdids is empty, then exit */ if (!mtdparts || !mtdids) return 0; /* Start the parsing by ignoring the extra 'mtdparts=' prefix, if any */ - if (strstr(mtdparts, "mtdparts=")) + if (!strncmp(mtdparts, "mtdparts=", sizeof("mtdparts=") - 1)) mtdparts += 9; /* For each MTD device in mtdparts */ - while (mtdparts[0] != '\0') { + for (; mtdparts[0] != '\0'; mtdparts = mtdparts_next) { char mtd_name[MTD_NAME_MAX_LEN], *colon; struct mtd_partition *parts; - int mtd_name_len, nparts; - int ret; + unsigned int mtd_name_len; + int nparts, ret; + + mtdparts_next = strchr(mtdparts, ';'); + if (!mtdparts_next) + mtdparts_next = mtdparts + strlen(mtdparts); + else + mtdparts_next++; colon = strchr(mtdparts, ':'); + if (colon > mtdparts_next) + colon = NULL; + if (!colon) { printf("Wrong mtdparts: %s\n", mtdparts); return -EINVAL; } - mtd_name_len = colon - mtdparts; + mtd_name_len = (unsigned int)(colon - mtdparts); + if (mtd_name_len + 1 > sizeof(mtd_name)) { + printf("MTD name too long: %s\n", mtdparts); + return -EINVAL; + } + strncpy(mtd_name, mtdparts, mtd_name_len); mtd_name[mtd_name_len] = '\0'; /* Move the pointer forward (including the ':') */ @@ -249,15 +302,23 @@ int mtd_probe_devices(void) if (ret || IS_ERR_OR_NULL(mtd)) { printf("Could not find a valid device for %s\n", mtd_name); - mtdparts = strchr(mtdparts, ';'); - if (mtdparts) - mtdparts++; - + mtdparts = mtdparts_next; continue; } } /* + * Call mtd_del_parts() again, even if it's already been called + * in mtd_del_all_parts(). We need to know if old partitions are + * still around (because they are still being used by someone), + * and if they are, we shouldn't create new partitions, so just + * skip this MTD device and try the next one. + */ + ret = mtd_del_parts(mtd, true); + if (ret < 0) + continue; + + /* * Parse the MTD device partitions. It will update the mtdparts * pointer, create an array of parts (that must be freed), and * return the number of partition structures in the array. @@ -281,6 +342,12 @@ int mtd_probe_devices(void) put_mtd_device(mtd); } + /* + * Call mtd_dev_list_updated() to clear updates generated by our own + * parts registration loop. + */ + mtd_dev_list_updated(); + return 0; } #else diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index fb6c779abbf..cb7ca38d074 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -87,14 +87,17 @@ struct idr_layer { struct idr { struct idr_layer id[MAX_IDR_ID]; + bool updated; }; #define DEFINE_IDR(name) struct idr name; void idr_remove(struct idr *idp, int id) { - if (idp->id[id].used) + if (idp->id[id].used) { idp->id[id].used = 0; + idp->updated = true; + } return; } @@ -134,6 +137,7 @@ int idr_alloc(struct idr *idp, void *ptr, int start, int end, gfp_t gfp_mask) if (idl->used == 0) { idl->used = 1; idl->ptr = ptr; + idp->updated = true; return i; } i++; @@ -155,6 +159,16 @@ struct mtd_info *__mtd_next_device(int i) } EXPORT_SYMBOL_GPL(__mtd_next_device); +bool mtd_dev_list_updated(void) +{ + if (mtd_idr.updated) { + mtd_idr.updated = false; + return true; + } + + return false; +} + #ifndef __UBOOT__ static LIST_HEAD(mtd_notifiers); @@ -514,6 +528,13 @@ int del_mtd_device(struct mtd_info *mtd) struct mtd_notifier *not; #endif + ret = del_mtd_partitions(mtd); + if (ret) { + debug("Failed to delete MTD partitions attached to %s (err %d)\n", + mtd->name, ret); + return ret; + } + mutex_lock(&mtd_table_mutex); if (idr_find(&mtd_idr, mtd->index) != mtd) { diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 4d2ac8107f0..fd8d8e5ea72 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -63,6 +63,18 @@ char *kstrdup(const char *s, gfp_t gfp) #define MTD_SIZE_REMAINING (~0LLU) #define MTD_OFFSET_NOT_SPECIFIED (~0LLU) +bool mtd_partitions_used(struct mtd_info *master) +{ + struct mtd_info *slave; + + list_for_each_entry(slave, &master->partitions, node) { + if (slave->usecount) + return true; + } + + return false; +} + /** * mtd_parse_partition - Parse @mtdparts partition definition, fill @partition * with it and update the @mtdparts string pointer. diff --git a/drivers/mtd/nand/raw/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c index 4c783f1e1e4..4d2712df4c7 100644 --- a/drivers/mtd/nand/raw/pxa3xx_nand.c +++ b/drivers/mtd/nand/raw/pxa3xx_nand.c @@ -195,6 +195,7 @@ struct pxa3xx_nand_info { int cs; int use_ecc; /* use HW ECC ? */ + int force_raw; /* prevent use_ecc to be set */ int ecc_bch; /* using BCH ECC? */ int use_spare; /* use spare ? */ int need_wait; @@ -326,14 +327,14 @@ static struct nand_ecclayout ecc_layout_2KB_bch4bit = { static struct nand_ecclayout ecc_layout_2KB_bch8bit = { .eccbytes = 64, .eccpos = { - 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127}, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95}, .oobfree = { {1, 4}, {6, 26} } }; @@ -579,7 +580,7 @@ static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask) static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len) { - if (info->ecc_bch) { + if (info->ecc_bch && !info->force_raw) { u32 ts; /* @@ -612,12 +613,22 @@ static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len) static void handle_data_pio(struct pxa3xx_nand_info *info) { + int data_len = info->step_chunk_size; + + /* + * In raw mode, include the spare area and the ECC bytes that are not + * consumed by the controller in the data section. Do not reorganize + * here, do it in the ->read_page_raw() handler instead. + */ + if (info->force_raw) + data_len += info->step_spare_size + info->ecc_size; + switch (info->state) { case STATE_PIO_WRITING: if (info->step_chunk_size) writesl(info->mmio_base + NDDB, info->data_buff + info->data_buff_pos, - DIV_ROUND_UP(info->step_chunk_size, 4)); + DIV_ROUND_UP(data_len, 4)); if (info->step_spare_size) writesl(info->mmio_base + NDDB, @@ -628,7 +639,10 @@ static void handle_data_pio(struct pxa3xx_nand_info *info) if (info->step_chunk_size) drain_fifo(info, info->data_buff + info->data_buff_pos, - DIV_ROUND_UP(info->step_chunk_size, 4)); + DIV_ROUND_UP(data_len, 4)); + + if (info->force_raw) + break; if (info->step_spare_size) drain_fifo(info, @@ -642,7 +656,7 @@ static void handle_data_pio(struct pxa3xx_nand_info *info) } /* Update buffer pointers for multi-page read/write */ - info->data_buff_pos += info->step_chunk_size; + info->data_buff_pos += data_len; info->oob_buff_pos += info->step_spare_size; } @@ -796,7 +810,8 @@ static void prepare_start_command(struct pxa3xx_nand_info *info, int command) case NAND_CMD_READ0: case NAND_CMD_READOOB: case NAND_CMD_PAGEPROG: - info->use_ecc = 1; + if (!info->force_raw) + info->use_ecc = 1; break; case NAND_CMD_PARAM: info->use_spare = 0; @@ -866,7 +881,13 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, * which is either naked-read or last-read according to the * state. */ - if (mtd->writesize == info->chunk_size) { + if (info->force_raw) { + info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8) | + NDCB0_LEN_OVRD | + NDCB0_EXT_CMD_TYPE(ext_cmd_type); + info->ndcb3 = info->step_chunk_size + + info->step_spare_size + info->ecc_size; + } else if (mtd->writesize == info->chunk_size) { info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8); } else if (mtd->writesize > info->chunk_size) { info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8) @@ -1216,6 +1237,7 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, { struct pxa3xx_nand_host *host = nand_get_controller_data(chip); struct pxa3xx_nand_info *info = host->info_data; + int bf; chip->read_buf(mtd, buf, mtd->writesize); chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); @@ -1223,12 +1245,30 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, if (info->retcode == ERR_CORERR && info->use_ecc) { mtd->ecc_stats.corrected += info->ecc_err_cnt; - } else if (info->retcode == ERR_UNCORERR) { + } else if (info->retcode == ERR_UNCORERR && info->ecc_bch) { /* - * for blank page (all 0xff), HW will calculate its ECC as - * 0, which is different from the ECC information within - * OOB, ignore such uncorrectable errors + * Empty pages will trigger uncorrectable errors. Re-read the + * entire page in raw mode and check for bits not being "1". + * If there are more than the supported strength, then it means + * this is an actual uncorrectable error. */ + chip->ecc.read_page_raw(mtd, chip, buf, oob_required, page); + bf = nand_check_erased_ecc_chunk(buf, mtd->writesize, + chip->oob_poi, mtd->oobsize, + NULL, 0, chip->ecc.strength); + if (bf < 0) { + mtd->ecc_stats.failed++; + } else if (bf) { + mtd->ecc_stats.corrected += bf; + info->max_bitflips = max_t(unsigned int, + info->max_bitflips, bf); + info->retcode = ERR_CORERR; + } else { + info->retcode = ERR_NONE; + } + + } else if (info->retcode == ERR_UNCORERR && !info->ecc_bch) { + /* Raw read is not supported with Hamming ECC engine */ if (is_buf_blank(buf, mtd->writesize)) info->retcode = ERR_NONE; else @@ -1238,6 +1278,69 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, return info->max_bitflips; } +static int pxa3xx_nand_read_page_raw(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) +{ + struct pxa3xx_nand_host *host = chip->priv; + struct pxa3xx_nand_info *info = host->info_data; + int chunk, ecc_off_buf; + + if (!info->ecc_bch) + return -ENOTSUPP; + + /* + * Set the force_raw boolean, then re-call ->cmdfunc() that will run + * pxa3xx_nand_start(), which will actually disable the ECC engine. + */ + info->force_raw = true; + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); + + ecc_off_buf = (info->nfullchunks * info->spare_size) + + info->last_spare_size; + for (chunk = 0; chunk < info->nfullchunks; chunk++) { + chip->read_buf(mtd, + buf + (chunk * info->chunk_size), + info->chunk_size); + chip->read_buf(mtd, + chip->oob_poi + + (chunk * (info->spare_size)), + info->spare_size); + chip->read_buf(mtd, + chip->oob_poi + ecc_off_buf + + (chunk * (info->ecc_size)), + info->ecc_size - 2); + } + + if (info->ntotalchunks > info->nfullchunks) { + chip->read_buf(mtd, + buf + (info->nfullchunks * info->chunk_size), + info->last_chunk_size); + chip->read_buf(mtd, + chip->oob_poi + + (info->nfullchunks * (info->spare_size)), + info->last_spare_size); + chip->read_buf(mtd, + chip->oob_poi + ecc_off_buf + + (info->nfullchunks * (info->ecc_size)), + info->ecc_size - 2); + } + + info->force_raw = false; + + return 0; +} + +static int pxa3xx_nand_read_oob_raw(struct mtd_info *mtd, + struct nand_chip *chip, int page) +{ + /* Invalidate page cache */ + chip->pagebuf = -1; + + return chip->ecc.read_page_raw(mtd, chip, chip->buffers->databuf, true, + page); +} + static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd) { struct nand_chip *chip = mtd_to_nand(mtd); @@ -1488,7 +1591,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, info->chunk_size = 1024; info->spare_size = 0; info->last_chunk_size = 1024; - info->last_spare_size = 64; + info->last_spare_size = 32; info->ecc_size = 32; ecc->mode = NAND_ECC_HW; ecc->size = info->chunk_size; @@ -1669,6 +1772,8 @@ static int alloc_nand_resource(struct pxa3xx_nand_info *info) nand_set_controller_data(chip, host); chip->ecc.read_page = pxa3xx_nand_read_page_hwecc; + chip->ecc.read_page_raw = pxa3xx_nand_read_page_raw; + chip->ecc.read_oob_raw = pxa3xx_nand_read_oob_raw; chip->ecc.write_page = pxa3xx_nand_write_page_hwecc; chip->controller = &info->controller; chip->waitfunc = pxa3xx_nand_waitfunc; diff --git a/drivers/mtd/spi/sf_mtd.c b/drivers/mtd/spi/sf_mtd.c index 58d7e443990..68c36002bee 100644 --- a/drivers/mtd/spi/sf_mtd.c +++ b/drivers/mtd/spi/sf_mtd.c @@ -10,6 +10,7 @@ #include <spi_flash.h> static struct mtd_info sf_mtd_info; +static bool sf_mtd_registered; static char sf_mtd_name[8]; static int spi_flash_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) @@ -17,6 +18,9 @@ static int spi_flash_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) struct spi_flash *flash = mtd->priv; int err; + if (!flash) + return -ENODEV; + instr->state = MTD_ERASING; err = spi_flash_erase(flash, instr->addr, instr->len); @@ -38,6 +42,9 @@ static int spi_flash_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, struct spi_flash *flash = mtd->priv; int err; + if (!flash) + return -ENODEV; + err = spi_flash_read(flash, from, len, buf); if (!err) *retlen = len; @@ -51,6 +58,9 @@ static int spi_flash_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, struct spi_flash *flash = mtd->priv; int err; + if (!flash) + return -ENODEV; + err = spi_flash_write(flash, to, len, buf); if (!err) *retlen = len; @@ -73,6 +83,17 @@ static int spi_flash_mtd_number(void) int spi_flash_mtd_register(struct spi_flash *flash) { + int ret; + + if (sf_mtd_registered) { + ret = del_mtd_device(&sf_mtd_info); + if (ret) + return ret; + + sf_mtd_registered = false; + } + + sf_mtd_registered = false; memset(&sf_mtd_info, 0, sizeof(sf_mtd_info)); sprintf(sf_mtd_name, "nor%d", spi_flash_mtd_number()); @@ -94,10 +115,33 @@ int spi_flash_mtd_register(struct spi_flash *flash) sf_mtd_info.numeraseregions = 0; sf_mtd_info.erasesize = flash->sector_size; - return add_mtd_device(&sf_mtd_info); + ret = add_mtd_device(&sf_mtd_info); + if (!ret) + sf_mtd_registered = true; + + return ret; } void spi_flash_mtd_unregister(void) { - del_mtd_device(&sf_mtd_info); + int ret; + + if (!sf_mtd_registered) + return; + + ret = del_mtd_device(&sf_mtd_info); + if (!ret) { + sf_mtd_registered = false; + return; + } + + /* + * Setting mtd->priv to NULL is the best we can do. Thanks to that, + * the MTD layer can still call mtd hooks without risking a + * use-after-free bug. Still, things should be fixed to prevent the + * spi_flash object from being destroyed when del_mtd_device() fails. + */ + sf_mtd_info.priv = NULL; + printf("Failed to unregister MTD %s and the spi_flash object is going away: you're in deep trouble!", + sf_mtd_info.name); } diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 5a2e932de8f..00f8558e701 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -144,6 +144,14 @@ static int spi_flash_std_probe(struct udevice *dev) return spi_flash_probe_slave(flash); } +static int spi_flash_std_remove(struct udevice *dev) +{ +#ifdef CONFIG_SPI_FLASH_MTD + spi_flash_mtd_unregister(); +#endif + return 0; +} + static const struct dm_spi_flash_ops spi_flash_std_ops = { .read = spi_flash_std_read, .write = spi_flash_std_write, @@ -161,6 +169,7 @@ U_BOOT_DRIVER(spi_flash_std) = { .id = UCLASS_SPI_FLASH, .of_match = spi_flash_std_ids, .probe = spi_flash_std_probe, + .remove = spi_flash_std_remove, .priv_auto_alloc_size = sizeof(struct spi_flash), .ops = &spi_flash_std_ops, }; diff --git a/drivers/net/e1000_spi.c b/drivers/net/e1000_spi.c index b38f4df9f31..aecd290d729 100644 --- a/drivers/net/e1000_spi.c +++ b/drivers/net/e1000_spi.c @@ -77,9 +77,6 @@ static inline struct e1000_hw *e1000_hw_from_spi(struct spi_slave *spi) return container_of(spi, struct e1000_hw, spi); } -/* Not sure why all of these are necessary */ -void spi_init(void) { /* Nothing to do */ } - struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int mode) { diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c index 37749e01852..a0abb232992 100644 --- a/drivers/net/phy/aquantia.c +++ b/drivers/net/phy/aquantia.c @@ -8,7 +8,7 @@ #include <common.h> #include <dm.h> #include <phy.h> -#include <crc.h> +#include <u-boot/crc.h> #include <malloc.h> #include <asm/byteorder.h> #include <fs.h> diff --git a/drivers/net/sandbox-raw-bus.c b/drivers/net/sandbox-raw-bus.c index 76d65afe6c8..0086f25fc1f 100644 --- a/drivers/net/sandbox-raw-bus.c +++ b/drivers/net/sandbox-raw-bus.c @@ -42,7 +42,7 @@ static int eth_raw_bus_post_bind(struct udevice *dev) device_probe(child); priv = dev_get_priv(child); if (priv) { - memcpy(priv->host_ifname, i->if_name, IFNAMSIZ); + strcpy(priv->host_ifname, i->if_name); priv->host_ifindex = i->if_index; priv->local = local; } diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c index eaacd4066e8..7d9b75c2c45 100644 --- a/drivers/pci/pci_rom.c +++ b/drivers/pci/pci_rom.c @@ -331,6 +331,7 @@ int vbe_setup_video_priv(struct vesa_mode_info *vesa, return log_msg_ret("No x resolution", -ENXIO); uc_priv->xsize = vesa->x_resolution; uc_priv->ysize = vesa->y_resolution; + uc_priv->line_length = vesa->bytes_per_scanline; switch (vesa->bits_per_pixel) { case 32: case 24: diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 14d82b93ed1..3921e39d7bc 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -155,4 +155,13 @@ config MSM8916_USB_PHY This PHY is found on qualcomm dragonboard410c development board. +config OMAP_USB2_PHY + bool "Support OMAP's USB2 PHY" + depends on PHY + depends on SYSCON + help + Support for the OMAP's USB2 PHY. + + This PHY is found on OMAP devices supporting USB2. + endmenu diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 8030d599e75..53dd5bd0f77 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_PHY_RCAR_GEN3) += phy-rcar-gen3.o obj-$(CONFIG_PHY_STM32_USBPHYC) += phy-stm32-usbphyc.o obj-$(CONFIG_MESON_GXL_USB_PHY) += meson-gxl-usb2.o meson-gxl-usb3.o obj-$(CONFIG_MSM8916_USB_PHY) += msm8916-usbh-phy.o +obj-$(CONFIG_OMAP_USB2_PHY) += omap-usb2-phy.o diff --git a/drivers/phy/omap-usb2-phy.c b/drivers/phy/omap-usb2-phy.c new file mode 100644 index 00000000000..fd20e8c1688 --- /dev/null +++ b/drivers/phy/omap-usb2-phy.c @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * OMAP USB2 PHY LAYER + * + * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com + * Written by Jean-Jacques Hiblot <jjhiblot@ti.com> + */ + +#include <common.h> +#include <asm/io.h> +#include <dm.h> +#include <errno.h> +#include <generic-phy.h> +#include <regmap.h> +#include <syscon.h> + +#define OMAP_USB2_CALIBRATE_FALSE_DISCONNECT BIT(0) + +#define OMAP_DEV_PHY_PD BIT(0) +#define OMAP_USB2_PHY_PD BIT(28) + +#define USB2PHY_DISCON_BYP_LATCH BIT(31) +#define USB2PHY_ANA_CONFIG1 (0x4c) + +DECLARE_GLOBAL_DATA_PTR; + +struct omap_usb2_phy { + struct regmap *pwr_regmap; + ulong flags; + void *phy_base; + u32 pwr_reg_offset; +}; + +struct usb_phy_data { + const char *label; + u8 flags; + u32 mask; + u32 power_on; + u32 power_off; +}; + +static const struct usb_phy_data omap5_usb2_data = { + .label = "omap5_usb2", + .flags = 0, + .mask = OMAP_DEV_PHY_PD, + .power_off = OMAP_DEV_PHY_PD, +}; + +static const struct usb_phy_data dra7x_usb2_data = { + .label = "dra7x_usb2", + .flags = OMAP_USB2_CALIBRATE_FALSE_DISCONNECT, + .mask = OMAP_DEV_PHY_PD, + .power_off = OMAP_DEV_PHY_PD, +}; + +static const struct usb_phy_data dra7x_usb2_phy2_data = { + .label = "dra7x_usb2_phy2", + .flags = OMAP_USB2_CALIBRATE_FALSE_DISCONNECT, + .mask = OMAP_USB2_PHY_PD, + .power_off = OMAP_USB2_PHY_PD, +}; + +static const struct udevice_id omap_usb2_id_table[] = { + { + .compatible = "ti,omap5-usb2", + .data = (ulong)&omap5_usb2_data, + }, + { + .compatible = "ti,dra7x-usb2", + .data = (ulong)&dra7x_usb2_data, + }, + { + .compatible = "ti,dra7x-usb2-phy2", + .data = (ulong)&dra7x_usb2_phy2_data, + }, + {}, +}; + +static int omap_usb_phy_power(struct phy *usb_phy, bool on) +{ + struct udevice *dev = usb_phy->dev; + const struct usb_phy_data *data; + const struct omap_usb2_phy *phy = dev_get_priv(dev); + u32 val; + int rc; + + data = (const struct usb_phy_data *)dev_get_driver_data(dev); + if (!data) + return -EINVAL; + + rc = regmap_read(phy->pwr_regmap, phy->pwr_reg_offset, &val); + if (rc) + return rc; + val &= ~data->mask; + if (on) + val |= data->power_on; + else + val |= data->power_off; + rc = regmap_write(phy->pwr_regmap, phy->pwr_reg_offset, val); + if (rc) + return rc; + + return 0; +} + +static int omap_usb2_phy_init(struct phy *usb_phy) +{ + struct udevice *dev = usb_phy->dev; + struct omap_usb2_phy *priv = dev_get_priv(dev); + u32 val; + + if (priv->flags & OMAP_USB2_CALIBRATE_FALSE_DISCONNECT) { + /* + * + * Reduce the sensitivity of internal PHY by enabling the + * DISCON_BYP_LATCH of the USB2PHY_ANA_CONFIG1 register. This + * resolves issues with certain devices which can otherwise + * be prone to false disconnects. + * + */ + val = readl(priv->phy_base + USB2PHY_ANA_CONFIG1); + val |= USB2PHY_DISCON_BYP_LATCH; + writel(val, priv->phy_base + USB2PHY_ANA_CONFIG1); + } + + return 0; +} + +static int omap_usb2_phy_power_on(struct phy *usb_phy) +{ + return omap_usb_phy_power(usb_phy, true); +} + +static int omap_usb2_phy_power_off(struct phy *usb_phy) +{ + return omap_usb_phy_power(usb_phy, false); +} + +static int omap_usb2_phy_exit(struct phy *usb_phy) +{ + return omap_usb_phy_power(usb_phy, false); +} + +struct phy_ops omap_usb2_phy_ops = { + .init = omap_usb2_phy_init, + .power_on = omap_usb2_phy_power_on, + .power_off = omap_usb2_phy_power_off, + .exit = omap_usb2_phy_exit, +}; + +int omap_usb2_phy_probe(struct udevice *dev) +{ + int rc; + struct regmap *regmap; + struct omap_usb2_phy *priv = dev_get_priv(dev); + const struct usb_phy_data *data; + u32 tmp[2]; + + data = (const struct usb_phy_data *)dev_get_driver_data(dev); + if (!data) + return -EINVAL; + + if (data->flags & OMAP_USB2_CALIBRATE_FALSE_DISCONNECT) { + u32 base = dev_read_addr(dev); + + if (base == FDT_ADDR_T_NONE) + return -EINVAL; + priv->phy_base = (void *)base; + priv->flags |= OMAP_USB2_CALIBRATE_FALSE_DISCONNECT; + } + + regmap = syscon_regmap_lookup_by_phandle(dev, "syscon-phy-power"); + if (IS_ERR(regmap)) { + printf("can't get regmap (err %ld)\n", PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + priv->pwr_regmap = regmap; + + rc = dev_read_u32_array(dev, "syscon-phy-power", tmp, 2); + if (rc) { + printf("couldn't get power reg. offset (err %d)\n", rc); + return rc; + } + priv->pwr_reg_offset = tmp[1]; + + return 0; +} + +U_BOOT_DRIVER(omap_usb2_phy) = { + .name = "omap_usb2_phy", + .id = UCLASS_PHY, + .of_match = omap_usb2_id_table, + .probe = omap_usb2_phy_probe, + .ops = &omap_usb2_phy_ops, + .priv_auto_alloc_size = sizeof(struct omap_usb2_phy), +}; diff --git a/drivers/phy/ti-pipe3-phy.c b/drivers/phy/ti-pipe3-phy.c index b22bbaf9851..e7e78e3c56d 100644 --- a/drivers/phy/ti-pipe3-phy.c +++ b/drivers/phy/ti-pipe3-phy.c @@ -141,7 +141,7 @@ static int omap_pipe3_dpll_program(struct omap_pipe3 *pipe3) omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION1, val); val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION2); - val &= ~PLL_SELFREQDCO_MASK; + val &= ~(PLL_SELFREQDCO_MASK | PLL_IDLE); val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT; omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION2, val); @@ -265,10 +265,13 @@ static int pipe3_exit(struct phy *phy) return -EBUSY; } - val = readl(pipe3->pll_reset_reg); - writel(val | SATA_PLL_SOFT_RESET, pipe3->pll_reset_reg); - mdelay(1); - writel(val & ~SATA_PLL_SOFT_RESET, pipe3->pll_reset_reg); + if (pipe3->pll_reset_reg) { + val = readl(pipe3->pll_reset_reg); + writel(val | SATA_PLL_SOFT_RESET, pipe3->pll_reset_reg); + mdelay(1); + writel(val & ~SATA_PLL_SOFT_RESET, pipe3->pll_reset_reg); + } + return 0; } @@ -331,9 +334,11 @@ static int pipe3_phy_probe(struct udevice *dev) if (!pipe3->power_reg) return -EINVAL; - pipe3->pll_reset_reg = get_reg(dev, "syscon-pllreset"); - if (!pipe3->pll_reset_reg) - return -EINVAL; + if (device_is_compatible(dev, "ti,phy-pipe3-sata")) { + pipe3->pll_reset_reg = get_reg(dev, "syscon-pllreset"); + if (!pipe3->pll_reset_reg) + return -EINVAL; + } pipe3->dpll_map = (struct pipe3_dpll_map *)dev_get_driver_data(dev); @@ -350,8 +355,19 @@ static struct pipe3_dpll_map dpll_map_sata[] = { { }, /* Terminator */ }; +static struct pipe3_dpll_map dpll_map_usb[] = { + {12000000, {1250, 5, 4, 20, 0} }, /* 12 MHz */ + {16800000, {3125, 20, 4, 20, 0} }, /* 16.8 MHz */ + {19200000, {1172, 8, 4, 20, 65537} }, /* 19.2 MHz */ + {20000000, {1000, 7, 4, 10, 0} }, /* 20 MHz */ + {26000000, {1250, 12, 4, 20, 0} }, /* 26 MHz */ + {38400000, {3125, 47, 4, 20, 92843} }, /* 38.4 MHz */ + { }, /* Terminator */ +}; + static const struct udevice_id pipe3_phy_ids[] = { { .compatible = "ti,phy-pipe3-sata", .data = (ulong)&dpll_map_sata }, + { .compatible = "ti,omap-usb3", .data = (ulong)&dpll_map_usb}, { } }; diff --git a/drivers/pinctrl/meson/pinctrl-meson-axg.c b/drivers/pinctrl/meson/pinctrl-meson-axg.c index a54fbce910a..3bbbe817b4a 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-axg.c +++ b/drivers/pinctrl/meson/pinctrl-meson-axg.c @@ -14,7 +14,7 @@ #include "pinctrl-meson-axg.h" -#define EE_OFF 14 +#define EE_OFF 15 /* emmc */ static const unsigned int emmc_nand_d0_pins[] = {BOOT_0}; @@ -893,17 +893,17 @@ static struct meson_pmx_func meson_axg_aobus_functions[] = { }; static struct meson_bank meson_axg_periphs_banks[] = { - /* name first last pullen pull dir out in */ - BANK("Z", GPIOZ_0, GPIOZ_10, 3, 0, 3, 0, 9, 0, 10, 0, 11, 0), - BANK("BOOT", BOOT_0, BOOT_14, 4, 0, 4, 0, 12, 0, 13, 0, 14, 0), - BANK("A", GPIOA_0, GPIOA_20, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0), - BANK("X", GPIOX_0, GPIOX_22, 2, 0, 2, 0, 6, 0, 7, 0, 8, 0), - BANK("Y", GPIOY_0, GPIOY_15, 1, 0, 1, 0, 3, 0, 4, 0, 5, 0), + /* name first last pullen pull dir out in */ + BANK("Z", PIN(GPIOZ_0, EE_OFF), PIN(GPIOZ_10, EE_OFF), 3, 0, 3, 0, 9, 0, 10, 0, 11, 0), + BANK("BOOT", PIN(BOOT_0, EE_OFF), PIN(BOOT_14, EE_OFF), 4, 0, 4, 0, 12, 0, 13, 0, 14, 0), + BANK("A", PIN(GPIOA_0, EE_OFF), PIN(GPIOA_20, EE_OFF), 0, 0, 0, 0, 0, 0, 1, 0, 2, 0), + BANK("X", PIN(GPIOX_0, EE_OFF), PIN(GPIOX_22, EE_OFF), 2, 0, 2, 0, 6, 0, 7, 0, 8, 0), + BANK("Y", PIN(GPIOY_0, EE_OFF), PIN(GPIOY_15, EE_OFF), 1, 0, 1, 0, 3, 0, 4, 0, 5, 0), }; static struct meson_bank meson_axg_aobus_banks[] = { - /* name first last pullen pull dir out in */ - BANK("AO", GPIOAO_0, GPIOAO_13, 0, 16, 0, 0, 0, 0, 0, 16, 1, 0), + /* name first last pullen pull dir out in */ + BANK("AO", PIN(GPIOAO_0, 0), PIN(GPIOAO_13, 0), 0, 16, 0, 0, 0, 0, 0, 16, 1, 0), }; static struct meson_pmx_bank meson_axg_periphs_pmx_banks[] = { @@ -931,11 +931,11 @@ static struct meson_axg_pmx_data meson_axg_aobus_pmx_banks_data = { struct meson_pinctrl_data meson_axg_periphs_pinctrl_data = { .name = "periphs-banks", - .pin_base = 11, + .pin_base = 15, .groups = meson_axg_periphs_groups, .funcs = meson_axg_periphs_functions, .banks = meson_axg_periphs_banks, - .num_pins = 100, + .num_pins = 86, .num_groups = ARRAY_SIZE(meson_axg_periphs_groups), .num_funcs = ARRAY_SIZE(meson_axg_periphs_functions), .num_banks = ARRAY_SIZE(meson_axg_periphs_banks), diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c index 0bd6152803d..b539749752c 100644 --- a/drivers/pinctrl/meson/pinctrl-meson.c +++ b/drivers/pinctrl/meson/pinctrl-meson.c @@ -136,7 +136,7 @@ int meson_gpio_direction_input(struct udevice *dev, unsigned int offset) if (ret) return ret; - clrsetbits_le32(priv->reg_gpio + reg, BIT(bit), 1); + setbits_le32(priv->reg_gpio + reg, BIT(bit)); return 0; } @@ -152,7 +152,7 @@ int meson_gpio_direction_output(struct udevice *dev, if (ret) return ret; - clrsetbits_le32(priv->reg_gpio + reg, BIT(bit), 0); + clrbits_le32(priv->reg_gpio + reg, BIT(bit)); ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_OUT, ®, &bit); if (ret) diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c index 6d4117d941f..24affe0414c 100644 --- a/drivers/pinctrl/pinctrl_stm32.c +++ b/drivers/pinctrl/pinctrl_stm32.c @@ -1,6 +1,7 @@ #include <common.h> #include <dm.h> #include <dm/pinctrl.h> +#include <hwspinlock.h> #include <asm/arch/gpio.h> #include <asm/gpio.h> #include <asm/io.h> @@ -14,8 +15,8 @@ DECLARE_GLOBAL_DATA_PTR; #define OTYPE_MSK 1 #define AFR_MASK 0xF -#ifndef CONFIG_SPL_BUILD struct stm32_pinctrl_priv { + struct hwspinlock hws; int pinctrl_ngpios; struct list_head gpio_dev; }; @@ -25,7 +26,7 @@ struct stm32_gpio_bank { struct list_head list; }; -#define MAX_PIN_PER_BANK 16 +#ifndef CONFIG_SPL_BUILD static char pin_name[PINNAME_SIZE]; #define PINMUX_MODE_COUNT 5 @@ -51,6 +52,39 @@ static int stm32_pinctrl_get_af(struct udevice *dev, unsigned int offset) return af; } +static int stm32_populate_gpio_dev_list(struct udevice *dev) +{ + struct stm32_pinctrl_priv *priv = dev_get_priv(dev); + struct udevice *gpio_dev; + struct udevice *child; + struct stm32_gpio_bank *gpio_bank; + int ret; + + /* + * parse pin-controller sub-nodes (ie gpio bank nodes) and fill + * a list with all gpio device reference which belongs to the + * current pin-controller. This list is used to find pin_name and + * pin muxing + */ + list_for_each_entry(child, &dev->child_head, sibling_node) { + ret = uclass_get_device_by_name(UCLASS_GPIO, child->name, + &gpio_dev); + if (ret < 0) + continue; + + gpio_bank = malloc(sizeof(*gpio_bank)); + if (!gpio_bank) { + dev_err(dev, "Not enough memory\n"); + return -ENOMEM; + } + + gpio_bank->gpio_dev = gpio_dev; + list_add_tail(&gpio_bank->list, &priv->gpio_dev); + } + + return 0; +} + static int stm32_pinctrl_get_pins_count(struct udevice *dev) { struct stm32_pinctrl_priv *priv = dev_get_priv(dev); @@ -64,6 +98,8 @@ static int stm32_pinctrl_get_pins_count(struct udevice *dev) if (priv->pinctrl_ngpios) return priv->pinctrl_ngpios; + if (list_empty(&priv->gpio_dev)) + stm32_populate_gpio_dev_list(dev); /* * walk through all banks to retrieve the pin-controller * pins number @@ -78,22 +114,34 @@ static int stm32_pinctrl_get_pins_count(struct udevice *dev) } static struct udevice *stm32_pinctrl_get_gpio_dev(struct udevice *dev, - unsigned int selector) + unsigned int selector, + unsigned int *idx) { struct stm32_pinctrl_priv *priv = dev_get_priv(dev); struct stm32_gpio_bank *gpio_bank; struct gpio_dev_priv *uc_priv; - int first_pin = 0; + int pin_count = 0; + + if (list_empty(&priv->gpio_dev)) + stm32_populate_gpio_dev_list(dev); /* look up for the bank which owns the requested pin */ list_for_each_entry(gpio_bank, &priv->gpio_dev, list) { uc_priv = dev_get_uclass_priv(gpio_bank->gpio_dev); - if (selector < (first_pin + uc_priv->gpio_count)) - /* we found the bank */ - return gpio_bank->gpio_dev; + if (selector < (pin_count + uc_priv->gpio_count)) { + /* + * we found the bank, convert pin selector to + * gpio bank index + */ + *idx = stm32_offset_to_index(gpio_bank->gpio_dev, + selector - pin_count); + if (*idx < 0) + return NULL; - first_pin += uc_priv->gpio_count; + return gpio_bank->gpio_dev; + } + pin_count += uc_priv->gpio_count; } return NULL; @@ -104,9 +152,10 @@ static const char *stm32_pinctrl_get_pin_name(struct udevice *dev, { struct gpio_dev_priv *uc_priv; struct udevice *gpio_dev; + unsigned int gpio_idx; /* look up for the bank which owns the requested pin */ - gpio_dev = stm32_pinctrl_get_gpio_dev(dev, selector); + gpio_dev = stm32_pinctrl_get_gpio_dev(dev, selector, &gpio_idx); if (!gpio_dev) { snprintf(pin_name, PINNAME_SIZE, "Error"); } else { @@ -114,7 +163,7 @@ static const char *stm32_pinctrl_get_pin_name(struct udevice *dev, snprintf(pin_name, PINNAME_SIZE, "%s%d", uc_priv->bank_name, - selector % MAX_PIN_PER_BANK); + gpio_idx); } return pin_name; @@ -127,23 +176,21 @@ static int stm32_pinctrl_get_pin_muxing(struct udevice *dev, { struct udevice *gpio_dev; const char *label; - int gpio_pin; int mode; int af_num; + unsigned int gpio_idx; /* look up for the bank which owns the requested pin */ - gpio_dev = stm32_pinctrl_get_gpio_dev(dev, selector); + gpio_dev = stm32_pinctrl_get_gpio_dev(dev, selector, &gpio_idx); if (!gpio_dev) return -ENODEV; - /* translate pin-controller pin number to gpio pin number */ - gpio_pin = selector % MAX_PIN_PER_BANK; + mode = gpio_get_raw_function(gpio_dev, gpio_idx, &label); - mode = gpio_get_raw_function(gpio_dev, gpio_pin, &label); + dev_dbg(dev, "selector = %d gpio_idx = %d mode = %d\n", + selector, gpio_idx, mode); - dev_dbg(dev, "selector = %d gpio_pin = %d mode = %d\n", - selector, gpio_pin, mode); switch (mode) { case GPIOF_UNKNOWN: @@ -153,7 +200,7 @@ static int stm32_pinctrl_get_pin_muxing(struct udevice *dev, snprintf(buf, size, "%s", pinmux_mode[mode]); break; case GPIOF_FUNC: - af_num = stm32_pinctrl_get_af(gpio_dev, gpio_pin); + af_num = stm32_pinctrl_get_af(gpio_dev, gpio_idx); snprintf(buf, size, "%s %d", pinmux_mode[mode], af_num); break; case GPIOF_OUTPUT: @@ -166,53 +213,44 @@ static int stm32_pinctrl_get_pin_muxing(struct udevice *dev, return 0; } +#endif + int stm32_pinctrl_probe(struct udevice *dev) { struct stm32_pinctrl_priv *priv = dev_get_priv(dev); - struct udevice *gpio_dev; - struct udevice *child; - struct stm32_gpio_bank *gpio_bank; int ret; INIT_LIST_HEAD(&priv->gpio_dev); - /* - * parse pin-controller sub-nodes (ie gpio bank nodes) and fill - * a list with all gpio device reference which belongs to the - * current pin-controller. This list is used to find pin_name and - * pin muxing - */ - list_for_each_entry(child, &dev->child_head, sibling_node) { - ret = uclass_get_device_by_name(UCLASS_GPIO, child->name, - &gpio_dev); - if (ret < 0) - continue; - - gpio_bank = malloc(sizeof(*gpio_bank)); - if (!gpio_bank) { - dev_err(dev, "Not enough memory\n"); - return -ENOMEM; - } - - gpio_bank->gpio_dev = gpio_dev; - list_add_tail(&gpio_bank->list, &priv->gpio_dev); - } + /* hwspinlock property is optional, just log the error */ + ret = hwspinlock_get_by_index(dev, 0, &priv->hws); + if (ret) + debug("%s: hwspinlock_get_by_index may have failed (%d)\n", + __func__, ret); return 0; } -#endif static int stm32_gpio_config(struct gpio_desc *desc, const struct stm32_gpio_ctl *ctl) { struct stm32_gpio_priv *priv = dev_get_priv(desc->dev); struct stm32_gpio_regs *regs = priv->regs; + struct stm32_pinctrl_priv *ctrl_priv; + int ret; u32 index; if (!ctl || ctl->af > 15 || ctl->mode > 3 || ctl->otype > 1 || ctl->pupd > 2 || ctl->speed > 3) return -EINVAL; + ctrl_priv = dev_get_priv(dev_get_parent(desc->dev)); + ret = hwspinlock_lock_timeout(&ctrl_priv->hws, 10); + if (ret == -ETIME) { + dev_err(desc->dev, "HWSpinlock timeout\n"); + return ret; + } + index = (desc->offset & 0x07) * 4; clrsetbits_le32(®s->afr[desc->offset >> 3], AFR_MASK << index, ctl->af << index); @@ -227,6 +265,8 @@ static int stm32_gpio_config(struct gpio_desc *desc, index = desc->offset; clrsetbits_le32(®s->otyper, OTYPE_MSK << index, ctl->otype << index); + hwspinlock_unlock(&ctrl_priv->hws); + return 0; } @@ -393,8 +433,6 @@ U_BOOT_DRIVER(pinctrl_stm32) = { .of_match = stm32_pinctrl_ids, .ops = &stm32_pinctrl_ops, .bind = dm_scan_fdt_dev, -#ifndef CONFIG_SPL_BUILD .probe = stm32_pinctrl_probe, .priv_auto_alloc_size = sizeof(struct stm32_pinctrl_priv), -#endif }; diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 1a3852442a8..9495dca33b9 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -197,6 +197,49 @@ config AXP_ALDO3_VOLT On A83T / H8 boards aldo3 is AVCC, VCC-PL, and VCC-LED, and should be 3.0V. +choice + prompt "axp pmic (a)ldo3 voltage rate control" + depends on AXP209_POWER + default AXP_ALDO3_VOLT_SLOPE_NONE + ---help--- + The AXP can slowly ramp up voltage to reduce the inrush current when + changing voltages. + Note, this does not apply when enabling/disabling LDO3. See + "axp pmic (a)ldo3 inrush quirk" below to enable a slew rate to limit + inrush current on broken board designs. + +config AXP_ALDO3_VOLT_SLOPE_NONE + bool "No voltage slope" + ---help--- + Tries to reach the next voltage setting near instantaneously. Measurements + indicate that this is about 0.0167 V/uS. + +config AXP_ALDO3_VOLT_SLOPE_16 + bool "1.6 mV per uS" + ---help--- + Increases the voltage by 1.6 mV per uS until the final voltage has + been reached. Note that the scaling is in 25 mV steps and thus + the slew rate in reality is about 25 mV/31.250 uS. + +config AXP_ALDO3_VOLT_SLOPE_08 + bool "0.8 mV per uS" + ---help--- + Increases the voltage by 0.8 mV per uS until the final voltage has + been reached. Note that the scaling is in 25 mV steps however and thus + the slew rate in reality is about 25 mV/15.625 uS. + This is the slowest supported rate. + +endchoice + +config AXP_ALDO3_INRUSH_QUIRK + bool "axp pmic (a)ldo3 inrush quirk" + depends on AXP209_POWER + default n + ---help--- + The reference design denotes a value of 4.7 uF for the output capacitor + of LDO3. Some boards have too high capacitance causing an inrush current + and resulting an AXP209 shutdown. + config AXP_ALDO4_VOLT int "axp pmic (a)ldo4 voltage" depends on AXP209_POWER diff --git a/drivers/power/axp209.c b/drivers/power/axp209.c index 6de5ec68258..67b420910c9 100644 --- a/drivers/power/axp209.c +++ b/drivers/power/axp209.c @@ -9,6 +9,16 @@ #include <asm/arch/pmic_bus.h> #include <axp_pmic.h> +#ifdef CONFIG_AXP_ALDO3_VOLT_SLOPE_08 +# define AXP209_VRC_SLOPE AXP209_VRC_LDO3_800uV_uS +#endif +#ifdef CONFIG_AXP_ALDO3_VOLT_SLOPE_16 +# define AXP209_VRC_SLOPE AXP209_VRC_LDO3_1600uV_uS +#endif +#if defined CONFIG_AXP_ALDO3_VOLT_SLOPE_NONE || !defined AXP209_VRC_SLOPE +# define AXP209_VRC_SLOPE 0x00 +#endif + static u8 axp209_mvolt_to_cfg(int mvolt, int min, int max, int div) { if (mvolt < min) @@ -81,8 +91,7 @@ int axp_set_aldo2(unsigned int mvolt) if (rc) return rc; - /* LDO2 configuration is in upper 4 bits */ - reg = (reg & 0x0f) | (cfg << 4); + reg |= AXP209_LDO24_LDO2_SET(reg, cfg); rc = pmic_bus_write(AXP209_LDO24_VOLTAGE, reg); if (rc) return rc; @@ -99,10 +108,49 @@ int axp_set_aldo3(unsigned int mvolt) return pmic_bus_clrbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO3); - if (mvolt == -1) - cfg = 0x80; /* determined by LDO3IN pin */ - else + /* + * Some boards have trouble reaching the target voltage without causing + * great inrush currents. To prevent this, boards can enable a certain + * slope to ramp up voltage. Note, this only works when changing an + * already active power rail. When toggling power on, the AXP ramps up + * steeply at 0.0167 V/uS. + */ + rc = pmic_bus_read(AXP209_VRC_DCDC2_LDO3, &cfg); + cfg = AXP209_VRC_LDO3_SLOPE_SET(cfg, AXP209_VRC_SLOPE); + rc |= pmic_bus_write(AXP209_VRC_DCDC2_LDO3, cfg); + + if (rc) + return rc; + +#ifdef CONFIG_AXP_ALDO3_INRUSH_QUIRK + /* + * On some boards, LDO3 has a too big capacitor installed. When + * turning on LDO3, this causes the AXP209 to shutdown on + * voltages over 1.9 volt. As a workaround, we enable LDO3 + * first with the lowest possible voltage. If this still causes + * high inrush currents, the voltage slope should be increased. + */ + rc = pmic_bus_read(AXP209_OUTPUT_CTRL, &cfg); + if (rc) + return rc; + + if (!(cfg & AXP209_OUTPUT_CTRL_LDO3)) { + rc = pmic_bus_write(AXP209_LDO3_VOLTAGE, 0x0); /* 0.7 Volt */ + mdelay(1); + rc |= pmic_bus_setbits(AXP209_OUTPUT_CTRL, + AXP209_OUTPUT_CTRL_LDO3); + + if (rc) + return rc; + } +#endif + + if (mvolt == -1) { + cfg = AXP209_LDO3_VOLTAGE_FROM_LDO3IN; + } else { cfg = axp209_mvolt_to_cfg(mvolt, 700, 3500, 25); + cfg = AXP209_LDO3_VOLTAGE_SET(cfg); + } rc = pmic_bus_write(AXP209_LDO3_VOLTAGE, cfg); if (rc) @@ -131,8 +179,7 @@ int axp_set_aldo4(unsigned int mvolt) if (rc) return rc; - /* LDO4 configuration is in lower 4 bits */ - reg = (reg & 0xf0) | (cfg << 0); + reg |= AXP209_LDO24_LDO4_SET(reg, cfg); rc = pmic_bus_write(AXP209_LDO24_VOLTAGE, reg); if (rc) return rc; @@ -153,10 +200,7 @@ int axp_init(void) if (rc) return rc; - /* Low 4 bits is chip version */ - ver &= 0x0f; - - if (ver != 0x1) + if ((ver & AXP209_CHIP_VERSION_MASK) != 0x1) return -EINVAL; /* Mask all interrupts */ diff --git a/drivers/power/palmas.c b/drivers/power/palmas.c index 6d5abba5a73..2584bea38d0 100644 --- a/drivers/power/palmas.c +++ b/drivers/power/palmas.c @@ -175,3 +175,42 @@ int twl603x_enable_bb_charge(u8 bb_fields) val, err); return err; } + +#ifdef CONFIG_DM_I2C +int palmas_i2c_write_u8(u8 chip_no, u8 reg, u8 val) +{ + struct udevice *dev; + int ret; + + ret = i2c_get_chip_for_busnum(0, chip_no, 1, &dev); + if (ret) { + pr_err("unable to get I2C bus. ret %d\n", ret); + return ret; + } + ret = dm_i2c_reg_write(dev, reg, val); + if (ret) { + pr_err("writing to palmas failed. ret %d\n", ret); + return ret; + } + return 0; +} + +int palmas_i2c_read_u8(u8 chip_no, u8 reg, u8 *valp) +{ + struct udevice *dev; + int ret; + + ret = i2c_get_chip_for_busnum(0, chip_no, 1, &dev); + if (ret) { + pr_err("unable to get I2C bus. ret %d\n", ret); + return ret; + } + ret = dm_i2c_reg_read(dev, reg); + if (ret < 0) { + pr_err("reading from palmas failed. ret %d\n", ret); + return ret; + } + *valp = (u8)ret; + return 0; +} +#endif diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index cba48e12da4..8cf60ebcf3d 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -48,6 +48,20 @@ config PMIC_AS3722 interface and is designs to cover most of the power managementment required for a tablets or laptop. +config DM_PMIC_FAN53555 + bool "Enable support for OnSemi FAN53555" + depends on DM_PMIC && DM_REGULATOR && DM_I2C + select DM_REGULATOR_FAN53555 + help + This config enables implementation of driver-model PMIC + uclass features for the FAN53555 regulator. The FAN53555 is + a (family of) single-output regulators that supports + transitioning between two different output voltages based on + an voltage selection pin. + + The driver implements read/write operations for use with the FAN53555 + regulator driver and binds the regulator driver to its node. + config DM_PMIC_PFUZE100 bool "Enable Driver Model for PMIC PFUZE100" depends on DM_PMIC diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 29ca4429332..637352ab2b7 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -4,6 +4,7 @@ # Lukasz Majewski <l.majewski@samsung.com> obj-$(CONFIG_DM_PMIC) += pmic-uclass.o +obj-$(CONFIG_DM_PMIC_FAN53555) += fan53555.o obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o obj-$(CONFIG_DM_PMIC_MAX8998) += max8998.o obj-$(CONFIG_DM_PMIC_MC34708) += mc34708.o diff --git a/drivers/power/pmic/fan53555.c b/drivers/power/pmic/fan53555.c new file mode 100644 index 00000000000..1ca59c5f0c5 --- /dev/null +++ b/drivers/power/pmic/fan53555.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) 2018 Theobroma Systems Design und Consulting GmbH + */ + +#include <common.h> +#include <dm.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/regulator.h> + +static int pmic_fan53555_reg_count(struct udevice *dev) +{ + return 1; +}; + +static int pmic_fan53555_read(struct udevice *dev, uint reg, + u8 *buff, int len) +{ + if (dm_i2c_read(dev, reg, buff, len)) { + pr_err("%s: read error for register: %#x!", dev->name, reg); + return -EIO; + } + + return 0; +} + +static int pmic_fan53555_write(struct udevice *dev, uint reg, + const u8 *buff, int len) +{ + if (dm_i2c_write(dev, reg, buff, len)) { + pr_err("%s: write error for register: %#x!", dev->name, reg); + return -EIO; + } + + return 0; +} + +static int pmic_fan53555_bind(struct udevice *dev) +{ + /* + * The FAN53555 has only a single regulator and therefore doesn't + * have a subnode. So we have to rebind a child device (the one + * regulator) here. + */ + + const char *regulator_driver_name = "fan53555_regulator"; + struct udevice *child; + struct driver *drv; + + debug("%s\n", __func__); + + drv = lists_driver_lookup_name(regulator_driver_name); + if (!drv) { + dev_err(dev, "no driver '%s'\n", regulator_driver_name); + return -ENOENT; + } + + return device_bind_with_driver_data(dev, drv, "SW", 0, + dev_ofnode(dev), &child); +}; + +static struct dm_pmic_ops pmic_fan53555_ops = { + .reg_count = pmic_fan53555_reg_count, + .read = pmic_fan53555_read, + .write = pmic_fan53555_write, +}; + +static const struct udevice_id pmic_fan53555_match[] = { + { .compatible = "fcs,fan53555" }, + { }, +}; + +U_BOOT_DRIVER(pmic_fan53555) = { + .name = "pmic_fan53555", + .id = UCLASS_PMIC, + .of_match = pmic_fan53555_match, + .bind = pmic_fan53555_bind, + .ops = &pmic_fan53555_ops, +}; diff --git a/drivers/power/pmic/pmic_tps62362.c b/drivers/power/pmic/pmic_tps62362.c index f2987de48e0..c3977fccc3b 100644 --- a/drivers/power/pmic/pmic_tps62362.c +++ b/drivers/power/pmic/pmic_tps62362.c @@ -10,6 +10,10 @@ #include <power/pmic.h> #include <power/tps62362.h> +#ifdef CONFIG_DM_I2C +struct udevice *tps62362_dev __attribute__((section(".data"))) = NULL; +#endif + /** * tps62362_voltage_update() - Function to change a voltage level, as this * is a multi-step process. @@ -22,9 +26,16 @@ int tps62362_voltage_update(unsigned char reg, unsigned char volt_sel) if (reg > TPS62362_NUM_REGS) return 1; +#ifndef CONFIG_DM_I2C return i2c_write(TPS62362_I2C_ADDR, reg, 1, &volt_sel, 1); +#else + if (!tps62362_dev) + return -ENODEV; + return dm_i2c_reg_write(tps62362_dev, reg, volt_sel); +#endif } +#ifndef CONFIG_DM_I2C int power_tps62362_init(unsigned char bus) { static const char name[] = "TPS62362"; @@ -44,3 +55,16 @@ int power_tps62362_init(unsigned char bus) return 0; } +#else +int power_tps62362_init(unsigned char bus) +{ + struct udevice *dev = NULL; + int rc; + + rc = i2c_get_chip_for_busnum(bus, TPS62362_I2C_ADDR, 1, &dev); + if (rc) + return rc; + tps62362_dev = dev; + return 0; +} +#endif diff --git a/drivers/power/pmic/pmic_tps65217.c b/drivers/power/pmic/pmic_tps65217.c index 01c0ad1a8c8..c839e318905 100644 --- a/drivers/power/pmic/pmic_tps65217.c +++ b/drivers/power/pmic/pmic_tps65217.c @@ -8,6 +8,8 @@ #include <i2c.h> #include <power/tps65217.h> +struct udevice *tps65217_dev __attribute__((section(".data"))) = NULL; + /** * tps65217_reg_read() - Generic function that can read a TPS65217 register * @src_reg: Source register address @@ -16,7 +18,11 @@ */ int tps65217_reg_read(uchar src_reg, uchar *src_val) { +#ifndef CONFIG_DM_I2C return i2c_read(TPS65217_CHIP_PM, src_reg, 1, src_val, 1); +#else + return dm_i2c_read(tps65217_dev, src_reg, src_val, 1); +#endif } /** @@ -46,9 +52,14 @@ int tps65217_reg_write(uchar prot_level, uchar dest_reg, uchar dest_val, * mask */ if (mask != TPS65217_MASK_ALL_BITS) { +#ifndef CONFIG_DM_I2C ret = i2c_read(TPS65217_CHIP_PM, dest_reg, 1, &read_val, 1); +#else + ret = dm_i2c_read(tps65217_dev, dest_reg, &read_val, 1); +#endif if (ret) return ret; + read_val &= (~mask); read_val |= (dest_val & mask); dest_val = read_val; @@ -56,23 +67,40 @@ int tps65217_reg_write(uchar prot_level, uchar dest_reg, uchar dest_val, if (prot_level > 0) { xor_reg = dest_reg ^ TPS65217_PASSWORD_UNLOCK; +#ifndef CONFIG_DM_I2C ret = i2c_write(TPS65217_CHIP_PM, TPS65217_PASSWORD, 1, &xor_reg, 1); +#else + ret = dm_i2c_write(tps65217_dev, TPS65217_PASSWORD, + &xor_reg, 1); +#endif if (ret) return ret; } - +#ifndef CONFIG_DM_I2C ret = i2c_write(TPS65217_CHIP_PM, dest_reg, 1, &dest_val, 1); +#else + ret = dm_i2c_write(tps65217_dev, dest_reg, &dest_val, 1); +#endif if (ret) return ret; if (prot_level == TPS65217_PROT_LEVEL_2) { +#ifndef CONFIG_DM_I2C ret = i2c_write(TPS65217_CHIP_PM, TPS65217_PASSWORD, 1, &xor_reg, 1); +#else + ret = dm_i2c_write(tps65217_dev, TPS65217_PASSWORD, + &xor_reg, 1); +#endif if (ret) return ret; +#ifndef CONFIG_DM_I2C ret = i2c_write(TPS65217_CHIP_PM, dest_reg, 1, &dest_val, 1); +#else + ret = dm_i2c_write(tps65217_dev, dest_reg, &dest_val, 1); +#endif if (ret) return ret; } @@ -106,3 +134,17 @@ int tps65217_voltage_update(uchar dc_cntrl_reg, uchar volt_sel) return 0; } + +int power_tps65217_init(unsigned char bus) +{ +#ifdef CONFIG_DM_I2C + struct udevice *dev = NULL; + int rc; + + rc = i2c_get_chip_for_busnum(bus, TPS65217_CHIP_PM, 1, &dev); + if (rc) + return rc; + tps65217_dev = dev; +#endif + return 0; +} diff --git a/drivers/power/pmic/pmic_tps65218.c b/drivers/power/pmic/pmic_tps65218.c index b50953bdc12..7c95e5e7580 100644 --- a/drivers/power/pmic/pmic_tps65218.c +++ b/drivers/power/pmic/pmic_tps65218.c @@ -10,6 +10,7 @@ #include <power/pmic.h> #include <power/tps65218.h> +#ifndef CONFIG_DM_I2C int tps65218_reg_read(uchar dest_reg, uchar *dest_val) { uchar read_val; @@ -84,6 +85,76 @@ int tps65218_reg_write(uchar prot_level, uchar dest_reg, uchar dest_val, return 0; } +#else +struct udevice *tps65218_dev __attribute__((section(".data"))) = NULL; + +int tps65218_reg_read(uchar dest_reg, uchar *dest_val) +{ + uchar read_val; + int ret; + + if (!tps65218_dev) + return -ENODEV; + + ret = dm_i2c_read(tps65218_dev, dest_reg, &read_val, 1); + if (ret) + return ret; + + *dest_val = read_val; + + return 0; +} + +int tps65218_reg_write(uchar prot_level, uchar dest_reg, uchar dest_val, + uchar mask) +{ + uchar read_val; + uchar xor_reg; + int ret; + + if (!tps65218_dev) + return -ENODEV; + + /* + * If we are affecting only a bit field, read dest_reg and apply the + * mask + */ + if (mask != TPS65218_MASK_ALL_BITS) { + ret = dm_i2c_read(tps65218_dev, dest_reg, &read_val, 1); + if (ret) + return ret; + + read_val &= (~mask); + read_val |= (dest_val & mask); + dest_val = read_val; + } + + if (prot_level > 0) { + xor_reg = dest_reg ^ TPS65218_PASSWORD_UNLOCK; + ret = dm_i2c_write(tps65218_dev, TPS65218_PASSWORD, &xor_reg, + 1); + if (ret) + return ret; + } + + ret = dm_i2c_write(tps65218_dev, dest_reg, &dest_val, 1); + if (ret) + return ret; + + if (prot_level == TPS65218_PROT_LEVEL_2) { + ret = dm_i2c_write(tps65218_dev, TPS65218_PASSWORD, &xor_reg, + 1); + if (ret) + return ret; + + ret = dm_i2c_write(tps65218_dev, dest_reg, &dest_val, 1); + if (ret) + return ret; + } + + return 0; +} +#endif /** * tps65218_voltage_update() - Function to change a voltage level, as this @@ -154,6 +225,7 @@ int tps65218_lock_fseal(void) return 0; } +#ifndef CONFIG_DM_I2C int power_tps65218_init(unsigned char bus) { static const char name[] = "TPS65218_PMIC"; @@ -173,3 +245,16 @@ int power_tps65218_init(unsigned char bus) return 0; } +#else +int power_tps65218_init(unsigned char bus) +{ + struct udevice *dev = NULL; + int rc; + + rc = i2c_get_chip_for_busnum(bus, TPS65218_CHIP_PM, 1, &dev); + if (rc) + return rc; + tps65218_dev = dev; + return 0; +} +#endif diff --git a/drivers/power/pmic/pmic_tps65910.c b/drivers/power/pmic/pmic_tps65910.c index f4d2aa1b7a4..4772de11be2 100644 --- a/drivers/power/pmic/pmic_tps65910.c +++ b/drivers/power/pmic/pmic_tps65910.c @@ -8,6 +8,47 @@ #include <i2c.h> #include <power/tps65910.h> +struct udevice *tps65910_dev __attribute__((section(".data"))) = NULL; + +static inline int tps65910_read_reg(int addr, uchar *buf) +{ +#ifndef CONFIG_DM_I2C + return i2c_read(TPS65910_CTRL_I2C_ADDR, addr, 1, buf, 1); +#else + int rc; + + rc = dm_i2c_reg_read(tps65910_dev, addr); + if (rc < 0) + return rc; + *buf = (uchar)rc; + return 0; +#endif +} + +static inline int tps65910_write_reg(int addr, uchar *buf) +{ +#ifndef CONFIG_DM_I2C + return i2c_write(TPS65910_CTRL_I2C_ADDR, addr, 1, buf, 1); +#else + return dm_i2c_reg_write(tps65910_dev, addr, *buf); +#endif +} + +int power_tps65910_init(unsigned char bus) +{ +#ifdef CONFIG_DM_I2C + struct udevice *dev = NULL; + int rc; + + rc = i2c_get_chip_for_busnum(bus, TPS65910_CTRL_I2C_ADDR, 1, &dev); + + if (rc) + return rc; + tps65910_dev = dev; +#endif + return 0; +} + /* * tps65910_set_i2c_control() - Set the TPS65910 to be controlled via the I2C * interface. @@ -19,16 +60,14 @@ int tps65910_set_i2c_control(void) uchar buf; /* VDD1/2 voltage selection register access by control i/f */ - ret = i2c_read(TPS65910_CTRL_I2C_ADDR, TPS65910_DEVCTRL_REG, 1, - &buf, 1); + ret = tps65910_read_reg(TPS65910_DEVCTRL_REG, &buf); if (ret) return ret; buf |= TPS65910_DEVCTRL_REG_SR_CTL_I2C_SEL_CTL_I2C; - return i2c_write(TPS65910_CTRL_I2C_ADDR, TPS65910_DEVCTRL_REG, 1, - &buf, 1); + return tps65910_write_reg(TPS65910_DEVCTRL_REG, &buf); } /* @@ -49,29 +88,29 @@ int tps65910_voltage_update(unsigned int module, unsigned char vddx_op_vol_sel) reg_offset = TPS65910_VDD2_OP_REG; /* Select VDDx OP */ - ret = i2c_read(TPS65910_CTRL_I2C_ADDR, reg_offset, 1, &buf, 1); + ret = tps65910_read_reg(reg_offset, &buf); if (ret) return ret; buf &= ~TPS65910_OP_REG_CMD_MASK; - ret = i2c_write(TPS65910_CTRL_I2C_ADDR, reg_offset, 1, &buf, 1); + ret = tps65910_write_reg(reg_offset, &buf); if (ret) return ret; /* Configure VDDx OP Voltage */ - ret = i2c_read(TPS65910_CTRL_I2C_ADDR, reg_offset, 1, &buf, 1); + ret = tps65910_read_reg(reg_offset, &buf); if (ret) return ret; buf &= ~TPS65910_OP_REG_SEL_MASK; buf |= vddx_op_vol_sel; - ret = i2c_write(TPS65910_CTRL_I2C_ADDR, reg_offset, 1, &buf, 1); + ret = tps65910_write_reg(reg_offset, &buf); if (ret) return ret; - ret = i2c_read(TPS65910_CTRL_I2C_ADDR, reg_offset, 1, &buf, 1); + ret = tps65910_read_reg(reg_offset, &buf); if (ret) return ret; diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index 2561a8a8561..09b311de8bb 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -69,6 +69,22 @@ config DM_REGULATOR_MAX77686 features for REGULATOR MAX77686. The driver implements get/set api for: value, enable and mode. +config DM_REGULATOR_FAN53555 + bool "Enable Driver Model for REGULATOR FAN53555" + depends on DM_PMIC_FAN53555 + help + This config enables implementation of driver-model regulator + uclass features for the FAN53555 regulator. The FAN53555 is + a (family of) single-output regulators that supports + transitioning between two different output voltages based on + an voltage selection pin. + + The driver implements a get/set api for the voltage of the + 'normal mode' voltage only. Switching to 'suspend mode' + (i.e. the alternate voltage), disabling output via software, + or switching the mode is not supported by this driver (at + this time). + config DM_REGULATOR_FIXED bool "Enable Driver Model for REGULATOR Fixed value" depends on DM_REGULATOR diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index a5f5683d6e9..8017045d542 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_REGULATOR_AS3722) += as3722_regulator.o obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100) += pfuze100.o obj-$(CONFIG_REGULATOR_PWM) += pwm_regulator.o +obj-$(CONFIG_$(SPL_)DM_REGULATOR_FAN53555) += fan53555.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_FIXED) += fixed.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_GPIO) += gpio-regulator.o obj-$(CONFIG_REGULATOR_RK8XX) += rk8xx.o diff --git a/drivers/power/regulator/fan53555.c b/drivers/power/regulator/fan53555.c new file mode 100644 index 00000000000..dbd55023779 --- /dev/null +++ b/drivers/power/regulator/fan53555.c @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) 2018 Theobroma Systems Design und Consulting GmbH + */ + +#include <common.h> +#include <bitfield.h> +#include <errno.h> +#include <dm.h> +#include <fdtdec.h> +#include <i2c.h> +#include <asm/gpio.h> +#include <power/pmic.h> +#include <power/regulator.h> + +/** + * struct ic_types - definition of fan53555-family devices + * + * @die_id: Identifies the DIE_ID (lower nibble of the ID1 register) + * @die_rev: Identifies the DIE_REV (lower nibble of the ID2 register) + * @vsel_min: starting voltage (step 0) in uV + * @vsel_step: increment of the voltage in uV + * + * The voltage ramp (i.e. minimum voltage and step) is selected from the + * combination of 2 nibbles: DIE_ID and DIE_REV. + * + * See http://www.onsemi.com/pub/Collateral/FAN53555-D.pdf for details. + */ +static const struct { + u8 die_id; + u8 die_rev; + u32 vsel_min; + u32 vsel_step; +} ic_types[] = { + { 0x0, 0x3, 600000, 10000 }, /* Option 00 */ + { 0x0, 0xf, 800000, 10000 }, /* Option 13 */ + { 0x0, 0xc, 600000, 12500 }, /* Option 23 */ + { 0x1, 0x3, 600000, 10000 }, /* Option 01 */ + { 0x3, 0x3, 600000, 10000 }, /* Option 03 */ + { 0x4, 0xf, 603000, 12826 }, /* Option 04 */ + { 0x5, 0x3, 600000, 10000 }, /* Option 05 */ + { 0x8, 0x1, 600000, 10000 }, /* Option 08 */ + { 0x8, 0xf, 600000, 10000 }, /* Option 08 */ + { 0xc, 0xf, 603000, 12826 }, /* Option 09 */ +}; + +/* I2C-accessible byte-sized registers */ +enum { + /* Voltage setting */ + FAN53555_VSEL0 = 0x00, + FAN53555_VSEL1, + /* Control register */ + FAN53555_CONTROL, + /* IC Type */ + FAN53555_ID1, + /* IC mask version */ + FAN53555_ID2, + /* Monitor register */ + FAN53555_MONITOR, +}; + +struct fan53555_platdata { + /* Voltage setting register */ + unsigned int vol_reg; + unsigned int sleep_reg; + +}; + +struct fan53555_priv { + /* IC Vendor */ + unsigned int vendor; + /* IC Type and Rev */ + unsigned int die_id; + unsigned int die_rev; + /* Voltage range and step(linear) */ + unsigned int vsel_min; + unsigned int vsel_step; + /* Voltage slew rate limiting */ + unsigned int slew_rate; + /* Sleep voltage cache */ + unsigned int sleep_vol_cache; +}; + +static int fan53555_regulator_ofdata_to_platdata(struct udevice *dev) +{ + struct fan53555_platdata *dev_pdata = dev_get_platdata(dev); + struct dm_regulator_uclass_platdata *uc_pdata = + dev_get_uclass_platdata(dev); + u32 sleep_vsel; + + /* This is a buck regulator */ + uc_pdata->type = REGULATOR_TYPE_BUCK; + + sleep_vsel = dev_read_u32_default(dev, "fcs,suspend-voltage-selector", + FAN53555_VSEL1); + + /* + * Depending on the device-tree settings, the 'normal mode' + * voltage is either controlled by VSEL0 or VSEL1. + */ + switch (sleep_vsel) { + case FAN53555_VSEL0: + dev_pdata->sleep_reg = FAN53555_VSEL0; + dev_pdata->vol_reg = FAN53555_VSEL1; + break; + case FAN53555_VSEL1: + dev_pdata->sleep_reg = FAN53555_VSEL1; + dev_pdata->vol_reg = FAN53555_VSEL0; + break; + default: + pr_err("%s: invalid vsel id %d\n", dev->name, sleep_vsel); + return -EINVAL; + } + + return 0; +} + +static int fan53555_regulator_get_value(struct udevice *dev) +{ + struct fan53555_platdata *pdata = dev_get_platdata(dev); + struct fan53555_priv *priv = dev_get_priv(dev); + int reg; + int voltage; + + /* We only support a single voltage selector (i.e. 'normal' mode). */ + reg = pmic_reg_read(dev->parent, pdata->vol_reg); + if (reg < 0) + return reg; + voltage = priv->vsel_min + (reg & 0x3f) * priv->vsel_step; + + debug("%s: %d uV\n", __func__, voltage); + return voltage; +} + +static int fan53555_regulator_set_value(struct udevice *dev, int uV) +{ + struct fan53555_platdata *pdata = dev_get_platdata(dev); + struct fan53555_priv *priv = dev_get_priv(dev); + u8 vol; + + vol = (uV - priv->vsel_min) / priv->vsel_step; + debug("%s: uV=%d; writing volume %d: %02x\n", + __func__, uV, pdata->vol_reg, vol); + + return pmic_clrsetbits(dev, pdata->vol_reg, GENMASK(6, 0), vol); +} + +static int fan53555_voltages_setup(struct udevice *dev) +{ + struct fan53555_priv *priv = dev_get_priv(dev); + int i; + + /* Init voltage range and step */ + for (i = 0; i < ARRAY_SIZE(ic_types); ++i) { + if (ic_types[i].die_id != priv->die_id) + continue; + + if (ic_types[i].die_rev != priv->die_rev) + continue; + + priv->vsel_min = ic_types[i].vsel_min; + priv->vsel_step = ic_types[i].vsel_step; + + return 0; + } + + pr_err("%s: %s: die id %d rev %d not supported!\n", + dev->name, __func__, priv->die_id, priv->die_rev); + return -EINVAL; +} + +enum { + DIE_ID_SHIFT = 0, + DIE_ID_WIDTH = 4, + DIE_REV_SHIFT = 0, + DIE_REV_WIDTH = 4, +}; + +static int fan53555_probe(struct udevice *dev) +{ + struct fan53555_priv *priv = dev_get_priv(dev); + int ID1, ID2; + + debug("%s\n", __func__); + + /* read chip ID1 and ID2 (two registers, starting at ID1) */ + ID1 = pmic_reg_read(dev->parent, FAN53555_ID1); + if (ID1 < 0) + return ID1; + + ID2 = pmic_reg_read(dev->parent, FAN53555_ID2); + if (ID2 < 0) + return ID2; + + /* extract vendor, die_id and die_rev */ + priv->vendor = bitfield_extract(ID1, 5, 3); + priv->die_id = ID1 & GENMASK(3, 0); + priv->die_rev = ID2 & GENMASK(3, 0); + + if (fan53555_voltages_setup(dev) < 0) + return -ENODATA; + + debug("%s: FAN53555 option %d rev %d detected\n", + __func__, priv->die_id, priv->die_rev); + + return 0; +} + +static const struct dm_regulator_ops fan53555_regulator_ops = { + .get_value = fan53555_regulator_get_value, + .set_value = fan53555_regulator_set_value, +}; + +U_BOOT_DRIVER(fan53555_regulator) = { + .name = "fan53555_regulator", + .id = UCLASS_REGULATOR, + .ops = &fan53555_regulator_ops, + .ofdata_to_platdata = fan53555_regulator_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct fan53555_platdata), + .priv_auto_alloc_size = sizeof(struct fan53555_priv), + .probe = fan53555_probe, +}; diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c index 4da8e43259f..4511625ff25 100644 --- a/drivers/power/regulator/regulator-uclass.c +++ b/drivers/power/regulator/regulator-uclass.c @@ -106,10 +106,15 @@ int regulator_get_enable(struct udevice *dev) int regulator_set_enable(struct udevice *dev, bool enable) { const struct dm_regulator_ops *ops = dev_get_driver_ops(dev); + struct dm_regulator_uclass_platdata *uc_pdata; if (!ops || !ops->set_enable) return -ENOSYS; + uc_pdata = dev_get_uclass_platdata(dev); + if (!enable && uc_pdata->always_on) + return -EACCES; + return ops->set_enable(dev, enable); } diff --git a/drivers/power/twl4030.c b/drivers/power/twl4030.c index 52460014bff..42c9001518b 100644 --- a/drivers/power/twl4030.c +++ b/drivers/power/twl4030.c @@ -179,3 +179,42 @@ int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return 0; } #endif + +#ifdef CONFIG_DM_I2C +int twl4030_i2c_write_u8(u8 chip_no, u8 reg, u8 val) +{ + struct udevice *dev; + int ret; + + ret = i2c_get_chip_for_busnum(0, chip_no, 1, &dev); + if (ret) { + pr_err("unable to get I2C bus. ret %d\n", ret); + return ret; + } + ret = dm_i2c_reg_write(dev, reg, val); + if (ret) { + pr_err("writing to twl4030 failed. ret %d\n", ret); + return ret; + } + return 0; +} + +int twl4030_i2c_read_u8(u8 chip_no, u8 reg, u8 *valp) +{ + struct udevice *dev; + int ret; + + ret = i2c_get_chip_for_busnum(0, chip_no, 1, &dev); + if (ret) { + pr_err("unable to get I2C bus. ret %d\n", ret); + return ret; + } + ret = dm_i2c_reg_read(dev, reg); + if (ret < 0) { + pr_err("reading from twl4030 failed. ret %d\n", ret); + return ret; + } + *valp = (u8)ret; + return 0; +} +#endif diff --git a/drivers/power/twl6030.c b/drivers/power/twl6030.c index e0cbda1f8c4..103960d48d2 100644 --- a/drivers/power/twl6030.c +++ b/drivers/power/twl6030.c @@ -268,3 +268,42 @@ void twl6030_usb_device_settings() value &= ~TWL6030_MISC2_VUSB_IN_PMID; twl6030_i2c_write_u8(TWL6030_CHIP_PM, TWL6030_MISC2, value); } + +#ifdef CONFIG_DM_I2C +int twl6030_i2c_write_u8(u8 chip_no, u8 reg, u8 val) +{ + struct udevice *dev; + int ret; + + ret = i2c_get_chip_for_busnum(0, chip_no, 1, &dev); + if (ret) { + pr_err("unable to get I2C bus. ret %d\n", ret); + return ret; + } + ret = dm_i2c_reg_write(dev, reg, val); + if (ret) { + pr_err("writing to twl6030 failed. ret %d\n", ret); + return ret; + } + return 0; +} + +int twl6030_i2c_read_u8(u8 chip_no, u8 reg, u8 *valp) +{ + struct udevice *dev; + int ret; + + ret = i2c_get_chip_for_busnum(0, chip_no, 1, &dev); + if (ret) { + pr_err("unable to get I2C bus. ret %d\n", ret); + return ret; + } + ret = dm_i2c_reg_read(dev, reg); + if (ret < 0) { + pr_err("reading from twl6030 failed. ret %d\n", ret); + return ret; + } + *valp = (u8)ret; + return 0; +} +#endif diff --git a/drivers/ram/rockchip/sdram_rk322x.c b/drivers/ram/rockchip/sdram_rk322x.c index 8bafd17f8ff..e079ef7a70c 100644 --- a/drivers/ram/rockchip/sdram_rk322x.c +++ b/drivers/ram/rockchip/sdram_rk322x.c @@ -49,7 +49,7 @@ struct rk322x_sdram_params { struct regmap *map; }; -#ifdef CONFIG_TPL_BUILD +#ifdef CONFIG_SPL_BUILD /* * [7:6] bank(n:n bit bank) * [5:4] row(13+n) @@ -750,7 +750,7 @@ static int rk322x_dmc_ofdata_to_platdata(struct udevice *dev) return 0; } -#endif /* CONFIG_TPL_BUILD */ +#endif /* CONFIG_SPL_BUILD */ #if CONFIG_IS_ENABLED(OF_PLATDATA) static int conv_of_platdata(struct udevice *dev) @@ -778,7 +778,7 @@ static int conv_of_platdata(struct udevice *dev) static int rk322x_dmc_probe(struct udevice *dev) { -#ifdef CONFIG_TPL_BUILD +#ifdef CONFIG_SPL_BUILD struct rk322x_sdram_params *plat = dev_get_platdata(dev); int ret; struct udevice *dev_clk; @@ -786,7 +786,7 @@ static int rk322x_dmc_probe(struct udevice *dev) struct dram_info *priv = dev_get_priv(dev); priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); -#ifdef CONFIG_TPL_BUILD +#ifdef CONFIG_SPL_BUILD #if CONFIG_IS_ENABLED(OF_PLATDATA) ret = conv_of_platdata(dev); if (ret) @@ -842,12 +842,12 @@ U_BOOT_DRIVER(dmc_rk322x) = { .id = UCLASS_RAM, .of_match = rk322x_dmc_ids, .ops = &rk322x_dmc_ops, -#ifdef CONFIG_TPL_BUILD +#ifdef CONFIG_SPL_BUILD .ofdata_to_platdata = rk322x_dmc_ofdata_to_platdata, #endif .probe = rk322x_dmc_probe, .priv_auto_alloc_size = sizeof(struct dram_info), -#ifdef CONFIG_TPL_BUILD +#ifdef CONFIG_SPL_BUILD .platdata_auto_alloc_size = sizeof(struct rk322x_sdram_params), #endif }; diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 3bcc61e7312..6252dd8c4b5 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -506,16 +506,10 @@ config BCM283X_PL011_SERIAL config BCM6345_SERIAL bool "Support for BCM6345 UART" - depends on DM_SERIAL && ARCH_BMIPS + depends on DM_SERIAL help Select this to enable UART on BCM6345 SoCs. -config BCM6858_SERIAL - bool "Support for BCM6858 UART" - depends on DM_SERIAL && ARCH_BCM6858 - help - Select this to enable UART on BCM6358 SoCs. - config FSL_LINFLEXUART bool "Freescale Linflex UART support" depends on DM_SERIAL diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index b6377b10768..2f8d065a4c2 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -35,7 +35,6 @@ obj-$(CONFIG_AR933X_UART) += serial_ar933x.o obj-$(CONFIG_ARM_DCC) += arm_dcc.o obj-$(CONFIG_ATMEL_USART) += atmel_usart.o obj-$(CONFIG_BCM6345_SERIAL) += serial_bcm6345.o -obj-$(CONFIG_BCM6858_SERIAL) += serial_bcm6858.o obj-$(CONFIG_EFI_APP) += serial_efi.o obj-$(CONFIG_LPC32XX_HSUART) += lpc32xx_hsuart.o obj-$(CONFIG_MCFUART) += mcfuart.o diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 25b9d172433..f3bd8dbcdf5 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -372,6 +372,25 @@ static int ns16550_serial_setconfig(struct udevice *dev, uint serial_config) return 0; } +static int ns16550_serial_getinfo(struct udevice *dev, + struct serial_device_info *info) +{ + struct NS16550 *const com_port = dev_get_priv(dev); + struct ns16550_platdata *plat = com_port->plat; + + info->type = SERIAL_CHIP_16550_COMPATIBLE; +#ifdef CONFIG_SYS_NS16550_PORT_MAPPED + info->addr_space = SERIAL_ADDRESS_SPACE_IO; +#else + info->addr_space = SERIAL_ADDRESS_SPACE_MEMORY; +#endif + info->addr = plat->base; + info->reg_width = plat->reg_width; + info->reg_shift = plat->reg_shift; + info->reg_offset = plat->reg_offset; + return 0; +} + int ns16550_serial_probe(struct udevice *dev) { struct NS16550 *const com_port = dev_get_priv(dev); @@ -446,6 +465,7 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev) plat->reg_offset = dev_read_u32_default(dev, "reg-offset", 0); plat->reg_shift = dev_read_u32_default(dev, "reg-shift", 0); + plat->reg_width = dev_read_u32_default(dev, "reg-io-width", 1); err = clk_get_by_index(dev, 0, &clk); if (!err) { @@ -478,7 +498,8 @@ const struct dm_serial_ops ns16550_serial_ops = { .pending = ns16550_serial_pending, .getc = ns16550_serial_getc, .setbrg = ns16550_serial_setbrg, - .setconfig = ns16550_serial_setconfig + .setconfig = ns16550_serial_setconfig, + .getinfo = ns16550_serial_getinfo, }; #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) diff --git a/drivers/serial/sandbox.c b/drivers/serial/sandbox.c index 4a05ea44ce9..33102fc872f 100644 --- a/drivers/serial/sandbox.c +++ b/drivers/serial/sandbox.c @@ -163,6 +163,18 @@ DEBUG_UART_FUNCS #endif /* CONFIG_DEBUG_UART_SANDBOX */ +static int sandbox_serial_getconfig(struct udevice *dev, uint *serial_config) +{ + uint config = SERIAL_DEFAULT_CONFIG; + + if (!serial_config) + return -EINVAL; + + *serial_config = config; + + return 0; +} + static int sandbox_serial_setconfig(struct udevice *dev, uint serial_config) { u8 parity = SERIAL_GET_PARITY(serial_config); @@ -176,6 +188,26 @@ static int sandbox_serial_setconfig(struct udevice *dev, uint serial_config) return 0; } +static int sandbox_serial_getinfo(struct udevice *dev, + struct serial_device_info *serial_info) +{ + struct serial_device_info info = { + .type = SERIAL_CHIP_UNKNOWN, + .addr_space = SERIAL_ADDRESS_SPACE_IO, + .addr = SERIAL_DEFAULT_ADDRESS, + .reg_width = 1, + .reg_offset = 0, + .reg_shift = 0, + }; + + if (!serial_info) + return -EINVAL; + + *serial_info = info; + + return 0; +} + #if CONFIG_IS_ENABLED(OF_CONTROL) static const char * const ansi_colour[] = { "black", "red", "green", "yellow", "blue", "megenta", "cyan", @@ -207,7 +239,9 @@ static const struct dm_serial_ops sandbox_serial_ops = { .putc = sandbox_serial_putc, .pending = sandbox_serial_pending, .getc = sandbox_serial_getc, + .getconfig = sandbox_serial_getconfig, .setconfig = sandbox_serial_setconfig, + .getinfo = sandbox_serial_getinfo, }; static const struct udevice_id sandbox_serial_ids[] = { diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index 3ded62732d4..ffcd6d15af2 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -294,6 +294,20 @@ void serial_setbrg(void) ops->setbrg(gd->cur_serial_dev, gd->baudrate); } +int serial_getconfig(uint *config) +{ + struct dm_serial_ops *ops; + + if (!gd->cur_serial_dev) + return 0; + + ops = serial_get_ops(gd->cur_serial_dev); + if (ops->getconfig) + return ops->getconfig(gd->cur_serial_dev, config); + + return 0; +} + int serial_setconfig(uint config) { struct dm_serial_ops *ops; @@ -308,6 +322,25 @@ int serial_setconfig(uint config) return 0; } +int serial_getinfo(struct serial_device_info *info) +{ + struct dm_serial_ops *ops; + + if (!gd->cur_serial_dev) + return -ENODEV; + + if (!info) + return -EINVAL; + + info->baudrate = gd->baudrate; + + ops = serial_get_ops(gd->cur_serial_dev); + if (ops->getinfo) + return ops->getinfo(gd->cur_serial_dev, info); + + return -EINVAL; +} + void serial_stdio_init(void) { } @@ -419,12 +452,16 @@ static int serial_post_probe(struct udevice *dev) ops->pending += gd->reloc_off; if (ops->clear) ops->clear += gd->reloc_off; + if (ops->getconfig) + ops->getconfig += gd->reloc_off; if (ops->setconfig) ops->setconfig += gd->reloc_off; #if CONFIG_POST & CONFIG_SYS_POST_UART if (ops->loop) ops->loop += gd->reloc_off; #endif + if (ops->getinfo) + ops->getinfo += gd->reloc_off; #endif /* Set the baud rate */ if (ops->setbrg) { diff --git a/drivers/serial/serial_bcm6345.c b/drivers/serial/serial_bcm6345.c index a0e709a11e9..9ad8c770d51 100644 --- a/drivers/serial/serial_bcm6345.c +++ b/drivers/serial/serial_bcm6345.c @@ -89,26 +89,26 @@ struct bcm6345_serial_priv { /* enable rx & tx operation on uart */ static void bcm6345_serial_enable(void __iomem *base) { - setbits_be32(base + UART_CTL_REG, UART_CTL_BRGEN_MASK | - UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK); + setbits_32(base + UART_CTL_REG, UART_CTL_BRGEN_MASK | + UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK); } /* disable rx & tx operation on uart */ static void bcm6345_serial_disable(void __iomem *base) { - clrbits_be32(base + UART_CTL_REG, UART_CTL_BRGEN_MASK | - UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK); + clrbits_32(base + UART_CTL_REG, UART_CTL_BRGEN_MASK | + UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK); } /* clear all unread data in rx fifo and unsent data in tx fifo */ static void bcm6345_serial_flush(void __iomem *base) { /* empty rx and tx fifo */ - setbits_be32(base + UART_CTL_REG, UART_CTL_RSTRXFIFO_MASK | - UART_CTL_RSTTXFIFO_MASK); + setbits_32(base + UART_CTL_REG, UART_CTL_RSTRXFIFO_MASK | + UART_CTL_RSTTXFIFO_MASK); /* read any pending char to make sure all irq status are cleared */ - readl_be(base + UART_FIFO_REG); + readl(base + UART_FIFO_REG); } static int bcm6345_serial_init(void __iomem *base, ulong clk, u32 baudrate) @@ -120,40 +120,40 @@ static int bcm6345_serial_init(void __iomem *base, ulong clk, u32 baudrate) bcm6345_serial_flush(base); /* set uart control config */ - clrsetbits_be32(base + UART_CTL_REG, - /* clear rx timeout */ - UART_CTL_RXTIMEOUT_MASK | - /* clear stop bits */ - UART_CTL_STOPBITS_MASK | - /* clear bits per symbol */ - UART_CTL_BITSPERSYM_MASK | - /* clear xmit break */ - UART_CTL_XMITBRK_MASK | - /* clear reserved bit */ - UART_CTL_RSVD_MASK | - /* disable parity */ - UART_CTL_RXPAREN_MASK | - UART_CTL_TXPAREN_MASK | - /* disable loopback */ - UART_CTL_LOOPBACK_MASK, - /* set timeout to 5 */ - UART_CTL_RXTIMEOUT_5 | - /* set 8 bits/symbol */ - UART_CTL_BITSPERSYM_8 | - /* set 1 stop bit */ - UART_CTL_STOPBITS_1 | - /* set parity to even */ - UART_CTL_RXPAREVEN_MASK | - UART_CTL_TXPAREVEN_MASK); + clrsetbits_32(base + UART_CTL_REG, + /* clear rx timeout */ + UART_CTL_RXTIMEOUT_MASK | + /* clear stop bits */ + UART_CTL_STOPBITS_MASK | + /* clear bits per symbol */ + UART_CTL_BITSPERSYM_MASK | + /* clear xmit break */ + UART_CTL_XMITBRK_MASK | + /* clear reserved bit */ + UART_CTL_RSVD_MASK | + /* disable parity */ + UART_CTL_RXPAREN_MASK | + UART_CTL_TXPAREN_MASK | + /* disable loopback */ + UART_CTL_LOOPBACK_MASK, + /* set timeout to 5 */ + UART_CTL_RXTIMEOUT_5 | + /* set 8 bits/symbol */ + UART_CTL_BITSPERSYM_8 | + /* set 1 stop bit */ + UART_CTL_STOPBITS_1 | + /* set parity to even */ + UART_CTL_RXPAREVEN_MASK | + UART_CTL_TXPAREVEN_MASK); /* set uart fifo config */ - clrsetbits_be32(base + UART_FIFO_CFG_REG, - /* clear fifo config */ - UART_FIFO_CFG_RX_MASK | - UART_FIFO_CFG_TX_MASK, - /* set fifo config to 4 */ - UART_FIFO_CFG_RX_4 | - UART_FIFO_CFG_TX_4); + clrsetbits_32(base + UART_FIFO_CFG_REG, + /* clear fifo config */ + UART_FIFO_CFG_RX_MASK | + UART_FIFO_CFG_TX_MASK, + /* set fifo config to 4 */ + UART_FIFO_CFG_RX_4 | + UART_FIFO_CFG_TX_4); /* set baud rate */ val = ((clk / baudrate) >> 4); @@ -161,10 +161,10 @@ static int bcm6345_serial_init(void __iomem *base, ulong clk, u32 baudrate) val = (val >> 1); else val = (val >> 1) - 1; - writel_be(val, base + UART_BAUD_REG); + writel(val, base + UART_BAUD_REG); /* clear interrupts */ - writel_be(0, base + UART_IR_REG); + writel(0, base + UART_IR_REG); /* enable uart */ bcm6345_serial_enable(base); @@ -175,7 +175,7 @@ static int bcm6345_serial_init(void __iomem *base, ulong clk, u32 baudrate) static int bcm6345_serial_pending(struct udevice *dev, bool input) { struct bcm6345_serial_priv *priv = dev_get_priv(dev); - u32 val = readl_be(priv->base + UART_IR_REG); + u32 val = readl(priv->base + UART_IR_REG); if (input) return !!(val & UART_IR_STAT(UART_IR_RXNOTEMPTY)); @@ -195,11 +195,11 @@ static int bcm6345_serial_putc(struct udevice *dev, const char ch) struct bcm6345_serial_priv *priv = dev_get_priv(dev); u32 val; - val = readl_be(priv->base + UART_IR_REG); + val = readl(priv->base + UART_IR_REG); if (!(val & UART_IR_STAT(UART_IR_TXEMPTY))) return -EAGAIN; - writel_be(ch, priv->base + UART_FIFO_REG); + writel(ch, priv->base + UART_FIFO_REG); return 0; } @@ -209,14 +209,13 @@ static int bcm6345_serial_getc(struct udevice *dev) struct bcm6345_serial_priv *priv = dev_get_priv(dev); u32 val; - val = readl_be(priv->base + UART_IR_REG); + val = readl(priv->base + UART_IR_REG); if (val & UART_IR_STAT(UART_IR_RXOVER)) - setbits_be32(priv->base + UART_CTL_REG, - UART_CTL_RSTRXFIFO_MASK); + setbits_32(priv->base + UART_CTL_REG, UART_CTL_RSTRXFIFO_MASK); if (!(val & UART_IR_STAT(UART_IR_RXNOTEMPTY))) return -EAGAIN; - val = readl_be(priv->base + UART_FIFO_REG); + val = readl(priv->base + UART_FIFO_REG); if (val & UART_FIFO_ANYERR_MASK) return -EAGAIN; @@ -277,7 +276,7 @@ static inline void _debug_uart_init(void) static inline void wait_xfered(void __iomem *base) { do { - u32 val = readl_be(base + UART_IR_REG); + u32 val = readl(base + UART_IR_REG); if (val & UART_IR_STAT(UART_IR_TXEMPTY)) break; } while (1); @@ -288,7 +287,7 @@ static inline void _debug_uart_putc(int ch) void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE; wait_xfered(base); - writel_be(ch, base + UART_FIFO_REG); + writel(ch, base + UART_FIFO_REG); wait_xfered(base); } diff --git a/drivers/serial/serial_bcm6858.c b/drivers/serial/serial_bcm6858.c deleted file mode 100644 index 8aa37055f0b..00000000000 --- a/drivers/serial/serial_bcm6858.c +++ /dev/null @@ -1,300 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2018 Philippe Reynes <philippe.reynes@softathome.com> - * - * Derived from linux/drivers/tty/serial/bcm63xx_uart.c: - * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> - * Derived from linux/drivers/tty/serial/serial_bcm6345.c - * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com> - */ - -#include <clk.h> -#include <dm.h> -#include <debug_uart.h> -#include <errno.h> -#include <serial.h> -#include <asm/io.h> -#include <asm/types.h> - -/* UART Control register */ -#define UART_CTL_REG 0x0 -#define UART_CTL_RXTIMEOUT_MASK 0x1f -#define UART_CTL_RXTIMEOUT_5 0x5 -#define UART_CTL_RSTRXFIFO_SHIFT 6 -#define UART_CTL_RSTRXFIFO_MASK (1 << UART_CTL_RSTRXFIFO_SHIFT) -#define UART_CTL_RSTTXFIFO_SHIFT 7 -#define UART_CTL_RSTTXFIFO_MASK (1 << UART_CTL_RSTTXFIFO_SHIFT) -#define UART_CTL_STOPBITS_SHIFT 8 -#define UART_CTL_STOPBITS_MASK (0xf << UART_CTL_STOPBITS_SHIFT) -#define UART_CTL_STOPBITS_1 (0x7 << UART_CTL_STOPBITS_SHIFT) -#define UART_CTL_BITSPERSYM_SHIFT 12 -#define UART_CTL_BITSPERSYM_MASK (0x3 << UART_CTL_BITSPERSYM_SHIFT) -#define UART_CTL_BITSPERSYM_8 (0x3 << UART_CTL_BITSPERSYM_SHIFT) -#define UART_CTL_XMITBRK_SHIFT 14 -#define UART_CTL_XMITBRK_MASK (1 << UART_CTL_XMITBRK_SHIFT) -#define UART_CTL_RSVD_SHIFT 15 -#define UART_CTL_RSVD_MASK (1 << UART_CTL_RSVD_SHIFT) -#define UART_CTL_RXPAREVEN_SHIFT 16 -#define UART_CTL_RXPAREVEN_MASK (1 << UART_CTL_RXPAREVEN_SHIFT) -#define UART_CTL_RXPAREN_SHIFT 17 -#define UART_CTL_RXPAREN_MASK (1 << UART_CTL_RXPAREN_SHIFT) -#define UART_CTL_TXPAREVEN_SHIFT 18 -#define UART_CTL_TXPAREVEN_MASK (1 << UART_CTL_TXPAREVEN_SHIFT) -#define UART_CTL_TXPAREN_SHIFT 19 -#define UART_CTL_TXPAREN_MASK (1 << UART_CTL_TXPAREN_SHIFT) -#define UART_CTL_LOOPBACK_SHIFT 20 -#define UART_CTL_LOOPBACK_MASK (1 << UART_CTL_LOOPBACK_SHIFT) -#define UART_CTL_RXEN_SHIFT 21 -#define UART_CTL_RXEN_MASK (1 << UART_CTL_RXEN_SHIFT) -#define UART_CTL_TXEN_SHIFT 22 -#define UART_CTL_TXEN_MASK (1 << UART_CTL_TXEN_SHIFT) -#define UART_CTL_BRGEN_SHIFT 23 -#define UART_CTL_BRGEN_MASK (1 << UART_CTL_BRGEN_SHIFT) - -/* UART Baudword register */ -#define UART_BAUD_REG 0x4 - -/* UART FIFO Config register */ -#define UART_FIFO_CFG_REG 0x8 -#define UART_FIFO_CFG_RX_SHIFT 8 -#define UART_FIFO_CFG_RX_MASK (0xf << UART_FIFO_CFG_RX_SHIFT) -#define UART_FIFO_CFG_RX_4 (0x4 << UART_FIFO_CFG_RX_SHIFT) -#define UART_FIFO_CFG_TX_SHIFT 12 -#define UART_FIFO_CFG_TX_MASK (0xf << UART_FIFO_CFG_TX_SHIFT) -#define UART_FIFO_CFG_TX_4 (0x4 << UART_FIFO_CFG_TX_SHIFT) - -/* UART Interrupt register */ -#define UART_IR_REG 0x10 -#define UART_IR_STAT(x) (1 << (x)) -#define UART_IR_TXEMPTY 5 -#define UART_IR_RXOVER 7 -#define UART_IR_RXNOTEMPTY 11 - -/* UART FIFO register */ -#define UART_FIFO_REG 0x14 -#define UART_FIFO_VALID_MASK 0xff -#define UART_FIFO_FRAMEERR_SHIFT 8 -#define UART_FIFO_FRAMEERR_MASK (1 << UART_FIFO_FRAMEERR_SHIFT) -#define UART_FIFO_PARERR_SHIFT 9 -#define UART_FIFO_PARERR_MASK (1 << UART_FIFO_PARERR_SHIFT) -#define UART_FIFO_BRKDET_SHIFT 10 -#define UART_FIFO_BRKDET_MASK (1 << UART_FIFO_BRKDET_SHIFT) -#define UART_FIFO_ANYERR_MASK (UART_FIFO_FRAMEERR_MASK | \ - UART_FIFO_PARERR_MASK | \ - UART_FIFO_BRKDET_MASK) - -struct bcm6858_serial_priv { - void __iomem *base; - ulong uartclk; -}; - -/* enable rx & tx operation on uart */ -static void bcm6858_serial_enable(void __iomem *base) -{ - setbits_le32(base + UART_CTL_REG, UART_CTL_BRGEN_MASK | - UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK); -} - -/* disable rx & tx operation on uart */ -static void bcm6858_serial_disable(void __iomem *base) -{ - clrbits_le32(base + UART_CTL_REG, UART_CTL_BRGEN_MASK | - UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK); -} - -/* clear all unread data in rx fifo and unsent data in tx fifo */ -static void bcm6858_serial_flush(void __iomem *base) -{ - /* empty rx and tx fifo */ - setbits_le32(base + UART_CTL_REG, UART_CTL_RSTRXFIFO_MASK | - UART_CTL_RSTTXFIFO_MASK); - - /* read any pending char to make sure all irq status are cleared */ - readl(base + UART_FIFO_REG); -} - -static int bcm6858_serial_init(void __iomem *base, ulong clk, u32 baudrate) -{ - u32 val; - - /* mask all irq and flush port */ - bcm6858_serial_disable(base); - bcm6858_serial_flush(base); - - /* set uart control config */ - clrsetbits_le32(base + UART_CTL_REG, - /* clear rx timeout */ - UART_CTL_RXTIMEOUT_MASK | - /* clear stop bits */ - UART_CTL_STOPBITS_MASK | - /* clear bits per symbol */ - UART_CTL_BITSPERSYM_MASK | - /* clear xmit break */ - UART_CTL_XMITBRK_MASK | - /* clear reserved bit */ - UART_CTL_RSVD_MASK | - /* disable parity */ - UART_CTL_RXPAREN_MASK | - UART_CTL_TXPAREN_MASK | - /* disable loopback */ - UART_CTL_LOOPBACK_MASK, - /* set timeout to 5 */ - UART_CTL_RXTIMEOUT_5 | - /* set 8 bits/symbol */ - UART_CTL_BITSPERSYM_8 | - /* set 1 stop bit */ - UART_CTL_STOPBITS_1 | - /* set parity to even */ - UART_CTL_RXPAREVEN_MASK | - UART_CTL_TXPAREVEN_MASK); - - /* set uart fifo config */ - clrsetbits_le32(base + UART_FIFO_CFG_REG, - /* clear fifo config */ - UART_FIFO_CFG_RX_MASK | - UART_FIFO_CFG_TX_MASK, - /* set fifo config to 4 */ - UART_FIFO_CFG_RX_4 | - UART_FIFO_CFG_TX_4); - - /* set baud rate */ - val = ((clk / baudrate) >> 4); - if (val & 0x1) - val = (val >> 1); - else - val = (val >> 1) - 1; - writel(val, base + UART_BAUD_REG); - - /* clear interrupts */ - writel(0, base + UART_IR_REG); - - /* enable uart */ - bcm6858_serial_enable(base); - - return 0; -} - -static int bcm6858_serial_pending(struct udevice *dev, bool input) -{ - struct bcm6858_serial_priv *priv = dev_get_priv(dev); - u32 val = readl(priv->base + UART_IR_REG); - - if (input) - return !!(val & UART_IR_STAT(UART_IR_RXNOTEMPTY)); - else - return !(val & UART_IR_STAT(UART_IR_TXEMPTY)); -} - -static int bcm6858_serial_setbrg(struct udevice *dev, int baudrate) -{ - struct bcm6858_serial_priv *priv = dev_get_priv(dev); - - return bcm6858_serial_init(priv->base, priv->uartclk, baudrate); -} - -static int bcm6858_serial_putc(struct udevice *dev, const char ch) -{ - struct bcm6858_serial_priv *priv = dev_get_priv(dev); - u32 val; - - val = readl(priv->base + UART_IR_REG); - if (!(val & UART_IR_STAT(UART_IR_TXEMPTY))) - return -EAGAIN; - - writel(ch, priv->base + UART_FIFO_REG); - - return 0; -} - -static int bcm6858_serial_getc(struct udevice *dev) -{ - struct bcm6858_serial_priv *priv = dev_get_priv(dev); - u32 val; - - val = readl(priv->base + UART_IR_REG); - if (val & UART_IR_STAT(UART_IR_RXOVER)) - setbits_le32(priv->base + UART_CTL_REG, - UART_CTL_RSTRXFIFO_MASK); - - if (!(val & UART_IR_STAT(UART_IR_RXNOTEMPTY))) - return -EAGAIN; - - val = readl(priv->base + UART_FIFO_REG); - if (val & UART_FIFO_ANYERR_MASK) - return -EAGAIN; - - return val & UART_FIFO_VALID_MASK; -} - -static int bcm6858_serial_probe(struct udevice *dev) -{ - struct bcm6858_serial_priv *priv = dev_get_priv(dev); - struct clk clk; - int ret; - - /* get address */ - priv->base = dev_remap_addr(dev); - if (!priv->base) - return -EINVAL; - - /* get clock rate */ - ret = clk_get_by_index(dev, 0, &clk); - if (ret < 0) - return ret; - priv->uartclk = clk_get_rate(&clk); - clk_free(&clk); - - /* initialize serial */ - return bcm6858_serial_init(priv->base, priv->uartclk, CONFIG_BAUDRATE); -} - -static const struct dm_serial_ops bcm6858_serial_ops = { - .putc = bcm6858_serial_putc, - .pending = bcm6858_serial_pending, - .getc = bcm6858_serial_getc, - .setbrg = bcm6858_serial_setbrg, -}; - -static const struct udevice_id bcm6858_serial_ids[] = { - { .compatible = "brcm,bcm6858-uart" }, - { /* sentinel */ } -}; - -U_BOOT_DRIVER(bcm6858_serial) = { - .name = "bcm6858-uart", - .id = UCLASS_SERIAL, - .of_match = bcm6858_serial_ids, - .probe = bcm6858_serial_probe, - .priv_auto_alloc_size = sizeof(struct bcm6858_serial_priv), - .ops = &bcm6858_serial_ops, - .flags = DM_FLAG_PRE_RELOC, -}; - -#ifdef CONFIG_DEBUG_UART_BCM6858 -static inline void _debug_uart_init(void) -{ - void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE; - - bcm6858_serial_init(base, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE); -} - -static inline void wait_xfered(void __iomem *base) -{ - do { - u32 val = readl(base + UART_IR_REG); - if (val & UART_IR_STAT(UART_IR_TXEMPTY)) - break; - } while (1); -} - -static inline void _debug_uart_putc(int ch) -{ - void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE; - - wait_xfered(base); - writel(ch, base + UART_FIFO_REG); - wait_xfered(base); -} - -DEBUG_UART_FUNCS -#endif diff --git a/drivers/serial/serial_omap.c b/drivers/serial/serial_omap.c index ee6ad9c9e59..a31d73766dd 100644 --- a/drivers/serial/serial_omap.c +++ b/drivers/serial/serial_omap.c @@ -7,7 +7,6 @@ */ #include <common.h> -#include <debug_uart.h> #include <dm.h> #include <dt-structs.h> #include <ns16550.h> @@ -20,6 +19,47 @@ #ifdef CONFIG_DEBUG_UART_OMAP +#ifndef CONFIG_SYS_NS16550_IER +#define CONFIG_SYS_NS16550_IER 0x00 +#endif + +#define UART_MCRVAL 0x00 +#define UART_LCRVAL UART_LCR_8N1 + +static inline void serial_out_shift(void *addr, int shift, int value) +{ +#ifdef CONFIG_SYS_NS16550_PORT_MAPPED + outb(value, (ulong)addr); +#elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_LITTLE_ENDIAN) + out_le32(addr, value); +#elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_BIG_ENDIAN) + out_be32(addr, value); +#elif defined(CONFIG_SYS_NS16550_MEM32) + writel(value, addr); +#elif defined(CONFIG_SYS_BIG_ENDIAN) + writeb(value, addr + (1 << shift) - 1); +#else + writeb(value, addr); +#endif +} + +static inline int serial_in_shift(void *addr, int shift) +{ +#ifdef CONFIG_SYS_NS16550_PORT_MAPPED + return inb((ulong)addr); +#elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_LITTLE_ENDIAN) + return in_le32(addr); +#elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_BIG_ENDIAN) + return in_be32(addr); +#elif defined(CONFIG_SYS_NS16550_MEM32) + return readl(addr); +#elif defined(CONFIG_SYS_BIG_ENDIAN) + return readb(addr + (1 << shift) - 1); +#else + return readb(addr); +#endif +} + #include <debug_uart.h> static inline void _debug_uart_init(void) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 516188ea88e..a7bb5b35c29 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -116,6 +116,20 @@ config ICH_SPI access the SPI NOR flash on platforms embedding this Intel ICH IP core. +config MESON_SPIFC + bool "Amlogic Meson SPI Flash Controller driver" + depends on ARCH_MESON + help + Enable the Amlogic Meson SPI Flash Controller SPIFC) driver. + This driver can be used to access the SPI NOR flash chips on + Amlogic Meson SoCs. + +config MPC8XX_SPI + bool "MPC8XX SPI Driver" + depends on MPC8xx + help + Enable support for SPI on MPC8XX + config MT7621_SPI bool "MediaTek MT7621 SPI driver" depends on ARCH_MT7620 @@ -124,6 +138,13 @@ config MT7621_SPI the SPI NOR flash on platforms embedding this Ralink / MediaTek SPI core, like MT7621/7628/7688. +config MTK_QSPI + bool "Mediatek QSPI driver" + help + Enable the Mediatek QSPI driver. This driver can be + used to access the SPI NOR flash on platforms embedding this + Mediatek QSPI IP core. + config MVEBU_A3700_SPI bool "Marvell Armada 3700 SPI driver" select CLK_ARMADA_3720 @@ -328,12 +349,6 @@ config LPC32XX_SSP help Enable support for SPI on LPC32xx -config MPC8XX_SPI - bool "MPC8XX SPI Driver" - depends on MPC8xx - help - Enable support for SPI on MPC8XX - config MPC8XXX_SPI bool "MPC8XXX SPI Driver" help diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 7242ea7e404..392a9257957 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -31,8 +31,10 @@ obj-$(CONFIG_FSL_QSPI) += fsl_qspi.o obj-$(CONFIG_ICH_SPI) += ich.o obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o obj-$(CONFIG_LPC32XX_SSP) += lpc32xx_ssp.o +obj-$(CONFIG_MESON_SPIFC) += meson_spifc.o obj-$(CONFIG_MPC8XX_SPI) += mpc8xx_spi.o obj-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o +obj-$(CONFIG_MTK_QSPI) += mtk_qspi.o obj-$(CONFIG_MT7621_SPI) += mt7621_spi.o obj-$(CONFIG_MVEBU_A3700_SPI) += mvebu_a3700_spi.o obj-$(CONFIG_MXC_SPI) += mxc_spi.o diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index 1db8bbef2bb..cf4de9ee1aa 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -34,11 +34,6 @@ static int spi_has_wdrbt(struct atmel_spi_slave *slave) return (ATMEL_SPI_VERSION_REV(ver) >= 0x210); } -void spi_init() -{ - -} - struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int mode) { diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index 07fa5e3b8a1..4d2c106440b 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -388,11 +388,6 @@ void spi_cs_deactivate(struct spi_slave *slave) /* do nothing */ } -void spi_init(void) -{ - /* do nothing */ -} - struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int mode) { diff --git a/drivers/spi/fsl_dspi.c b/drivers/spi/fsl_dspi.c index f7ed8fbe08b..764c94215e7 100644 --- a/drivers/spi/fsl_dspi.c +++ b/drivers/spi/fsl_dspi.c @@ -390,11 +390,6 @@ static int fsl_dspi_cfg_speed(struct fsl_dspi_priv *priv, uint speed) return 0; } #ifndef CONFIG_DM_SPI -void spi_init(void) -{ - /* Nothing to do */ -} - int spi_cs_is_valid(unsigned int bus, unsigned int cs) { if (((cs >= 0) && (cs < 8)) && ((bus >= 0) && (bus < 8))) diff --git a/drivers/spi/fsl_espi.c b/drivers/spi/fsl_espi.c index e9941593f5f..7444ae1a068 100644 --- a/drivers/spi/fsl_espi.c +++ b/drivers/spi/fsl_espi.c @@ -118,11 +118,6 @@ void spi_free_slave(struct spi_slave *slave) free(fsl); } -void spi_init(void) -{ - -} - int spi_claim_bus(struct spi_slave *slave) { struct fsl_spi_slave *fsl = to_fsl_spi_slave(slave); diff --git a/drivers/spi/lpc32xx_ssp.c b/drivers/spi/lpc32xx_ssp.c index ce12eee6571..4b09366317a 100644 --- a/drivers/spi/lpc32xx_ssp.c +++ b/drivers/spi/lpc32xx_ssp.c @@ -47,15 +47,6 @@ static inline struct lpc32xx_spi_slave *to_lpc32xx_spi_slave( return container_of(slave, struct lpc32xx_spi_slave, slave); } -/* spi_init is called during boot when CONFIG_CMD_SPI is defined */ -void spi_init(void) -{ - /* - * nothing to do: clocking was enabled in lpc32xx_ssp_enable() - * and configuration will be done in spi_setup_slave() - */ -} - /* the following is called in sequence by do_spi_xfer() */ struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode) diff --git a/drivers/spi/meson_spifc.c b/drivers/spi/meson_spifc.c new file mode 100644 index 00000000000..3d551694cb0 --- /dev/null +++ b/drivers/spi/meson_spifc.c @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> + * Copyright (C) 2018 BayLibre, SAS + * Author: Neil Armstrong <narmstrong@baylibre.com> + * + * Amlogic Meson SPI Flash Controller driver + */ + +#include <common.h> +#include <spi.h> +#include <clk.h> +#include <dm.h> +#include <regmap.h> +#include <errno.h> +#include <asm/io.h> +#include <linux/bitfield.h> + +/* register map */ +#define REG_CMD 0x00 +#define REG_ADDR 0x04 +#define REG_CTRL 0x08 +#define REG_CTRL1 0x0c +#define REG_STATUS 0x10 +#define REG_CTRL2 0x14 +#define REG_CLOCK 0x18 +#define REG_USER 0x1c +#define REG_USER1 0x20 +#define REG_USER2 0x24 +#define REG_USER3 0x28 +#define REG_USER4 0x2c +#define REG_SLAVE 0x30 +#define REG_SLAVE1 0x34 +#define REG_SLAVE2 0x38 +#define REG_SLAVE3 0x3c +#define REG_C0 0x40 +#define REG_B8 0x60 +#define REG_MAX 0x7c + +/* register fields */ +#define CMD_USER BIT(18) +#define CTRL_ENABLE_AHB BIT(17) +#define CLOCK_SOURCE BIT(31) +#define CLOCK_DIV_SHIFT 12 +#define CLOCK_DIV_MASK (0x3f << CLOCK_DIV_SHIFT) +#define CLOCK_CNT_HIGH_SHIFT 6 +#define CLOCK_CNT_HIGH_MASK (0x3f << CLOCK_CNT_HIGH_SHIFT) +#define CLOCK_CNT_LOW_SHIFT 0 +#define CLOCK_CNT_LOW_MASK (0x3f << CLOCK_CNT_LOW_SHIFT) +#define USER_DIN_EN_MS BIT(0) +#define USER_CMP_MODE BIT(2) +#define USER_CLK_NOT_INV BIT(7) +#define USER_UC_DOUT_SEL BIT(27) +#define USER_UC_DIN_SEL BIT(28) +#define USER_UC_MASK ((BIT(5) - 1) << 27) +#define USER1_BN_UC_DOUT_SHIFT 17 +#define USER1_BN_UC_DOUT_MASK (0xff << 16) +#define USER1_BN_UC_DIN_SHIFT 8 +#define USER1_BN_UC_DIN_MASK (0xff << 8) +#define USER4_CS_POL_HIGH BIT(23) +#define USER4_IDLE_CLK_HIGH BIT(29) +#define USER4_CS_ACT BIT(30) +#define SLAVE_TRST_DONE BIT(4) +#define SLAVE_OP_MODE BIT(30) +#define SLAVE_SW_RST BIT(31) + +#define SPIFC_BUFFER_SIZE 64 + +struct meson_spifc_priv { + struct regmap *regmap; + struct clk clk; +}; + +/** + * meson_spifc_drain_buffer() - copy data from device buffer to memory + * @spifc: the Meson SPI device + * @buf: the destination buffer + * @len: number of bytes to copy + */ +static void meson_spifc_drain_buffer(struct meson_spifc_priv *spifc, + u8 *buf, int len) +{ + u32 data; + int i = 0; + + while (i < len) { + regmap_read(spifc->regmap, REG_C0 + i, &data); + + if (len - i >= 4) { + *((u32 *)buf) = data; + buf += 4; + } else { + memcpy(buf, &data, len - i); + break; + } + i += 4; + } +} + +/** + * meson_spifc_fill_buffer() - copy data from memory to device buffer + * @spifc: the Meson SPI device + * @buf: the source buffer + * @len: number of bytes to copy + */ +static void meson_spifc_fill_buffer(struct meson_spifc_priv *spifc, + const u8 *buf, int len) +{ + u32 data = 0; + int i = 0; + + while (i < len) { + if (len - i >= 4) + data = *(u32 *)buf; + else + memcpy(&data, buf, len - i); + + regmap_write(spifc->regmap, REG_C0 + i, data); + + buf += 4; + i += 4; + } +} + +/** + * meson_spifc_txrx() - transfer a chunk of data + * @spifc: the Meson SPI device + * @dout: data buffer for TX + * @din: data buffer for RX + * @offset: offset of the data to transfer + * @len: length of the data to transfer + * @last_xfer: whether this is the last transfer of the message + * @last_chunk: whether this is the last chunk of the transfer + * Return: 0 on success, a negative value on error + */ +static int meson_spifc_txrx(struct meson_spifc_priv *spifc, + const u8 *dout, u8 *din, int offset, + int len, bool last_xfer, bool last_chunk) +{ + bool keep_cs = true; + u32 data; + int ret; + + if (dout) + meson_spifc_fill_buffer(spifc, dout + offset, len); + + /* enable DOUT stage */ + regmap_update_bits(spifc->regmap, REG_USER, USER_UC_MASK, + USER_UC_DOUT_SEL); + regmap_write(spifc->regmap, REG_USER1, + (8 * len - 1) << USER1_BN_UC_DOUT_SHIFT); + + /* enable data input during DOUT */ + regmap_update_bits(spifc->regmap, REG_USER, USER_DIN_EN_MS, + USER_DIN_EN_MS); + + if (last_chunk && last_xfer) + keep_cs = false; + + regmap_update_bits(spifc->regmap, REG_USER4, USER4_CS_ACT, + keep_cs ? USER4_CS_ACT : 0); + + /* clear transition done bit */ + regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_TRST_DONE, 0); + /* start transfer */ + regmap_update_bits(spifc->regmap, REG_CMD, CMD_USER, CMD_USER); + + /* wait for the current operation to terminate */ + ret = regmap_read_poll_timeout(spifc->regmap, REG_SLAVE, data, + (data & SLAVE_TRST_DONE), + 0, 5 * CONFIG_SYS_HZ); + + if (!ret && din) + meson_spifc_drain_buffer(spifc, din + offset, len); + + return ret; +} + +/** + * meson_spifc_xfer() - perform a single transfer + * @dev: the SPI controller device + * @bitlen: length of the transfer + * @dout: data buffer for TX + * @din: data buffer for RX + * @flags: transfer flags + * Return: 0 on success, a negative value on error + */ +static int meson_spifc_xfer(struct udevice *slave, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct meson_spifc_priv *spifc = dev_get_priv(slave->parent); + int blen = bitlen / 8; + int len, done = 0, ret = 0; + + if (bitlen % 8) + return -EINVAL; + + debug("xfer len %d (%d) dout %p din %p\n", bitlen, blen, dout, din); + + regmap_update_bits(spifc->regmap, REG_CTRL, CTRL_ENABLE_AHB, 0); + + while (done < blen && !ret) { + len = min_t(int, blen - done, SPIFC_BUFFER_SIZE); + ret = meson_spifc_txrx(spifc, dout, din, done, len, + flags & SPI_XFER_END, + done + len >= blen); + done += len; + } + + regmap_update_bits(spifc->regmap, REG_CTRL, CTRL_ENABLE_AHB, + CTRL_ENABLE_AHB); + + return ret; +} + +/** + * meson_spifc_set_speed() - program the clock divider + * @dev: the SPI controller device + * @speed: desired speed in Hz + */ +static int meson_spifc_set_speed(struct udevice *dev, uint speed) +{ + struct meson_spifc_priv *spifc = dev_get_priv(dev); + unsigned long parent, value; + int n; + + parent = clk_get_rate(&spifc->clk); + n = max_t(int, parent / speed - 1, 1); + + debug("parent %lu, speed %u, n %d\n", parent, speed, n); + + value = (n << CLOCK_DIV_SHIFT) & CLOCK_DIV_MASK; + value |= (n << CLOCK_CNT_LOW_SHIFT) & CLOCK_CNT_LOW_MASK; + value |= (((n + 1) / 2 - 1) << CLOCK_CNT_HIGH_SHIFT) & + CLOCK_CNT_HIGH_MASK; + + regmap_write(spifc->regmap, REG_CLOCK, value); + + return 0; +} + +/** + * meson_spifc_set_mode() - setups the SPI bus mode + * @dev: the SPI controller device + * @mode: desired mode bitfield + * Return: 0 on success, -ENODEV on error + */ +static int meson_spifc_set_mode(struct udevice *dev, uint mode) +{ + struct meson_spifc_priv *spifc = dev_get_priv(dev); + + if (mode & (SPI_CPHA | SPI_RX_QUAD | SPI_RX_DUAL | + SPI_TX_QUAD | SPI_TX_DUAL)) + return -ENODEV; + + regmap_update_bits(spifc->regmap, REG_USER, USER_CLK_NOT_INV, + mode & SPI_CPOL ? USER_CLK_NOT_INV : 0); + + regmap_update_bits(spifc->regmap, REG_USER4, USER4_CS_POL_HIGH, + mode & SPI_CS_HIGH ? USER4_CS_POL_HIGH : 0); + + return 0; +} + +/** + * meson_spifc_hw_init() - reset and initialize the SPI controller + * @spifc: the Meson SPI device + */ +static void meson_spifc_hw_init(struct meson_spifc_priv *spifc) +{ + /* reset device */ + regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_SW_RST, + SLAVE_SW_RST); + /* disable compatible mode */ + regmap_update_bits(spifc->regmap, REG_USER, USER_CMP_MODE, 0); + /* set master mode */ + regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_OP_MODE, 0); +} + +static const struct dm_spi_ops meson_spifc_ops = { + .xfer = meson_spifc_xfer, + .set_speed = meson_spifc_set_speed, + .set_mode = meson_spifc_set_mode, +}; + +static int meson_spifc_probe(struct udevice *dev) +{ + struct meson_spifc_priv *priv = dev_get_priv(dev); + int ret; + + ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap); + if (ret) + return ret; + + ret = clk_get_by_index(dev, 0, &priv->clk); + if (ret) + return ret; + + ret = clk_enable(&priv->clk); + if (ret) + return ret; + + meson_spifc_hw_init(priv); + + return 0; +} + +static const struct udevice_id meson_spifc_ids[] = { + { .compatible = "amlogic,meson-gxbb-spifc", }, + { } +}; + +U_BOOT_DRIVER(meson_spifc) = { + .name = "meson_spifc", + .id = UCLASS_SPI, + .of_match = meson_spifc_ids, + .ops = &meson_spifc_ops, + .probe = meson_spifc_probe, + .priv_auto_alloc_size = sizeof(struct meson_spifc_priv), +}; diff --git a/drivers/spi/mtk_qspi.c b/drivers/spi/mtk_qspi.c new file mode 100644 index 00000000000..b510733e92c --- /dev/null +++ b/drivers/spi/mtk_qspi.c @@ -0,0 +1,359 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 MediaTek, Inc. + * Author : Guochun.Mao@mediatek.com + */ + +#include <common.h> +#include <dm.h> +#include <malloc.h> +#include <spi.h> +#include <asm/io.h> +#include <linux/iopoll.h> +#include <linux/ioport.h> + +/* Register Offset */ +struct mtk_qspi_regs { + u32 cmd; + u32 cnt; + u32 rdsr; + u32 rdata; + u32 radr[3]; + u32 wdata; + u32 prgdata[6]; + u32 shreg[10]; + u32 cfg[2]; + u32 shreg10; + u32 mode_mon; + u32 status[4]; + u32 flash_time; + u32 flash_cfg; + u32 reserved_0[3]; + u32 sf_time; + u32 pp_dw_data; + u32 reserved_1; + u32 delsel_0[2]; + u32 intrstus; + u32 intren; + u32 reserved_2; + u32 cfg3; + u32 reserved_3; + u32 chksum; + u32 aaicmd; + u32 wrprot; + u32 radr3; + u32 dual; + u32 delsel_1[3]; +}; + +struct mtk_qspi_platdata { + fdt_addr_t reg_base; + fdt_addr_t mem_base; +}; + +struct mtk_qspi_priv { + struct mtk_qspi_regs *regs; + unsigned long *mem_base; + u8 op; + u8 tx[3]; /* only record max 3 bytes paras, when it's address. */ + u32 txlen; /* dout buffer length - op code length */ + u8 *rx; + u32 rxlen; +}; + +#define MTK_QSPI_CMD_POLLINGREG_US 500000 +#define MTK_QSPI_WRBUF_SIZE 256 +#define MTK_QSPI_COMMAND_ENABLE 0x30 + +/* NOR flash controller commands */ +#define MTK_QSPI_RD_TRIGGER BIT(0) +#define MTK_QSPI_READSTATUS BIT(1) +#define MTK_QSPI_PRG_CMD BIT(2) +#define MTK_QSPI_WR_TRIGGER BIT(4) +#define MTK_QSPI_WRITESTATUS BIT(5) +#define MTK_QSPI_AUTOINC BIT(7) + +#define MTK_QSPI_MAX_RX_TX_SHIFT 0x6 +#define MTK_QSPI_MAX_SHIFT 0x8 + +#define MTK_QSPI_WR_BUF_ENABLE 0x1 +#define MTK_QSPI_WR_BUF_DISABLE 0x0 + +static int mtk_qspi_execute_cmd(struct mtk_qspi_priv *priv, u8 cmd) +{ + u8 tmp; + u8 val = cmd & ~MTK_QSPI_AUTOINC; + + writeb(cmd, &priv->regs->cmd); + + return readb_poll_timeout(&priv->regs->cmd, tmp, !(val & tmp), + MTK_QSPI_CMD_POLLINGREG_US); +} + +static int mtk_qspi_tx_rx(struct mtk_qspi_priv *priv) +{ + int len = 1 + priv->txlen + priv->rxlen; + int i, ret, idx; + + if (len > MTK_QSPI_MAX_SHIFT) + return -ERR_INVAL; + + writeb(len * 8, &priv->regs->cnt); + + /* start at PRGDATA5, go down to PRGDATA0 */ + idx = MTK_QSPI_MAX_RX_TX_SHIFT - 1; + + /* opcode */ + writeb(priv->op, &priv->regs->prgdata[idx]); + idx--; + + /* program TX data */ + for (i = 0; i < priv->txlen; i++, idx--) + writeb(priv->tx[i], &priv->regs->prgdata[idx]); + + /* clear out rest of TX registers */ + while (idx >= 0) { + writeb(0, &priv->regs->prgdata[idx]); + idx--; + } + + ret = mtk_qspi_execute_cmd(priv, MTK_QSPI_PRG_CMD); + if (ret) + return ret; + + /* restart at first RX byte */ + idx = priv->rxlen - 1; + + /* read out RX data */ + for (i = 0; i < priv->rxlen; i++, idx--) + priv->rx[i] = readb(&priv->regs->shreg[idx]); + + return 0; +} + +static int mtk_qspi_read(struct mtk_qspi_priv *priv, + u32 addr, u8 *buf, u32 len) +{ + memcpy(buf, (u8 *)priv->mem_base + addr, len); + return 0; +} + +static void mtk_qspi_set_addr(struct mtk_qspi_priv *priv, u32 addr) +{ + int i; + + for (i = 0; i < 3; i++) { + writeb(addr & 0xff, &priv->regs->radr[i]); + addr >>= 8; + } +} + +static int mtk_qspi_write_single_byte(struct mtk_qspi_priv *priv, + u32 addr, u32 length, const u8 *data) +{ + int i, ret; + + mtk_qspi_set_addr(priv, addr); + + for (i = 0; i < length; i++) { + writeb(*data++, &priv->regs->wdata); + ret = mtk_qspi_execute_cmd(priv, MTK_QSPI_WR_TRIGGER); + if (ret < 0) + return ret; + } + return 0; +} + +static int mtk_qspi_write_buffer(struct mtk_qspi_priv *priv, u32 addr, + const u8 *buf) +{ + int i, data; + + mtk_qspi_set_addr(priv, addr); + + for (i = 0; i < MTK_QSPI_WRBUF_SIZE; i += 4) { + data = buf[i + 3] << 24 | buf[i + 2] << 16 | + buf[i + 1] << 8 | buf[i]; + writel(data, &priv->regs->pp_dw_data); + } + + return mtk_qspi_execute_cmd(priv, MTK_QSPI_WR_TRIGGER); +} + +static int mtk_qspi_write(struct mtk_qspi_priv *priv, + u32 addr, const u8 *buf, u32 len) +{ + int ret; + + /* setting pre-fetch buffer for page program */ + writel(MTK_QSPI_WR_BUF_ENABLE, &priv->regs->cfg[1]); + while (len >= MTK_QSPI_WRBUF_SIZE) { + ret = mtk_qspi_write_buffer(priv, addr, buf); + if (ret < 0) + return ret; + + len -= MTK_QSPI_WRBUF_SIZE; + addr += MTK_QSPI_WRBUF_SIZE; + buf += MTK_QSPI_WRBUF_SIZE; + } + /* disable pre-fetch buffer for page program */ + writel(MTK_QSPI_WR_BUF_DISABLE, &priv->regs->cfg[1]); + + if (len) + return mtk_qspi_write_single_byte(priv, addr, len, buf); + + return 0; +} + +static int mtk_qspi_claim_bus(struct udevice *dev) +{ + /* nothing to do */ + return 0; +} + +static int mtk_qspi_release_bus(struct udevice *dev) +{ + /* nothing to do */ + return 0; +} + +static int mtk_qspi_transfer(struct mtk_qspi_priv *priv, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + u32 bytes = DIV_ROUND_UP(bitlen, 8); + u32 addr; + + if (!bytes) + return -ERR_INVAL; + + if (dout) { + if (flags & SPI_XFER_BEGIN) { + /* parse op code and potential paras first */ + priv->op = *(u8 *)dout; + if (bytes > 1) + memcpy(priv->tx, (u8 *)dout + 1, + bytes <= 4 ? bytes - 1 : 3); + priv->txlen = bytes - 1; + } + + if (flags == SPI_XFER_ONCE) { + /* operations without receiving or sending data. + * for example: erase, write flash register or write + * enable... + */ + priv->rx = NULL; + priv->rxlen = 0; + return mtk_qspi_tx_rx(priv); + } + + if (flags & SPI_XFER_END) { + /* here, dout should be data to be written. + * and priv->tx should be filled 3Bytes address. + */ + addr = priv->tx[0] << 16 | priv->tx[1] << 8 | + priv->tx[2]; + return mtk_qspi_write(priv, addr, (u8 *)dout, bytes); + } + } + + if (din) { + if (priv->txlen >= 3) { + /* if run to here, priv->tx[] should be the address + * where read data from, + * and, din is the buf to receive data. + */ + addr = priv->tx[0] << 16 | priv->tx[1] << 8 | + priv->tx[2]; + return mtk_qspi_read(priv, addr, (u8 *)din, bytes); + } + + /* should be reading flash's register */ + priv->rx = (u8 *)din; + priv->rxlen = bytes; + return mtk_qspi_tx_rx(priv); + } + + return 0; +} + +static int mtk_qspi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct udevice *bus = dev->parent; + struct mtk_qspi_priv *priv = dev_get_priv(bus); + + return mtk_qspi_transfer(priv, bitlen, dout, din, flags); +} + +static int mtk_qspi_set_speed(struct udevice *bus, uint speed) +{ + /* nothing to do */ + return 0; +} + +static int mtk_qspi_set_mode(struct udevice *bus, uint mode) +{ + /* nothing to do */ + return 0; +} + +static int mtk_qspi_ofdata_to_platdata(struct udevice *bus) +{ + struct resource res_reg, res_mem; + struct mtk_qspi_platdata *plat = bus->platdata; + int ret; + + ret = dev_read_resource_byname(bus, "reg_base", &res_reg); + if (ret) { + debug("can't get reg_base resource(ret = %d)\n", ret); + return -ENOMEM; + } + + ret = dev_read_resource_byname(bus, "mem_base", &res_mem); + if (ret) { + debug("can't get map_base resource(ret = %d)\n", ret); + return -ENOMEM; + } + + plat->mem_base = res_mem.start; + plat->reg_base = res_reg.start; + + return 0; +} + +static int mtk_qspi_probe(struct udevice *bus) +{ + struct mtk_qspi_platdata *plat = dev_get_platdata(bus); + struct mtk_qspi_priv *priv = dev_get_priv(bus); + + priv->regs = (struct mtk_qspi_regs *)plat->reg_base; + priv->mem_base = (unsigned long *)plat->mem_base; + + writel(MTK_QSPI_COMMAND_ENABLE, &priv->regs->wrprot); + + return 0; +} + +static const struct dm_spi_ops mtk_qspi_ops = { + .claim_bus = mtk_qspi_claim_bus, + .release_bus = mtk_qspi_release_bus, + .xfer = mtk_qspi_xfer, + .set_speed = mtk_qspi_set_speed, + .set_mode = mtk_qspi_set_mode, +}; + +static const struct udevice_id mtk_qspi_ids[] = { + { .compatible = "mediatek,mt7629-qspi" }, + { } +}; + +U_BOOT_DRIVER(mtk_qspi) = { + .name = "mtk_qspi", + .id = UCLASS_SPI, + .of_match = mtk_qspi_ids, + .ops = &mtk_qspi_ops, + .ofdata_to_platdata = mtk_qspi_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct mtk_qspi_platdata), + .priv_auto_alloc_size = sizeof(struct mtk_qspi_priv), + .probe = mtk_qspi_probe, +}; diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index 0dccc38b82d..b2636909ce6 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -400,10 +400,6 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, return mxc_spi_xfer_internal(mxcs, bitlen, dout, din, flags); } -void spi_init(void) -{ -} - /* * Some SPI devices require active chip-select over multiple * transactions, we achieve this using a GPIO. Still, the SPI diff --git a/drivers/spi/mxs_spi.c b/drivers/spi/mxs_spi.c index 006fe8281c5..5065e407f82 100644 --- a/drivers/spi/mxs_spi.c +++ b/drivers/spi/mxs_spi.c @@ -39,10 +39,6 @@ static inline struct mxs_spi_slave *to_mxs_slave(struct spi_slave *slave) return container_of(slave, struct mxs_spi_slave, slave); } -void spi_init(void) -{ -} - int spi_cs_is_valid(unsigned int bus, unsigned int cs) { /* MXS SPI: 4 ports and 3 chip selects maximum */ diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c index ecf54bb7148..c7fcf050a58 100644 --- a/drivers/spi/omap3_spi.c +++ b/drivers/spi/omap3_spi.c @@ -461,11 +461,6 @@ static inline struct omap3_spi_priv *to_omap3_spi(struct spi_slave *slave) return container_of(slave, struct omap3_spi_priv, slave); } -void spi_init(void) -{ - /* do nothing */ -} - void spi_free_slave(struct spi_slave *slave) { struct omap3_spi_priv *priv = to_omap3_spi(slave); diff --git a/drivers/spi/pl022_spi.c b/drivers/spi/pl022_spi.c index 86b71d2e21a..32bb8c8d212 100644 --- a/drivers/spi/pl022_spi.c +++ b/drivers/spi/pl022_spi.c @@ -9,16 +9,11 @@ * Driver for ARM PL022 SPI Controller. */ -#include <asm/io.h> #include <clk.h> #include <common.h> #include <dm.h> -#include <dm/platform_data/pl022_spi.h> -#include <fdtdec.h> -#include <linux/bitops.h> -#include <linux/bug.h> +#include <dm/platform_data/spi_pl022.h> #include <linux/io.h> -#include <linux/kernel.h> #include <spi.h> #define SSP_CR0 0x000 @@ -72,11 +67,7 @@ struct pl022_spi_slave { void *base; -#if !CONFIG_IS_ENABLED(OF_PLATDATA) - struct clk clk; -#else unsigned int freq; -#endif }; /* @@ -96,30 +87,13 @@ static int pl022_is_supported(struct pl022_spi_slave *ps) return 0; } -#if !CONFIG_IS_ENABLED(OF_PLATDATA) -static int pl022_spi_ofdata_to_platdata(struct udevice *bus) -{ - struct pl022_spi_pdata *plat = bus->platdata; - const void *fdt = gd->fdt_blob; - int node = dev_of_offset(bus); - - plat->addr = fdtdec_get_addr_size(fdt, node, "reg", &plat->size); - - return clk_get_by_index(bus, 0, &plat->clk); -} -#endif - static int pl022_spi_probe(struct udevice *bus) { struct pl022_spi_pdata *plat = dev_get_platdata(bus); struct pl022_spi_slave *ps = dev_get_priv(bus); ps->base = ioremap(plat->addr, plat->size); -#if !CONFIG_IS_ENABLED(OF_PLATDATA) - ps->clk = plat->clk; -#else ps->freq = plat->freq; -#endif /* Check the PL022 version */ if (!pl022_is_supported(ps)) @@ -240,11 +214,7 @@ static int pl022_spi_set_speed(struct udevice *bus, uint speed) u16 scr = SSP_SCR_MIN, cr0 = 0, cpsr = SSP_CPSR_MIN, best_scr = scr, best_cpsr = cpsr; u32 min, max, best_freq = 0, tmp; -#if !CONFIG_IS_ENABLED(OF_PLATDATA) - u32 rate = clk_get_rate(&ps->clk); -#else u32 rate = ps->freq; -#endif bool found = false; max = spi_rate(rate, SSP_CPSR_MIN, SSP_SCR_MIN); @@ -316,6 +286,25 @@ static const struct dm_spi_ops pl022_spi_ops = { }; #if !CONFIG_IS_ENABLED(OF_PLATDATA) +static int pl022_spi_ofdata_to_platdata(struct udevice *bus) +{ + struct pl022_spi_pdata *plat = bus->platdata; + const void *fdt = gd->fdt_blob; + int node = dev_of_offset(bus); + struct clk clkdev; + int ret; + + plat->addr = fdtdec_get_addr_size(fdt, node, "reg", &plat->size); + + ret = clk_get_by_index(bus, 0, &clkdev); + if (ret) + return ret; + + plat->freq = clk_get_rate(&clkdev); + + return 0; +} + static const struct udevice_id pl022_spi_ids[] = { { .compatible = "arm,pl022-spi" }, { } @@ -327,11 +316,9 @@ U_BOOT_DRIVER(pl022_spi) = { .id = UCLASS_SPI, #if !CONFIG_IS_ENABLED(OF_PLATDATA) .of_match = pl022_spi_ids, -#endif - .ops = &pl022_spi_ops, -#if !CONFIG_IS_ENABLED(OF_PLATDATA) .ofdata_to_platdata = pl022_spi_ofdata_to_platdata, #endif + .ops = &pl022_spi_ops, .platdata_auto_alloc_size = sizeof(struct pl022_spi_pdata), .priv_auto_alloc_size = sizeof(struct pl022_spi_slave), .probe = pl022_spi_probe, diff --git a/drivers/spi/sh_qspi.c b/drivers/spi/sh_qspi.c index 64dfd748d67..5ae203d8d4f 100644 --- a/drivers/spi/sh_qspi.c +++ b/drivers/spi/sh_qspi.c @@ -247,11 +247,6 @@ void spi_cs_deactivate(struct spi_slave *slave) sh_qspi_cs_deactivate(ss); } -void spi_init(void) -{ - /* nothing to do */ -} - struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int mode) { diff --git a/drivers/spi/sh_spi.c b/drivers/spi/sh_spi.c index bc2bd638e6f..c58fd0ebc43 100644 --- a/drivers/spi/sh_spi.c +++ b/drivers/spi/sh_spi.c @@ -66,10 +66,6 @@ static int write_fifo_empty_wait(struct sh_spi *ss) return 0; } -void spi_init(void) -{ -} - static void sh_spi_set_cs(struct sh_spi *ss, unsigned int cs) { unsigned long val = 0; diff --git a/drivers/spi/soft_spi_legacy.c b/drivers/spi/soft_spi_legacy.c index 0aac0c065da..cc5ab5f991d 100644 --- a/drivers/spi/soft_spi_legacy.c +++ b/drivers/spi/soft_spi_legacy.c @@ -36,13 +36,6 @@ static inline struct soft_spi_slave *to_soft_spi(struct spi_slave *slave) /* Public Functions */ /*=====================================================================*/ -/*----------------------------------------------------------------------- - * Initialization - */ -void spi_init (void) -{ -} - struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int mode) { diff --git a/drivers/sysreset/sysreset_sandbox.c b/drivers/sysreset/sysreset_sandbox.c index 7f6d4186e16..38e2a7e241d 100644 --- a/drivers/sysreset/sysreset_sandbox.c +++ b/drivers/sysreset/sysreset_sandbox.c @@ -84,7 +84,13 @@ int sandbox_sysreset_get_status(struct udevice *dev, char *buf, int size) int sandbox_sysreset_get_last(struct udevice *dev) { - return SYSRESET_COLD; + struct sandbox_state *state = state_get_current(); + + /* + * The first phase is a power reset, after that we assume we don't + * know. + */ + return state->jumped_fname ? SYSRESET_WARM : SYSRESET_POWER; } static struct sysreset_ops sandbox_sysreset_ops = { diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index d456beb43fc..98f83433bed 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -52,6 +52,20 @@ config SPL_DM_USB depends on DM_USB default y +config DM_USB_GADGET + bool "Enable driver model for USB Gadget" + depends on DM_USB + help + Enable driver model for USB Gadget (Peripheral + mode) + +config SPL_DM_USB_GADGET + bool "Enable driver model for USB Gadget in sPL" + depends on SPL_DM_USB + help + Enable driver model for USB Gadget in SPL + (Peripheral mode) + source "drivers/usb/host/Kconfig" source "drivers/usb/dwc3/Kconfig" diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 943b7630eba..bbd8105c06f 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -38,10 +38,11 @@ config USB_DWC3_OMAP Say 'Y' here if you have one such device config USB_DWC3_GENERIC - bool "Xilinx ZynqMP and similar Platforms" - depends on DM_USB && USB_DWC3 + bool "Generic implementation of a DWC3 wrapper (aka dwc3 glue)" + depends on DM_USB && USB_DWC3 && MISC help - Some platforms can reuse this DWC3 generic implementation. + Select this for Xilinx ZynqMP and similar Platforms. + This wrapper supports Host and Peripheral operation modes. config USB_DWC3_UNIPHIER bool "DesignWare USB3 Host Support on UniPhier Platforms" diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index f1ca6191ce4..56e2a046bf0 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -19,7 +19,7 @@ #include <asm/dma-mapping.h> #include <linux/ioport.h> #include <dm.h> - +#include <generic-phy.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> @@ -789,8 +789,92 @@ MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver"); -#if CONFIG_IS_ENABLED(DM_USB) +#if CONFIG_IS_ENABLED(PHY) && CONFIG_IS_ENABLED(DM_USB) +int dwc3_setup_phy(struct udevice *dev, struct phy **array, int *num_phys) +{ + int i, ret, count; + struct phy *usb_phys; + + /* Return if no phy declared */ + if (!dev_read_prop(dev, "phys", NULL)) + return 0; + count = dev_count_phandle_with_args(dev, "phys", "#phy-cells"); + if (count <= 0) + return count; + + usb_phys = devm_kcalloc(dev, count, sizeof(struct phy), + GFP_KERNEL); + if (!usb_phys) + return -ENOMEM; + + for (i = 0; i < count; i++) { + ret = generic_phy_get_by_index(dev, i, &usb_phys[i]); + if (ret && ret != -ENOENT) { + pr_err("Failed to get USB PHY%d for %s\n", + i, dev->name); + return ret; + } + } + + for (i = 0; i < count; i++) { + ret = generic_phy_init(&usb_phys[i]); + if (ret) { + pr_err("Can't init USB PHY%d for %s\n", + i, dev->name); + goto phys_init_err; + } + } + + for (i = 0; i < count; i++) { + ret = generic_phy_power_on(&usb_phys[i]); + if (ret) { + pr_err("Can't power USB PHY%d for %s\n", + i, dev->name); + goto phys_poweron_err; + } + } + + *array = usb_phys; + *num_phys = count; + return 0; + +phys_poweron_err: + for (i = count - 1; i >= 0; i--) + generic_phy_power_off(&usb_phys[i]); + for (i = 0; i < count; i++) + generic_phy_exit(&usb_phys[i]); + + return ret; + +phys_init_err: + for (; i >= 0; i--) + generic_phy_exit(&usb_phys[i]); + + return ret; +} + +int dwc3_shutdown_phy(struct udevice *dev, struct phy *usb_phys, int num_phys) +{ + int i, ret; + + for (i = 0; i < num_phys; i++) { + if (!generic_phy_valid(&usb_phys[i])) + continue; + + ret = generic_phy_power_off(&usb_phys[i]); + ret |= generic_phy_exit(&usb_phys[i]); + if (ret) { + pr_err("Can't shutdown USB PHY%d for %s\n", + i, dev->name); + } + } + + return 0; +} +#endif + +#if CONFIG_IS_ENABLED(DM_USB_GADGET) int dwc3_init(struct dwc3 *dwc) { int ret; @@ -841,5 +925,4 @@ void dwc3_remove(struct dwc3 *dwc) dwc3_core_exit(dwc); kfree(dwc->mem); } - #endif diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c index 56c9fd657fb..bc6bba198e9 100644 --- a/drivers/usb/dwc3/dwc3-generic.c +++ b/drivers/usb/dwc3/dwc3-generic.c @@ -8,72 +8,89 @@ */ #include <common.h> +#include <asm-generic/io.h> #include <dm.h> #include <dm/device-internal.h> #include <dm/lists.h> -#include <linux/usb/otg.h> -#include <linux/compat.h> +#include <dwc3-uboot.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> #include <malloc.h> #include <usb.h> #include "core.h" #include "gadget.h" -#include "linux-compat.h" +#include <reset.h> +#include <clk.h> -DECLARE_GLOBAL_DATA_PTR; +#if CONFIG_IS_ENABLED(DM_USB_GADGET) +struct dwc3_generic_peripheral { + struct dwc3 dwc3; + struct phy *phys; + int num_phys; + fdt_addr_t base; +}; -int usb_gadget_handle_interrupts(int index) +int dm_usb_gadget_handle_interrupts(struct udevice *dev) { - struct dwc3 *priv; - struct udevice *dev; - int ret; - - ret = uclass_first_device(UCLASS_USB_DEV_GENERIC, &dev); - if (!dev || ret) { - pr_err("No USB device found\n"); - return -ENODEV; - } - - priv = dev_get_priv(dev); + struct dwc3_generic_peripheral *priv = dev_get_priv(dev); + struct dwc3 *dwc3 = &priv->dwc3; - dwc3_gadget_uboot_handle_interrupt(priv); + dwc3_gadget_uboot_handle_interrupt(dwc3); return 0; } static int dwc3_generic_peripheral_probe(struct udevice *dev) { - struct dwc3 *priv = dev_get_priv(dev); + int rc; + struct dwc3_generic_peripheral *priv = dev_get_priv(dev); + struct dwc3 *dwc3 = &priv->dwc3; - return dwc3_init(priv); + rc = dwc3_setup_phy(dev, &priv->phys, &priv->num_phys); + if (rc) + return rc; + + dwc3->regs = map_physmem(priv->base, DWC3_OTG_REGS_END, MAP_NOCACHE); + dwc3->regs += DWC3_GLOBALS_REGS_START; + dwc3->dev = dev; + + rc = dwc3_init(dwc3); + if (rc) { + unmap_physmem(dwc3->regs, MAP_NOCACHE); + return rc; + } + + return 0; } static int dwc3_generic_peripheral_remove(struct udevice *dev) { - struct dwc3 *priv = dev_get_priv(dev); + struct dwc3_generic_peripheral *priv = dev_get_priv(dev); + struct dwc3 *dwc3 = &priv->dwc3; - dwc3_remove(priv); + dwc3_remove(dwc3); + dwc3_shutdown_phy(dev, priv->phys, priv->num_phys); + unmap_physmem(dwc3->regs, MAP_NOCACHE); return 0; } static int dwc3_generic_peripheral_ofdata_to_platdata(struct udevice *dev) { - struct dwc3 *priv = dev_get_priv(dev); + struct dwc3_generic_peripheral *priv = dev_get_priv(dev); + struct dwc3 *dwc3 = &priv->dwc3; int node = dev_of_offset(dev); - priv->regs = (void *)devfdt_get_addr(dev); - priv->regs += DWC3_GLOBALS_REGS_START; + priv->base = devfdt_get_addr(dev); - priv->maximum_speed = usb_get_maximum_speed(node); - if (priv->maximum_speed == USB_SPEED_UNKNOWN) { + dwc3->maximum_speed = usb_get_maximum_speed(node); + if (dwc3->maximum_speed == USB_SPEED_UNKNOWN) { pr_err("Invalid usb maximum speed\n"); return -ENODEV; } - priv->dr_mode = usb_get_dr_mode(node); - if (priv->dr_mode == USB_DR_MODE_UNKNOWN) { + dwc3->dr_mode = usb_get_dr_mode(node); + if (dwc3->dr_mode == USB_DR_MODE_UNKNOWN) { pr_err("Invalid usb mode setup\n"); return -ENODEV; } @@ -81,24 +98,112 @@ static int dwc3_generic_peripheral_ofdata_to_platdata(struct udevice *dev) return 0; } -static int dwc3_generic_peripheral_bind(struct udevice *dev) -{ - return device_probe(dev); -} - U_BOOT_DRIVER(dwc3_generic_peripheral) = { .name = "dwc3-generic-peripheral", - .id = UCLASS_USB_DEV_GENERIC, + .id = UCLASS_USB_GADGET_GENERIC, .ofdata_to_platdata = dwc3_generic_peripheral_ofdata_to_platdata, .probe = dwc3_generic_peripheral_probe, .remove = dwc3_generic_peripheral_remove, - .bind = dwc3_generic_peripheral_bind, - .platdata_auto_alloc_size = sizeof(struct usb_platdata), - .priv_auto_alloc_size = sizeof(struct dwc3), - .flags = DM_FLAG_ALLOC_PRIV_DMA, + .priv_auto_alloc_size = sizeof(struct dwc3_generic_peripheral), +}; +#endif + +struct dwc3_glue_data { + struct clk_bulk clks; + struct reset_ctl_bulk resets; + fdt_addr_t regs; }; -static int dwc3_generic_bind(struct udevice *parent) +struct dwc3_glue_ops { + void (*select_dr_mode)(struct udevice *dev, int index, + enum usb_dr_mode mode); +}; + +void dwc3_ti_select_dr_mode(struct udevice *dev, int index, + enum usb_dr_mode mode) +{ +#define USBOTGSS_UTMI_OTG_STATUS 0x0084 +#define USBOTGSS_UTMI_OTG_OFFSET 0x0480 + +/* UTMI_OTG_STATUS REGISTER */ +#define USBOTGSS_UTMI_OTG_STATUS_SW_MODE BIT(31) +#define USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT BIT(9) +#define USBOTGSS_UTMI_OTG_STATUS_TXBITSTUFFENABLE BIT(8) +#define USBOTGSS_UTMI_OTG_STATUS_IDDIG BIT(4) +#define USBOTGSS_UTMI_OTG_STATUS_SESSEND BIT(3) +#define USBOTGSS_UTMI_OTG_STATUS_SESSVALID BIT(2) +#define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID BIT(1) +enum dwc3_omap_utmi_mode { + DWC3_OMAP_UTMI_MODE_UNKNOWN = 0, + DWC3_OMAP_UTMI_MODE_HW, + DWC3_OMAP_UTMI_MODE_SW, +}; + + u32 use_id_pin; + u32 host_mode; + u32 reg; + u32 utmi_mode; + u32 utmi_status_offset = USBOTGSS_UTMI_OTG_STATUS; + + struct dwc3_glue_data *glue = dev_get_platdata(dev); + void *base = map_physmem(glue->regs, 0x10000, MAP_NOCACHE); + + if (device_is_compatible(dev, "ti,am437x-dwc3")) + utmi_status_offset += USBOTGSS_UTMI_OTG_OFFSET; + + utmi_mode = dev_read_u32_default(dev, "utmi-mode", + DWC3_OMAP_UTMI_MODE_UNKNOWN); + if (utmi_mode != DWC3_OMAP_UTMI_MODE_HW) { + debug("%s: OTG is not supported. defaulting to PERIPHERAL\n", + dev->name); + mode = USB_DR_MODE_PERIPHERAL; + } + + switch (mode) { + case USB_DR_MODE_PERIPHERAL: + use_id_pin = 0; + host_mode = 0; + break; + case USB_DR_MODE_HOST: + use_id_pin = 0; + host_mode = 1; + break; + case USB_DR_MODE_OTG: + default: + use_id_pin = 1; + host_mode = 0; + break; + } + + reg = readl(base + utmi_status_offset); + + reg &= ~(USBOTGSS_UTMI_OTG_STATUS_SW_MODE); + if (!use_id_pin) + reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE; + + writel(reg, base + utmi_status_offset); + + reg &= ~(USBOTGSS_UTMI_OTG_STATUS_SESSEND | + USBOTGSS_UTMI_OTG_STATUS_VBUSVALID | + USBOTGSS_UTMI_OTG_STATUS_IDDIG); + + reg |= USBOTGSS_UTMI_OTG_STATUS_SESSVALID | + USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT; + + if (!host_mode) + reg |= USBOTGSS_UTMI_OTG_STATUS_IDDIG | + USBOTGSS_UTMI_OTG_STATUS_VBUSVALID; + + writel(reg, base + utmi_status_offset); + + unmap_physmem(base, MAP_NOCACHE); +} + +struct dwc3_glue_ops ti_ops = { + .select_dr_mode = dwc3_ti_select_dr_mode, +}; + +static int dwc3_glue_bind(struct udevice *parent) { const void *fdt = gd->fdt_blob; int node; @@ -109,29 +214,32 @@ static int dwc3_generic_bind(struct udevice *parent) const char *name = fdt_get_name(fdt, node, NULL); enum usb_dr_mode dr_mode; struct udevice *dev; - const char *driver; + const char *driver = NULL; debug("%s: subnode name: %s\n", __func__, name); - if (strncmp(name, "dwc3@", 4)) - continue; dr_mode = usb_get_dr_mode(node); switch (dr_mode) { case USB_DR_MODE_PERIPHERAL: case USB_DR_MODE_OTG: +#if CONFIG_IS_ENABLED(DM_USB_GADGET) debug("%s: dr_mode: OTG or Peripheral\n", __func__); driver = "dwc3-generic-peripheral"; +#endif break; case USB_DR_MODE_HOST: debug("%s: dr_mode: HOST\n", __func__); - driver = "dwc3-generic-host"; + driver = "xhci-dwc3"; break; default: debug("%s: unsupported dr_mode\n", __func__); return -ENODEV; }; + if (!driver) + continue; + ret = device_bind_driver_to_node(parent, driver, name, offset_to_ofnode(node), &dev); if (ret) { @@ -144,14 +252,107 @@ static int dwc3_generic_bind(struct udevice *parent) return 0; } -static const struct udevice_id dwc3_generic_ids[] = { +static int dwc3_glue_reset_init(struct udevice *dev, + struct dwc3_glue_data *glue) +{ + int ret; + + ret = reset_get_bulk(dev, &glue->resets); + if (ret == -ENOTSUPP) + return 0; + else if (ret) + return ret; + + ret = reset_deassert_bulk(&glue->resets); + if (ret) { + reset_release_bulk(&glue->resets); + return ret; + } + + return 0; +} + +static int dwc3_glue_clk_init(struct udevice *dev, + struct dwc3_glue_data *glue) +{ + int ret; + + ret = clk_get_bulk(dev, &glue->clks); + if (ret == -ENOSYS) + return 0; + if (ret) + return ret; + +#if CONFIG_IS_ENABLED(CLK) + ret = clk_enable_bulk(&glue->clks); + if (ret) { + clk_release_bulk(&glue->clks); + return ret; + } +#endif + + return 0; +} + +static int dwc3_glue_probe(struct udevice *dev) +{ + struct dwc3_glue_ops *ops = (struct dwc3_glue_ops *)dev_get_driver_data(dev); + struct dwc3_glue_data *glue = dev_get_platdata(dev); + struct udevice *child = NULL; + int index = 0; + int ret; + + glue->regs = dev_read_addr(dev); + + ret = dwc3_glue_clk_init(dev, glue); + if (ret) + return ret; + + ret = dwc3_glue_reset_init(dev, glue); + if (ret) + return ret; + + ret = device_find_first_child(dev, &child); + if (ret) + return ret; + + while (child) { + enum usb_dr_mode dr_mode; + + dr_mode = usb_get_dr_mode(dev_of_offset(child)); + device_find_next_child(&child); + if (ops && ops->select_dr_mode) + ops->select_dr_mode(dev, index, dr_mode); + index++; + } + + return 0; +} + +static int dwc3_glue_remove(struct udevice *dev) +{ + struct dwc3_glue_data *glue = dev_get_platdata(dev); + + reset_release_bulk(&glue->resets); + + clk_release_bulk(&glue->clks); + + return dm_scan_fdt_dev(dev); +} + +static const struct udevice_id dwc3_glue_ids[] = { { .compatible = "xlnx,zynqmp-dwc3" }, + { .compatible = "ti,dwc3", .data = (ulong)&ti_ops }, { } }; U_BOOT_DRIVER(dwc3_generic_wrapper) = { .name = "dwc3-generic-wrapper", .id = UCLASS_MISC, - .of_match = dwc3_generic_ids, - .bind = dwc3_generic_bind, + .of_match = dwc3_glue_ids, + .bind = dwc3_glue_bind, + .probe = dwc3_glue_probe, + .remove = dwc3_glue_remove, + .platdata_auto_alloc_size = sizeof(struct dwc3_glue_data), + }; diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 4f68887b8d5..818efb3e8d7 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -12,7 +12,7 @@ * * commit c00552ebaf : Merge 3.18-rc7 into usb-next */ - +#include <common.h> #include <linux/kernel.h> #include <linux/list.h> diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 193583b437c..3b3d9af6810 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -100,9 +100,6 @@ struct eth_dev { struct usb_gadget *gadget; struct usb_request *req; /* for control responses */ struct usb_request *stat_req; /* for cdc & rndis status */ -#if CONFIG_IS_ENABLED(DM_USB) - struct udevice *usb_udev; -#endif u8 config; struct usb_ep *in_ep, *out_ep, *status_ep; @@ -2336,40 +2333,17 @@ fail: } /*-------------------------------------------------------------------------*/ - -#if CONFIG_IS_ENABLED(DM_USB) -int dm_usb_init(struct eth_dev *e_dev) -{ - struct udevice *dev = NULL; - int ret; - - ret = uclass_first_device(UCLASS_USB_DEV_GENERIC, &dev); - if (!dev || ret) { - pr_err("No USB device found\n"); - return -ENODEV; - } - - e_dev->usb_udev = dev; - - return ret; -} -#endif - static int _usb_eth_init(struct ether_priv *priv) { struct eth_dev *dev = &priv->ethdev; struct usb_gadget *gadget; unsigned long ts; + int ret; unsigned long timeout = USB_CONNECT_TIMEOUT; -#if CONFIG_IS_ENABLED(DM_USB) - if (dm_usb_init(dev)) { - pr_err("USB ether not found\n"); - return -ENODEV; - } -#else - board_usb_init(0, USB_INIT_DEVICE); -#endif + ret = usb_gadget_initialize(0); + if (ret) + return ret; /* Configure default mac-addresses for the USB ethernet device */ #ifdef CONFIG_USBNET_DEV_ADDR @@ -2541,9 +2515,7 @@ void _usb_eth_halt(struct ether_priv *priv) } usb_gadget_unregister_driver(&priv->eth_driver); -#if !CONFIG_IS_ENABLED(DM_USB) - board_usb_cleanup(0, USB_INIT_DEVICE); -#endif + usb_gadget_release(0); } #ifndef CONFIG_DM_ETH @@ -2699,7 +2671,7 @@ int usb_ether_init(void) struct udevice *usb_dev; int ret; - ret = uclass_first_device(UCLASS_USB_DEV_GENERIC, &usb_dev); + ret = uclass_first_device(UCLASS_USB_GADGET_GENERIC, &usb_dev); if (!usb_dev || ret) { pr_err("No USB device found\n"); return ret; diff --git a/drivers/usb/gadget/udc/Makefile b/drivers/usb/gadget/udc/Makefile index 449339f2c44..38ac2dd475e 100644 --- a/drivers/usb/gadget/udc/Makefile +++ b/drivers/usb/gadget/udc/Makefile @@ -2,4 +2,8 @@ # # USB peripheral controller drivers +ifndef CONFIG_$(SPL_)DM_USB_GADGET obj-$(CONFIG_USB_DWC3_GADGET) += udc-core.o +endif + +obj-$(CONFIG_$(SPL_)DM_USB_GADGET) += udc-uclass.o udc-core.o diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index f5c30dd7507..62b47781ddc 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -18,7 +18,8 @@ #include <asm/cache.h> #include <asm/dma-mapping.h> #include <common.h> - +#include <dm.h> +#include <dm/device-internal.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> diff --git a/drivers/usb/gadget/udc/udc-uclass.c b/drivers/usb/gadget/udc/udc-uclass.c new file mode 100644 index 00000000000..062051857a9 --- /dev/null +++ b/drivers/usb/gadget/udc/udc-uclass.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com + * Written by Jean-Jacques Hiblot <jjhiblot@ti.com> + */ + +#include <common.h> +#include <dm.h> +#include <dm/device-internal.h> +#include <linux/usb/gadget.h> + +#define MAX_UDC_DEVICES 4 +static struct udevice *dev_array[MAX_UDC_DEVICES]; +int usb_gadget_initialize(int index) +{ + int ret; + struct udevice *dev = NULL; + + if (index < 0 || index >= ARRAY_SIZE(dev_array)) + return -EINVAL; + if (dev_array[index]) + return 0; + ret = uclass_get_device(UCLASS_USB_GADGET_GENERIC, index, &dev); + if (!dev || ret) { + pr_err("No USB device found\n"); + return -ENODEV; + } + dev_array[index] = dev; + return 0; +} + +int usb_gadget_release(int index) +{ +#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE) + int ret; + if (index < 0 || index >= ARRAY_SIZE(dev_array)) + return -EINVAL; + + ret = device_remove(dev_array[index], DM_REMOVE_NORMAL); + if (!ret) + dev_array[index] = NULL; + return ret; +#else + return -ENOTSUPP; +#endif +} + +int usb_gadget_handle_interrupts(int index) +{ + if (index < 0 || index >= ARRAY_SIZE(dev_array)) + return -EINVAL; + return dm_usb_gadget_handle_interrupts(dev_array[index]); +} + +UCLASS_DRIVER(usb_gadget_generic) = { + .id = UCLASS_USB_GADGET_GENERIC, + .name = "usb_gadget_generic", +}; diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c index dd0d156027e..83b9f119e71 100644 --- a/drivers/usb/host/xhci-dwc3.c +++ b/drivers/usb/host/xhci-dwc3.c @@ -12,6 +12,7 @@ #include <fdtdec.h> #include <generic-phy.h> #include <usb.h> +#include <dwc3-uboot.h> #include "xhci.h" #include <asm/io.h> @@ -110,105 +111,21 @@ void dwc3_set_fladj(struct dwc3 *dwc3_reg, u32 val) } #if CONFIG_IS_ENABLED(DM_USB) -static int xhci_dwc3_setup_phy(struct udevice *dev) -{ - struct xhci_dwc3_platdata *plat = dev_get_platdata(dev); - int i, ret, count; - - /* Return if no phy declared */ - if (!dev_read_prop(dev, "phys", NULL)) - return 0; - - count = dev_count_phandle_with_args(dev, "phys", "#phy-cells"); - if (count <= 0) - return count; - - plat->usb_phys = devm_kcalloc(dev, count, sizeof(struct phy), - GFP_KERNEL); - if (!plat->usb_phys) - return -ENOMEM; - - for (i = 0; i < count; i++) { - ret = generic_phy_get_by_index(dev, i, &plat->usb_phys[i]); - if (ret && ret != -ENOENT) { - pr_err("Failed to get USB PHY%d for %s\n", - i, dev->name); - return ret; - } - - ++plat->num_phys; - } - - for (i = 0; i < plat->num_phys; i++) { - ret = generic_phy_init(&plat->usb_phys[i]); - if (ret) { - pr_err("Can't init USB PHY%d for %s\n", - i, dev->name); - goto phys_init_err; - } - } - - for (i = 0; i < plat->num_phys; i++) { - ret = generic_phy_power_on(&plat->usb_phys[i]); - if (ret) { - pr_err("Can't power USB PHY%d for %s\n", - i, dev->name); - goto phys_poweron_err; - } - } - - return 0; - -phys_poweron_err: - for (; i >= 0; i--) - generic_phy_power_off(&plat->usb_phys[i]); - - for (i = 0; i < plat->num_phys; i++) - generic_phy_exit(&plat->usb_phys[i]); - - return ret; - -phys_init_err: - for (; i >= 0; i--) - generic_phy_exit(&plat->usb_phys[i]); - - return ret; -} - -static int xhci_dwc3_shutdown_phy(struct udevice *dev) -{ - struct xhci_dwc3_platdata *plat = dev_get_platdata(dev); - int i, ret; - - for (i = 0; i < plat->num_phys; i++) { - if (!generic_phy_valid(&plat->usb_phys[i])) - continue; - - ret = generic_phy_power_off(&plat->usb_phys[i]); - ret |= generic_phy_exit(&plat->usb_phys[i]); - if (ret) { - pr_err("Can't shutdown USB PHY%d for %s\n", - i, dev->name); - } - } - - return 0; -} - static int xhci_dwc3_probe(struct udevice *dev) { struct xhci_hcor *hcor; struct xhci_hccr *hccr; struct dwc3 *dwc3_reg; enum usb_dr_mode dr_mode; + struct xhci_dwc3_platdata *plat = dev_get_platdata(dev); int ret; hccr = (struct xhci_hccr *)((uintptr_t)dev_read_addr(dev)); hcor = (struct xhci_hcor *)((uintptr_t)hccr + HC_LENGTH(xhci_readl(&(hccr)->cr_capbase))); - ret = xhci_dwc3_setup_phy(dev); - if (ret) + ret = dwc3_setup_phy(dev, &plat->usb_phys, &plat->num_phys); + if (ret && (ret != -ENOTSUPP)) return ret; dwc3_reg = (struct dwc3 *)((char *)(hccr) + DWC3_REG_OFFSET); @@ -227,7 +144,9 @@ static int xhci_dwc3_probe(struct udevice *dev) static int xhci_dwc3_remove(struct udevice *dev) { - xhci_dwc3_shutdown_phy(dev); + struct xhci_dwc3_platdata *plat = dev_get_platdata(dev); + + dwc3_shutdown_phy(dev, plat->usb_phys, plat->num_phys); return xhci_deregister(dev); } diff --git a/drivers/usb/musb-new/omap2430.c b/drivers/usb/musb-new/omap2430.c index 58aed72b7d3..32743aa72c5 100644 --- a/drivers/usb/musb-new/omap2430.c +++ b/drivers/usb/musb-new/omap2430.c @@ -263,7 +263,7 @@ U_BOOT_DRIVER(omap2430_musb) = { #ifdef CONFIG_USB_MUSB_HOST .id = UCLASS_USB, #else - .id = UCLASS_USB_DEV_GENERIC, + .id = UCLASS_USB_GADGET_GENERIC, #endif .of_match = omap2430_musb_ids, .ofdata_to_platdata = omap2430_musb_ofdata_to_platdata, diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c index 6cf9826cda1..d7170a3078c 100644 --- a/drivers/usb/musb-new/sunxi.c +++ b/drivers/usb/musb-new/sunxi.c @@ -535,7 +535,7 @@ U_BOOT_DRIVER(usb_musb) = { #ifdef CONFIG_USB_MUSB_HOST .id = UCLASS_USB, #else - .id = UCLASS_USB_DEV_GENERIC, + .id = UCLASS_USB_GADGET_GENERIC, #endif .of_match = sunxi_musb_ids, .probe = musb_usb_probe, diff --git a/drivers/video/pwm_backlight.c b/drivers/video/pwm_backlight.c index c13a9077090..bd733f5f1ca 100644 --- a/drivers/video/pwm_backlight.c +++ b/drivers/video/pwm_backlight.c @@ -78,7 +78,7 @@ static int enable_sequence(struct udevice *dev, int seq) ret = regulator_set_enable(priv->reg, true); if (ret) { log_debug("Cannot enable regulator for PWM '%s'\n", - __func__, dev->name); + dev->name); return log_ret(ret); } mdelay(120); diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c index b6551b69d3a..f307cf243bd 100644 --- a/drivers/video/video-uclass.c +++ b/drivers/video/video-uclass.c @@ -226,7 +226,9 @@ static int video_post_probe(struct udevice *dev) /* Set up the line and display size */ priv->fb = map_sysmem(plat->base, plat->size); - priv->line_length = priv->xsize * VNBYTES(priv->bpix); + if (!priv->line_length) + priv->line_length = priv->xsize * VNBYTES(priv->bpix); + priv->fb_size = priv->line_length * priv->ysize; /* Set up colors */ diff --git a/drivers/video/video_bmp.c b/drivers/video/video_bmp.c index 1377e190817..2898b0b55d7 100644 --- a/drivers/video/video_bmp.c +++ b/drivers/video/video_bmp.c @@ -7,6 +7,7 @@ #include <bmp_layout.h> #include <dm.h> #include <mapmem.h> +#include <splash.h> #include <video.h> #include <watchdog.h> #include <asm/unaligned.h> @@ -140,8 +141,6 @@ __weak void fb_put_word(uchar **fb, uchar **from) } #endif /* CONFIG_BMP_16BPP */ -#define BMP_ALIGN_CENTER 0x7fff - /** * video_splash_align_axis() - Align a single coordinate * diff --git a/drivers/w1/w1-uclass.c b/drivers/w1/w1-uclass.c index cb41b68eff1..042b3b5ce0a 100644 --- a/drivers/w1/w1-uclass.c +++ b/drivers/w1/w1-uclass.c @@ -84,10 +84,6 @@ static int w1_enumerate(struct udevice *bus) rn |= (tmp64 << i); } - /* last device or error, aborting here */ - if ((triplet_ret & 0x03) == 0x03) - last_device = true; - if ((triplet_ret & 0x03) != 0x03) { if (desc_bit == last_zero || last_zero < 0) { last_device = 1; |