diff options
Diffstat (limited to 'drivers')
93 files changed, 3056 insertions, 712 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index 5d03f37..b23076f 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -14,3 +14,4 @@ obj-y += twserial/ obj-y += video/ obj-y += watchdog/ obj-$(CONFIG_QE) += qe/ +obj-y += memory/ diff --git a/drivers/core/device.c b/drivers/core/device.c index 55ba281..c73c339 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -30,9 +30,9 @@ * @dev: The device that is to be stripped of its children * @return 0 on success, -ve on error */ -static int device_chld_unbind(struct device *dev) +static int device_chld_unbind(struct udevice *dev) { - struct device *pos, *n; + struct udevice *pos, *n; int ret, saved_ret = 0; assert(dev); @@ -51,9 +51,9 @@ static int device_chld_unbind(struct device *dev) * @dev: The device whose children are to be removed * @return 0 on success, -ve on error */ -static int device_chld_remove(struct device *dev) +static int device_chld_remove(struct udevice *dev) { - struct device *pos, *n; + struct udevice *pos, *n; int ret; assert(dev); @@ -67,10 +67,10 @@ static int device_chld_remove(struct device *dev) return 0; } -int device_bind(struct device *parent, struct driver *drv, const char *name, - void *platdata, int of_offset, struct device **devp) +int device_bind(struct udevice *parent, struct driver *drv, const char *name, + void *platdata, int of_offset, struct udevice **devp) { - struct device *dev; + struct udevice *dev; struct uclass *uc; int ret = 0; @@ -82,7 +82,7 @@ int device_bind(struct device *parent, struct driver *drv, const char *name, if (ret) return ret; - dev = calloc(1, sizeof(struct device)); + dev = calloc(1, sizeof(struct udevice)); if (!dev) return -ENOMEM; @@ -129,8 +129,8 @@ fail_bind: return ret; } -int device_bind_by_name(struct device *parent, const struct driver_info *info, - struct device **devp) +int device_bind_by_name(struct udevice *parent, const struct driver_info *info, + struct udevice **devp) { struct driver *drv; @@ -142,7 +142,7 @@ int device_bind_by_name(struct device *parent, const struct driver_info *info, -1, devp); } -int device_unbind(struct device *dev) +int device_unbind(struct udevice *dev) { struct driver *drv; int ret; @@ -181,7 +181,7 @@ int device_unbind(struct device *dev) * device_free() - Free memory buffers allocated by a device * @dev: Device that is to be started */ -static void device_free(struct device *dev) +static void device_free(struct udevice *dev) { int size; @@ -200,7 +200,7 @@ static void device_free(struct device *dev) } } -int device_probe(struct device *dev) +int device_probe(struct udevice *dev) { struct driver *drv; int size = 0; @@ -279,7 +279,7 @@ fail: return ret; } -int device_remove(struct device *dev) +int device_remove(struct udevice *dev) { struct driver *drv; int ret; @@ -327,7 +327,7 @@ err: return ret; } -void *dev_get_platdata(struct device *dev) +void *dev_get_platdata(struct udevice *dev) { if (!dev) { dm_warn("%s: null device", __func__); @@ -337,7 +337,7 @@ void *dev_get_platdata(struct device *dev) return dev->platdata; } -void *dev_get_priv(struct device *dev) +void *dev_get_priv(struct udevice *dev) { if (!dev) { dm_warn("%s: null device", __func__); diff --git a/drivers/core/lists.c b/drivers/core/lists.c index 4f2c126..afb59d1 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -14,6 +14,7 @@ #include <dm/platdata.h> #include <dm/uclass.h> #include <dm/util.h> +#include <fdtdec.h> #include <linux/compiler.h> struct driver *lists_driver_lookup_name(const char *name) @@ -60,13 +61,13 @@ struct uclass_driver *lists_uclass_lookup(enum uclass_id id) return NULL; } -int lists_bind_drivers(struct device *parent) +int lists_bind_drivers(struct udevice *parent) { struct driver_info *info = ll_entry_start(struct driver_info, driver_info); const int n_ents = ll_entry_count(struct driver_info, driver_info); struct driver_info *entry; - struct device *dev; + struct udevice *dev; int result = 0; int ret; @@ -94,7 +95,7 @@ int lists_bind_drivers(struct device *parent) * tree error */ static int driver_check_compatible(const void *blob, int offset, - const struct device_id *of_match) + const struct udevice_id *of_match) { int ret; @@ -116,12 +117,12 @@ static int driver_check_compatible(const void *blob, int offset, return -ENOENT; } -int lists_bind_fdt(struct device *parent, const void *blob, int offset) +int lists_bind_fdt(struct udevice *parent, const void *blob, int offset) { struct driver *driver = ll_entry_start(struct driver, driver); const int n_ents = ll_entry_count(struct driver, driver); struct driver *entry; - struct device *dev; + struct udevice *dev; const char *name; int result = 0; int ret; diff --git a/drivers/core/root.c b/drivers/core/root.c index 407bc0d..1cbb096 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -10,6 +10,7 @@ #include <common.h> #include <errno.h> #include <malloc.h> +#include <libfdt.h> #include <dm/device.h> #include <dm/device-internal.h> #include <dm/lists.h> @@ -24,7 +25,7 @@ static const struct driver_info root_info = { .name = "root_driver", }; -struct device *dm_root(void) +struct udevice *dm_root(void) { if (!gd->dm_root) { dm_warn("Virtual root driver does not exist!\n"); @@ -42,9 +43,9 @@ int dm_init(void) dm_warn("Virtual root driver already exists!\n"); return -EINVAL; } - INIT_LIST_HEAD(&gd->uclass_root); + INIT_LIST_HEAD(&DM_UCLASS_ROOT_NON_CONST); - ret = device_bind_by_name(NULL, &root_info, &gd->dm_root); + ret = device_bind_by_name(NULL, &root_info, &DM_ROOT_NON_CONST); if (ret) return ret; @@ -55,7 +56,7 @@ int dm_scan_platdata(void) { int ret; - ret = lists_bind_drivers(gd->dm_root); + ret = lists_bind_drivers(DM_ROOT_NON_CONST); if (ret == -ENOENT) { dm_warn("Some drivers were not found\n"); ret = 0; diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 4df5a8b..34723ec 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -75,7 +75,7 @@ static int uclass_add(enum uclass_id id, struct uclass **ucp) uc->uc_drv = uc_drv; INIT_LIST_HEAD(&uc->sibling_node); INIT_LIST_HEAD(&uc->dev_head); - list_add(&uc->sibling_node, &gd->uclass_root); + list_add(&uc->sibling_node, &DM_UCLASS_ROOT_NON_CONST); if (uc_drv->init) { ret = uc_drv->init(uc); @@ -101,7 +101,7 @@ fail_mem: int uclass_destroy(struct uclass *uc) { struct uclass_driver *uc_drv; - struct device *dev, *tmp; + struct udevice *dev, *tmp; int ret; list_for_each_entry_safe(dev, tmp, &uc->dev_head, uclass_node) { @@ -137,10 +137,10 @@ int uclass_get(enum uclass_id id, struct uclass **ucp) return 0; } -int uclass_find_device(enum uclass_id id, int index, struct device **devp) +int uclass_find_device(enum uclass_id id, int index, struct udevice **devp) { struct uclass *uc; - struct device *dev; + struct udevice *dev; int ret; *devp = NULL; @@ -158,9 +158,9 @@ int uclass_find_device(enum uclass_id id, int index, struct device **devp) return -ENODEV; } -int uclass_get_device(enum uclass_id id, int index, struct device **devp) +int uclass_get_device(enum uclass_id id, int index, struct udevice **devp) { - struct device *dev; + struct udevice *dev; int ret; *devp = NULL; @@ -177,10 +177,10 @@ int uclass_get_device(enum uclass_id id, int index, struct device **devp) return 0; } -int uclass_first_device(enum uclass_id id, struct device **devp) +int uclass_first_device(enum uclass_id id, struct udevice **devp) { struct uclass *uc; - struct device *dev; + struct udevice *dev; int ret; *devp = NULL; @@ -190,7 +190,7 @@ int uclass_first_device(enum uclass_id id, struct device **devp) if (list_empty(&uc->dev_head)) return 0; - dev = list_first_entry(&uc->dev_head, struct device, uclass_node); + dev = list_first_entry(&uc->dev_head, struct udevice, uclass_node); ret = device_probe(dev); if (ret) return ret; @@ -199,16 +199,17 @@ int uclass_first_device(enum uclass_id id, struct device **devp) return 0; } -int uclass_next_device(struct device **devp) +int uclass_next_device(struct udevice **devp) { - struct device *dev = *devp; + struct udevice *dev = *devp; int ret; *devp = NULL; if (list_is_last(&dev->uclass_node, &dev->uclass->dev_head)) return 0; - dev = list_entry(dev->uclass_node.next, struct device, uclass_node); + dev = list_entry(dev->uclass_node.next, struct udevice, + uclass_node); ret = device_probe(dev); if (ret) return ret; @@ -217,7 +218,7 @@ int uclass_next_device(struct device **devp) return 0; } -int uclass_bind_device(struct device *dev) +int uclass_bind_device(struct udevice *dev) { struct uclass *uc; int ret; @@ -237,7 +238,7 @@ int uclass_bind_device(struct device *dev) return 0; } -int uclass_unbind_device(struct device *dev) +int uclass_unbind_device(struct udevice *dev) { struct uclass *uc; int ret; @@ -253,7 +254,7 @@ int uclass_unbind_device(struct device *dev) return 0; } -int uclass_post_probe_device(struct device *dev) +int uclass_post_probe_device(struct udevice *dev) { struct uclass_driver *uc_drv = dev->uclass->uc_drv; @@ -263,7 +264,7 @@ int uclass_post_probe_device(struct device *dev) return 0; } -int uclass_pre_remove_device(struct device *dev) +int uclass_pre_remove_device(struct udevice *dev) { struct uclass_driver *uc_drv; struct uclass *uc; diff --git a/drivers/crypto/ace_sha.c b/drivers/crypto/ace_sha.c index ed4f541..efef491 100644 --- a/drivers/crypto/ace_sha.c +++ b/drivers/crypto/ace_sha.c @@ -8,8 +8,8 @@ #include "ace_sha.h" #ifdef CONFIG_SHA_HW_ACCEL -#include <sha256.h> -#include <sha1.h> +#include <u-boot/sha256.h> +#include <u-boot/sha1.h> #include <asm/errno.h> /* SHA1 value for the message of zero length */ diff --git a/drivers/ddr/fsl/ctrl_regs.c b/drivers/ddr/fsl/ctrl_regs.c index 78e82bb..dcf6287 100644 --- a/drivers/ddr/fsl/ctrl_regs.c +++ b/drivers/ddr/fsl/ctrl_regs.c @@ -2304,5 +2304,10 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts, ddr->debug[2] = 0x00000400; ddr->debug[4] = 0xff800000; #endif +#ifdef CONFIG_SYS_FSL_ERRATUM_A004508 + if ((ip_rev >= 0x40000) && (ip_rev < 0x40400)) + ddr->debug[2] |= 0x00000200; /* set bit 22 */ +#endif + return check_fsl_memctl_config_regs(ddr); } diff --git a/drivers/ddr/fsl/interactive.c b/drivers/ddr/fsl/interactive.c index cfe1e1f..7fb4187 100644 --- a/drivers/ddr/fsl/interactive.c +++ b/drivers/ddr/fsl/interactive.c @@ -12,6 +12,7 @@ */ #include <common.h> +#include <cli.h> #include <linux/ctype.h> #include <asm/types.h> #include <asm/io.h> @@ -1578,7 +1579,7 @@ void ddr4_spd_dump(const struct ddr4_spd_eeprom_s *spd) printf("%-3d-%3d: ", 128, 255); for (i = 128; i <= 255; i++) - printf("%02x", spd->mod_section.uc[i - 60]); + printf("%02x", spd->mod_section.uc[i - 128]); break; } @@ -1864,11 +1865,12 @@ unsigned long long fsl_ddr_interactive(fsl_ddr_info_t *pinfo, int var_is_set) } else { /* * No need to worry for buffer overflow here in - * this function; readline() maxes out at CFG_CBSIZE + * this function; cli_readline() maxes out at + * CFG_CBSIZE */ - readline_into_buffer(prompt, buffer, 0); + cli_readline_into_buffer(prompt, buffer, 0); } - argc = parse_line(buffer, argv); + argc = cli_simple_parse_line(buffer, argv); if (argc == 0) continue; diff --git a/drivers/demo/demo-shape.c b/drivers/demo/demo-shape.c index 2f0eb96..3fa9c59 100644 --- a/drivers/demo/demo-shape.c +++ b/drivers/demo/demo-shape.c @@ -23,7 +23,7 @@ struct shape_data { }; /* Crazy little function to draw shapes on the console */ -static int shape_hello(struct device *dev, int ch) +static int shape_hello(struct udevice *dev, int ch) { const struct dm_demo_pdata *pdata = dev_get_platdata(dev); struct shape_data *data = dev_get_priv(dev); @@ -81,7 +81,7 @@ static int shape_hello(struct device *dev, int ch) return 0; } -static int shape_status(struct device *dev, int *status) +static int shape_status(struct udevice *dev, int *status) { struct shape_data *data = dev_get_priv(dev); @@ -94,7 +94,7 @@ static const struct demo_ops shape_ops = { .status = shape_status, }; -static int shape_ofdata_to_platdata(struct device *dev) +static int shape_ofdata_to_platdata(struct udevice *dev) { struct dm_demo_pdata *pdata = dev_get_platdata(dev); int ret; @@ -111,7 +111,7 @@ static int shape_ofdata_to_platdata(struct device *dev) return 0; } -static const struct device_id demo_shape_id[] = { +static const struct udevice_id demo_shape_id[] = { { "demo-shape", 0 }, { }, }; diff --git a/drivers/demo/demo-simple.c b/drivers/demo/demo-simple.c index 6ba8131..2bcb7df 100644 --- a/drivers/demo/demo-simple.c +++ b/drivers/demo/demo-simple.c @@ -12,7 +12,7 @@ #include <dm-demo.h> #include <asm/io.h> -static int simple_hello(struct device *dev, int ch) +static int simple_hello(struct udevice *dev, int ch) { const struct dm_demo_pdata *pdata = dev_get_platdata(dev); @@ -26,13 +26,13 @@ static const struct demo_ops simple_ops = { .hello = simple_hello, }; -static int demo_shape_ofdata_to_platdata(struct device *dev) +static int demo_shape_ofdata_to_platdata(struct udevice *dev) { /* Parse the data that is common with all demo devices */ return demo_parse_dt(dev); } -static const struct device_id demo_shape_id[] = { +static const struct udevice_id demo_shape_id[] = { { "demo-simple", 0 }, { }, }; diff --git a/drivers/demo/demo-uclass.c b/drivers/demo/demo-uclass.c index 48588be..636fd88 100644 --- a/drivers/demo/demo-uclass.c +++ b/drivers/demo/demo-uclass.c @@ -22,7 +22,7 @@ UCLASS_DRIVER(demo) = { .id = UCLASS_DEMO, }; -int demo_hello(struct device *dev, int ch) +int demo_hello(struct udevice *dev, int ch) { const struct demo_ops *ops = device_get_ops(dev); @@ -32,7 +32,7 @@ int demo_hello(struct device *dev, int ch) return ops->hello(dev, ch); } -int demo_status(struct device *dev, int *status) +int demo_status(struct udevice *dev, int *status) { const struct demo_ops *ops = device_get_ops(dev); @@ -42,7 +42,7 @@ int demo_status(struct device *dev, int *status) return ops->status(dev, status); } -int demo_parse_dt(struct device *dev) +int demo_parse_dt(struct udevice *dev) { struct dm_demo_pdata *pdata = dev_get_platdata(dev); int dn = dev->of_offset; diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c index a938109..dc09ff6 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -13,6 +13,7 @@ #include <mmc.h> #include <fat.h> #include <dfu.h> +#include <hash.h> #include <linux/list.h> #include <linux/compiler.h> @@ -20,6 +21,7 @@ static bool dfu_reset_request; static LIST_HEAD(dfu_list); static int dfu_alt_num; static int alt_num_cnt; +static struct hash_algo *dfu_hash_algo; bool dfu_reset(void) { @@ -99,6 +101,23 @@ unsigned char *dfu_get_buf(void) return dfu_buf; } +static char *dfu_get_hash_algo(void) +{ + char *s; + + s = getenv("dfu_hash_algo"); + if (!s) + return NULL; + + if (!strcmp(s, "crc32")) { + debug("%s: DFU hash method: %s\n", __func__, s); + return s; + } + + error("DFU hash method: %s not supported!\n", s); + return NULL; +} + static int dfu_write_buffer_drain(struct dfu_entity *dfu) { long w_size; @@ -109,8 +128,9 @@ static int dfu_write_buffer_drain(struct dfu_entity *dfu) if (w_size == 0) return 0; - /* update CRC32 */ - dfu->crc = crc32(dfu->crc, dfu->i_buf_start, w_size); + if (dfu_hash_algo) + dfu_hash_algo->hash_update(dfu_hash_algo, &dfu->crc, + dfu->i_buf_start, w_size, 0); ret = dfu->write_medium(dfu, dfu->offset, dfu->i_buf_start, &w_size); if (ret) @@ -138,7 +158,9 @@ int dfu_flush(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) if (dfu->flush_medium) ret = dfu->flush_medium(dfu); - printf("\nDFU complete CRC32: 0x%08x\n", dfu->crc); + if (dfu_hash_algo) + printf("\nDFU complete %s: 0x%08x\n", dfu_hash_algo->name, + dfu->crc); /* clear everything */ dfu_free_buf(); @@ -238,7 +260,11 @@ static int dfu_read_buffer_fill(struct dfu_entity *dfu, void *buf, int size) /* consume */ if (chunk > 0) { memcpy(buf, dfu->i_buf, chunk); - dfu->crc = crc32(dfu->crc, buf, chunk); + if (dfu_hash_algo) + dfu_hash_algo->hash_update(dfu_hash_algo, + &dfu->crc, buf, + chunk, 0); + dfu->i_buf += chunk; dfu->b_left -= chunk; dfu->r_left -= chunk; @@ -322,7 +348,9 @@ int dfu_read(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) } if (ret < size) { - debug("%s: %s CRC32: 0x%x\n", __func__, dfu->name, dfu->crc); + if (dfu_hash_algo) + debug("%s: %s %s: 0x%x\n", __func__, dfu->name, + dfu_hash_algo->name, dfu->crc); puts("\nUPLOAD ... done\nCtrl+C to exit ...\n"); dfu_free_buf(); @@ -397,6 +425,14 @@ int dfu_config_entities(char *env, char *interface, int num) dfu_alt_num = dfu_find_alt_num(env); debug("%s: dfu_alt_num=%d\n", __func__, dfu_alt_num); + dfu_hash_algo = NULL; + s = dfu_get_hash_algo(); + if (s) { + ret = hash_lookup_algo(s, &dfu_hash_algo); + if (ret) + error("Hash algorithm %s not supported\n", s); + } + dfu = calloc(sizeof(*dfu), dfu_alt_num); if (!dfu) return -1; diff --git a/drivers/fpga/altera.c b/drivers/fpga/altera.c index af189f4..6e34a8e 100644 --- a/drivers/fpga/altera.c +++ b/drivers/fpga/altera.c @@ -153,9 +153,9 @@ int altera_info( Altera_desc *desc ) printf ("Unsupported interface type, %d\n", desc->iface); } - printf ("Device Size: \t%d bytes\n" - "Cookie: \t0x%x (%d)\n", - desc->size, desc->cookie, desc->cookie); + printf("Device Size: \t%zd bytes\n" + "Cookie: \t0x%x (%d)\n", + desc->size, desc->cookie, desc->cookie); if (desc->iface_fns) { printf ("Device Function Table @ 0x%p\n", desc->iface_fns); diff --git a/drivers/fpga/xilinx.c b/drivers/fpga/xilinx.c index 3795c1a..adb4b8c 100644 --- a/drivers/fpga/xilinx.c +++ b/drivers/fpga/xilinx.c @@ -220,9 +220,9 @@ int xilinx_info(xilinx_desc *desc) printf ("Unsupported interface type, %d\n", desc->iface); } - printf ("Device Size: \t%d bytes\n" - "Cookie: \t0x%x (%d)\n", - desc->size, desc->cookie, desc->cookie); + printf("Device Size: \t%zd bytes\n" + "Cookie: \t0x%x (%d)\n", + desc->size, desc->cookie, desc->cookie); if (desc->name) printf("Device name: \t%s\n", desc->name); diff --git a/drivers/gpio/at91_gpio.c b/drivers/gpio/at91_gpio.c index 0b70071..6517af1 100644 --- a/drivers/gpio/at91_gpio.c +++ b/drivers/gpio/at91_gpio.c @@ -34,6 +34,7 @@ static struct at91_port *at91_pio_get_port(unsigned port) #endif #endif default: + printf("Error: at91_gpio: Fail to get PIO base!\n"); return NULL; } } @@ -200,7 +201,7 @@ int at91_set_pio_output(unsigned port, u32 pin, int value) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if ((port < ATMEL_PIO_PORTS) && (pin < 32)) { + if (at91_port && (port < ATMEL_PIO_PORTS) && (pin < 32)) { mask = 1 << pin; writel(mask, &at91_port->idr); writel(mask, &at91_port->pudr); diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index 56bfd11..f1bbc58 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -17,11 +17,11 @@ * or GPIO blocks registered with the GPIO controller. Returns * entry on success, NULL on error. */ -static int gpio_to_device(unsigned int gpio, struct device **devp, +static int gpio_to_device(unsigned int gpio, struct udevice **devp, unsigned int *offset) { struct gpio_dev_priv *uc_priv; - struct device *dev; + struct udevice *dev; int ret; for (ret = uclass_first_device(UCLASS_GPIO, &dev); @@ -40,11 +40,11 @@ static int gpio_to_device(unsigned int gpio, struct device **devp, return ret ? ret : -EINVAL; } -int gpio_lookup_name(const char *name, struct device **devp, +int gpio_lookup_name(const char *name, struct udevice **devp, unsigned int *offsetp, unsigned int *gpiop) { struct gpio_dev_priv *uc_priv; - struct device *dev; + struct udevice *dev; int ret; if (devp) @@ -58,7 +58,7 @@ int gpio_lookup_name(const char *name, struct device **devp, uc_priv = dev->uclass_priv; len = uc_priv->bank_name ? strlen(uc_priv->bank_name) : 0; - if (!strncmp(name, uc_priv->bank_name, len)) { + if (!strncasecmp(name, uc_priv->bank_name, len)) { if (strict_strtoul(name + len, 10, &offset)) continue; if (devp) @@ -86,7 +86,7 @@ int gpio_lookup_name(const char *name, struct device **devp, int gpio_request(unsigned gpio, const char *label) { unsigned int offset; - struct device *dev; + struct udevice *dev; int ret; ret = gpio_to_device(gpio, &dev, &offset); @@ -110,7 +110,7 @@ int gpio_request(unsigned gpio, const char *label) int gpio_free(unsigned gpio) { unsigned int offset; - struct device *dev; + struct udevice *dev; int ret; ret = gpio_to_device(gpio, &dev, &offset); @@ -133,7 +133,7 @@ int gpio_free(unsigned gpio) int gpio_direction_input(unsigned gpio) { unsigned int offset; - struct device *dev; + struct udevice *dev; int ret; ret = gpio_to_device(gpio, &dev, &offset); @@ -155,7 +155,7 @@ int gpio_direction_input(unsigned gpio) int gpio_direction_output(unsigned gpio, int value) { unsigned int offset; - struct device *dev; + struct udevice *dev; int ret; ret = gpio_to_device(gpio, &dev, &offset); @@ -177,7 +177,7 @@ int gpio_direction_output(unsigned gpio, int value) int gpio_get_value(unsigned gpio) { unsigned int offset; - struct device *dev; + struct udevice *dev; int ret; ret = gpio_to_device(gpio, &dev, &offset); @@ -199,7 +199,7 @@ int gpio_get_value(unsigned gpio) int gpio_set_value(unsigned gpio, int value) { unsigned int offset; - struct device *dev; + struct udevice *dev; int ret; ret = gpio_to_device(gpio, &dev, &offset); @@ -209,7 +209,7 @@ int gpio_set_value(unsigned gpio, int value) return gpio_get_ops(dev)->set_value(dev, offset, value); } -const char *gpio_get_bank_info(struct device *dev, int *bit_count) +const char *gpio_get_bank_info(struct udevice *dev, int *bit_count) { struct gpio_dev_priv *priv; @@ -225,7 +225,7 @@ const char *gpio_get_bank_info(struct device *dev, int *bit_count) static int gpio_renumber(void) { struct gpio_dev_priv *uc_priv; - struct device *dev; + struct udevice *dev; struct uclass *uc; unsigned base; int ret; @@ -247,12 +247,12 @@ static int gpio_renumber(void) return 0; } -static int gpio_post_probe(struct device *dev) +static int gpio_post_probe(struct udevice *dev) { return gpio_renumber(); } -static int gpio_pre_remove(struct device *dev) +static int gpio_pre_remove(struct udevice *dev) { return gpio_renumber(); } diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c index 22b6a5f..75ada5d 100644 --- a/drivers/gpio/sandbox.c +++ b/drivers/gpio/sandbox.c @@ -22,7 +22,7 @@ struct gpio_state { }; /* Access routines for GPIO state */ -static u8 *get_gpio_flags(struct device *dev, unsigned offset) +static u8 *get_gpio_flags(struct udevice *dev, unsigned offset) { struct gpio_dev_priv *uc_priv = dev->uclass_priv; struct gpio_state *state = dev_get_priv(dev); @@ -36,12 +36,12 @@ static u8 *get_gpio_flags(struct device *dev, unsigned offset) return &state[offset].flags; } -static int get_gpio_flag(struct device *dev, unsigned offset, int flag) +static int get_gpio_flag(struct udevice *dev, unsigned offset, int flag) { return (*get_gpio_flags(dev, offset) & flag) != 0; } -static int set_gpio_flag(struct device *dev, unsigned offset, int flag, +static int set_gpio_flag(struct udevice *dev, unsigned offset, int flag, int value) { u8 *gpio = get_gpio_flags(dev, offset); @@ -54,7 +54,7 @@ static int set_gpio_flag(struct device *dev, unsigned offset, int flag, return 0; } -static int check_reserved(struct device *dev, unsigned offset, +static int check_reserved(struct udevice *dev, unsigned offset, const char *func) { if (!get_gpio_flag(dev, offset, GPIOF_RESERVED)) { @@ -70,24 +70,24 @@ static int check_reserved(struct device *dev, unsigned offset, * Back-channel sandbox-internal-only access to GPIO state */ -int sandbox_gpio_get_value(struct device *dev, unsigned offset) +int sandbox_gpio_get_value(struct udevice *dev, unsigned offset) { if (get_gpio_flag(dev, offset, GPIOF_OUTPUT)) debug("sandbox_gpio: get_value on output gpio %u\n", offset); return get_gpio_flag(dev, offset, GPIOF_HIGH); } -int sandbox_gpio_set_value(struct device *dev, unsigned offset, int value) +int sandbox_gpio_set_value(struct udevice *dev, unsigned offset, int value) { return set_gpio_flag(dev, offset, GPIOF_HIGH, value); } -int sandbox_gpio_get_direction(struct device *dev, unsigned offset) +int sandbox_gpio_get_direction(struct udevice *dev, unsigned offset) { return get_gpio_flag(dev, offset, GPIOF_OUTPUT); } -int sandbox_gpio_set_direction(struct device *dev, unsigned offset, int output) +int sandbox_gpio_set_direction(struct udevice *dev, unsigned offset, int output) { return set_gpio_flag(dev, offset, GPIOF_OUTPUT, output); } @@ -97,7 +97,7 @@ int sandbox_gpio_set_direction(struct device *dev, unsigned offset, int output) */ /* set GPIO port 'offset' as an input */ -static int sb_gpio_direction_input(struct device *dev, unsigned offset) +static int sb_gpio_direction_input(struct udevice *dev, unsigned offset) { debug("%s: offset:%u\n", __func__, offset); @@ -108,7 +108,7 @@ static int sb_gpio_direction_input(struct device *dev, unsigned offset) } /* set GPIO port 'offset' as an output, with polarity 'value' */ -static int sb_gpio_direction_output(struct device *dev, unsigned offset, +static int sb_gpio_direction_output(struct udevice *dev, unsigned offset, int value) { debug("%s: offset:%u, value = %d\n", __func__, offset, value); @@ -121,7 +121,7 @@ static int sb_gpio_direction_output(struct device *dev, unsigned offset, } /* read GPIO IN value of port 'offset' */ -static int sb_gpio_get_value(struct device *dev, unsigned offset) +static int sb_gpio_get_value(struct udevice *dev, unsigned offset) { debug("%s: offset:%u\n", __func__, offset); @@ -132,7 +132,7 @@ static int sb_gpio_get_value(struct device *dev, unsigned offset) } /* write GPIO OUT value to port 'offset' */ -static int sb_gpio_set_value(struct device *dev, unsigned offset, int value) +static int sb_gpio_set_value(struct udevice *dev, unsigned offset, int value) { debug("%s: offset:%u, value = %d\n", __func__, offset, value); @@ -148,7 +148,7 @@ static int sb_gpio_set_value(struct device *dev, unsigned offset, int value) return sandbox_gpio_set_value(dev, offset, value); } -static int sb_gpio_request(struct device *dev, unsigned offset, +static int sb_gpio_request(struct udevice *dev, unsigned offset, const char *label) { struct gpio_dev_priv *uc_priv = dev->uclass_priv; @@ -171,7 +171,7 @@ static int sb_gpio_request(struct device *dev, unsigned offset, return set_gpio_flag(dev, offset, GPIOF_RESERVED, 1); } -static int sb_gpio_free(struct device *dev, unsigned offset) +static int sb_gpio_free(struct udevice *dev, unsigned offset) { struct gpio_state *state = dev_get_priv(dev); @@ -184,7 +184,7 @@ static int sb_gpio_free(struct device *dev, unsigned offset) return set_gpio_flag(dev, offset, GPIOF_RESERVED, 0); } -static int sb_gpio_get_state(struct device *dev, unsigned int offset, +static int sb_gpio_get_state(struct udevice *dev, unsigned int offset, char *buf, int bufsize) { struct gpio_dev_priv *uc_priv = dev->uclass_priv; @@ -213,7 +213,7 @@ static const struct dm_gpio_ops gpio_sandbox_ops = { .get_state = sb_gpio_get_state, }; -static int sandbox_gpio_ofdata_to_platdata(struct device *dev) +static int sandbox_gpio_ofdata_to_platdata(struct udevice *dev) { struct gpio_dev_priv *uc_priv = dev->uclass_priv; @@ -225,7 +225,7 @@ static int sandbox_gpio_ofdata_to_platdata(struct device *dev) return 0; } -static int gpio_sandbox_probe(struct device *dev) +static int gpio_sandbox_probe(struct udevice *dev) { struct gpio_dev_priv *uc_priv = dev->uclass_priv; @@ -239,7 +239,7 @@ static int gpio_sandbox_probe(struct device *dev) return 0; } -static const struct device_id sandbox_gpio_ids[] = { +static const struct udevice_id sandbox_gpio_ids[] = { { .compatible = "sandbox,gpio" }, { } }; diff --git a/drivers/gpio/spear_gpio.c b/drivers/gpio/spear_gpio.c index 367b670..6fb4117 100644 --- a/drivers/gpio/spear_gpio.c +++ b/drivers/gpio/spear_gpio.c @@ -36,7 +36,10 @@ int gpio_set_value(unsigned gpio, int value) { struct gpio_regs *regs = (struct gpio_regs *)CONFIG_GPIO_BASE; - writel(1 << gpio, ®s->gpiodata[DATA_REG_ADDR(gpio)]); + if (value) + writel(1 << gpio, ®s->gpiodata[DATA_REG_ADDR(gpio)]); + else + writel(0, ®s->gpiodata[DATA_REG_ADDR(gpio)]); return 0; } diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index e33586d..96bd45d 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_SYS_I2C) += i2c_core.o obj-$(CONFIG_SYS_I2C_DAVINCI) += davinci_i2c.o obj-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o obj-$(CONFIG_SYS_I2C_FTI2C010) += fti2c010.o +obj-$(CONFIG_SYS_I2C_IHS) += ihs_i2c.o obj-$(CONFIG_SYS_I2C_KONA) += kona_i2c.o obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o obj-$(CONFIG_SYS_I2C_OMAP24XX) += omap24xx_i2c.o diff --git a/drivers/i2c/ihs_i2c.c b/drivers/i2c/ihs_i2c.c new file mode 100644 index 0000000..fe66ce2 --- /dev/null +++ b/drivers/i2c/ihs_i2c.c @@ -0,0 +1,203 @@ +/* + * (C) Copyright 2013 + * Dirk Eibach, Guntermann & Drunck GmbH, eibach@gdsys.de + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <i2c.h> +#include <gdsys_fpga.h> + +DECLARE_GLOBAL_DATA_PTR; + +enum { + I2CINT_ERROR_EV = 1 << 13, + I2CINT_TRANSMIT_EV = 1 << 14, + I2CINT_RECEIVE_EV = 1 << 15, +}; + +enum { + I2CMB_WRITE = 1 << 10, + I2CMB_2BYTE = 1 << 11, + I2CMB_HOLD_BUS = 1 << 13, + I2CMB_NATIVE = 2 << 14, +}; + +static int wait_for_int(bool read) +{ + u16 val; + unsigned int ctr = 0; + + FPGA_GET_REG(I2C_ADAP_HWNR, i2c.interrupt_status, &val); + while (!(val & (I2CINT_ERROR_EV + | (read ? I2CINT_RECEIVE_EV : I2CINT_TRANSMIT_EV)))) { + udelay(10); + if (ctr++ > 5000) { + return 1; + } + FPGA_GET_REG(I2C_ADAP_HWNR, i2c.interrupt_status, &val); + } + + return (val & I2CINT_ERROR_EV) ? 1 : 0; +} + +static int ihs_i2c_transfer(uchar chip, uchar *buffer, int len, bool read, + bool is_last) +{ + u16 val; + + FPGA_SET_REG(I2C_ADAP_HWNR, i2c.interrupt_status, I2CINT_ERROR_EV + | I2CINT_RECEIVE_EV | I2CINT_TRANSMIT_EV); + FPGA_GET_REG(I2C_ADAP_HWNR, i2c.interrupt_status, &val); + + if (!read && len) { + val = buffer[0]; + + if (len > 1) + val |= buffer[1] << 8; + FPGA_SET_REG(I2C_ADAP_HWNR, i2c.write_mailbox_ext, val); + } + + FPGA_SET_REG(I2C_ADAP_HWNR, i2c.write_mailbox, + I2CMB_NATIVE + | (read ? 0 : I2CMB_WRITE) + | (chip << 1) + | ((len > 1) ? I2CMB_2BYTE : 0) + | (is_last ? 0 : I2CMB_HOLD_BUS)); + + if (wait_for_int(read)) + return 1; + + if (read) { + FPGA_GET_REG(I2C_ADAP_HWNR, i2c.read_mailbox_ext, &val); + buffer[0] = val & 0xff; + if (len > 1) + buffer[1] = val >> 8; + } + + return 0; +} + +static int ihs_i2c_address(uchar chip, uint addr, int alen, bool hold_bus) +{ + int shift = (alen-1) * 8; + + while (alen) { + int transfer = MIN(alen, 2); + uchar buf[2]; + bool is_last = alen <= transfer; + + buf[0] = addr >> shift; + if (alen > 1) + buf[1] = addr >> (shift - 8); + + if (ihs_i2c_transfer(chip, buf, transfer, false, + hold_bus ? false : is_last)) + return 1; + + shift -= 16; + alen -= transfer; + } + + return 0; +} + +static int ihs_i2c_access(struct i2c_adapter *adap, uchar chip, uint addr, + int alen, uchar *buffer, int len, bool read) +{ + if (len <= 0) + return 1; + + if (ihs_i2c_address(chip, addr, alen, !read)) + return 1; + + while (len) { + int transfer = MIN(len, 2); + + if (ihs_i2c_transfer(chip, buffer, transfer, read, + len <= transfer)) + return 1; + + buffer += transfer; + addr += transfer; + len -= transfer; + } + + return 0; +} + + +static void ihs_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr) +{ +#ifdef CONFIG_SYS_I2C_INIT_BOARD + /* + * Call board specific i2c bus reset routine before accessing the + * environment, which might be in a chip on that bus. For details + * about this problem see doc/I2C_Edge_Conditions. + */ + i2c_init_board(); +#endif +} + +static int ihs_i2c_probe(struct i2c_adapter *adap, uchar chip) +{ + uchar buffer[2]; + + if (ihs_i2c_transfer(chip, buffer, 0, true, true)) + return 1; + + return 0; +} + +static int ihs_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr, + int alen, uchar *buffer, int len) +{ + return ihs_i2c_access(adap, chip, addr, alen, buffer, len, true); +} + +static int ihs_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr, + int alen, uchar *buffer, int len) +{ + return ihs_i2c_access(adap, chip, addr, alen, buffer, len, false); +} + +static unsigned int ihs_i2c_set_bus_speed(struct i2c_adapter *adap, + unsigned int speed) +{ + if (speed != adap->speed) + return 1; + return speed; +} + +/* + * Register IHS i2c adapters + */ +#ifdef CONFIG_SYS_I2C_IHS_CH0 +U_BOOT_I2C_ADAP_COMPLETE(ihs0, ihs_i2c_init, ihs_i2c_probe, + ihs_i2c_read, ihs_i2c_write, + ihs_i2c_set_bus_speed, + CONFIG_SYS_I2C_IHS_SPEED_0, + CONFIG_SYS_I2C_IHS_SLAVE_0, 0) +#endif +#ifdef CONFIG_SYS_I2C_IHS_CH1 +U_BOOT_I2C_ADAP_COMPLETE(ihs1, ihs_i2c_init, ihs_i2c_probe, + ihs_i2c_read, ihs_i2c_write, + ihs_i2c_set_bus_speed, + CONFIG_SYS_I2C_IHS_SPEED_1, + CONFIG_SYS_I2C_IHS_SLAVE_1, 1) +#endif +#ifdef CONFIG_SYS_I2C_IHS_CH2 +U_BOOT_I2C_ADAP_COMPLETE(ihs2, ihs_i2c_init, ihs_i2c_probe, + ihs_i2c_read, ihs_i2c_write, + ihs_i2c_set_bus_speed, + CONFIG_SYS_I2C_IHS_SPEED_2, + CONFIG_SYS_I2C_IHS_SLAVE_2, 2) +#endif +#ifdef CONFIG_SYS_I2C_IHS_CH3 +U_BOOT_I2C_ADAP_COMPLETE(ihs3, ihs_i2c_init, ihs_i2c_probe, + ihs_i2c_read, ihs_i2c_write, + ihs_i2c_set_bus_speed, + CONFIG_SYS_I2C_IHS_SPEED_3, + CONFIG_SYS_I2C_IHS_SLAVE_3, 3) +#endif diff --git a/drivers/i2c/kona_i2c.c b/drivers/i2c/kona_i2c.c index 0b1715a..5eab338 100644 --- a/drivers/i2c/kona_i2c.c +++ b/drivers/i2c/kona_i2c.c @@ -663,7 +663,7 @@ static int kona_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr, static int kona_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr, int alen, uchar *buffer, int len) { - struct i2c_msg msg[0]; + struct i2c_msg msg[1]; unsigned char msgbuf0[64]; unsigned int i; struct bcm_kona_i2c_dev *dev = kona_get_dev(adap); diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 48468d7..c14797c 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -429,6 +429,11 @@ static void * const i2c_bases[] = { (void *)I2C3_BASE_ADDR #elif defined(CONFIG_VF610) (void *)I2C0_BASE_ADDR +#elif defined(CONFIG_FSL_LSCH3) + (void *)I2C1_BASE_ADDR, + (void *)I2C2_BASE_ADDR, + (void *)I2C3_BASE_ADDR, + (void *)I2C4_BASE_ADDR #else #error "architecture not supported" #endif diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c index 594e5dd..257b72f 100644 --- a/drivers/i2c/tegra_i2c.c +++ b/drivers/i2c/tegra_i2c.c @@ -110,7 +110,8 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus) static void send_packet_headers( struct i2c_bus *i2c_bus, struct i2c_trans_info *trans, - u32 packet_id) + u32 packet_id, + bool end_with_repeated_start) { u32 data; @@ -132,6 +133,8 @@ static void send_packet_headers( /* Enable Read if it is not a write transaction */ if (!(trans->flags & I2C_IS_WRITE)) data |= PKT_HDR3_READ_MODE_MASK; + if (end_with_repeated_start) + data |= PKT_HDR3_REPEAT_START_MASK; /* Write I2C specific header */ writel(data, &i2c_bus->control->tx_fifo); @@ -209,7 +212,8 @@ static int send_recv_packets(struct i2c_bus *i2c_bus, int_status = readl(&control->int_status); writel(int_status, &control->int_status); - send_packet_headers(i2c_bus, trans, 1); + send_packet_headers(i2c_bus, trans, 1, + trans->flags & I2C_USE_REPEATED_START); words = DIV_ROUND_UP(trans->num_bytes, 4); last_bytes = trans->num_bytes & 3; @@ -220,14 +224,16 @@ static int send_recv_packets(struct i2c_bus *i2c_bus, if (is_write) { /* deal with word alignment */ - if ((unsigned)dptr & 3) { + if ((words == 1) && last_bytes) { + local = 0; + memcpy(&local, dptr, last_bytes); + } else if ((unsigned)dptr & 3) { memcpy(&local, dptr, sizeof(u32)); - writel(local, &control->tx_fifo); - debug("pkt data sent (0x%x)\n", local); } else { - writel(*wptr, &control->tx_fifo); - debug("pkt data sent (0x%x)\n", *wptr); + local = *wptr; } + writel(local, &control->tx_fifo); + debug("pkt data sent (0x%x)\n", local); if (!wait_for_tx_fifo_empty(control)) { error = -1; goto exit; @@ -267,7 +273,7 @@ exit: } static int tegra_i2c_write_data(struct i2c_bus *bus, u32 addr, u8 *data, - u32 len) + u32 len, bool end_with_repeated_start) { int error; struct i2c_trans_info trans_info; @@ -275,6 +281,8 @@ static int tegra_i2c_write_data(struct i2c_bus *bus, u32 addr, u8 *data, trans_info.address = addr; trans_info.buf = data; trans_info.flags = I2C_IS_WRITE; + if (end_with_repeated_start) + trans_info.flags |= I2C_USE_REPEATED_START; trans_info.num_bytes = len; trans_info.is_10bit_address = 0; @@ -463,7 +471,8 @@ static void tegra_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr) } /* i2c write version without the register address */ -int i2c_write_data(struct i2c_bus *bus, uchar chip, uchar *buffer, int len) +int i2c_write_data(struct i2c_bus *bus, uchar chip, uchar *buffer, int len, + bool end_with_repeated_start) { int rc; @@ -475,7 +484,8 @@ int i2c_write_data(struct i2c_bus *bus, uchar chip, uchar *buffer, int len) debug("\n"); /* Shift 7-bit address over for lower-level i2c functions */ - rc = tegra_i2c_write_data(bus, chip << 1, buffer, len); + rc = tegra_i2c_write_data(bus, chip << 1, buffer, len, + end_with_repeated_start); if (rc) debug("i2c_write_data(): rc=%d\n", rc); @@ -516,7 +526,7 @@ static int tegra_i2c_probe(struct i2c_adapter *adap, uchar chip) if (!bus) return 1; reg = 0; - rc = i2c_write_data(bus, chip, ®, 1); + rc = i2c_write_data(bus, chip, ®, 1, false); if (rc) { debug("Error probing 0x%x.\n", chip); return 1; @@ -538,8 +548,8 @@ static int tegra_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr, uint offset; int i; - debug("i2c_read: chip=0x%x, addr=0x%x, len=0x%x\n", - chip, addr, len); + debug("i2c_read: chip=0x%x, addr=0x%x, alen=0x%x len=0x%x\n", + chip, addr, alen, len); bus = tegra_i2c_get_bus(adap); if (!bus) return 1; @@ -554,7 +564,7 @@ static int tegra_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr, data[alen - i - 1] = (addr + offset) >> (8 * i); } - if (i2c_write_data(bus, chip, data, alen)) { + if (i2c_write_data(bus, chip, data, alen, true)) { debug("i2c_read: error sending (0x%x)\n", addr); return 1; @@ -577,8 +587,8 @@ static int tegra_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr, uint offset; int i; - debug("i2c_write: chip=0x%x, addr=0x%x, len=0x%x\n", - chip, addr, len); + debug("i2c_write: chip=0x%x, addr=0x%x, alen=0x%x len=0x%x\n", + chip, addr, alen, len); bus = tegra_i2c_get_bus(adap); if (!bus) return 1; @@ -591,7 +601,7 @@ static int tegra_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr, for (i = 0; i < alen; i++) data[alen - i - 1] = (addr + offset) >> (8 * i); data[alen] = buffer[offset]; - if (i2c_write_data(bus, chip, data, alen + 1)) { + if (i2c_write_data(bus, chip, data, alen + 1, false)) { debug("i2c_write: error sending (0x%x)\n", addr); return 1; } diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile new file mode 100644 index 0000000..9bfb9c7 --- /dev/null +++ b/drivers/memory/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_TI_AEMIF) += ti-aemif.o diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c new file mode 100644 index 0000000..f821dae --- /dev/null +++ b/drivers/memory/ti-aemif.c @@ -0,0 +1,80 @@ +/* + * Keystone2: Asynchronous EMIF Configuration + * + * (C) Copyright 2012-2014 + * Texas Instruments Incorporated, <www.ti.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/ti-common/ti-aemif.h> + +#define AEMIF_WAITCYCLE_CONFIG (CONFIG_AEMIF_CNTRL_BASE + 0x4) +#define AEMIF_NAND_CONTROL (CONFIG_AEMIF_CNTRL_BASE + 0x60) +#define AEMIF_ONENAND_CONTROL (CONFIG_AEMIF_CNTRL_BASE + 0x5c) +#define AEMIF_CONFIG(cs) (CONFIG_AEMIF_CNTRL_BASE + 0x10 \ + + (cs * 4)) + +#define AEMIF_CFG_SELECT_STROBE(v) ((v) ? 1 << 31 : 0) +#define AEMIF_CFG_EXTEND_WAIT(v) ((v) ? 1 << 30 : 0) +#define AEMIF_CFG_WR_SETUP(v) (((v) & 0x0f) << 26) +#define AEMIF_CFG_WR_STROBE(v) (((v) & 0x3f) << 20) +#define AEMIF_CFG_WR_HOLD(v) (((v) & 0x07) << 17) +#define AEMIF_CFG_RD_SETUP(v) (((v) & 0x0f) << 13) +#define AEMIF_CFG_RD_STROBE(v) (((v) & 0x3f) << 7) +#define AEMIF_CFG_RD_HOLD(v) (((v) & 0x07) << 4) +#define AEMIF_CFG_TURN_AROUND(v) (((v) & 0x03) << 2) +#define AEMIF_CFG_WIDTH(v) (((v) & 0x03) << 0) + +#define set_config_field(reg, field, val) \ + do { \ + if (val != -1) { \ + reg &= ~AEMIF_CFG_##field(0xffffffff); \ + reg |= AEMIF_CFG_##field(val); \ + } \ + } while (0) + +static void aemif_configure(int cs, struct aemif_config *cfg) +{ + unsigned long tmp; + + if (cfg->mode == AEMIF_MODE_NAND) { + tmp = __raw_readl(AEMIF_NAND_CONTROL); + tmp |= (1 << cs); + __raw_writel(tmp, AEMIF_NAND_CONTROL); + + } else if (cfg->mode == AEMIF_MODE_ONENAND) { + tmp = __raw_readl(AEMIF_ONENAND_CONTROL); + tmp |= (1 << cs); + __raw_writel(tmp, AEMIF_ONENAND_CONTROL); + } + + tmp = __raw_readl(AEMIF_CONFIG(cs)); + + set_config_field(tmp, SELECT_STROBE, cfg->select_strobe); + set_config_field(tmp, EXTEND_WAIT, cfg->extend_wait); + set_config_field(tmp, WR_SETUP, cfg->wr_setup); + set_config_field(tmp, WR_STROBE, cfg->wr_strobe); + set_config_field(tmp, WR_HOLD, cfg->wr_hold); + set_config_field(tmp, RD_SETUP, cfg->rd_setup); + set_config_field(tmp, RD_STROBE, cfg->rd_strobe); + set_config_field(tmp, RD_HOLD, cfg->rd_hold); + set_config_field(tmp, TURN_AROUND, cfg->turn_around); + set_config_field(tmp, WIDTH, cfg->width); + + __raw_writel(tmp, AEMIF_CONFIG(cs)); +} + +void aemif_init(int num_cs, struct aemif_config *config) +{ + int cs; + + if (num_cs > AEMIF_NUM_CS) { + num_cs = AEMIF_NUM_CS; + printf("AEMIF: csnum has to be <= 5"); + } + + for (cs = 0; cs < num_cs; cs++) + aemif_configure(cs, config + cs); +} diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c index 4bb1d60..8a04af5 100644 --- a/drivers/misc/cros_ec_sandbox.c +++ b/drivers/misc/cros_ec_sandbox.c @@ -13,7 +13,7 @@ #include <hash.h> #include <malloc.h> #include <os.h> -#include <sha256.h> +#include <u-boot/sha256.h> #include <spi.h> #include <asm/state.h> #include <asm/sdl.h> diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index eb4e2be..5bf36a0 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -284,8 +284,8 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) static void dwmci_set_ios(struct mmc *mmc) { - struct dwmci_host *host = mmc->priv; - u32 ctype; + struct dwmci_host *host = (struct dwmci_host *)mmc->priv; + u32 ctype, regs; debug("Buswidth = %d, clock: %d\n",mmc->bus_width, mmc->clock); @@ -304,6 +304,14 @@ static void dwmci_set_ios(struct mmc *mmc) dwmci_writel(host, DWMCI_CTYPE, ctype); + regs = dwmci_readl(host, DWMCI_UHS_REG); + if (mmc->card_caps & MMC_MODE_DDR_52MHz) + regs |= DWMCI_DDR_MODE; + else + regs &= DWMCI_DDR_MODE; + + dwmci_writel(host, DWMCI_UHS_REG, regs); + if (host->clksel) host->clksel(host); } diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c index de8cdcc..d96dfe1 100644 --- a/drivers/mmc/exynos_dw_mmc.c +++ b/drivers/mmc/exynos_dw_mmc.c @@ -13,6 +13,8 @@ #include <asm/arch/dwmmc.h> #include <asm/arch/clk.h> #include <asm/arch/pinmux.h> +#include <asm/gpio.h> +#include <asm-generic/errno.h> #define DWMMC_MAX_CH_NUM 4 #define DWMMC_MAX_FREQ 52000000 @@ -44,7 +46,11 @@ unsigned int exynos_dwmci_get_clk(struct dwmci_host *host) & DWMCI_DIVRATIO_MASK) + 1; sclk = get_mmc_clk(host->dev_index); - return sclk / clk_div; + /* + * Assume to know divider value. + * When clock unit is broken, need to set "host->div" + */ + return sclk / clk_div / (host->div + 1); } static void exynos_dwmci_board_init(struct dwmci_host *host) @@ -60,48 +66,36 @@ static void exynos_dwmci_board_init(struct dwmci_host *host) } } -/* - * This function adds the mmc channel to be registered with mmc core. - * index - mmc channel number. - * regbase - register base address of mmc channel specified in 'index'. - * bus_width - operating bus width of mmc channel specified in 'index'. - * clksel - value to be written into CLKSEL register in case of FDT. - * NULL in case od non-FDT. - */ -int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel) +static int exynos_dwmci_core_init(struct dwmci_host *host, int index) { - struct dwmci_host *host = NULL; unsigned int div; unsigned long freq, sclk; - host = malloc(sizeof(struct dwmci_host)); - if (!host) { - printf("dwmci_host malloc fail!\n"); - return 1; - } + + if (host->bus_hz) + freq = host->bus_hz; + else + freq = DWMMC_MAX_FREQ; + /* request mmc clock vlaue of 52MHz. */ - freq = 52000000; sclk = get_mmc_clk(index); div = DIV_ROUND_UP(sclk, freq); /* set the clock divisor for mmc */ set_mmc_clk(index, div); host->name = "EXYNOS DWMMC"; - host->ioaddr = (void *)regbase; - host->buswidth = bus_width; #ifdef CONFIG_EXYNOS5420 host->quirks = DWMCI_QUIRK_DISABLE_SMU; #endif host->board_init = exynos_dwmci_board_init; - if (clksel) { - host->clksel_val = clksel; - } else { - if (0 == index) + if (!host->clksel_val) { + if (index == 0) host->clksel_val = DWMMC_MMC0_CLKSEL_VAL; - if (2 == index) + else if (index == 2) host->clksel_val = DWMMC_MMC2_CLKSEL_VAL; } + host->caps = MMC_MODE_DDR_52MHz; host->clksel = exynos_dwmci_clksel; host->dev_index = index; host->get_mmc_clk = exynos_dwmci_get_clk; @@ -113,69 +107,134 @@ int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel) return 0; } +/* + * This function adds the mmc channel to be registered with mmc core. + * index - mmc channel number. + * regbase - register base address of mmc channel specified in 'index'. + * bus_width - operating bus width of mmc channel specified in 'index'. + * clksel - value to be written into CLKSEL register in case of FDT. + * NULL in case od non-FDT. + */ +int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel) +{ + struct dwmci_host *host = NULL; + + host = malloc(sizeof(struct dwmci_host)); + if (!host) { + error("dwmci_host malloc fail!\n"); + return -ENOMEM; + } + + host->ioaddr = (void *)regbase; + host->buswidth = bus_width; + + if (clksel) + host->clksel_val = clksel; + + return exynos_dwmci_core_init(host, index); +} + #ifdef CONFIG_OF_CONTROL -int exynos_dwmmc_init(const void *blob) +static struct dwmci_host dwmci_host[DWMMC_MAX_CH_NUM]; + +static int do_dwmci_init(struct dwmci_host *host) { - int index, bus_width; - int node_list[DWMMC_MAX_CH_NUM]; - int err = 0, dev_id, flag, count, i; - u32 clksel_val, base, timing[3]; + int index, flag, err; - count = fdtdec_find_aliases_for_id(blob, "mmc", - COMPAT_SAMSUNG_EXYNOS5_DWMMC, node_list, - DWMMC_MAX_CH_NUM); + index = host->dev_index; - for (i = 0; i < count; i++) { - int node = node_list[i]; + flag = host->buswidth == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE; + err = exynos_pinmux_config(host->dev_id, flag); + if (err) { + debug("DWMMC not configure\n"); + return err; + } - if (node <= 0) - continue; + return exynos_dwmci_core_init(host, index); +} - /* Extract device id for each mmc channel */ - dev_id = pinmux_decode_periph_id(blob, node); +static int exynos_dwmci_get_config(const void *blob, int node, + struct dwmci_host *host) +{ + int err = 0; + u32 base, clksel_val, timing[3]; - /* Get the bus width from the device node */ - bus_width = fdtdec_get_int(blob, node, "samsung,bus-width", 0); - if (bus_width <= 0) { - debug("DWMMC: Can't get bus-width\n"); - return -1; - } - if (8 == bus_width) - flag = PINMUX_FLAG_8BIT_MODE; - else - flag = PINMUX_FLAG_NONE; + /* Extract device id for each mmc channel */ + host->dev_id = pinmux_decode_periph_id(blob, node); - /* config pinmux for each mmc channel */ - err = exynos_pinmux_config(dev_id, flag); - if (err) { - debug("DWMMC not configured\n"); - return err; - } + /* Get the bus width from the device node */ + host->buswidth = fdtdec_get_int(blob, node, "samsung,bus-width", 0); + if (host->buswidth <= 0) { + debug("DWMMC: Can't get bus-width\n"); + return -EINVAL; + } - index = dev_id - PERIPH_ID_SDMMC0; + host->dev_index = fdtdec_get_int(blob, node, "index", host->dev_id); + if (host->dev_index == host->dev_id) + host->dev_index = host->dev_id - PERIPH_ID_SDMMC0; - /* Get the base address from the device node */ - base = fdtdec_get_addr(blob, node, "reg"); - if (!base) { - debug("DWMMC: Can't get base address\n"); - return -1; - } - /* Extract the timing info from the node */ - err = fdtdec_get_int_array(blob, node, "samsung,timing", - timing, 3); + /* Set the base address from the device node */ + base = fdtdec_get_addr(blob, node, "reg"); + if (!base) { + debug("DWMMC: Can't get base address\n"); + return -EINVAL; + } + host->ioaddr = (void *)base; + + /* Extract the timing info from the node */ + err = fdtdec_get_int_array(blob, node, "samsung,timing", timing, 3); + if (err) { + debug("Can't get sdr-timings for devider\n"); + return -EINVAL; + } + + clksel_val = (DWMCI_SET_SAMPLE_CLK(timing[0]) | + DWMCI_SET_DRV_CLK(timing[1]) | + DWMCI_SET_DIV_RATIO(timing[2])); + if (clksel_val) + host->clksel_val = clksel_val; + + host->fifoth_val = fdtdec_get_int(blob, node, "fifoth_val", 0); + host->bus_hz = fdtdec_get_int(blob, node, "bus_hz", 0); + host->div = fdtdec_get_int(blob, node, "div", 0); + + return 0; +} + +static int exynos_dwmci_process_node(const void *blob, + int node_list[], int count) +{ + struct dwmci_host *host; + int i, node, err; + + for (i = 0; i < count; i++) { + node = node_list[i]; + if (node <= 0) + continue; + host = &dwmci_host[i]; + err = exynos_dwmci_get_config(blob, node, host); if (err) { - debug("Can't get sdr-timings for divider\n"); - return -1; + debug("%s: failed to decode dev %d\n", __func__, i); + return err; } - clksel_val = (DWMCI_SET_SAMPLE_CLK(timing[0]) | - DWMCI_SET_DRV_CLK(timing[1]) | - DWMCI_SET_DIV_RATIO(timing[2])); - /* Initialise each mmc channel */ - err = exynos_dwmci_add_port(index, base, bus_width, clksel_val); - if (err) - debug("dwmmc Channel-%d init failed\n", index); + do_dwmci_init(host); } return 0; } + +int exynos_dwmmc_init(const void *blob) +{ + int compat_id; + int node_list[DWMMC_MAX_CH_NUM]; + int err = 0, count; + + compat_id = COMPAT_SAMSUNG_EXYNOS_DWMMC; + + count = fdtdec_find_aliases_for_id(blob, "mmc", + compat_id, node_list, DWMMC_MAX_CH_NUM); + err = exynos_dwmci_process_node(blob, node_list, count); + + return err; +} #endif diff --git a/drivers/mmc/gen_atmel_mci.c b/drivers/mmc/gen_atmel_mci.c index acca026..a57a9b1 100644 --- a/drivers/mmc/gen_atmel_mci.c +++ b/drivers/mmc/gen_atmel_mci.c @@ -243,9 +243,10 @@ mci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) #ifdef DEBUG if (data->flags & MMC_DATA_READ) { + u32 cnt = word_count * 4; printf("Read Data:\n"); - print_buffer(0, data->dest, 1, - word_count*4, 0); + print_buffer(0, data->dest + cnt * block_count, + 1, cnt, 0); } #endif #ifdef DEBUG diff --git a/drivers/mmc/kona_sdhci.c b/drivers/mmc/kona_sdhci.c index 77e42c8..f804f4c 100644 --- a/drivers/mmc/kona_sdhci.c +++ b/drivers/mmc/kona_sdhci.c @@ -113,16 +113,20 @@ int kona_sdhci_init(int dev_index, u32 min_clk, u32 quirks) __func__, dev_index); ret = -EINVAL; } - if (ret) + if (ret) { + free(host); return ret; + } host->name = "kona-sdhci"; host->ioaddr = reg_base; host->quirks = quirks; host->host_caps = MMC_MODE_HC; - if (init_kona_mmc_core(host)) + if (init_kona_mmc_core(host)) { + free(host); return -EINVAL; + } if (quirks & SDHCI_QUIRK_REG32_RW) host->version = sdhci_readl(host, SDHCI_HOST_VERSION - 2) >> 16; diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 8b53ead..b5477b1 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -10,6 +10,7 @@ #include <config.h> #include <common.h> #include <command.h> +#include <errno.h> #include <mmc.h> #include <part.h> #include <malloc.h> @@ -160,6 +161,9 @@ int mmc_set_blocklen(struct mmc *mmc, int len) { struct mmc_cmd cmd; + if (mmc->card_caps & MMC_MODE_DDR_52MHz) + return 0; + cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; cmd.resp_type = MMC_RSP_R1; cmd.cmdarg = len; @@ -516,10 +520,13 @@ static int mmc_change_freq(struct mmc *mmc) return 0; /* High Speed is set, there are two types: 52MHz and 26MHz */ - if (cardtype & MMC_HS_52MHZ) + if (cardtype & EXT_CSD_CARD_TYPE_52) { + if (cardtype & EXT_CSD_CARD_TYPE_DDR_52) + mmc->card_caps |= MMC_MODE_DDR_52MHz; mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; - else + } else { mmc->card_caps |= MMC_MODE_HS; + } return 0; } @@ -558,19 +565,19 @@ int mmc_select_hwpart(int dev_num, int hwpart) int ret; if (!mmc) - return -1; + return -ENODEV; if (mmc->part_num == hwpart) return 0; if (mmc->part_config == MMCPART_NOAVAILABLE) { printf("Card doesn't support part_switch\n"); - return -1; + return -EMEDIUMTYPE; } ret = mmc_switch_part(dev_num, hwpart); if (ret) - return -1; + return ret; mmc->part_num = hwpart; @@ -1082,6 +1089,8 @@ static int mmc_startup(struct mmc *mmc) /* An array of possible bus widths in order of preference */ static unsigned ext_csd_bits[] = { + EXT_CSD_DDR_BUS_WIDTH_8, + EXT_CSD_DDR_BUS_WIDTH_4, EXT_CSD_BUS_WIDTH_8, EXT_CSD_BUS_WIDTH_4, EXT_CSD_BUS_WIDTH_1, @@ -1089,13 +1098,15 @@ static int mmc_startup(struct mmc *mmc) /* An array to map CSD bus widths to host cap bits */ static unsigned ext_to_hostcaps[] = { + [EXT_CSD_DDR_BUS_WIDTH_4] = MMC_MODE_DDR_52MHz, + [EXT_CSD_DDR_BUS_WIDTH_8] = MMC_MODE_DDR_52MHz, [EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT, [EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT, }; /* An array to map chosen bus width to an integer */ static unsigned widths[] = { - 8, 4, 1, + 8, 4, 8, 4, 1, }; for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) { diff --git a/drivers/mmc/rpmb.c b/drivers/mmc/rpmb.c index 05936f5..9d0b8bc 100644 --- a/drivers/mmc/rpmb.c +++ b/drivers/mmc/rpmb.c @@ -11,7 +11,7 @@ #include <config.h> #include <common.h> #include <mmc.h> -#include <sha256.h> +#include <u-boot/sha256.h> #include "mmc_private.h" /* Request codes */ diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c index ccae4cc..2ff0ec2 100644 --- a/drivers/mmc/s5p_sdhci.c +++ b/drivers/mmc/s5p_sdhci.c @@ -65,17 +65,9 @@ static void s5p_sdhci_set_control_reg(struct sdhci_host *host) sdhci_writel(host, ctrl, SDHCI_CONTROL2); } -int s5p_sdhci_init(u32 regbase, int index, int bus_width) +static int s5p_sdhci_core_init(struct sdhci_host *host) { - struct sdhci_host *host = NULL; - host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host)); - if (!host) { - printf("sdhci__host malloc fail!\n"); - return 1; - } - host->name = S5P_NAME; - host->ioaddr = (void *)regbase; host->quirks = SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_VOLTAGE | SDHCI_QUIRK_BROKEN_R1B | SDHCI_QUIRK_32BIT_DMA_ADDR | @@ -85,15 +77,28 @@ int s5p_sdhci_init(u32 regbase, int index, int bus_width) host->set_control_reg = &s5p_sdhci_set_control_reg; host->set_clock = set_mmc_clk; - host->index = index; host->host_caps = MMC_MODE_HC; - if (bus_width == 8) + if (host->bus_width == 8) host->host_caps |= MMC_MODE_8BIT; return add_sdhci(host, 52000000, 400000); } +int s5p_sdhci_init(u32 regbase, int index, int bus_width) +{ + struct sdhci_host *host = malloc(sizeof(struct sdhci_host)); + if (!host) { + printf("sdhci__host malloc fail!\n"); + return 1; + } + host->ioaddr = (void *)regbase; + host->index = index; + host->bus_width = bus_width; + + return s5p_sdhci_core_init(host); +} + #ifdef CONFIG_OF_CONTROL struct sdhci_host sdhci_host[SDHCI_MAX_HOSTS]; @@ -126,20 +131,7 @@ static int do_sdhci_init(struct sdhci_host *host) } } - host->name = S5P_NAME; - - host->quirks = SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_VOLTAGE | - SDHCI_QUIRK_BROKEN_R1B | SDHCI_QUIRK_32BIT_DMA_ADDR | - SDHCI_QUIRK_WAIT_SEND_CMD; - host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; - host->version = sdhci_readw(host, SDHCI_HOST_VERSION); - - host->set_control_reg = &s5p_sdhci_set_control_reg; - host->set_clock = set_mmc_clk; - - host->host_caps = MMC_MODE_HC; - - return add_sdhci(host, 52000000, 400000); + return s5p_sdhci_core_init(host); } static int sdhci_get_config(const void *blob, int node, struct sdhci_host *host) diff --git a/drivers/mtd/nand/am335x_spl_bch.c b/drivers/mtd/nand/am335x_spl_bch.c index bd89b06..ce65d8e 100644 --- a/drivers/mtd/nand/am335x_spl_bch.c +++ b/drivers/mtd/nand/am335x_spl_bch.c @@ -55,7 +55,7 @@ static int nand_command(int block, int page, uint32_t offs, } /* Shift the offset from byte addressing to word addressing. */ - if (this->options & NAND_BUSWIDTH_16) + if ((this->options & NAND_BUSWIDTH_16) && !nand_opcode_8bits(cmd)) offs >>= 1; /* Set ALE and clear CLE to start address cycle */ diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index e1fc48f..e73834d 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -1195,7 +1195,7 @@ static int nand_command(int block, int page, uint32_t offs, u8 cmd) hwctrl(&mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE); - if (this->options & NAND_BUSWIDTH_16) + if ((this->options & NAND_BUSWIDTH_16) && !nand_opcode_8bits(cmd)) offs >>= 1; hwctrl(&mtd, offs & 0xff, NAND_CTRL_ALE | NAND_CTRL_CHANGE); diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 75b03a7..5d42509 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -32,8 +32,7 @@ #include <common.h> #include <asm/io.h> #include <nand.h> -#include <asm/arch/nand_defs.h> -#include <asm/arch/emif_defs.h> +#include <asm/ti-common/davinci_nand.h> /* Definitions for 4-bit hardware ECC */ #define NAND_TIMEOUT 10240 diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 1ce55fd..376976d 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -575,7 +575,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, /* Serially input address */ if (column != -1) { /* Adjust columns for 16 bit buswidth */ - if (chip->options & NAND_BUSWIDTH_16) + if ((chip->options & NAND_BUSWIDTH_16) && + !nand_opcode_8bits(command)) column >>= 1; chip->cmd_ctrl(mtd, column, ctrl); ctrl &= ~NAND_CTRL_CHANGE; @@ -668,7 +669,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, /* Serially input address */ if (column != -1) { /* Adjust columns for 16 bit buswidth */ - if (chip->options & NAND_BUSWIDTH_16) + if ((chip->options & NAND_BUSWIDTH_16) && + !nand_opcode_8bits(command)) column >>= 1; chip->cmd_ctrl(mtd, column, ctrl); ctrl &= ~NAND_CTRL_CHANGE; @@ -2582,7 +2584,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, int *busw) { struct nand_onfi_params *p = &chip->onfi_params; - int i; + int i, j; int val; /* Try ONFI for unknown chip or LP */ @@ -2593,7 +2595,8 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); for (i = 0; i < 3; i++) { - chip->read_buf(mtd, (uint8_t *)p, sizeof(*p)); + for (j = 0; j < sizeof(*p); j++) + ((uint8_t *)p)[j] = chip->read_byte(mtd); if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) == le16_to_cpu(p->crc)) { pr_info("ONFI param page %d valid\n", i); diff --git a/drivers/mtd/nand/nand_spl_simple.c b/drivers/mtd/nand/nand_spl_simple.c index cead4b5..700ca32 100644 --- a/drivers/mtd/nand/nand_spl_simple.c +++ b/drivers/mtd/nand/nand_spl_simple.c @@ -78,7 +78,7 @@ static int nand_command(int block, int page, uint32_t offs, } /* Shift the offset from byte addressing to word addressing. */ - if (this->options & NAND_BUSWIDTH_16) + if ((this->options & NAND_BUSWIDTH_16) && !nand_opcode_8bits(cmd)) offs >>= 1; /* Begin command latch cycle */ diff --git a/drivers/mtd/nand/omap_elm.c b/drivers/mtd/nand/omap_elm.c index 47b1f1b..d963e6c 100644 --- a/drivers/mtd/nand/omap_elm.c +++ b/drivers/mtd/nand/omap_elm.c @@ -16,23 +16,21 @@ #include <common.h> #include <asm/io.h> #include <asm/errno.h> -#include <linux/mtd/omap_gpmc.h> #include <linux/mtd/omap_elm.h> #include <asm/arch/hardware.h> +#define DRIVER_NAME "omap-elm" #define ELM_DEFAULT_POLY (0) struct elm *elm_cfg; /** - * elm_load_syndromes - Load BCH syndromes based on nibble selection + * elm_load_syndromes - Load BCH syndromes based on bch_type selection * @syndrome: BCH syndrome - * @nibbles: + * @bch_type: BCH4/BCH8/BCH16 * @poly: Syndrome Polynomial set to use - * - * Load BCH syndromes based on nibble selection */ -static void elm_load_syndromes(u8 *syndrome, u32 nibbles, u8 poly) +static void elm_load_syndromes(u8 *syndrome, enum bch_level bch_type, u8 poly) { u32 *ptr; u32 val; @@ -48,8 +46,7 @@ static void elm_load_syndromes(u8 *syndrome, u32 nibbles, u8 poly) (syndrome[7] << 24); writel(val, ptr); - /* BCH 8-bit with 26 nibbles (4*8=32) */ - if (nibbles > 13) { + if (bch_type == BCH_8_BIT || bch_type == BCH_16_BIT) { /* reg 2 */ ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[2]; val = syndrome[8] | (syndrome[9] << 8) | (syndrome[10] << 16) | @@ -62,8 +59,7 @@ static void elm_load_syndromes(u8 *syndrome, u32 nibbles, u8 poly) writel(val, ptr); } - /* BCH 16-bit with 52 nibbles (7*8=56) */ - if (nibbles > 26) { + if (bch_type == BCH_16_BIT) { /* reg 4 */ ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[4]; val = syndrome[16] | (syndrome[17] << 8) | @@ -87,7 +83,7 @@ static void elm_load_syndromes(u8 *syndrome, u32 nibbles, u8 poly) /** * elm_check_errors - Check for BCH errors and return error locations * @syndrome: BCH syndrome - * @nibbles: + * @bch_type: BCH4/BCH8/BCH16 * @error_count: Returns number of errrors in the syndrome * @error_locations: Returns error locations (in decimal) in this array * @@ -95,14 +91,14 @@ static void elm_load_syndromes(u8 *syndrome, u32 nibbles, u8 poly) * and locations in the array passed. Returns -1 if error is not correctable, * else returns 0 */ -int elm_check_error(u8 *syndrome, u32 nibbles, u32 *error_count, +int elm_check_error(u8 *syndrome, enum bch_level bch_type, u32 *error_count, u32 *error_locations) { u8 poly = ELM_DEFAULT_POLY; s8 i; u32 location_status; - elm_load_syndromes(syndrome, nibbles, poly); + elm_load_syndromes(syndrome, bch_type, poly); /* start processing */ writel((readl(&elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6]) @@ -118,8 +114,10 @@ int elm_check_error(u8 *syndrome, u32 nibbles, u32 *error_count, /* check if correctable */ location_status = readl(&elm_cfg->error_location[poly].location_status); - if (!(location_status & ELM_LOCATION_STATUS_ECC_CORRECTABLE_MASK)) - return -1; + if (!(location_status & ELM_LOCATION_STATUS_ECC_CORRECTABLE_MASK)) { + printf("%s: uncorrectable ECC errors\n", DRIVER_NAME); + return -EBADMSG; + } /* get error count */ *error_count = readl(&elm_cfg->error_location[poly].location_status) & diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c index bf99b8e..1acf06b 100644 --- a/drivers/mtd/nand/omap_gpmc.c +++ b/drivers/mtd/nand/omap_gpmc.c @@ -148,35 +148,20 @@ static int __maybe_unused omap_correct_data(struct mtd_info *mtd, uint8_t *dat, } /* - * Generic BCH interface + * Driver configurations */ -struct nand_bch_priv { - uint8_t mode; - uint8_t type; - uint8_t nibbles; +struct omap_nand_info { struct bch_control *control; enum omap_ecc ecc_scheme; }; -/* bch types */ -#define ECC_BCH4 0 -#define ECC_BCH8 1 -#define ECC_BCH16 2 - -/* BCH nibbles for diff bch levels */ -#define ECC_BCH4_NIBBLES 13 -#define ECC_BCH8_NIBBLES 26 -#define ECC_BCH16_NIBBLES 52 - /* * This can be a single instance cause all current users have only one NAND * with nearly the same setup (BCH8, some with ELM and others with sw BCH * library). * When some users with other BCH strength will exists this have to change! */ -static __maybe_unused struct nand_bch_priv bch_priv = { - .type = ECC_BCH8, - .nibbles = ECC_BCH8_NIBBLES, +static __maybe_unused struct omap_nand_info omap_nand_info = { .control = NULL }; @@ -206,7 +191,7 @@ __maybe_unused static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode) { struct nand_chip *nand = mtd->priv; - struct nand_bch_priv *bch = nand->priv; + struct omap_nand_info *info = nand->priv; unsigned int dev_width = (nand->options & NAND_BUSWIDTH_16) ? 1 : 0; unsigned int ecc_algo = 0; unsigned int bch_type = 0; @@ -215,7 +200,7 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode) u32 ecc_config_val = 0; /* configure GPMC for specific ecc-scheme */ - switch (bch->ecc_scheme) { + switch (info->ecc_scheme) { case OMAP_ECC_HAM1_CODE_SW: return; case OMAP_ECC_HAM1_CODE_HW: @@ -239,6 +224,19 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode) eccsize1 = 2; /* non-ECC bits in nibbles per sector */ } break; + case OMAP_ECC_BCH16_CODE_HW: + ecc_algo = 0x1; + bch_type = 0x2; + if (mode == NAND_ECC_WRITE) { + bch_wrapmode = 0x01; + eccsize0 = 0; /* extra bits in nibbles per sector */ + eccsize1 = 52; /* OOB bits in nibbles per sector */ + } else { + bch_wrapmode = 0x01; + eccsize0 = 52; /* ECC bits in nibbles per sector */ + eccsize1 = 0; /* non-ECC bits in nibbles per sector */ + } + break; default: return; } @@ -277,11 +275,11 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat, uint8_t *ecc_code) { struct nand_chip *chip = mtd->priv; - struct nand_bch_priv *bch = chip->priv; + struct omap_nand_info *info = chip->priv; uint32_t *ptr, val = 0; int8_t i = 0, j; - switch (bch->ecc_scheme) { + switch (info->ecc_scheme) { case OMAP_ECC_HAM1_CODE_HW: val = readl(&gpmc_cfg->ecc1_result); ecc_code[0] = val & 0xFF; @@ -305,11 +303,34 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat, ptr--; } break; + case OMAP_ECC_BCH16_CODE_HW: + val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[2]); + ecc_code[i++] = (val >> 8) & 0xFF; + ecc_code[i++] = (val >> 0) & 0xFF; + val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[1]); + ecc_code[i++] = (val >> 24) & 0xFF; + ecc_code[i++] = (val >> 16) & 0xFF; + ecc_code[i++] = (val >> 8) & 0xFF; + ecc_code[i++] = (val >> 0) & 0xFF; + val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[0]); + ecc_code[i++] = (val >> 24) & 0xFF; + ecc_code[i++] = (val >> 16) & 0xFF; + ecc_code[i++] = (val >> 8) & 0xFF; + ecc_code[i++] = (val >> 0) & 0xFF; + for (j = 3; j >= 0; j--) { + val = readl(&gpmc_cfg->bch_result_0_3[0].bch_result_x[j] + ); + ecc_code[i++] = (val >> 24) & 0xFF; + ecc_code[i++] = (val >> 16) & 0xFF; + ecc_code[i++] = (val >> 8) & 0xFF; + ecc_code[i++] = (val >> 0) & 0xFF; + } + break; default: return -EINVAL; } /* ECC scheme specific syndrome customizations */ - switch (bch->ecc_scheme) { + switch (info->ecc_scheme) { case OMAP_ECC_HAM1_CODE_HW: break; #ifdef CONFIG_BCH @@ -323,6 +344,8 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat, case OMAP_ECC_BCH8_CODE_HW: ecc_code[chip->ecc.bytes - 1] = 0x00; break; + case OMAP_ECC_BCH16_CODE_HW: + break; default: return -EINVAL; } @@ -345,16 +368,17 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc) { struct nand_chip *chip = mtd->priv; - struct nand_bch_priv *bch = chip->priv; - uint32_t eccbytes = chip->ecc.bytes; + struct omap_nand_info *info = chip->priv; + struct nand_ecc_ctrl *ecc = &chip->ecc; uint32_t error_count = 0, error_max; - uint32_t error_loc[8]; + uint32_t error_loc[ELM_MAX_ERROR_COUNT]; + enum bch_level bch_type; uint32_t i, ecc_flag = 0; uint8_t count, err = 0; uint32_t byte_pos, bit_pos; /* check calculated ecc */ - for (i = 0; i < chip->ecc.bytes && !ecc_flag; i++) { + for (i = 0; i < ecc->bytes && !ecc_flag; i++) { if (calc_ecc[i] != 0x00) ecc_flag = 1; } @@ -363,7 +387,7 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat, /* check for whether its a erased-page */ ecc_flag = 0; - for (i = 0; i < chip->ecc.bytes && !ecc_flag; i++) { + for (i = 0; i < ecc->bytes && !ecc_flag; i++) { if (read_ecc[i] != 0xff) ecc_flag = 1; } @@ -374,25 +398,33 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat, * while reading ECC result we read it in big endian. * Hence while loading to ELM we have rotate to get the right endian. */ - switch (bch->ecc_scheme) { + switch (info->ecc_scheme) { case OMAP_ECC_BCH8_CODE_HW: - omap_reverse_list(calc_ecc, eccbytes - 1); + bch_type = BCH_8_BIT; + omap_reverse_list(calc_ecc, ecc->bytes - 1); + break; + case OMAP_ECC_BCH16_CODE_HW: + bch_type = BCH_16_BIT; + omap_reverse_list(calc_ecc, ecc->bytes); break; default: return -EINVAL; } /* use elm module to check for errors */ - elm_config((enum bch_level)(bch->type)); - if (elm_check_error(calc_ecc, bch->nibbles, &error_count, error_loc)) { - printf("nand: error: uncorrectable ECC errors\n"); - return -EINVAL; - } + elm_config(bch_type); + err = elm_check_error(calc_ecc, bch_type, &error_count, error_loc); + if (err) + return err; + /* correct bch error */ for (count = 0; count < error_count; count++) { - switch (bch->type) { - case ECC_BCH8: + switch (info->ecc_scheme) { + case OMAP_ECC_BCH8_CODE_HW: /* 14th byte in ECC is reserved to match ROM layout */ - error_max = SECTOR_BYTES + (eccbytes - 1); + error_max = SECTOR_BYTES + (ecc->bytes - 1); + break; + case OMAP_ECC_BCH16_CODE_HW: + error_max = SECTOR_BYTES + ecc->bytes; break; default: return -EINVAL; @@ -496,10 +528,10 @@ static int omap_correct_data_bch_sw(struct mtd_info *mtd, u_char *data, /* cannot correct more than 8 errors */ unsigned int errloc[8]; struct nand_chip *chip = mtd->priv; - struct nand_bch_priv *chip_priv = chip->priv; - struct bch_control *bch = chip_priv->control; + struct omap_nand_info *info = chip->priv; - count = decode_bch(bch, NULL, 512, read_ecc, calc_ecc, NULL, errloc); + count = decode_bch(info->control, NULL, 512, read_ecc, calc_ecc, + NULL, errloc); if (count > 0) { /* correct errors */ for (i = 0; i < count; i++) { @@ -535,15 +567,11 @@ static int omap_correct_data_bch_sw(struct mtd_info *mtd, u_char *data, static void __maybe_unused omap_free_bch(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; - struct nand_bch_priv *chip_priv = chip->priv; - struct bch_control *bch = NULL; - - if (chip_priv) - bch = chip_priv->control; + struct omap_nand_info *info = chip->priv; - if (bch) { - free_bch(bch); - chip_priv->control = NULL; + if (info->control) { + free_bch(info->control); + info->control = NULL; } } #endif /* CONFIG_BCH */ @@ -557,7 +585,7 @@ static void __maybe_unused omap_free_bch(struct mtd_info *mtd) */ static int omap_select_ecc_scheme(struct nand_chip *nand, enum omap_ecc ecc_scheme, unsigned int pagesize, unsigned int oobsize) { - struct nand_bch_priv *bch = nand->priv; + struct omap_nand_info *info = nand->priv; struct nand_ecclayout *ecclayout = &omap_ecclayout; int eccsteps = pagesize / SECTOR_BYTES; int i; @@ -567,12 +595,10 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, debug("nand: selected OMAP_ECC_HAM1_CODE_SW\n"); /* For this ecc-scheme, ecc.bytes, ecc.layout, ... are * initialized in nand_scan_tail(), so just set ecc.mode */ - bch_priv.control = NULL; - bch_priv.type = 0; + info->control = NULL; nand->ecc.mode = NAND_ECC_SOFT; nand->ecc.layout = NULL; nand->ecc.size = 0; - bch->ecc_scheme = OMAP_ECC_HAM1_CODE_SW; break; case OMAP_ECC_HAM1_CODE_HW: @@ -583,8 +609,7 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, (3 * eccsteps) + BADBLOCK_MARKER_LENGTH)); return -EINVAL; } - bch_priv.control = NULL; - bch_priv.type = 0; + info->control = NULL; /* populate ecc specific fields */ memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl)); nand->ecc.mode = NAND_ECC_HW; @@ -605,7 +630,6 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes - BADBLOCK_MARKER_LENGTH; - bch->ecc_scheme = OMAP_ECC_HAM1_CODE_HW; break; case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: @@ -618,12 +642,11 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, return -EINVAL; } /* check if BCH S/W library can be used for error detection */ - bch_priv.control = init_bch(13, 8, 0x201b); - if (!bch_priv.control) { + info->control = init_bch(13, 8, 0x201b); + if (!info->control) { printf("nand: error: could not init_bch()\n"); return -ENODEV; } - bch_priv.type = ECC_BCH8; /* populate ecc specific fields */ memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl)); nand->ecc.mode = NAND_ECC_HW; @@ -647,7 +670,6 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes - BADBLOCK_MARKER_LENGTH; - bch->ecc_scheme = OMAP_ECC_BCH8_CODE_HW_DETECTION_SW; break; #else printf("nand: error: CONFIG_BCH required for ECC\n"); @@ -665,7 +687,7 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, } /* intialize ELM for ECC error detection */ elm_init(); - bch_priv.type = ECC_BCH8; + info->control = NULL; /* populate ecc specific fields */ memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl)); nand->ecc.mode = NAND_ECC_HW; @@ -683,13 +705,44 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes - BADBLOCK_MARKER_LENGTH; - bch->ecc_scheme = OMAP_ECC_BCH8_CODE_HW; break; #else printf("nand: error: CONFIG_NAND_OMAP_ELM required for ECC\n"); return -EINVAL; #endif + case OMAP_ECC_BCH16_CODE_HW: +#ifdef CONFIG_NAND_OMAP_ELM + debug("nand: using OMAP_ECC_BCH16_CODE_HW\n"); + /* check ecc-scheme requirements before updating ecc info */ + if ((26 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) { + printf("nand: error: insufficient OOB: require=%d\n", ( + (26 * eccsteps) + BADBLOCK_MARKER_LENGTH)); + return -EINVAL; + } + /* intialize ELM for ECC error detection */ + elm_init(); + /* populate ecc specific fields */ + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.size = SECTOR_BYTES; + nand->ecc.bytes = 26; + nand->ecc.strength = 16; + nand->ecc.hwctl = omap_enable_hwecc; + nand->ecc.correct = omap_correct_data_bch; + nand->ecc.calculate = omap_calculate_ecc; + nand->ecc.read_page = omap_read_page_bch; + /* define ecc-layout */ + ecclayout->eccbytes = nand->ecc.bytes * eccsteps; + for (i = 0; i < ecclayout->eccbytes; i++) + ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH; + ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; + ecclayout->oobfree[0].length = oobsize - nand->ecc.bytes - + BADBLOCK_MARKER_LENGTH; + break; +#else + printf("nand: error: CONFIG_NAND_OMAP_ELM required for ECC\n"); + return -EINVAL; +#endif default: debug("nand: error: ecc scheme not enabled or supported\n"); return -EINVAL; @@ -699,6 +752,7 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, if (ecc_scheme != OMAP_ECC_HAM1_CODE_SW) nand->ecc.layout = ecclayout; + info->ecc_scheme = ecc_scheme; return 0; } @@ -802,16 +856,21 @@ int board_nand_init(struct nand_chip *nand) nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat; nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd; - nand->priv = &bch_priv; + nand->priv = &omap_nand_info; nand->cmd_ctrl = omap_nand_hwcontrol; nand->options |= NAND_NO_PADDING | NAND_CACHEPRG; - /* If we are 16 bit dev, our gpmc config tells us that */ - if ((readl(&gpmc_cfg->cs[cs].config1) & 0x3000) == 0x1000) - nand->options |= NAND_BUSWIDTH_16; - nand->chip_delay = 100; nand->ecc.layout = &omap_ecclayout; + /* configure driver and controller based on NAND device bus-width */ + gpmc_config = readl(&gpmc_cfg->cs[cs].config1); +#if defined(CONFIG_SYS_NAND_BUSWIDTH_16BIT) + nand->options |= NAND_BUSWIDTH_16; + writel(gpmc_config | (0x1 << 12), &gpmc_cfg->cs[cs].config1); +#else + nand->options &= ~NAND_BUSWIDTH_16; + writel(gpmc_config & ~(0x1 << 12), &gpmc_cfg->cs[cs].config1); +#endif /* select ECC scheme */ #if defined(CONFIG_NAND_OMAP_ECCSCHEME) err = omap_select_ecc_scheme(nand, CONFIG_NAND_OMAP_ECCSCHEME, diff --git a/drivers/mtd/spi/sf_params.c b/drivers/mtd/spi/sf_params.c index eb372b7..ac886fd 100644 --- a/drivers/mtd/spi/sf_params.c +++ b/drivers/mtd/spi/sf_params.c @@ -60,6 +60,7 @@ const struct spi_flash_params spi_flash_params_table[] = { {"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512, RD_FULL, WR_QPP}, {"S25FL512S_256K", 0x010220, 0x4d00, 256 * 1024, 256, RD_FULL, WR_QPP}, {"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024, RD_FULL, WR_QPP}, + {"S25FL512S_512K", 0x010220, 0x4f00, 256 * 1024, 256, RD_FULL, WR_QPP}, #endif #ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ {"M25P10", 0x202011, 0x0, 32 * 1024, 4, 0, 0}, diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 0a46fe3..36ae5e0 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -197,16 +197,6 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, /* Go for default supported write cmd */ flash->write_cmd = CMD_PAGE_PROGRAM; - /* Set the quad enable bit - only for quad commands */ - if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) || - (flash->read_cmd == CMD_READ_QUAD_IO_FAST) || - (flash->write_cmd == CMD_QUAD_PAGE_PROGRAM)) { - if (spi_flash_set_qeb(flash, idcode[0])) { - debug("SF: Fail to set QEB for %02x\n", idcode[0]); - return NULL; - } - } - /* Read dummy_byte: dummy byte is determined based on the * dummy cycles of a particular command. * Fast commands - dummy_byte = dummy_cycles/8 @@ -327,6 +317,16 @@ static struct spi_flash *spi_flash_probe_slave(struct spi_slave *spi) if (!flash) goto err_read_id; + /* Set the quad enable bit - only for quad commands */ + if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) || + (flash->read_cmd == CMD_READ_QUAD_IO_FAST) || + (flash->write_cmd == CMD_QUAD_PAGE_PROGRAM)) { + if (spi_flash_set_qeb(flash, idcode[0])) { + debug("SF: Fail to set QEB for %02x\n", idcode[0]); + return NULL; + } + } + #ifdef CONFIG_OF_CONTROL if (spi_flash_decode_fdt(gd->fdt_blob, flash)) { debug("SF: FDT decode error\n"); diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 6005f7e..6226cb2 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -64,3 +64,4 @@ obj-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o obj-$(CONFIG_XILINX_LL_TEMAC) += xilinx_ll_temac.o xilinx_ll_temac_mdio.o \ xilinx_ll_temac_fifo.o xilinx_ll_temac_sdma.o obj-$(CONFIG_ZYNQ_GEM) += zynq_gem.o +obj-$(CONFIG_FSL_MC_ENET) += fsl_mc/ diff --git a/drivers/net/fsl_mc/Makefile b/drivers/net/fsl_mc/Makefile new file mode 100644 index 0000000..4834086 --- /dev/null +++ b/drivers/net/fsl_mc/Makefile @@ -0,0 +1,8 @@ +# +# Copyright 2014 Freescale Semiconductor, Inc. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +# Layerscape MC driver +obj-y += mc.o diff --git a/drivers/net/fsl_mc/mc.c b/drivers/net/fsl_mc/mc.c new file mode 100644 index 0000000..df84568 --- /dev/null +++ b/drivers/net/fsl_mc/mc.c @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2014 Freescale Semiconductor + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <errno.h> +#include <asm/io.h> +#include <fsl_mc.h> + +DECLARE_GLOBAL_DATA_PTR; +static int mc_boot_status; + +/** + * Copying MC firmware or DPL image to DDR + */ +static int mc_copy_image(const char *title, + u64 image_addr, u32 image_size, u64 mc_ram_addr) +{ + debug("%s copied to address %p\n", title, (void *)mc_ram_addr); + memcpy((void *)mc_ram_addr, (void *)image_addr, image_size); + return 0; +} + +/** + * MC firmware FIT image parser checks if the image is in FIT + * format, verifies integrity of the image and calculates + * raw image address and size values. + * Returns 0 if success and 1 if any of the above mentioned + * task fail. + **/ + +int parse_mc_firmware_fit_image(const void **raw_image_addr, + size_t *raw_image_size) +{ + int format; + void *fit_hdr; + int node_offset; + const void *data; + size_t size; + const char *uname = "firmware"; + + /* Check if the image is in NOR flash*/ +#ifdef CONFIG_SYS_LS_MC_FW_IN_NOR + fit_hdr = (void *)CONFIG_SYS_LS_MC_FW_ADDR; +#else +#error "No CONFIG_SYS_LS_MC_FW_IN_xxx defined" +#endif + + /* Check if Image is in FIT format */ + format = genimg_get_format(fit_hdr); + + if (format != IMAGE_FORMAT_FIT) { + debug("Not a FIT image\n"); + return 1; + } + + if (!fit_check_format(fit_hdr)) { + debug("Bad FIT image format\n"); + return 1; + } + + node_offset = fit_image_get_node(fit_hdr, uname); + + if (node_offset < 0) { + debug("Can not find %s subimage\n", uname); + return 1; + } + + /* Verify MC firmware image */ + if (!(fit_image_verify(fit_hdr, node_offset))) { + debug("Bad MC firmware hash"); + return 1; + } + + /* Get address and size of raw image */ + fit_image_get_data(fit_hdr, node_offset, &data, &size); + + *raw_image_addr = data; + *raw_image_size = size; + + return 0; +} + +int mc_init(bd_t *bis) +{ + int error = 0; + int timeout = 200000; + struct mc_ccsr_registers __iomem *mc_ccsr_regs = MC_CCSR_BASE_ADDR; + u64 mc_ram_addr; + u64 mc_dpl_offset; + u32 reg_gsr; + u32 mc_fw_boot_status; + void *fdt_hdr; + int dpl_size; + const void *raw_image_addr; + size_t raw_image_size = 0; + + BUILD_BUG_ON(CONFIG_SYS_LS_MC_FW_LENGTH % 4 != 0); + + /* + * The MC private DRAM block was already carved at the end of DRAM + * by board_init_f() using CONFIG_SYS_MEM_TOP_HIDE: + */ + if (gd->bd->bi_dram[1].start) { + mc_ram_addr = + gd->bd->bi_dram[1].start + gd->bd->bi_dram[1].size; + } else { + mc_ram_addr = + gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size; + } + + /* + * Management Complex cores should be held at reset out of POR. + * U-boot should be the first software to touch MC. To be safe, + * we reset all cores again by setting GCR1 to 0. It doesn't do + * anything if they are held at reset. After we setup the firmware + * we kick off MC by deasserting the reset bit for core 0, and + * deasserting the reset bits for Command Portal Managers. + * The stop bits are not touched here. They are used to stop the + * cores when they are active. Setting stop bits doesn't stop the + * cores from fetching instructions when they are released from + * reset. + */ + out_le32(&mc_ccsr_regs->reg_gcr1, 0); + dmb(); + + error = parse_mc_firmware_fit_image(&raw_image_addr, &raw_image_size); + if (error != 0) + goto out; + /* + * Load the MC FW at the beginning of the MC private DRAM block: + */ + mc_copy_image( + "MC Firmware", + (u64)raw_image_addr, + raw_image_size, + mc_ram_addr); + + /* + * Calculate offset in the MC private DRAM block at which the MC DPL + * blob is to be placed: + */ +#ifdef CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET + BUILD_BUG_ON( + (CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET & 0x3) != 0 || + CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET > 0xffffffff); + + mc_dpl_offset = CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET; +#else + mc_dpl_offset = mc_get_dram_block_size() - + roundup(CONFIG_SYS_LS_MC_DPL_LENGTH, 4096); + + if ((mc_dpl_offset & 0x3) != 0 || mc_dpl_offset > 0xffffffff) { + printf("%s: Invalid MC DPL offset: %llu\n", + __func__, mc_dpl_offset); + error = -EINVAL; + goto out; + } +#endif + + /* Check if DPL image is in NOR flash */ +#ifdef CONFIG_SYS_LS_MC_DPL_IN_NOR + fdt_hdr = (void *)CONFIG_SYS_LS_MC_DPL_ADDR; +#else +#error "No CONFIG_SYS_LS_MC_DPL_IN_xxx defined" +#endif + + dpl_size = fdt_totalsize(fdt_hdr); + + /* + * Load the MC DPL blob at the far end of the MC private DRAM block: + */ + mc_copy_image( + "MC DPL blob", + (u64)fdt_hdr, + dpl_size, + mc_ram_addr + mc_dpl_offset); + + debug("mc_ccsr_regs %p\n", mc_ccsr_regs); + + /* + * Tell MC where the MC Firmware image was loaded in DDR: + */ + out_le32(&mc_ccsr_regs->reg_mcfbalr, (u32)mc_ram_addr); + out_le32(&mc_ccsr_regs->reg_mcfbahr, (u32)((u64)mc_ram_addr >> 32)); + out_le32(&mc_ccsr_regs->reg_mcfapr, MCFAPR_BYPASS_ICID_MASK); + + /* + * Tell MC where the DPL blob was loaded in DDR, by indicating + * its offset relative to the beginning of the DDR block + * allocated to the MC firmware. The MC firmware is responsible + * for checking that there is no overlap between the DPL blob + * and the runtime heap and stack of the MC firmware itself. + * + * NOTE: bits [31:2] of this offset need to be stored in bits [29:0] of + * the GSR MC CCSR register. So, this offset is assumed to be 4-byte + * aligned. + * Care must be taken not to write 1s into bits 31 and 30 of the GSR in + * this case as the SoC COP or PIC will be signaled. + */ + out_le32(&mc_ccsr_regs->reg_gsr, (u32)(mc_dpl_offset >> 2)); + + /* + * Deassert reset and release MC core 0 to run + */ + out_le32(&mc_ccsr_regs->reg_gcr1, GCR1_P1_DE_RST | GCR1_M_ALL_DE_RST); + dmb(); + debug("Polling mc_ccsr_regs->reg_gsr ...\n"); + + for (;;) { + reg_gsr = in_le32(&mc_ccsr_regs->reg_gsr); + mc_fw_boot_status = (reg_gsr & GSR_FS_MASK); + if (mc_fw_boot_status & 0x1) + break; + + udelay(1000); /* throttle polling */ + if (timeout-- <= 0) + break; + } + + if (timeout <= 0) { + printf("%s: timeout booting management complex firmware\n", + __func__); + + /* TODO: Get an error status from an MC CCSR register */ + error = -ETIMEDOUT; + goto out; + } + + printf("Management complex booted (boot status: %#x)\n", + mc_fw_boot_status); + + if (mc_fw_boot_status != 0x1) { + /* + * TODO: Identify critical errors from the GSR register's FS + * field and for those errors, set error to -ENODEV or other + * appropriate errno, so that the status property is set to + * failure in the fsl,dprc device tree node. + */ + } + +out: + if (error != 0) + mc_boot_status = -error; + else + mc_boot_status = 0; + + return error; +} + +int get_mc_boot_status(void) +{ + return mc_boot_status; +} + +/** + * Return the actual size of the MC private DRAM block. + * + * NOTE: For now this function always returns the minimum required size, + * However, in the future, the actual size may be obtained from an environment + * variable. + */ +unsigned long mc_get_dram_block_size(void) +{ + return CONFIG_SYS_LS_MC_DRAM_BLOCK_MIN_SIZE; +} diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 781a272..01a94a4 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -40,17 +40,21 @@ #include "macb.h" -#define CONFIG_SYS_MACB_RX_BUFFER_SIZE 4096 -#define CONFIG_SYS_MACB_RX_RING_SIZE (CONFIG_SYS_MACB_RX_BUFFER_SIZE / 128) -#define CONFIG_SYS_MACB_TX_RING_SIZE 16 -#define CONFIG_SYS_MACB_TX_TIMEOUT 1000 -#define CONFIG_SYS_MACB_AUTONEG_TIMEOUT 5000000 +#define MACB_RX_BUFFER_SIZE 4096 +#define MACB_RX_RING_SIZE (MACB_RX_BUFFER_SIZE / 128) +#define MACB_TX_RING_SIZE 16 +#define MACB_TX_TIMEOUT 1000 +#define MACB_AUTONEG_TIMEOUT 5000000 struct macb_dma_desc { u32 addr; u32 ctrl; }; +#define DMA_DESC_BYTES(n) (n * sizeof(struct macb_dma_desc)) +#define MACB_TX_DMA_DESC_SIZE (DMA_DESC_BYTES(MACB_TX_RING_SIZE)) +#define MACB_RX_DMA_DESC_SIZE (DMA_DESC_BYTES(MACB_RX_RING_SIZE)) + #define RXADDR_USED 0x00000001 #define RXADDR_WRAP 0x00000002 @@ -170,7 +174,7 @@ int macb_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value) struct eth_device *dev = eth_get_dev_by_name(devname); struct macb_device *macb = to_macb(dev); - if ( macb->phy_addr != phy_adr ) + if (macb->phy_addr != phy_adr) return -1; arch_get_mdio_control(devname); @@ -184,7 +188,7 @@ int macb_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value) struct eth_device *dev = eth_get_dev_by_name(devname); struct macb_device *macb = to_macb(dev); - if ( macb->phy_addr != phy_adr ) + if (macb->phy_addr != phy_adr) return -1; arch_get_mdio_control(devname); @@ -194,6 +198,39 @@ int macb_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value) } #endif +#define RX 1 +#define TX 0 +static inline void macb_invalidate_ring_desc(struct macb_device *macb, bool rx) +{ + if (rx) + invalidate_dcache_range(macb->rx_ring_dma, macb->rx_ring_dma + + MACB_RX_DMA_DESC_SIZE); + else + invalidate_dcache_range(macb->tx_ring_dma, macb->tx_ring_dma + + MACB_TX_DMA_DESC_SIZE); +} + +static inline void macb_flush_ring_desc(struct macb_device *macb, bool rx) +{ + if (rx) + flush_dcache_range(macb->rx_ring_dma, macb->rx_ring_dma + + MACB_RX_DMA_DESC_SIZE); + else + flush_dcache_range(macb->tx_ring_dma, macb->tx_ring_dma + + MACB_TX_DMA_DESC_SIZE); +} + +static inline void macb_flush_rx_buffer(struct macb_device *macb) +{ + flush_dcache_range(macb->rx_buffer_dma, macb->rx_buffer_dma + + MACB_RX_BUFFER_SIZE); +} + +static inline void macb_invalidate_rx_buffer(struct macb_device *macb) +{ + invalidate_dcache_range(macb->rx_buffer_dma, macb->rx_buffer_dma + + MACB_RX_BUFFER_SIZE); +} #if defined(CONFIG_CMD_NET) @@ -208,23 +245,28 @@ static int macb_send(struct eth_device *netdev, void *packet, int length) ctrl = length & TXBUF_FRMLEN_MASK; ctrl |= TXBUF_FRAME_END; - if (tx_head == (CONFIG_SYS_MACB_TX_RING_SIZE - 1)) { + if (tx_head == (MACB_TX_RING_SIZE - 1)) { ctrl |= TXBUF_WRAP; macb->tx_head = 0; - } else + } else { macb->tx_head++; + } macb->tx_ring[tx_head].ctrl = ctrl; macb->tx_ring[tx_head].addr = paddr; barrier(); + macb_flush_ring_desc(macb, TX); + /* Do we need check paddr and length is dcache line aligned? */ + flush_dcache_range(paddr, paddr + length); macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE) | MACB_BIT(TSTART)); /* * I guess this is necessary because the networking core may * re-use the transmit buffer as soon as we return... */ - for (i = 0; i <= CONFIG_SYS_MACB_TX_TIMEOUT; i++) { + for (i = 0; i <= MACB_TX_TIMEOUT; i++) { barrier(); + macb_invalidate_ring_desc(macb, TX); ctrl = macb->tx_ring[tx_head].ctrl; if (ctrl & TXBUF_USED) break; @@ -233,7 +275,7 @@ static int macb_send(struct eth_device *netdev, void *packet, int length) dma_unmap_single(packet, length, paddr); - if (i <= CONFIG_SYS_MACB_TX_TIMEOUT) { + if (i <= MACB_TX_TIMEOUT) { if (ctrl & TXBUF_UNDERRUN) printf("%s: TX underrun\n", netdev->name); if (ctrl & TXBUF_EXHAUSTED) @@ -253,10 +295,12 @@ static void reclaim_rx_buffers(struct macb_device *macb, unsigned int i; i = macb->rx_tail; + + macb_invalidate_ring_desc(macb, RX); while (i > new_tail) { macb->rx_ring[i].addr &= ~RXADDR_USED; i++; - if (i > CONFIG_SYS_MACB_RX_RING_SIZE) + if (i > MACB_RX_RING_SIZE) i = 0; } @@ -266,6 +310,7 @@ static void reclaim_rx_buffers(struct macb_device *macb, } barrier(); + macb_flush_ring_desc(macb, RX); macb->rx_tail = new_tail; } @@ -279,6 +324,8 @@ static int macb_recv(struct eth_device *netdev) u32 status; for (;;) { + macb_invalidate_ring_desc(macb, RX); + if (!(macb->rx_ring[rx_tail].addr & RXADDR_USED)) return -1; @@ -292,10 +339,12 @@ static int macb_recv(struct eth_device *netdev) if (status & RXBUF_FRAME_END) { buffer = macb->rx_buffer + 128 * macb->rx_tail; length = status & RXBUF_FRMLEN_MASK; + + macb_invalidate_rx_buffer(macb); if (wrapped) { unsigned int headlen, taillen; - headlen = 128 * (CONFIG_SYS_MACB_RX_RING_SIZE + headlen = 128 * (MACB_RX_RING_SIZE - macb->rx_tail); taillen = length - headlen; memcpy((void *)NetRxPackets[0], @@ -306,11 +355,11 @@ static int macb_recv(struct eth_device *netdev) } NetReceive(buffer, length); - if (++rx_tail >= CONFIG_SYS_MACB_RX_RING_SIZE) + if (++rx_tail >= MACB_RX_RING_SIZE) rx_tail = 0; reclaim_rx_buffers(macb, rx_tail); } else { - if (++rx_tail >= CONFIG_SYS_MACB_RX_RING_SIZE) { + if (++rx_tail >= MACB_RX_RING_SIZE) { wrapped = 1; rx_tail = 0; } @@ -333,7 +382,7 @@ static void macb_phy_reset(struct macb_device *macb) macb_mdio_write(macb, MII_BMCR, (BMCR_ANENABLE | BMCR_ANRESTART)); - for (i = 0; i < CONFIG_SYS_MACB_AUTONEG_TIMEOUT / 100; i++) { + for (i = 0; i < MACB_AUTONEG_TIMEOUT / 100; i++) { status = macb_mdio_read(macb, MII_BMSR); if (status & BMSR_ANEGCOMPLETE) break; @@ -385,9 +434,8 @@ static int macb_phy_init(struct macb_device *macb) arch_get_mdio_control(netdev->name); #ifdef CONFIG_MACB_SEARCH_PHY /* Auto-detect phy_addr */ - if (!macb_phy_find(macb)) { + if (!macb_phy_find(macb)) return 0; - } #endif /* CONFIG_MACB_SEARCH_PHY */ /* Check if the PHY is up to snuff... */ @@ -414,7 +462,7 @@ static int macb_phy_init(struct macb_device *macb) /* Try to re-negotiate if we don't have link already. */ macb_phy_reset(macb); - for (i = 0; i < CONFIG_SYS_MACB_AUTONEG_TIMEOUT / 100; i++) { + for (i = 0; i < MACB_AUTONEG_TIMEOUT / 100; i++) { status = macb_mdio_read(macb, MII_BMSR); if (status & BMSR_LSTATUS) break; @@ -499,21 +547,28 @@ static int macb_init(struct eth_device *netdev, bd_t *bd) /* initialize DMA descriptors */ paddr = macb->rx_buffer_dma; - for (i = 0; i < CONFIG_SYS_MACB_RX_RING_SIZE; i++) { - if (i == (CONFIG_SYS_MACB_RX_RING_SIZE - 1)) + for (i = 0; i < MACB_RX_RING_SIZE; i++) { + if (i == (MACB_RX_RING_SIZE - 1)) paddr |= RXADDR_WRAP; macb->rx_ring[i].addr = paddr; macb->rx_ring[i].ctrl = 0; paddr += 128; } - for (i = 0; i < CONFIG_SYS_MACB_TX_RING_SIZE; i++) { + macb_flush_ring_desc(macb, RX); + macb_flush_rx_buffer(macb); + + for (i = 0; i < MACB_TX_RING_SIZE; i++) { macb->tx_ring[i].addr = 0; - if (i == (CONFIG_SYS_MACB_TX_RING_SIZE - 1)) + if (i == (MACB_TX_RING_SIZE - 1)) macb->tx_ring[i].ctrl = TXBUF_USED | TXBUF_WRAP; else macb->tx_ring[i].ctrl = TXBUF_USED; } - macb->rx_tail = macb->tx_head = macb->tx_tail = 0; + macb_flush_ring_desc(macb, TX); + + macb->rx_tail = 0; + macb->tx_head = 0; + macb->tx_tail = 0; macb_writel(macb, RBQP, macb->rx_ring_dma); macb_writel(macb, TBQP, macb->tx_ring_dma); @@ -654,15 +709,15 @@ int macb_eth_initialize(int id, void *regs, unsigned int phy_addr) netdev = &macb->netdev; - macb->rx_buffer = dma_alloc_coherent(CONFIG_SYS_MACB_RX_BUFFER_SIZE, + macb->rx_buffer = dma_alloc_coherent(MACB_RX_BUFFER_SIZE, &macb->rx_buffer_dma); - macb->rx_ring = dma_alloc_coherent(CONFIG_SYS_MACB_RX_RING_SIZE - * sizeof(struct macb_dma_desc), + macb->rx_ring = dma_alloc_coherent(MACB_RX_DMA_DESC_SIZE, &macb->rx_ring_dma); - macb->tx_ring = dma_alloc_coherent(CONFIG_SYS_MACB_TX_RING_SIZE - * sizeof(struct macb_dma_desc), + macb->tx_ring = dma_alloc_coherent(MACB_TX_DMA_DESC_SIZE, &macb->tx_ring_dma); + /* TODO: we need check the rx/tx_ring_dma is dcache line aligned */ + macb->regs = regs; macb->phy_addr = phy_addr; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 230ed97..aac85c4 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -609,10 +609,8 @@ static struct phy_device *create_phy_by_mask(struct mii_dev *bus, while (phy_mask) { int addr = ffs(phy_mask) - 1; int r = get_phy_id(bus, addr, devad, &phy_id); - if (r < 0) - return ERR_PTR(r); /* If the PHY ID is mostly f's, we didn't find anything */ - if ((phy_id & 0x1fffffff) != 0x1fffffff) + if (r == 0 && (phy_id & 0x1fffffff) != 0x1fffffff) return phy_device_create(bus, addr, phy_id, interface); phy_mask &= ~(1 << addr); } diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 5e132f2..81e8ddb 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -67,7 +67,8 @@ int sh_eth_send(struct eth_device *dev, void *packet, int len) /* packet must be a 4 byte boundary */ if ((int)packet & 3) { - printf(SHETHER_NAME ": %s: packet not 4 byte alligned\n", __func__); + printf(SHETHER_NAME ": %s: packet not 4 byte alligned\n" + , __func__); ret = -EFAULT; goto err; } @@ -148,7 +149,7 @@ int sh_eth_recv(struct eth_device *dev) static int sh_eth_reset(struct sh_eth_dev *eth) { -#if defined(SH_ETH_TYPE_GETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) int ret = 0, i; /* Start e-dmac transmitter and receiver */ @@ -156,7 +157,7 @@ static int sh_eth_reset(struct sh_eth_dev *eth) /* Perform a software reset and wait for it to complete */ sh_eth_write(eth, EDMR_SRST, EDMR); - for (i = 0; i < TIMEOUT_CNT ; i++) { + for (i = 0; i < TIMEOUT_CNT; i++) { if (!(sh_eth_read(eth, EDMR) & EDMR_SRST)) break; udelay(1000); @@ -218,7 +219,7 @@ static int sh_eth_tx_desc_init(struct sh_eth_dev *eth) /* Point the controller to the tx descriptor list. Must use physical addresses */ sh_eth_write(eth, ADDR_TO_PHY(port_info->tx_desc_base), TDLAR); -#if defined(SH_ETH_TYPE_GETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) sh_eth_write(eth, ADDR_TO_PHY(port_info->tx_desc_base), TDFAR); sh_eth_write(eth, ADDR_TO_PHY(cur_tx_desc), TDFXR); sh_eth_write(eth, 0x01, TDFFR);/* Last discriptor bit */ @@ -288,7 +289,7 @@ static int sh_eth_rx_desc_init(struct sh_eth_dev *eth) /* Point the controller to the rx descriptor list */ sh_eth_write(eth, ADDR_TO_PHY(port_info->rx_desc_base), RDLAR); -#if defined(SH_ETH_TYPE_GETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) sh_eth_write(eth, ADDR_TO_PHY(port_info->rx_desc_base), RDFAR); sh_eth_write(eth, ADDR_TO_PHY(cur_rx_desc), RDFXR); sh_eth_write(eth, RDFFR_RDLF, RDFFR); @@ -384,7 +385,7 @@ static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd) sh_eth_write(eth, 0, TFTR); sh_eth_write(eth, (FIFO_SIZE_T | FIFO_SIZE_R), FDR); sh_eth_write(eth, RMCR_RST, RMCR); -#if defined(SH_ETH_TYPE_GETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) sh_eth_write(eth, 0, RPADIR); #endif sh_eth_write(eth, (FIFO_F_D_RFF | FIFO_F_D_RFD), FCFTR); @@ -403,6 +404,8 @@ static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd) sh_eth_write(eth, RFLR_RFL_MIN, RFLR); #if defined(SH_ETH_TYPE_GETHER) sh_eth_write(eth, 0, PIPR); +#endif +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) sh_eth_write(eth, APR_AP, APR); sh_eth_write(eth, MPR_MP, MPR); sh_eth_write(eth, TPAUSER_TPAUSE, TPAUSER); @@ -521,41 +524,41 @@ void sh_eth_halt(struct eth_device *dev) int sh_eth_initialize(bd_t *bd) { - int ret = 0; + int ret = 0; struct sh_eth_dev *eth = NULL; - struct eth_device *dev = NULL; + struct eth_device *dev = NULL; - eth = (struct sh_eth_dev *)malloc(sizeof(struct sh_eth_dev)); + eth = (struct sh_eth_dev *)malloc(sizeof(struct sh_eth_dev)); if (!eth) { printf(SHETHER_NAME ": %s: malloc failed\n", __func__); ret = -ENOMEM; goto err; } - dev = (struct eth_device *)malloc(sizeof(struct eth_device)); + dev = (struct eth_device *)malloc(sizeof(struct eth_device)); if (!dev) { printf(SHETHER_NAME ": %s: malloc failed\n", __func__); ret = -ENOMEM; goto err; } - memset(dev, 0, sizeof(struct eth_device)); - memset(eth, 0, sizeof(struct sh_eth_dev)); + memset(dev, 0, sizeof(struct eth_device)); + memset(eth, 0, sizeof(struct sh_eth_dev)); eth->port = CONFIG_SH_ETHER_USE_PORT; eth->port_info[eth->port].phy_addr = CONFIG_SH_ETHER_PHY_ADDR; - dev->priv = (void *)eth; - dev->iobase = 0; - dev->init = sh_eth_init; - dev->halt = sh_eth_halt; - dev->send = sh_eth_send; - dev->recv = sh_eth_recv; - eth->port_info[eth->port].dev = dev; + dev->priv = (void *)eth; + dev->iobase = 0; + dev->init = sh_eth_init; + dev->halt = sh_eth_halt; + dev->send = sh_eth_send; + dev->recv = sh_eth_recv; + eth->port_info[eth->port].dev = dev; sprintf(dev->name, SHETHER_NAME); - /* Register Device to EtherNet subsystem */ - eth_register(dev); + /* Register Device to EtherNet subsystem */ + eth_register(dev); bb_miiphy_buses[0].priv = eth; miiphy_register(dev->name, bb_miiphy_read, bb_miiphy_write); diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h index 331c07c..d0d9aaa 100644 --- a/drivers/net/sh_eth.h +++ b/drivers/net/sh_eth.h @@ -230,6 +230,61 @@ static const u16 sh_eth_offset_gigabit[SH_ETH_MAX_REGISTER_OFFSET] = { [RMII_MII] = 0x0790, }; +#if defined(SH_ETH_TYPE_RZ) +static const u16 sh_eth_offset_rz[SH_ETH_MAX_REGISTER_OFFSET] = { + [EDSR] = 0x0000, + [EDMR] = 0x0400, + [EDTRR] = 0x0408, + [EDRRR] = 0x0410, + [EESR] = 0x0428, + [EESIPR] = 0x0430, + [TDLAR] = 0x0010, + [TDFAR] = 0x0014, + [TDFXR] = 0x0018, + [TDFFR] = 0x001c, + [RDLAR] = 0x0030, + [RDFAR] = 0x0034, + [RDFXR] = 0x0038, + [RDFFR] = 0x003c, + [TRSCER] = 0x0438, + [RMFCR] = 0x0440, + [TFTR] = 0x0448, + [FDR] = 0x0450, + [RMCR] = 0x0458, + [RPADIR] = 0x0460, + [FCFTR] = 0x0468, + [CSMR] = 0x04E4, + + [ECMR] = 0x0500, + [ECSR] = 0x0510, + [ECSIPR] = 0x0518, + [PSR] = 0x0528, + [PIPR] = 0x052c, + [RFLR] = 0x0508, + [APR] = 0x0554, + [MPR] = 0x0558, + [PFTCR] = 0x055c, + [PFRCR] = 0x0560, + [TPAUSER] = 0x0564, + [GECMR] = 0x05b0, + [BCULR] = 0x05b4, + [MAHR] = 0x05c0, + [MALR] = 0x05c8, + [TROCR] = 0x0700, + [CDCR] = 0x0708, + [LCCR] = 0x0710, + [CEFCR] = 0x0740, + [FRECR] = 0x0748, + [TSFRCR] = 0x0750, + [TLFRCR] = 0x0758, + [RFCR] = 0x0760, + [CERCR] = 0x0768, + [CEECR] = 0x0770, + [MAFCR] = 0x0778, + [RMII_MII] = 0x0790, +}; +#endif + static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = { [ECMR] = 0x0100, [RFLR] = 0x0108, @@ -306,13 +361,16 @@ static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = { #elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791) #define SH_ETH_TYPE_ETHER #define BASE_IO_ADDR 0xEE700200 +#elif defined(CONFIG_R7S72100) +#define SH_ETH_TYPE_RZ +#define BASE_IO_ADDR 0xE8203000 #endif /* * Register's bits * Copy from Linux driver source code */ -#if defined(SH_ETH_TYPE_GETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) /* EDSR */ enum EDSR_BIT { EDSR_ENT = 0x01, EDSR_ENR = 0x02, @@ -323,7 +381,7 @@ enum EDSR_BIT { /* EDMR */ enum DMAC_M_BIT { EDMR_DL1 = 0x20, EDMR_DL0 = 0x10, -#if defined(SH_ETH_TYPE_GETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) EDMR_SRST = 0x03, /* Receive/Send reset */ EMDR_DESC_R = 0x30, /* Descriptor reserve size */ EDMR_EL = 0x40, /* Litte endian */ @@ -349,7 +407,7 @@ enum DMAC_M_BIT { /* EDTRR */ enum DMAC_T_BIT { -#if defined(SH_ETH_TYPE_GETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) EDTRR_TRNS = 0x03, #else EDTRR_TRNS = 0x01, @@ -394,7 +452,6 @@ enum PHY_STATUS_BIT { PHY_ST_LINK = 0x01, }; /* EESR */ enum EESR_BIT { - #if defined(SH_ETH_TYPE_ETHER) EESR_TWB = 0x40000000, #else @@ -419,12 +476,12 @@ enum EESR_BIT { EESR_CD = 0x00000200, EESR_RTO = 0x00000100, EESR_RMAF = 0x00000080, EESR_CEEF = 0x00000040, EESR_CELF = 0x00000020, EESR_RRF = 0x00000010, - rESR_RTLF = 0x00000008, EESR_RTSF = 0x00000004, + EESR_RTLF = 0x00000008, EESR_RTSF = 0x00000004, EESR_PRE = 0x00000002, EESR_CERF = 0x00000001, }; -#if defined(SH_ETH_TYPE_GETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) # define TX_CHECK (EESR_TC1 | EESR_FTC) # define EESR_ERR_CHECK (EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE \ | EESR_RFRMER | EESR_TFE | EESR_TDE | EESR_ECI) @@ -484,7 +541,8 @@ enum FCFTR_BIT { /* Transfer descriptor bit */ enum TD_STS_BIT { -#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_ETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_ETHER) || \ + defined(SH_ETH_TYPE_RZ) TD_TACT = 0x80000000, #else TD_TACT = 0x7fffffff, @@ -500,9 +558,9 @@ enum TD_STS_BIT { enum RECV_RST_BIT { RMCR_RST = 0x01, }; /* ECMR */ enum FELIC_MODE_BIT { -#if defined(SH_ETH_TYPE_GETHER) - ECMR_TRCCM=0x04000000, ECMR_RCSC= 0x00800000, ECMR_DPAD= 0x00200000, - ECMR_RZPF = 0x00100000, +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) + ECMR_TRCCM = 0x04000000, ECMR_RCSC = 0x00800000, + ECMR_DPAD = 0x00200000, ECMR_RZPF = 0x00100000, #endif ECMR_ZPF = 0x00080000, ECMR_PFR = 0x00040000, ECMR_RXF = 0x00020000, ECMR_TXF = 0x00010000, ECMR_MCT = 0x00002000, ECMR_PRCEF = 0x00001000, @@ -517,9 +575,9 @@ enum FELIC_MODE_BIT { }; -#if defined(SH_ETH_TYPE_GETHER) -#define ECMR_CHG_DM (ECMR_TRCCM | ECMR_RZPF | ECMR_ZPF | ECMR_PFR | ECMR_RXF | \ - ECMR_TXF | ECMR_MCT) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) +#define ECMR_CHG_DM (ECMR_TRCCM | ECMR_RZPF | ECMR_ZPF | ECMR_PFR | \ + ECMR_RXF | ECMR_TXF | ECMR_MCT) #elif defined(SH_ETH_TYPE_ETHER) #define ECMR_CHG_DM (ECMR_ZPF | ECMR_PFR | ECMR_RXF | ECMR_TXF) #else @@ -535,7 +593,7 @@ enum ECSR_STATUS_BIT { ECSR_MPD = 0x02, ECSR_ICD = 0x01, }; -#if defined(SH_ETH_TYPE_GETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) # define ECSR_INIT (ECSR_ICD | ECSIPR_MPDIP) #else # define ECSR_INIT (ECSR_BRCRX | ECSR_PSRTO | \ @@ -556,7 +614,7 @@ enum ECSIPR_STATUS_MASK_BIT { ECSIPR_ICDIP = 0x01, }; -#if defined(SH_ETH_TYPE_GETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) # define ECSIPR_INIT (ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP) #else # define ECSIPR_INIT (ECSIPR_BRCRXIP | ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | \ @@ -587,7 +645,7 @@ enum RPADIR_BIT { RPADIR_PADR = 0x0003f, }; -#if defined(SH_ETH_TYPE_GETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) # define RPADIR_INIT (0x00) #else # define RPADIR_INIT (RPADIR_PADS1) @@ -605,6 +663,8 @@ static inline unsigned long sh_eth_reg_addr(struct sh_eth_dev *eth, const u16 *reg_offset = sh_eth_offset_gigabit; #elif defined(SH_ETH_TYPE_ETHER) const u16 *reg_offset = sh_eth_offset_fast_sh4; +#elif defined(SH_ETH_TYPE_RZ) + const u16 *reg_offset = sh_eth_offset_rz; #else #error #endif diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index ae3cafb..91821f4 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -7,7 +7,6 @@ obj-$(CONFIG_I82365) += i82365.o obj-$(CONFIG_8xx) += mpc8xx_pcmcia.o -obj-y += rpx_pcmcia.o obj-$(CONFIG_IDE_TI_CARDBUS) += ti_pci1410a.o obj-y += tqm8xx_pcmcia.o obj-$(CONFIG_MARUBUN_PCCARD) += marubun_pcmcia.o diff --git a/drivers/pcmcia/mpc8xx_pcmcia.c b/drivers/pcmcia/mpc8xx_pcmcia.c index 6638277..af77426 100644 --- a/drivers/pcmcia/mpc8xx_pcmcia.c +++ b/drivers/pcmcia/mpc8xx_pcmcia.c @@ -211,16 +211,6 @@ static u_int m8xx_get_graycode(u_int size) #if 0 -#if defined(CONFIG_RPXLITE) - -/* The RPX boards seems to have it's bus monitor timeout set to 6*8 clocks. - * SYPCR is write once only, therefore must the slowest memory be faster - * than the bus monitor or we will get a machine check due to the bus timeout. - */ -#undef PCMCIA_BMT_LIMIT -#define PCMCIA_BMT_LIMIT (6*8) -#endif - static u_int m8xx_get_speed(u_int ns, u_int is_io) { u_int reg, clocks, psst, psl, psht; diff --git a/drivers/pcmcia/rpx_pcmcia.c b/drivers/pcmcia/rpx_pcmcia.c deleted file mode 100644 index 5b24f0b..0000000 --- a/drivers/pcmcia/rpx_pcmcia.c +++ /dev/null @@ -1,73 +0,0 @@ -/* -------------------------------------------------------------------- */ -/* RPX Boards from Embedded Planet */ -/* -------------------------------------------------------------------- */ -#include <common.h> -#ifdef CONFIG_8xx -#include <mpc8xx.h> -#endif -#include <pcmcia.h> - -#undef CONFIG_PCMCIA - -#if defined(CONFIG_CMD_PCMCIA) -#define CONFIG_PCMCIA -#endif - -#if defined(CONFIG_CMD_IDE) && defined(CONFIG_IDE_8xx_PCCARD) -#define CONFIG_PCMCIA -#endif - -#if defined(CONFIG_PCMCIA) \ - && defined(CONFIG_RPXLITE) - -#define PCMCIA_BOARD_MSG "RPX CLASSIC or RPX LITE" - -int pcmcia_voltage_set(int slot, int vcc, int vpp) -{ - u_long reg = 0; - - switch(vcc) { - case 0: break; - case 33: reg |= BCSR1_PCVCTL4; break; - case 50: reg |= BCSR1_PCVCTL5; break; - default: return 1; - } - - switch(vpp) { - case 0: break; - case 33: - case 50: - if(vcc == vpp) - reg |= BCSR1_PCVCTL6; - else - return 1; - break; - case 120: - reg |= BCSR1_PCVCTL7; - default: return 1; - } - - /* first, turn off all power */ - *((uint *)RPX_CSR_ADDR) &= ~(BCSR1_PCVCTL4 | BCSR1_PCVCTL5 - | BCSR1_PCVCTL6 | BCSR1_PCVCTL7); - - /* enable new powersettings */ - *((uint *)RPX_CSR_ADDR) |= reg; - - return 0; -} - -int pcmcia_hardware_enable (int slot) -{ - return 0; /* No hardware to enable */ -} - -#if defined(CONFIG_CMD_PCMCIA) -static int pcmcia_hardware_disable(int slot) -{ - return 0; /* No hardware to disable */ -} -#endif - - -#endif /* CONFIG_PCMCIA && CONFIG_RPXLITE */ diff --git a/drivers/power/battery/bat_trats.c b/drivers/power/battery/bat_trats.c index 41b179f..bfde692 100644 --- a/drivers/power/battery/bat_trats.c +++ b/drivers/power/battery/bat_trats.c @@ -19,7 +19,7 @@ static int power_battery_charge(struct pmic *bat) struct battery *battery = p_bat->bat; int k; - if (bat->chrg->chrg_state(p_bat->chrg, CHARGER_ENABLE, 450)) + if (bat->chrg->chrg_state(p_bat->chrg, PMIC_CHARGER_ENABLE, 450)) return -1; for (k = 0; bat->chrg->chrg_bat_present(p_bat->chrg) && @@ -42,7 +42,7 @@ static int power_battery_charge(struct pmic *bat) } } exit: - bat->chrg->chrg_state(p_bat->chrg, CHARGER_DISABLE, 0); + bat->chrg->chrg_state(p_bat->chrg, PMIC_CHARGER_DISABLE, 0); return 0; } diff --git a/drivers/power/battery/bat_trats2.c b/drivers/power/battery/bat_trats2.c index 94015aa..57221ad 100644 --- a/drivers/power/battery/bat_trats2.c +++ b/drivers/power/battery/bat_trats2.c @@ -17,7 +17,7 @@ static int power_battery_charge(struct pmic *bat) { struct power_battery *p_bat = bat->pbat; - if (bat->chrg->chrg_state(p_bat->chrg, CHARGER_ENABLE, 450)) + if (bat->chrg->chrg_state(p_bat->chrg, PMIC_CHARGER_ENABLE, 450)) return -1; return 0; diff --git a/drivers/power/mfd/pmic_max77693.c b/drivers/power/mfd/pmic_max77693.c index 1a4416b..6b28e28 100644 --- a/drivers/power/mfd/pmic_max77693.c +++ b/drivers/power/mfd/pmic_max77693.c @@ -22,7 +22,7 @@ static int max77693_charger_state(struct pmic *p, int state, int current) val = MAX77693_CHG_UNLOCK; pmic_reg_write(p, MAX77693_CHG_CNFG_06, val); - if (state == CHARGER_DISABLE) { + if (state == PMIC_CHARGER_DISABLE) { puts("Disable the charger.\n"); pmic_reg_read(p, MAX77693_CHG_CNFG_00, &val); val &= ~0x01; diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 920bbdc..a472f61 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -11,5 +11,7 @@ obj-$(CONFIG_POWER_MAX8997) += pmic_max8997.o obj-$(CONFIG_POWER_MUIC_MAX8997) += muic_max8997.o obj-$(CONFIG_POWER_MAX77686) += pmic_max77686.o obj-$(CONFIG_POWER_PFUZE100) += pmic_pfuze100.o +obj-$(CONFIG_POWER_TPS65090) += pmic_tps65090.o obj-$(CONFIG_POWER_TPS65217) += pmic_tps65217.o +obj-$(CONFIG_POWER_TPS65218) += pmic_tps65218.o obj-$(CONFIG_POWER_TPS65910) += pmic_tps65910.o diff --git a/drivers/power/pmic/pmic_max77686.c b/drivers/power/pmic/pmic_max77686.c index d4c430e..df1fd91 100644 --- a/drivers/power/pmic/pmic_max77686.c +++ b/drivers/power/pmic/pmic_max77686.c @@ -210,6 +210,10 @@ int pmic_init(unsigned char bus) { static const char name[] = "MAX77686_PMIC"; struct pmic *p = pmic_alloc(); +#ifdef CONFIG_OF_CONTROL + const void *blob = gd->fdt_blob; + int node, parent, tmp; +#endif if (!p) { printf("%s: POWER allocation error!\n", __func__); @@ -217,9 +221,6 @@ int pmic_init(unsigned char bus) } #ifdef CONFIG_OF_CONTROL - const void *blob = gd->fdt_blob; - int node, parent; - node = fdtdec_next_compatible(blob, 0, COMPAT_MAXIM_MAX77686_PMIC); if (node < 0) { debug("PMIC: No node for PMIC Chip in device tree\n"); @@ -233,11 +234,13 @@ int pmic_init(unsigned char bus) return -1; } - p->bus = i2c_get_bus_num_fdt(parent); - if (p->bus < 0) { + /* tmp since p->bus is unsigned */ + tmp = i2c_get_bus_num_fdt(parent); + if (tmp < 0) { debug("%s: Cannot find I2C bus\n", __func__); return -1; } + p->bus = tmp; p->hw.i2c.addr = fdtdec_get_int(blob, node, "reg", 9); #else p->bus = bus; diff --git a/drivers/power/pmic/pmic_max8997.c b/drivers/power/pmic/pmic_max8997.c index ba01692..a36a9a0 100644 --- a/drivers/power/pmic/pmic_max8997.c +++ b/drivers/power/pmic/pmic_max8997.c @@ -35,7 +35,7 @@ static int pmic_charger_state(struct pmic *p, int state, int current) if (pmic_probe(p)) return -1; - if (state == CHARGER_DISABLE) { + if (state == PMIC_CHARGER_DISABLE) { puts("Disable the charger.\n"); pmic_reg_read(p, MAX8997_REG_MBCCTRL2, &val); val &= ~(MBCHOSTEN | VCHGR_FC); diff --git a/drivers/power/pmic/pmic_tps65090.c b/drivers/power/pmic/pmic_tps65090.c new file mode 100644 index 0000000..337903a --- /dev/null +++ b/drivers/power/pmic/pmic_tps65090.c @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <errno.h> +#include <fdtdec.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/tps65090_pmic.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define TPS65090_NAME "TPS65090_PMIC" + +/* TPS65090 register addresses */ +enum { + REG_IRQ1 = 0, + REG_CG_CTRL0 = 4, + REG_CG_STATUS1 = 0xa, + REG_FET1_CTRL = 0x0f, + REG_FET2_CTRL, + REG_FET3_CTRL, + REG_FET4_CTRL, + REG_FET5_CTRL, + REG_FET6_CTRL, + REG_FET7_CTRL, + TPS65090_NUM_REGS, +}; + +enum { + IRQ1_VBATG = 1 << 3, + CG_CTRL0_ENC_MASK = 0x01, + + MAX_FET_NUM = 7, + MAX_CTRL_READ_TRIES = 5, + + /* TPS65090 FET_CTRL register values */ + FET_CTRL_TOFET = 1 << 7, /* Timeout, startup, overload */ + FET_CTRL_PGFET = 1 << 4, /* Power good for FET status */ + FET_CTRL_WAIT = 3 << 2, /* Overcurrent timeout max */ + FET_CTRL_ADENFET = 1 << 1, /* Enable output auto discharge */ + FET_CTRL_ENFET = 1 << 0, /* Enable FET */ +}; + +/** + * Checks for a valid FET number + * + * @param fet_id FET number to check + * @return 0 if ok, -EINVAL if FET value is out of range + */ +static int tps65090_check_fet(unsigned int fet_id) +{ + if (fet_id == 0 || fet_id > MAX_FET_NUM) { + debug("parameter fet_id is out of range, %u not in 1 ~ %u\n", + fet_id, MAX_FET_NUM); + return -EINVAL; + } + + return 0; +} + +/** + * Set the power state for a FET + * + * @param pmic pmic structure for the tps65090 + * @param fet_id Fet number to set (1..MAX_FET_NUM) + * @param set 1 to power on FET, 0 to power off + * @return -EIO if we got a comms error, -EAGAIN if the FET failed to + * change state. If all is ok, returns 0. + */ +static int tps65090_fet_set(struct pmic *pmic, int fet_id, bool set) +{ + int retry; + u32 reg, value; + + value = FET_CTRL_ADENFET | FET_CTRL_WAIT; + if (set) + value |= FET_CTRL_ENFET; + + if (pmic_reg_write(pmic, REG_FET1_CTRL + fet_id - 1, value)) + return -EIO; + + /* Try reading until we get a result */ + for (retry = 0; retry < MAX_CTRL_READ_TRIES; retry++) { + if (pmic_reg_read(pmic, REG_FET1_CTRL + fet_id - 1, ®)) + return -EIO; + + /* Check that the fet went into the expected state */ + if (!!(reg & FET_CTRL_PGFET) == set) + return 0; + + /* If we got a timeout, there is no point in waiting longer */ + if (reg & FET_CTRL_TOFET) + break; + + mdelay(1); + } + + debug("FET %d: Power good should have set to %d but reg=%#02x\n", + fet_id, set, reg); + return -EAGAIN; +} + +int tps65090_fet_enable(unsigned int fet_id) +{ + struct pmic *pmic; + ulong start; + int loops; + int ret; + + ret = tps65090_check_fet(fet_id); + if (ret) + return ret; + + pmic = pmic_get(TPS65090_NAME); + if (!pmic) + return -EACCES; + + start = get_timer(0); + for (loops = 0;; loops++) { + ret = tps65090_fet_set(pmic, fet_id, true); + if (!ret) + break; + + if (get_timer(start) > 100) + break; + + /* Turn it off and try again until we time out */ + tps65090_fet_set(pmic, fet_id, false); + } + + if (ret) + debug("%s: FET%d failed to power on: time=%lums, loops=%d\n", + __func__, fet_id, get_timer(start), loops); + else if (loops) + debug("%s: FET%d powered on after %lums, loops=%d\n", + __func__, fet_id, get_timer(start), loops); + + /* + * Unfortunately, there are some conditions where the power + * good bit will be 0, but the fet still comes up. One such + * case occurs with the lcd backlight. We'll just return 0 here + * and assume that the fet will eventually come up. + */ + if (ret == -EAGAIN) + ret = 0; + + return ret; +} + +int tps65090_fet_disable(unsigned int fet_id) +{ + struct pmic *pmic; + int ret; + + ret = tps65090_check_fet(fet_id); + if (ret) + return ret; + + pmic = pmic_get(TPS65090_NAME); + if (!pmic) + return -EACCES; + ret = tps65090_fet_set(pmic, fet_id, false); + + return ret; +} + +int tps65090_fet_is_enabled(unsigned int fet_id) +{ + struct pmic *pmic; + u32 reg; + int ret; + + ret = tps65090_check_fet(fet_id); + if (ret) + return ret; + + pmic = pmic_get(TPS65090_NAME); + if (!pmic) + return -ENODEV; + ret = pmic_reg_read(pmic, REG_FET1_CTRL + fet_id - 1, ®); + if (ret) { + debug("fail to read FET%u_CTRL register over I2C", fet_id); + return -EIO; + } + + return reg & FET_CTRL_ENFET; +} + +int tps65090_get_charging(void) +{ + struct pmic *pmic; + u32 val; + int ret; + + pmic = pmic_get(TPS65090_NAME); + if (!pmic) + return -EACCES; + + ret = pmic_reg_read(pmic, REG_CG_CTRL0, &val); + if (ret) + return ret; + + return !!(val & CG_CTRL0_ENC_MASK); +} + +static int tps65090_charger_state(struct pmic *pmic, int state, + int current) +{ + u32 val; + int ret; + + ret = pmic_reg_read(pmic, REG_CG_CTRL0, &val); + if (!ret) { + if (state == PMIC_CHARGER_ENABLE) + val |= CG_CTRL0_ENC_MASK; + else + val &= ~CG_CTRL0_ENC_MASK; + ret = pmic_reg_write(pmic, REG_CG_CTRL0, val); + } + if (ret) { + debug("%s: Failed to read/write register\n", __func__); + return ret; + } + + return 0; +} + +int tps65090_get_status(void) +{ + struct pmic *pmic; + u32 val; + int ret; + + pmic = pmic_get(TPS65090_NAME); + if (!pmic) + return -EACCES; + + ret = pmic_reg_read(pmic, REG_CG_STATUS1, &val); + if (ret) + return ret; + + return val; +} + +static int tps65090_charger_bat_present(struct pmic *pmic) +{ + u32 val; + int ret; + + ret = pmic_reg_read(pmic, REG_IRQ1, &val); + if (ret) + return ret; + + return !!(val & IRQ1_VBATG); +} + +static struct power_chrg power_chrg_pmic_ops = { + .chrg_bat_present = tps65090_charger_bat_present, + .chrg_state = tps65090_charger_state, +}; + +int tps65090_init(void) +{ + struct pmic *p; + int bus; + int addr; + const void *blob = gd->fdt_blob; + int node, parent; + + node = fdtdec_next_compatible(blob, 0, COMPAT_TI_TPS65090); + if (node < 0) { + debug("PMIC: No node for PMIC Chip in device tree\n"); + debug("node = %d\n", node); + return -ENODEV; + } + + parent = fdt_parent_offset(blob, node); + if (parent < 0) { + debug("%s: Cannot find node parent\n", __func__); + return -EINVAL; + } + + bus = i2c_get_bus_num_fdt(parent); + if (bus < 0) { + debug("%s: Cannot find I2C bus\n", __func__); + return -ENOENT; + } + addr = fdtdec_get_int(blob, node, "reg", TPS65090_I2C_ADDR); + p = pmic_alloc(); + if (!p) { + printf("%s: POWER allocation error!\n", __func__); + return -ENOMEM; + } + + p->name = TPS65090_NAME; + p->bus = bus; + p->interface = PMIC_I2C; + p->number_of_regs = TPS65090_NUM_REGS; + p->hw.i2c.addr = addr; + p->hw.i2c.tx_num = 1; + p->chrg = &power_chrg_pmic_ops; + + puts("TPS65090 PMIC init\n"); + + return 0; +} diff --git a/drivers/power/pmic/pmic_tps65218.c b/drivers/power/pmic/pmic_tps65218.c new file mode 100644 index 0000000..0952456 --- /dev/null +++ b/drivers/power/pmic/pmic_tps65218.c @@ -0,0 +1,97 @@ +/* + * (C) Copyright 2011-2013 + * Texas Instruments, <www.ti.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <i2c.h> +#include <power/tps65218.h> + +/** + * tps65218_reg_write() - Generic function that can write a TPS65218 PMIC + * register or bit field regardless of protection + * level. + * + * @prot_level: Register password protection. Use + * TPS65218_PROT_LEVEL_NONE, + * TPS65218_PROT_LEVEL_1 or TPS65218_PROT_LEVEL_2 + * @dest_reg: Register address to write. + * @dest_val: Value to write. + * @mask: Bit mask (8 bits) to be applied. Function will only + * change bits that are set in the bit mask. + * + * @return: 0 for success, not 0 on failure, as per the i2c API + */ +int tps65218_reg_write(uchar prot_level, uchar dest_reg, uchar dest_val, + uchar mask) +{ + uchar read_val; + uchar xor_reg; + int ret; + + /* + * If we are affecting only a bit field, read dest_reg and apply the + * mask + */ + if (mask != TPS65218_MASK_ALL_BITS) { + ret = i2c_read(TPS65218_CHIP_PM, dest_reg, 1, &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 = i2c_write(TPS65218_CHIP_PM, TPS65218_PASSWORD, 1, + &xor_reg, 1); + if (ret) + return ret; + } + + ret = i2c_write(TPS65218_CHIP_PM, dest_reg, 1, &dest_val, 1); + if (ret) + return ret; + + if (prot_level == TPS65218_PROT_LEVEL_2) { + ret = i2c_write(TPS65218_CHIP_PM, TPS65218_PASSWORD, 1, + &xor_reg, 1); + if (ret) + return ret; + + ret = i2c_write(TPS65218_CHIP_PM, dest_reg, 1, &dest_val, 1); + if (ret) + return ret; + } + + return 0; +} + +/** + * tps65218_voltage_update() - Function to change a voltage level, as this + * is a multi-step process. + * @dc_cntrl_reg: DC voltage control register to change. + * @volt_sel: New value for the voltage register + * @return: 0 for success, not 0 on failure. + */ +int tps65218_voltage_update(uchar dc_cntrl_reg, uchar volt_sel) +{ + if ((dc_cntrl_reg != TPS65218_DCDC1) && + (dc_cntrl_reg != TPS65218_DCDC2)) + return 1; + + /* set voltage level */ + if (tps65218_reg_write(TPS65218_PROT_LEVEL_2, dc_cntrl_reg, volt_sel, + TPS65218_MASK_ALL_BITS)) + return 1; + + /* set GO bit to initiate voltage transition */ + if (tps65218_reg_write(TPS65218_PROT_LEVEL_2, TPS65218_SLEW, + TPS65218_DCDC_GO, TPS65218_DCDC_GO)) + return 1; + + return 0; +} diff --git a/drivers/power/power_fsl.c b/drivers/power/power_fsl.c index ac0b541..a64161b 100644 --- a/drivers/power/power_fsl.c +++ b/drivers/power/power_fsl.c @@ -11,9 +11,9 @@ #include <fsl_pmic.h> #include <errno.h> -#if defined(CONFIG_PMIC_FSL_MC13892) +#if defined(CONFIG_POWER_FSL_MC13892) #define FSL_PMIC_I2C_LENGTH 3 -#elif defined(CONFIG_PMIC_FSL_MC34704) +#elif defined(CONFIG_POWER_FSL_MC34704) #define FSL_PMIC_I2C_LENGTH 1 #endif @@ -51,7 +51,7 @@ int pmic_init(unsigned char bus) p->hw.i2c.addr = CONFIG_SYS_FSL_PMIC_I2C_ADDR; p->hw.i2c.tx_num = FSL_PMIC_I2C_LENGTH; #else -#error "You must select CONFIG_POWER_SPI or CONFIG_PMIC_I2C" +#error "You must select CONFIG_POWER_SPI or CONFIG_POWER_I2C" #endif return 0; diff --git a/drivers/power/power_i2c.c b/drivers/power/power_i2c.c index ac76870..594cd11 100644 --- a/drivers/power/power_i2c.c +++ b/drivers/power/power_i2c.c @@ -23,6 +23,8 @@ int pmic_reg_write(struct pmic *p, u32 reg, u32 val) if (check_reg(p, reg)) return -1; + I2C_SET_BUS(p->bus); + switch (pmic_i2c_tx_num) { case 3: if (p->sensor_byte_order == PMIC_SENSOR_BYTE_ORDER_BIG) { @@ -66,6 +68,8 @@ int pmic_reg_read(struct pmic *p, u32 reg, u32 *val) if (check_reg(p, reg)) return -1; + I2C_SET_BUS(p->bus); + if (i2c_read(pmic_i2c_addr, reg, 1, buf, pmic_i2c_tx_num)) return -1; diff --git a/drivers/sound/sandbox.c b/drivers/sound/sandbox.c index fe5c9e9..5599bb9 100644 --- a/drivers/sound/sandbox.c +++ b/drivers/sound/sandbox.c @@ -5,7 +5,7 @@ */ #include <common.h> -#include <asm/arch/sound.h> +#include <asm/sound.h> #include <asm/sdl.h> int sound_play(uint32_t msec, uint32_t frequency) diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 81b6af6..f02c35a 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -8,6 +8,7 @@ # There are many options which enable SPI, so make this library available obj-y += spi.o +obj-$(CONFIG_EP93XX_SPI) += ep93xx_spi.o obj-$(CONFIG_ALTERA_SPI) += altera_spi.o obj-$(CONFIG_ANDES_SPI) += andes_spi.o obj-$(CONFIG_ARMADA100_SPI) += armada100_spi.o @@ -40,3 +41,4 @@ obj-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o obj-$(CONFIG_TI_QSPI) += ti_qspi.o obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o obj-$(CONFIG_ZYNQ_SPI) += zynq_spi.o +obj-$(CONFIG_FSL_QSPI) += fsl_qspi.o diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index 28fb3a2..0ec5b9d 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -41,7 +41,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, break; #ifdef CONFIG_SYS_SPI1 case SPI1_BUS: - ds->regs = (struct davinci_spi_regs *)SPI0_BASE; + ds->regs = (struct davinci_spi_regs *)SPI1_BASE; break; #endif #ifdef CONFIG_SYS_SPI2 diff --git a/drivers/spi/ep93xx_spi.c b/drivers/spi/ep93xx_spi.c new file mode 100644 index 0000000..235557e --- /dev/null +++ b/drivers/spi/ep93xx_spi.c @@ -0,0 +1,274 @@ +/* + * SPI Driver for EP93xx + * + * Copyright (C) 2013 Sergey Kostanabev <sergey.kostanbaev <at> fairwaves.ru> + * + * Inspired form linux kernel driver and atmel uboot driver + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <spi.h> +#include <malloc.h> + +#include <asm/io.h> + +#include <asm/arch/ep93xx.h> + + +#define BIT(x) (1<<(x)) +#define SSPBASE SPI_BASE + +#define SSPCR0 0x0000 +#define SSPCR0_MODE_SHIFT 6 +#define SSPCR0_SCR_SHIFT 8 +#define SSPCR0_SPH BIT(7) +#define SSPCR0_SPO BIT(6) +#define SSPCR0_FRF_SPI 0 +#define SSPCR0_DSS_8BIT 7 + +#define SSPCR1 0x0004 +#define SSPCR1_RIE BIT(0) +#define SSPCR1_TIE BIT(1) +#define SSPCR1_RORIE BIT(2) +#define SSPCR1_LBM BIT(3) +#define SSPCR1_SSE BIT(4) +#define SSPCR1_MS BIT(5) +#define SSPCR1_SOD BIT(6) + +#define SSPDR 0x0008 + +#define SSPSR 0x000c +#define SSPSR_TFE BIT(0) +#define SSPSR_TNF BIT(1) +#define SSPSR_RNE BIT(2) +#define SSPSR_RFF BIT(3) +#define SSPSR_BSY BIT(4) +#define SSPCPSR 0x0010 + +#define SSPIIR 0x0014 +#define SSPIIR_RIS BIT(0) +#define SSPIIR_TIS BIT(1) +#define SSPIIR_RORIS BIT(2) +#define SSPICR SSPIIR + +#define SSPCLOCK 14745600 +#define SSP_MAX_RATE (SSPCLOCK / 2) +#define SSP_MIN_RATE (SSPCLOCK / (254 * 256)) + +/* timeout in milliseconds */ +#define SPI_TIMEOUT 5 +/* maximum depth of RX/TX FIFO */ +#define SPI_FIFO_SIZE 8 + +struct ep93xx_spi_slave { + struct spi_slave slave; + + unsigned sspcr0; + unsigned sspcpsr; +}; + +static inline struct ep93xx_spi_slave *to_ep93xx_spi(struct spi_slave *slave) +{ + return container_of(slave, struct ep93xx_spi_slave, slave); +} + +void spi_init() +{ +} + +static inline void ep93xx_spi_write_u8(u16 reg, u8 value) +{ + writel(value, (unsigned int *)(SSPBASE + reg)); +} + +static inline u8 ep93xx_spi_read_u8(u16 reg) +{ + return readl((unsigned int *)(SSPBASE + reg)); +} + +static inline void ep93xx_spi_write_u16(u16 reg, u16 value) +{ + writel(value, (unsigned int *)(SSPBASE + reg)); +} + +static inline u16 ep93xx_spi_read_u16(u16 reg) +{ + return (u16)readl((unsigned int *)(SSPBASE + reg)); +} + +static int ep93xx_spi_init_hw(unsigned int rate, unsigned int mode, + struct ep93xx_spi_slave *slave) +{ + unsigned cpsr, scr; + + if (rate > SSP_MAX_RATE) + rate = SSP_MAX_RATE; + + if (rate < SSP_MIN_RATE) + return -1; + + /* Calculate divisors so that we can get speed according the + * following formula: + * rate = spi_clock_rate / (cpsr * (1 + scr)) + * + * cpsr must be even number and starts from 2, scr can be any number + * between 0 and 255. + */ + for (cpsr = 2; cpsr <= 254; cpsr += 2) { + for (scr = 0; scr <= 255; scr++) { + if ((SSPCLOCK / (cpsr * (scr + 1))) <= rate) { + /* Set CHPA and CPOL, SPI format and 8bit */ + unsigned sspcr0 = (scr << SSPCR0_SCR_SHIFT) | + SSPCR0_FRF_SPI | SSPCR0_DSS_8BIT; + if (mode & SPI_CPHA) + sspcr0 |= SSPCR0_SPH; + if (mode & SPI_CPOL) + sspcr0 |= SSPCR0_SPO; + + slave->sspcr0 = sspcr0; + slave->sspcpsr = cpsr; + return 0; + } + } + } + + return -1; +} + +void spi_set_speed(struct spi_slave *slave, unsigned int hz) +{ + struct ep93xx_spi_slave *as = to_ep93xx_spi(slave); + + unsigned int mode = 0; + if (as->sspcr0 & SSPCR0_SPH) + mode |= SPI_CPHA; + if (as->sspcr0 & SSPCR0_SPO) + mode |= SPI_CPOL; + + ep93xx_spi_init_hw(hz, mode, as); +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct ep93xx_spi_slave *as; + + if (!spi_cs_is_valid(bus, cs)) + return NULL; + + as = spi_alloc_slave(struct ep93xx_spi_slave, bus, cs); + if (!as) + return NULL; + + if (ep93xx_spi_init_hw(max_hz, mode, as)) { + free(as); + return NULL; + } + + return &as->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + struct ep93xx_spi_slave *as = to_ep93xx_spi(slave); + + free(as); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + struct ep93xx_spi_slave *as = to_ep93xx_spi(slave); + + /* Enable the SPI hardware */ + ep93xx_spi_write_u8(SSPCR1, SSPCR1_SSE); + + + ep93xx_spi_write_u8(SSPCPSR, as->sspcpsr); + ep93xx_spi_write_u16(SSPCR0, as->sspcr0); + + debug("Select CS:%d SSPCPSR=%02x SSPCR0=%04x\n", + slave->cs, as->sspcpsr, as->sspcr0); + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + /* Disable the SPI hardware */ + ep93xx_spi_write_u8(SSPCR1, 0); +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + unsigned int len_tx; + unsigned int len_rx; + unsigned int len; + u32 status; + const u8 *txp = dout; + u8 *rxp = din; + u8 value; + + debug("spi_xfer: slave %u:%u dout %p din %p bitlen %u\n", + slave->bus, slave->cs, (uint *)dout, (uint *)din, bitlen); + + + if (bitlen == 0) + /* Finish any previously submitted transfers */ + goto out; + + if (bitlen % 8) { + /* Errors always terminate an ongoing transfer */ + flags |= SPI_XFER_END; + goto out; + } + + len = bitlen / 8; + + + if (flags & SPI_XFER_BEGIN) { + /* Empty RX FIFO */ + while ((ep93xx_spi_read_u8(SSPSR) & SSPSR_RNE)) + ep93xx_spi_read_u8(SSPDR); + + spi_cs_activate(slave); + } + + for (len_tx = 0, len_rx = 0; len_rx < len; ) { + status = ep93xx_spi_read_u8(SSPSR); + + if ((len_tx < len) && (status & SSPSR_TNF)) { + if (txp) + value = *txp++; + else + value = 0xff; + + ep93xx_spi_write_u8(SSPDR, value); + len_tx++; + } + + if (status & SSPSR_RNE) { + value = ep93xx_spi_read_u8(SSPDR); + + if (rxp) + *rxp++ = value; + len_rx++; + } + } + +out: + if (flags & SPI_XFER_END) { + /* + * Wait until the transfer is completely done before + * we deactivate CS. + */ + do { + status = ep93xx_spi_read_u8(SSPSR); + } while (status & SSPSR_BSY); + + spi_cs_deactivate(slave); + } + + return 0; +} diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c index 4d5def2..c92276f 100644 --- a/drivers/spi/exynos_spi.c +++ b/drivers/spi/exynos_spi.c @@ -302,7 +302,10 @@ static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo, } } else { if (rxp || stopping) { - *rxp = temp; + if (step == 4) + *(uint32_t *)rxp = temp; + else + *rxp = temp; rxp += step; } in_bytes -= step; diff --git a/drivers/spi/fsl_espi.c b/drivers/spi/fsl_espi.c index 7c84582..ae0fe58 100644 --- a/drivers/spi/fsl_espi.c +++ b/drivers/spi/fsl_espi.c @@ -15,8 +15,10 @@ struct fsl_spi_slave { struct spi_slave slave; + ccsr_espi_t *espi; unsigned int div16; unsigned int pm; + int tx_timeout; unsigned int mode; size_t cmd_len; u8 cmd_buf[16]; @@ -25,11 +27,17 @@ struct fsl_spi_slave { }; #define to_fsl_spi_slave(s) container_of(s, struct fsl_spi_slave, slave) +#define US_PER_SECOND 1000000UL #define ESPI_MAX_CS_NUM 4 +#define ESPI_FIFO_WIDTH_BIT 32 #define ESPI_EV_RNE (1 << 9) #define ESPI_EV_TNF (1 << 8) +#define ESPI_EV_DON (1 << 14) +#define ESPI_EV_TXE (1 << 15) +#define ESPI_EV_RFCNT_SHIFT 24 +#define ESPI_EV_RFCNT_MASK (0x3f << ESPI_EV_RFCNT_SHIFT) #define ESPI_MODE_EN (1 << 31) /* Enable interface */ #define ESPI_MODE_TXTHR(x) ((x) << 8) /* Tx FIFO threshold */ @@ -61,6 +69,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, struct fsl_spi_slave *fsl; sys_info_t sysinfo; unsigned long spibrg = 0; + unsigned long spi_freq = 0; unsigned char pm = 0; if (!spi_cs_is_valid(bus, cs)) @@ -70,6 +79,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, if (!fsl) return NULL; + fsl->espi = (void *)(CONFIG_SYS_MPC85xx_ESPI_ADDR); fsl->mode = mode; fsl->max_transfer_length = ESPI_MAX_DATA_TRANSFER_LEN; @@ -91,6 +101,15 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, pm--; fsl->pm = pm; + if (fsl->div16) + spi_freq = spibrg / ((pm + 1) * 2 * 16); + else + spi_freq = spibrg / ((pm + 1) * 2); + + /* set tx_timeout to 10 times of one espi FIFO entry go out */ + fsl->tx_timeout = DIV_ROUND_UP((US_PER_SECOND * ESPI_FIFO_WIDTH_BIT + * 10), spi_freq); + return &fsl->slave; } @@ -108,7 +127,7 @@ void spi_init(void) int spi_claim_bus(struct spi_slave *slave) { struct fsl_spi_slave *fsl = to_fsl_spi_slave(slave); - ccsr_espi_t *espi = (void *)(CONFIG_SYS_MPC85xx_ESPI_ADDR); + ccsr_espi_t *espi = fsl->espi; unsigned char pm = fsl->pm; unsigned int cs = slave->cs; unsigned int mode = fsl->mode; @@ -161,24 +180,86 @@ void spi_release_bus(struct spi_slave *slave) } +static void fsl_espi_tx(struct fsl_spi_slave *fsl, const void *dout) +{ + ccsr_espi_t *espi = fsl->espi; + unsigned int tmpdout, event; + int tmp_tx_timeout; + + if (dout) + tmpdout = *(u32 *)dout; + else + tmpdout = 0; + + out_be32(&espi->tx, tmpdout); + out_be32(&espi->event, ESPI_EV_TNF); + debug("***spi_xfer:...%08x written\n", tmpdout); + + tmp_tx_timeout = fsl->tx_timeout; + /* Wait for eSPI transmit to go out */ + while (tmp_tx_timeout--) { + event = in_be32(&espi->event); + if (event & ESPI_EV_DON || event & ESPI_EV_TXE) { + out_be32(&espi->event, ESPI_EV_TXE); + break; + } + udelay(1); + } + + if (tmp_tx_timeout < 0) + debug("***spi_xfer:...Tx timeout! event = %08x\n", event); +} + +static int fsl_espi_rx(struct fsl_spi_slave *fsl, void *din, unsigned int bytes) +{ + ccsr_espi_t *espi = fsl->espi; + unsigned int tmpdin, rx_times; + unsigned char *buf, *p_cursor; + + if (bytes <= 0) + return 0; + + rx_times = DIV_ROUND_UP(bytes, 4); + buf = (unsigned char *)malloc(4 * rx_times); + if (!buf) { + debug("SF: Failed to malloc memory.\n"); + return -1; + } + p_cursor = buf; + while (rx_times--) { + tmpdin = in_be32(&espi->rx); + debug("***spi_xfer:...%08x readed\n", tmpdin); + *(u32 *)p_cursor = tmpdin; + p_cursor += 4; + } + + if (din) + memcpy(din, buf, bytes); + + free(buf); + out_be32(&espi->event, ESPI_EV_RNE); + + return bytes; +} + int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *data_out, void *data_in, unsigned long flags) { struct fsl_spi_slave *fsl = to_fsl_spi_slave(slave); - ccsr_espi_t *espi = (void *)(CONFIG_SYS_MPC85xx_ESPI_ADDR); - unsigned int tmpdout, tmpdin, event; + ccsr_espi_t *espi = fsl->espi; + unsigned int event, rx_bytes; const void *dout = NULL; void *din = NULL; int len = 0; int num_blks, num_chunks, max_tran_len, tran_len; int num_bytes; - unsigned char *ch; unsigned char *buffer = NULL; size_t buf_len; u8 *cmd_buf = fsl->cmd_buf; size_t cmd_len = fsl->cmd_len; size_t data_len = bitlen / 8; size_t rx_offset = 0; + int rf_cnt; max_tran_len = fsl->max_transfer_length; switch (flags) { @@ -217,9 +298,8 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *data_out, break; } - debug("spi_xfer: slave %u:%u dout %08X(%p) din %08X(%p) len %u\n", - slave->bus, slave->cs, *(uint *) dout, - dout, *(uint *) din, din, len); + debug("spi_xfer: data_out %08X(%p) data_in %08X(%p) len %u\n", + *(uint *)data_out, data_out, *(uint *)data_in, data_in, len); num_chunks = DIV_ROUND_UP(data_len, max_tran_len); while (num_chunks--) { @@ -235,41 +315,34 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *data_out, /* Clear all eSPI events */ out_be32(&espi->event , 0xffffffff); /* handle data in 32-bit chunks */ - while (num_blks--) { - + while (num_blks) { event = in_be32(&espi->event); if (event & ESPI_EV_TNF) { - tmpdout = *(u32 *)dout; - + fsl_espi_tx(fsl, dout); /* Set up the next iteration */ if (len > 4) { len -= 4; dout += 4; } - - out_be32(&espi->tx, tmpdout); - out_be32(&espi->event, ESPI_EV_TNF); - debug("***spi_xfer:...%08x written\n", tmpdout); } - /* Wait for eSPI transmit to get out */ - udelay(80); - event = in_be32(&espi->event); if (event & ESPI_EV_RNE) { - tmpdin = in_be32(&espi->rx); - if (num_blks == 0 && num_bytes != 0) { - ch = (unsigned char *)&tmpdin; - while (num_bytes--) - *(unsigned char *)din++ = *ch++; - } else { - *(u32 *) din = tmpdin; - din += 4; + rf_cnt = ((event & ESPI_EV_RFCNT_MASK) + >> ESPI_EV_RFCNT_SHIFT); + if (rf_cnt >= 4) + rx_bytes = 4; + else if (num_blks == 1 && rf_cnt == num_bytes) + rx_bytes = num_bytes; + else + continue; + if (fsl_espi_rx(fsl, din, rx_bytes) + == rx_bytes) { + num_blks--; + if (din) + din = (unsigned char *)din + + rx_bytes; } - - out_be32(&espi->event, in_be32(&espi->event) - | ESPI_EV_RNE); - debug("***spi_xfer:...%08x readed\n", tmpdin); } } if (data_in) { @@ -295,7 +368,7 @@ int spi_cs_is_valid(unsigned int bus, unsigned int cs) void spi_cs_activate(struct spi_slave *slave) { struct fsl_spi_slave *fsl = to_fsl_spi_slave(slave); - ccsr_espi_t *espi = (void *)(CONFIG_SYS_MPC85xx_ESPI_ADDR); + ccsr_espi_t *espi = fsl->espi; unsigned int com = 0; size_t data_len = fsl->data_len; @@ -307,7 +380,8 @@ void spi_cs_activate(struct spi_slave *slave) void spi_cs_deactivate(struct spi_slave *slave) { - ccsr_espi_t *espi = (void *)(CONFIG_SYS_MPC85xx_ESPI_ADDR); + struct fsl_spi_slave *fsl = to_fsl_spi_slave(slave); + ccsr_espi_t *espi = fsl->espi; /* clear the RXCNT and TXCNT */ out_be32(&espi->mode, in_be32(&espi->mode) & (~ESPI_MODE_EN)); diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c new file mode 100644 index 0000000..ba20bef --- /dev/null +++ b/drivers/spi/fsl_qspi.c @@ -0,0 +1,482 @@ +/* + * Copyright 2013-2014 Freescale Semiconductor, Inc. + * + * Freescale Quad Serial Peripheral Interface (QSPI) driver + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <malloc.h> +#include <spi.h> +#include <asm/io.h> +#include <linux/sizes.h> +#include "fsl_qspi.h" + +#define RX_BUFFER_SIZE 0x80 +#define TX_BUFFER_SIZE 0x40 + +#define OFFSET_BITS_MASK 0x00ffffff + +#define FLASH_STATUS_WEL 0x02 + +/* SEQID */ +#define SEQID_WREN 1 +#define SEQID_FAST_READ 2 +#define SEQID_RDSR 3 +#define SEQID_SE 4 +#define SEQID_CHIP_ERASE 5 +#define SEQID_PP 6 +#define SEQID_RDID 7 + +/* Flash opcodes */ +#define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ +#define OPCODE_RDSR 0x05 /* Read status register */ +#define OPCODE_WREN 0x06 /* Write enable */ +#define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */ +#define OPCODE_CHIP_ERASE 0xc7 /* Erase whole flash chip */ +#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */ +#define OPCODE_RDID 0x9f /* Read JEDEC ID */ + +/* 4-byte address opcodes - used on Spansion and some Macronix flashes */ +#define OPCODE_FAST_READ_4B 0x0c /* Read data bytes (high frequency) */ +#define OPCODE_PP_4B 0x12 /* Page program (up to 256 bytes) */ +#define OPCODE_SE_4B 0xdc /* Sector erase (usually 64KiB) */ + +#ifdef CONFIG_SYS_FSL_QSPI_LE +#define qspi_read32 in_le32 +#define qspi_write32 out_le32 +#elif defined(CONFIG_SYS_FSL_QSPI_BE) +#define qspi_read32 in_be32 +#define qspi_write32 out_be32 +#endif + +static unsigned long spi_bases[] = { + QSPI0_BASE_ADDR, +}; + +static unsigned long amba_bases[] = { + QSPI0_AMBA_BASE, +}; + +struct fsl_qspi { + struct spi_slave slave; + unsigned long reg_base; + unsigned long amba_base; + u32 sf_addr; + u8 cur_seqid; +}; + +/* QSPI support swapping the flash read/write data + * in hardware for LS102xA, but not for VF610 */ +static inline u32 qspi_endian_xchg(u32 data) +{ +#ifdef CONFIG_VF610 + return swab32(data); +#else + return data; +#endif +} + +static inline struct fsl_qspi *to_qspi_spi(struct spi_slave *slave) +{ + return container_of(slave, struct fsl_qspi, slave); +} + +static void qspi_set_lut(struct fsl_qspi *qspi) +{ + struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base; + u32 lut_base; + + /* Unlock the LUT */ + qspi_write32(®s->lutkey, LUT_KEY_VALUE); + qspi_write32(®s->lckcr, QSPI_LCKCR_UNLOCK); + + /* Write Enable */ + lut_base = SEQID_WREN * 4; + qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_WREN) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD)); + qspi_write32(®s->lut[lut_base + 1], 0); + qspi_write32(®s->lut[lut_base + 2], 0); + qspi_write32(®s->lut[lut_base + 3], 0); + + /* Fast Read */ + lut_base = SEQID_FAST_READ * 4; + if (FSL_QSPI_FLASH_SIZE <= SZ_16M) + qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_FAST_READ) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | + PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); + else + qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_FAST_READ_4B) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) | + PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); + qspi_write32(®s->lut[lut_base + 1], OPRND0(8) | PAD0(LUT_PAD1) | + INSTR0(LUT_DUMMY) | OPRND1(RX_BUFFER_SIZE) | PAD1(LUT_PAD1) | + INSTR1(LUT_READ)); + qspi_write32(®s->lut[lut_base + 2], 0); + qspi_write32(®s->lut[lut_base + 3], 0); + + /* Read Status */ + lut_base = SEQID_RDSR * 4; + qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_RDSR) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) | + PAD1(LUT_PAD1) | INSTR1(LUT_READ)); + qspi_write32(®s->lut[lut_base + 1], 0); + qspi_write32(®s->lut[lut_base + 2], 0); + qspi_write32(®s->lut[lut_base + 3], 0); + + /* Erase a sector */ + lut_base = SEQID_SE * 4; + if (FSL_QSPI_FLASH_SIZE <= SZ_16M) + qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_SE) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | + PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); + else + qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_SE_4B) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) | + PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); + qspi_write32(®s->lut[lut_base + 1], 0); + qspi_write32(®s->lut[lut_base + 2], 0); + qspi_write32(®s->lut[lut_base + 3], 0); + + /* Erase the whole chip */ + lut_base = SEQID_CHIP_ERASE * 4; + qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_CHIP_ERASE) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD)); + qspi_write32(®s->lut[lut_base + 1], 0); + qspi_write32(®s->lut[lut_base + 2], 0); + qspi_write32(®s->lut[lut_base + 3], 0); + + /* Page Program */ + lut_base = SEQID_PP * 4; + if (FSL_QSPI_FLASH_SIZE <= SZ_16M) + qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_PP) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | + PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); + else + qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_PP_4B) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) | + PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); + qspi_write32(®s->lut[lut_base + 1], OPRND0(TX_BUFFER_SIZE) | + PAD0(LUT_PAD1) | INSTR0(LUT_WRITE)); + qspi_write32(®s->lut[lut_base + 2], 0); + qspi_write32(®s->lut[lut_base + 3], 0); + + /* READ ID */ + lut_base = SEQID_RDID * 4; + qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_RDID) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(8) | + PAD1(LUT_PAD1) | INSTR1(LUT_READ)); + qspi_write32(®s->lut[lut_base + 1], 0); + qspi_write32(®s->lut[lut_base + 2], 0); + qspi_write32(®s->lut[lut_base + 3], 0); + + /* Lock the LUT */ + qspi_write32(®s->lutkey, LUT_KEY_VALUE); + qspi_write32(®s->lckcr, QSPI_LCKCR_LOCK); +} + +void spi_init() +{ + /* do nothing */ +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct fsl_qspi *qspi; + struct fsl_qspi_regs *regs; + u32 reg_val, smpr_val; + u32 total_size, seq_id; + + if (bus >= ARRAY_SIZE(spi_bases)) + return NULL; + + qspi = spi_alloc_slave(struct fsl_qspi, bus, cs); + if (!qspi) + return NULL; + + qspi->reg_base = spi_bases[bus]; + qspi->amba_base = amba_bases[bus]; + + qspi->slave.max_write_size = TX_BUFFER_SIZE; + + regs = (struct fsl_qspi_regs *)qspi->reg_base; + qspi_write32(®s->mcr, QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK); + + smpr_val = qspi_read32(®s->smpr); + qspi_write32(®s->smpr, smpr_val & ~(QSPI_SMPR_FSDLY_MASK | + QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK)); + qspi_write32(®s->mcr, QSPI_MCR_RESERVED_MASK); + + total_size = FSL_QSPI_FLASH_SIZE * FSL_QSPI_FLASH_NUM; + qspi_write32(®s->sfa1ad, FSL_QSPI_FLASH_SIZE | qspi->amba_base); + qspi_write32(®s->sfa2ad, FSL_QSPI_FLASH_SIZE | qspi->amba_base); + qspi_write32(®s->sfb1ad, total_size | qspi->amba_base); + qspi_write32(®s->sfb2ad, total_size | qspi->amba_base); + + qspi_set_lut(qspi); + + smpr_val = qspi_read32(®s->smpr); + smpr_val &= ~QSPI_SMPR_DDRSMP_MASK; + qspi_write32(®s->smpr, smpr_val); + qspi_write32(®s->mcr, QSPI_MCR_RESERVED_MASK); + + seq_id = 0; + reg_val = qspi_read32(®s->bfgencr); + reg_val &= ~QSPI_BFGENCR_SEQID_MASK; + reg_val |= (seq_id << QSPI_BFGENCR_SEQID_SHIFT); + reg_val &= ~QSPI_BFGENCR_PAR_EN_MASK; + qspi_write32(®s->bfgencr, reg_val); + + return &qspi->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + struct fsl_qspi *qspi = to_qspi_spi(slave); + + free(qspi); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + return 0; +} + +static void qspi_op_rdid(struct fsl_qspi *qspi, u32 *rxbuf, u32 len) +{ + struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base; + u32 mcr_reg, rbsr_reg, data; + int i, size; + + mcr_reg = qspi_read32(®s->mcr); + qspi_write32(®s->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | + QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); + qspi_write32(®s->rbct, QSPI_RBCT_RXBRD_USEIPS); + + qspi_write32(®s->sfar, qspi->amba_base); + + qspi_write32(®s->ipcr, (SEQID_RDID << QSPI_IPCR_SEQID_SHIFT) | 0); + while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) + ; + + i = 0; + size = len; + while ((RX_BUFFER_SIZE >= size) && (size > 0)) { + rbsr_reg = qspi_read32(®s->rbsr); + if (rbsr_reg & QSPI_RBSR_RDBFL_MASK) { + data = qspi_read32(®s->rbdr[i]); + data = qspi_endian_xchg(data); + memcpy(rxbuf, &data, 4); + rxbuf++; + size -= 4; + i++; + } + } + + qspi_write32(®s->mcr, mcr_reg); +} + +static void qspi_op_read(struct fsl_qspi *qspi, u32 *rxbuf, u32 len) +{ + struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base; + u32 mcr_reg, data; + int i, size; + u32 to_or_from; + + mcr_reg = qspi_read32(®s->mcr); + qspi_write32(®s->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | + QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); + qspi_write32(®s->rbct, QSPI_RBCT_RXBRD_USEIPS); + + to_or_from = qspi->sf_addr + qspi->amba_base; + + while (len > 0) { + qspi_write32(®s->sfar, to_or_from); + + size = (len > RX_BUFFER_SIZE) ? + RX_BUFFER_SIZE : len; + + qspi_write32(®s->ipcr, + (SEQID_FAST_READ << QSPI_IPCR_SEQID_SHIFT) | size); + while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) + ; + + to_or_from += size; + len -= size; + + i = 0; + while ((RX_BUFFER_SIZE >= size) && (size > 0)) { + data = qspi_read32(®s->rbdr[i]); + data = qspi_endian_xchg(data); + memcpy(rxbuf, &data, 4); + rxbuf++; + size -= 4; + i++; + } + qspi_write32(®s->mcr, qspi_read32(®s->mcr) | + QSPI_MCR_CLR_RXF_MASK); + } + + qspi_write32(®s->mcr, mcr_reg); +} + +static void qspi_op_pp(struct fsl_qspi *qspi, u32 *txbuf, u32 len) +{ + struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base; + u32 mcr_reg, data, reg, status_reg; + int i, size, tx_size; + u32 to_or_from = 0; + + mcr_reg = qspi_read32(®s->mcr); + qspi_write32(®s->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | + QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); + qspi_write32(®s->rbct, QSPI_RBCT_RXBRD_USEIPS); + + status_reg = 0; + while ((status_reg & FLASH_STATUS_WEL) != FLASH_STATUS_WEL) { + qspi_write32(®s->ipcr, + (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0); + while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) + ; + + qspi_write32(®s->ipcr, + (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 1); + while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) + ; + + reg = qspi_read32(®s->rbsr); + if (reg & QSPI_RBSR_RDBFL_MASK) { + status_reg = qspi_read32(®s->rbdr[0]); + status_reg = qspi_endian_xchg(status_reg); + } + qspi_write32(®s->mcr, + qspi_read32(®s->mcr) | QSPI_MCR_CLR_RXF_MASK); + } + + to_or_from = qspi->sf_addr + qspi->amba_base; + qspi_write32(®s->sfar, to_or_from); + + tx_size = (len > TX_BUFFER_SIZE) ? + TX_BUFFER_SIZE : len; + + size = (tx_size + 3) / 4; + + for (i = 0; i < size; i++) { + data = qspi_endian_xchg(*txbuf); + qspi_write32(®s->tbdr, data); + txbuf++; + } + + qspi_write32(®s->ipcr, + (SEQID_PP << QSPI_IPCR_SEQID_SHIFT) | tx_size); + while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) + ; + + qspi_write32(®s->mcr, mcr_reg); +} + +static void qspi_op_rdsr(struct fsl_qspi *qspi, u32 *rxbuf) +{ + struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base; + u32 mcr_reg, reg, data; + + mcr_reg = qspi_read32(®s->mcr); + qspi_write32(®s->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | + QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); + qspi_write32(®s->rbct, QSPI_RBCT_RXBRD_USEIPS); + + qspi_write32(®s->sfar, qspi->amba_base); + + qspi_write32(®s->ipcr, + (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 0); + while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) + ; + + while (1) { + reg = qspi_read32(®s->rbsr); + if (reg & QSPI_RBSR_RDBFL_MASK) { + data = qspi_read32(®s->rbdr[0]); + data = qspi_endian_xchg(data); + memcpy(rxbuf, &data, 4); + qspi_write32(®s->mcr, qspi_read32(®s->mcr) | + QSPI_MCR_CLR_RXF_MASK); + break; + } + } + + qspi_write32(®s->mcr, mcr_reg); +} + +static void qspi_op_se(struct fsl_qspi *qspi) +{ + struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base; + u32 mcr_reg; + u32 to_or_from = 0; + + mcr_reg = qspi_read32(®s->mcr); + qspi_write32(®s->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | + QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); + qspi_write32(®s->rbct, QSPI_RBCT_RXBRD_USEIPS); + + to_or_from = qspi->sf_addr + qspi->amba_base; + qspi_write32(®s->sfar, to_or_from); + + qspi_write32(®s->ipcr, + (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0); + while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) + ; + + qspi_write32(®s->ipcr, + (SEQID_SE << QSPI_IPCR_SEQID_SHIFT) | 0); + while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) + ; + + qspi_write32(®s->mcr, mcr_reg); +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct fsl_qspi *qspi = to_qspi_spi(slave); + u32 bytes = DIV_ROUND_UP(bitlen, 8); + static u32 pp_sfaddr; + u32 txbuf; + + if (dout) { + memcpy(&txbuf, dout, 4); + qspi->cur_seqid = *(u8 *)dout; + + if (flags == SPI_XFER_END) { + qspi->sf_addr = pp_sfaddr; + qspi_op_pp(qspi, (u32 *)dout, bytes); + return 0; + } + + if (qspi->cur_seqid == OPCODE_FAST_READ) { + qspi->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK; + } else if (qspi->cur_seqid == OPCODE_SE) { + qspi->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK; + qspi_op_se(qspi); + } else if (qspi->cur_seqid == OPCODE_PP) { + pp_sfaddr = swab32(txbuf) & OFFSET_BITS_MASK; + } + } + + if (din) { + if (qspi->cur_seqid == OPCODE_FAST_READ) + qspi_op_read(qspi, din, bytes); + else if (qspi->cur_seqid == OPCODE_RDID) + qspi_op_rdid(qspi, din, bytes); + else if (qspi->cur_seqid == OPCODE_RDSR) + qspi_op_rdsr(qspi, din); + } + + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + /* Nothing to do */ +} diff --git a/drivers/spi/fsl_qspi.h b/drivers/spi/fsl_qspi.h new file mode 100644 index 0000000..db400e6 --- /dev/null +++ b/drivers/spi/fsl_qspi.h @@ -0,0 +1,127 @@ +/* + * Copyright 2013-2014 Freescale Semiconductor, Inc. + * + * Register definitions for Freescale QSPI + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _FSL_QSPI_H_ +#define _FSL_QSPI_H_ + +struct fsl_qspi_regs { + u32 mcr; + u32 rsvd0[1]; + u32 ipcr; + u32 flshcr; + u32 buf0cr; + u32 buf1cr; + u32 buf2cr; + u32 buf3cr; + u32 bfgencr; + u32 soccr; + u32 rsvd1[2]; + u32 buf0ind; + u32 buf1ind; + u32 buf2ind; + u32 rsvd2[49]; + u32 sfar; + u32 rsvd3[1]; + u32 smpr; + u32 rbsr; + u32 rbct; + u32 rsvd4[15]; + u32 tbsr; + u32 tbdr; + u32 rsvd5[1]; + u32 sr; + u32 fr; + u32 rser; + u32 spndst; + u32 sptrclr; + u32 rsvd6[4]; + u32 sfa1ad; + u32 sfa2ad; + u32 sfb1ad; + u32 sfb2ad; + u32 rsvd7[28]; + u32 rbdr[32]; + u32 rsvd8[32]; + u32 lutkey; + u32 lckcr; + u32 rsvd9[2]; + u32 lut[64]; +}; + +#define QSPI_IPCR_SEQID_SHIFT 24 +#define QSPI_IPCR_SEQID_MASK (0xf << QSPI_IPCR_SEQID_SHIFT) + +#define QSPI_MCR_END_CFD_SHIFT 2 +#define QSPI_MCR_END_CFD_MASK (3 << QSPI_MCR_END_CFD_SHIFT) +#define QSPI_MCR_END_CFD_LE (1 << QSPI_MCR_END_CFD_SHIFT) +#define QSPI_MCR_DDR_EN_SHIFT 7 +#define QSPI_MCR_DDR_EN_MASK (1 << QSPI_MCR_DDR_EN_SHIFT) +#define QSPI_MCR_CLR_RXF_SHIFT 10 +#define QSPI_MCR_CLR_RXF_MASK (1 << QSPI_MCR_CLR_RXF_SHIFT) +#define QSPI_MCR_CLR_TXF_SHIFT 11 +#define QSPI_MCR_CLR_TXF_MASK (1 << QSPI_MCR_CLR_TXF_SHIFT) +#define QSPI_MCR_MDIS_SHIFT 14 +#define QSPI_MCR_MDIS_MASK (1 << QSPI_MCR_MDIS_SHIFT) +#define QSPI_MCR_RESERVED_SHIFT 16 +#define QSPI_MCR_RESERVED_MASK (0xf << QSPI_MCR_RESERVED_SHIFT) + +#define QSPI_SMPR_HSENA_SHIFT 0 +#define QSPI_SMPR_HSENA_MASK (1 << QSPI_SMPR_HSENA_SHIFT) +#define QSPI_SMPR_FSPHS_SHIFT 5 +#define QSPI_SMPR_FSPHS_MASK (1 << QSPI_SMPR_FSPHS_SHIFT) +#define QSPI_SMPR_FSDLY_SHIFT 6 +#define QSPI_SMPR_FSDLY_MASK (1 << QSPI_SMPR_FSDLY_SHIFT) +#define QSPI_SMPR_DDRSMP_SHIFT 16 +#define QSPI_SMPR_DDRSMP_MASK (7 << QSPI_SMPR_DDRSMP_SHIFT) + +#define QSPI_BFGENCR_SEQID_SHIFT 12 +#define QSPI_BFGENCR_SEQID_MASK (0xf << QSPI_BFGENCR_SEQID_SHIFT) +#define QSPI_BFGENCR_PAR_EN_SHIFT 16 +#define QSPI_BFGENCR_PAR_EN_MASK (1 << QSPI_BFGENCR_PAR_EN_SHIFT) + +#define QSPI_RBSR_RDBFL_SHIFT 8 +#define QSPI_RBSR_RDBFL_MASK (0x3f << QSPI_RBSR_RDBFL_SHIFT) + +#define QSPI_RBCT_RXBRD_SHIFT 8 +#define QSPI_RBCT_RXBRD_USEIPS (1 << QSPI_RBCT_RXBRD_SHIFT) + +#define QSPI_SR_BUSY_SHIFT 0 +#define QSPI_SR_BUSY_MASK (1 << QSPI_SR_BUSY_SHIFT) + +#define QSPI_LCKCR_LOCK 0x1 +#define QSPI_LCKCR_UNLOCK 0x2 + +#define LUT_KEY_VALUE 0x5af05af0 + +#define OPRND0_SHIFT 0 +#define OPRND0(x) ((x) << OPRND0_SHIFT) +#define PAD0_SHIFT 8 +#define PAD0(x) ((x) << PAD0_SHIFT) +#define INSTR0_SHIFT 10 +#define INSTR0(x) ((x) << INSTR0_SHIFT) +#define OPRND1_SHIFT 16 +#define OPRND1(x) ((x) << OPRND1_SHIFT) +#define PAD1_SHIFT 24 +#define PAD1(x) ((x) << PAD1_SHIFT) +#define INSTR1_SHIFT 26 +#define INSTR1(x) ((x) << INSTR1_SHIFT) + +#define LUT_CMD 1 +#define LUT_ADDR 2 +#define LUT_DUMMY 3 +#define LUT_READ 7 +#define LUT_WRITE 8 + +#define LUT_PAD1 0 +#define LUT_PAD2 1 +#define LUT_PAD4 2 + +#define ADDR24BIT 0x18 +#define ADDR32BIT 0x20 + +#endif /* _FSL_QSPI_H_ */ diff --git a/drivers/spi/soft_spi.c b/drivers/spi/soft_spi.c index 5d22351..c969be3 100644 --- a/drivers/spi/soft_spi.c +++ b/drivers/spi/soft_spi.c @@ -136,10 +136,14 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, /* * Check if it is time to work on a new byte. */ - if((j % 8) == 0) { - tmpdout = *txd++; + if ((j % 8) == 0) { + if (txd) + tmpdout = *txd++; + else + tmpdout = 0; if(j != 0) { - *rxd++ = tmpdin; + if (rxd) + *rxd++ = tmpdin; } tmpdin = 0; } @@ -164,9 +168,11 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, * bits over to left-justify them. Then store the last byte * read in. */ - if((bitlen % 8) != 0) - tmpdin <<= 8 - (bitlen % 8); - *rxd++ = tmpdin; + if (rxd) { + if ((bitlen % 8) != 0) + tmpdin <<= 8 - (bitlen % 8); + *rxd++ = tmpdin; + } if (flags & SPI_XFER_END) spi_cs_deactivate(slave); diff --git a/drivers/spi/ti_qspi.c b/drivers/spi/ti_qspi.c index c5d2245..fd7fea8 100644 --- a/drivers/spi/ti_qspi.c +++ b/drivers/spi/ti_qspi.c @@ -106,6 +106,7 @@ static void ti_spi_setup_spi_register(struct ti_qspi_slave *qslave) slave->memory_map = (void *)MMAP_START_ADDR_DRA; #else slave->memory_map = (void *)MMAP_START_ADDR_AM43x; + slave->op_mode_rx = 8; #endif memval |= QSPI_CMD_READ | QSPI_SETUP0_NUM_A_BYTES | diff --git a/drivers/tpm/tpm.c b/drivers/tpm/tpm.c index b657334..bc0f964 100644 --- a/drivers/tpm/tpm.c +++ b/drivers/tpm/tpm.c @@ -411,7 +411,7 @@ static ssize_t tpm_transmit(const unsigned char *buf, size_t bufsiz) goto out_recv; } - if ((status == chip->vendor.req_canceled)) { + if (status == chip->vendor.req_canceled) { error("Operation Canceled\n"); rc = -ECANCELED; goto out; diff --git a/drivers/usb/eth/asix.c b/drivers/usb/eth/asix.c index ce133f0..6557055 100644 --- a/drivers/usb/eth/asix.c +++ b/drivers/usb/eth/asix.c @@ -565,7 +565,7 @@ struct asix_dongle { int flags; }; -static const struct asix_dongle const asix_dongles[] = { +static const struct asix_dongle asix_dongles[] = { { 0x05ac, 0x1402, FLAG_TYPE_AX88772 }, /* Apple USB Ethernet Adapter */ { 0x07d1, 0x3c05, FLAG_TYPE_AX88772 }, /* D-Link DUB-E100 H/W Ver B1 */ { 0x2001, 0x1a02, FLAG_TYPE_AX88772 }, /* D-Link DUB-E100 H/W Ver C1 */ diff --git a/drivers/usb/eth/mcs7830.c b/drivers/usb/eth/mcs7830.c index c353286..8e738d4 100644 --- a/drivers/usb/eth/mcs7830.c +++ b/drivers/usb/eth/mcs7830.c @@ -666,7 +666,7 @@ struct mcs7830_dongle { /* * mcs7830_dongles - the list of supported Moschip based USB ethernet dongles */ -static const struct mcs7830_dongle const mcs7830_dongles[] = { +static const struct mcs7830_dongle mcs7830_dongles[] = { { 0x9710, 0x7832, }, /* Moschip 7832 */ { 0x9710, 0x7830, }, /* Moschip 7830 */ { 0x9710, 0x7730, }, /* Moschip 7730 */ diff --git a/drivers/usb/eth/smsc95xx.c b/drivers/usb/eth/smsc95xx.c index 7bf0a34..7a7a676 100644 --- a/drivers/usb/eth/smsc95xx.c +++ b/drivers/usb/eth/smsc95xx.c @@ -799,6 +799,7 @@ static const struct smsc95xx_dongle smsc95xx_dongles[] = { { 0x0424, 0x9500 }, /* LAN9500 Ethernet */ { 0x0424, 0x9730 }, /* LAN9730 Ethernet (HSIC) */ { 0x0424, 0x9900 }, /* SMSC9500 USB Ethernet Device (SAL10) */ + { 0x0424, 0x9e00 }, /* LAN9500A Ethernet */ { 0x0000, 0x0000 } /* END - Do not remove */ }; diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index c99208d..2c70973 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -314,7 +314,7 @@ usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) DBG(DBG_GADGET, "ep_alloc_request: %p, 0x%x\n", _ep, gfp_flags); - req = malloc(sizeof(struct usba_request)); + req = calloc(1, sizeof(struct usba_request)); if (!req) return NULL; diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c index 9cd0036..4cd19c3 100644 --- a/drivers/usb/gadget/ci_udc.c +++ b/drivers/usb/gadget/ci_udc.c @@ -34,6 +34,22 @@ #error This driver can not work on systems with caches longer than 128b #endif +/* + * Every QTD must be individually aligned, since we can program any + * QTD's address into HW. Cache flushing requires ARCH_DMA_MINALIGN, + * and the USB HW requires 32-byte alignment. Align to both: + */ +#define ILIST_ALIGN roundup(ARCH_DMA_MINALIGN, 32) +/* Each QTD is this size */ +#define ILIST_ENT_RAW_SZ sizeof(struct ept_queue_item) +/* + * Align the size of the QTD too, so we can add this value to each + * QTD's address to get another aligned address. + */ +#define ILIST_ENT_SZ roundup(ILIST_ENT_RAW_SZ, ILIST_ALIGN) +/* For each endpoint, we need 2 QTDs, one for each of IN and OUT */ +#define ILIST_SZ (NUM_ENDPOINTS * 2 * ILIST_ENT_SZ) + #ifndef DEBUG #define DBG(x...) do {} while (0) #else @@ -56,14 +72,7 @@ static const char *reqname(unsigned r) } #endif -static struct usb_endpoint_descriptor ep0_out_desc = { - .bLength = sizeof(struct usb_endpoint_descriptor), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 0, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, -}; - -static struct usb_endpoint_descriptor ep0_in_desc = { +static struct usb_endpoint_descriptor ep0_desc = { .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, @@ -137,7 +146,9 @@ static struct ept_queue_head *ci_get_qh(int ep_num, int dir_in) */ static struct ept_queue_item *ci_get_qtd(int ep_num, int dir_in) { - return controller.items[(ep_num * 2) + dir_in]; + int index = (ep_num * 2) + dir_in; + uint8_t *imem = controller.items_mem + (index * ILIST_ENT_SZ); + return (struct ept_queue_item *)imem; } /** @@ -180,8 +191,7 @@ static void ci_flush_qtd(int ep_num) { struct ept_queue_item *item = ci_get_qtd(ep_num, 0); const uint32_t start = (uint32_t)item; - const uint32_t end_raw = start + 2 * sizeof(*item); - const uint32_t end = roundup(end_raw, ARCH_DMA_MINALIGN); + const uint32_t end = start + 2 * ILIST_ENT_SZ; flush_dcache_range(start, end); } @@ -196,8 +206,7 @@ static void ci_invalidate_qtd(int ep_num) { struct ept_queue_item *item = ci_get_qtd(ep_num, 0); const uint32_t start = (uint32_t)item; - const uint32_t end_raw = start + 2 * sizeof(*item); - const uint32_t end = roundup(end_raw, ARCH_DMA_MINALIGN); + const uint32_t end = start + 2 * ILIST_ENT_SZ; invalidate_dcache_range(start, end); } @@ -205,23 +214,39 @@ static void ci_invalidate_qtd(int ep_num) static struct usb_request * ci_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags) { + struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep); + int num; struct ci_req *ci_req; - ci_req = memalign(ARCH_DMA_MINALIGN, sizeof(*ci_req)); + num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + if (num == 0 && controller.ep0_req) + return &controller.ep0_req->req; + + ci_req = calloc(1, sizeof(*ci_req)); if (!ci_req) return NULL; INIT_LIST_HEAD(&ci_req->queue); - ci_req->b_buf = 0; + + if (num == 0) + controller.ep0_req = ci_req; return &ci_req->req; } static void ci_ep_free_request(struct usb_ep *ep, struct usb_request *req) { - struct ci_req *ci_req; + struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep); + struct ci_req *ci_req = container_of(req, struct ci_req, req); + int num; + + num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + if (num == 0) { + if (!controller.ep0_req) + return; + controller.ep0_req = 0; + } - ci_req = container_of(req, struct ci_req, req); if (ci_req->b_buf) free(ci_req->b_buf); free(ci_req); @@ -362,18 +387,51 @@ static void ci_ep_submit_next_request(struct ci_ep *ci_ep) ci_req = list_first_entry(&ci_ep->queue, struct ci_req, queue); len = ci_req->req.length; - item->next = TERMINATE; - item->info = INFO_BYTES(len) | INFO_IOC | INFO_ACTIVE; + item->info = INFO_BYTES(len) | INFO_ACTIVE; item->page0 = (uint32_t)ci_req->hw_buf; item->page1 = ((uint32_t)ci_req->hw_buf & 0xfffff000) + 0x1000; item->page2 = ((uint32_t)ci_req->hw_buf & 0xfffff000) + 0x2000; item->page3 = ((uint32_t)ci_req->hw_buf & 0xfffff000) + 0x3000; item->page4 = ((uint32_t)ci_req->hw_buf & 0xfffff000) + 0x4000; - ci_flush_qtd(num); head->next = (unsigned) item; head->info = 0; + /* + * When sending the data for an IN transaction, the attached host + * knows that all data for the IN is sent when one of the following + * occurs: + * a) A zero-length packet is transmitted. + * b) A packet with length that isn't an exact multiple of the ep's + * maxpacket is transmitted. + * c) Enough data is sent to exactly fill the host's maximum expected + * IN transaction size. + * + * One of these conditions MUST apply at the end of an IN transaction, + * or the transaction will not be considered complete by the host. If + * none of (a)..(c) already applies, then we must force (a) to apply + * by explicitly sending an extra zero-length packet. + */ + /* IN !a !b !c */ + if (in && len && !(len % ci_ep->ep.maxpacket) && ci_req->req.zero) { + /* + * Each endpoint has 2 items allocated, even though typically + * only 1 is used at a time since either an IN or an OUT but + * not both is queued. For an IN transaction, item currently + * points at the second of these items, so we know that we + * can use the other to transmit the extra zero-length packet. + */ + struct ept_queue_item *other_item = ci_get_qtd(num, 0); + item->next = (unsigned)other_item; + item = other_item; + item->info = INFO_ACTIVE; + } + + item->next = TERMINATE; + item->info |= INFO_IOC; + + ci_flush_qtd(num); + DBG("ept%d %s queue len %x, req %p, buffer %p\n", num, in ? "in" : "out", len, ci_req, ci_req->hw_buf); ci_flush_qh(num); @@ -397,6 +455,21 @@ static int ci_ep_queue(struct usb_ep *ep, num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; in = (ci_ep->desc->bEndpointAddress & USB_DIR_IN) != 0; + if (!num && ci_ep->req_primed) { + /* + * The flipping of ep0 between IN and OUT relies on + * ci_ep_queue consuming the current IN/OUT setting + * immediately. If this is deferred to a later point when the + * req is pulled out of ci_req->queue, then the IN/OUT setting + * may have been changed since the req was queued, and state + * will get out of sync. This condition doesn't occur today, + * but could if bugs were introduced later, and this error + * check will save a lot of debugging time. + */ + printf("%s: ep0 transaction already in progress\n", __func__); + return -EPROTO; + } + ret = ci_bounce(ci_req, in); if (ret) return ret; @@ -411,16 +484,25 @@ static int ci_ep_queue(struct usb_ep *ep, return 0; } -static void handle_ep_complete(struct ci_ep *ep) +static void flip_ep0_direction(void) +{ + if (ep0_desc.bEndpointAddress == USB_DIR_IN) { + DBG("%s: Flipping ep0 to OUT\n", __func__); + ep0_desc.bEndpointAddress = 0; + } else { + DBG("%s: Flipping ep0 to IN\n", __func__); + ep0_desc.bEndpointAddress = USB_DIR_IN; + } +} + +static void handle_ep_complete(struct ci_ep *ci_ep) { struct ept_queue_item *item; int num, in, len; struct ci_req *ci_req; - num = ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - in = (ep->desc->bEndpointAddress & USB_DIR_IN) != 0; - if (num == 0) - ep->desc = &ep0_out_desc; + num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + in = (ci_ep->desc->bEndpointAddress & USB_DIR_IN) != 0; item = ci_get_qtd(num, in); ci_invalidate_qtd(num); @@ -429,23 +511,30 @@ static void handle_ep_complete(struct ci_ep *ep) printf("EP%d/%s FAIL info=%x pg0=%x\n", num, in ? "in" : "out", item->info, item->page0); - ci_req = list_first_entry(&ep->queue, struct ci_req, queue); + ci_req = list_first_entry(&ci_ep->queue, struct ci_req, queue); list_del_init(&ci_req->queue); - ep->req_primed = false; + ci_ep->req_primed = false; - if (!list_empty(&ep->queue)) - ci_ep_submit_next_request(ep); + if (!list_empty(&ci_ep->queue)) + ci_ep_submit_next_request(ci_ep); ci_req->req.actual = ci_req->req.length - len; ci_debounce(ci_req, in); DBG("ept%d %s req %p, complete %x\n", num, in ? "in" : "out", ci_req, len); - ci_req->req.complete(&ep->ep, &ci_req->req); - if (num == 0) { + if (num != 0 || controller.ep0_data_phase) + ci_req->req.complete(&ci_ep->ep, &ci_req->req); + if (num == 0 && controller.ep0_data_phase) { + /* + * Data Stage is complete, so flip ep0 dir for Status Stage, + * which always transfers a packet in the opposite direction. + */ + DBG("%s: flip ep0 dir for Status Stage\n", __func__); + flip_ep0_direction(); + controller.ep0_data_phase = false; ci_req->req.length = 0; - usb_ep_queue(&ep->ep, &ci_req->req, 0); - ep->desc = &ep0_in_desc; + usb_ep_queue(&ci_ep->ep, &ci_req->req, 0); } } @@ -463,7 +552,7 @@ static void handle_setup(void) int num, in, _num, _in, i; char *buf; - ci_req = list_first_entry(&ci_ep->queue, struct ci_req, queue); + ci_req = controller.ep0_req; req = &ci_req->req; head = ci_get_qh(0, 0); /* EP0 OUT */ @@ -474,8 +563,26 @@ static void handle_setup(void) #else writel(EPT_RX(0), &udc->epstat); #endif - DBG("handle setup %s, %x, %x index %x value %x\n", reqname(r.bRequest), - r.bRequestType, r.bRequest, r.wIndex, r.wValue); + DBG("handle setup %s, %x, %x index %x value %x length %x\n", + reqname(r.bRequest), r.bRequestType, r.bRequest, r.wIndex, + r.wValue, r.wLength); + + /* Set EP0 dir for Data Stage based on Setup Stage data */ + if (r.bRequestType & USB_DIR_IN) { + DBG("%s: Set ep0 to IN for Data Stage\n", __func__); + ep0_desc.bEndpointAddress = USB_DIR_IN; + } else { + DBG("%s: Set ep0 to OUT for Data Stage\n", __func__); + ep0_desc.bEndpointAddress = 0; + } + if (r.wLength) { + controller.ep0_data_phase = true; + } else { + /* 0 length -> no Data Stage. Flip dir for Status Stage */ + DBG("%s: 0 length: flip ep0 dir for Status Stage\n", __func__); + flip_ep0_direction(); + controller.ep0_data_phase = false; + } list_del_init(&ci_req->queue); ci_ep->req_primed = false; @@ -646,6 +753,17 @@ int usb_gadget_handle_interrupts(void) return value; } +void udc_disconnect(void) +{ + struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor; + /* disable pullup */ + stop_activity(); + writel(USBCMD_FS2, &udc->usbcmd); + udelay(800); + if (controller.driver) + controller.driver->disconnect(&controller.gadget); +} + static int ci_pullup(struct usb_gadget *gadget, int is_on) { struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor; @@ -664,31 +782,15 @@ static int ci_pullup(struct usb_gadget *gadget, int is_on) /* Turn on the USB connection by enabling the pullup resistor */ writel(USBCMD_ITC(MICRO_8FRAME) | USBCMD_RUN, &udc->usbcmd); } else { - stop_activity(); - writel(USBCMD_FS2, &udc->usbcmd); - udelay(800); - if (controller.driver) - controller.driver->disconnect(gadget); + udc_disconnect(); } return 0; } -void udc_disconnect(void) -{ - struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor; - /* disable pullup */ - stop_activity(); - writel(USBCMD_FS2, &udc->usbcmd); - udelay(800); - if (controller.driver) - controller.driver->disconnect(&controller.gadget); -} - static int ci_udc_probe(void) { struct ept_queue_head *head; - uint8_t *imem; int i; const int num = 2 * NUM_ENDPOINTS; @@ -698,29 +800,18 @@ static int ci_udc_probe(void) const int eplist_raw_sz = num * sizeof(struct ept_queue_head); const int eplist_sz = roundup(eplist_raw_sz, ARCH_DMA_MINALIGN); - const int ilist_align = roundup(ARCH_DMA_MINALIGN, 32); - const int ilist_ent_raw_sz = 2 * sizeof(struct ept_queue_item); - const int ilist_ent_sz = roundup(ilist_ent_raw_sz, ARCH_DMA_MINALIGN); - const int ilist_sz = NUM_ENDPOINTS * ilist_ent_sz; - /* The QH list must be aligned to 4096 bytes. */ controller.epts = memalign(eplist_align, eplist_sz); if (!controller.epts) return -ENOMEM; memset(controller.epts, 0, eplist_sz); - /* - * Each qTD item must be 32-byte aligned, each qTD touple must be - * cacheline aligned. There are two qTD items for each endpoint and - * only one of them is used for the endpoint at time, so we can group - * them together. - */ - controller.items_mem = memalign(ilist_align, ilist_sz); + controller.items_mem = memalign(ILIST_ALIGN, ILIST_SZ); if (!controller.items_mem) { free(controller.epts); return -ENOMEM; } - memset(controller.items_mem, 0, ilist_sz); + memset(controller.items_mem, 0, ILIST_SZ); for (i = 0; i < 2 * NUM_ENDPOINTS; i++) { /* @@ -740,15 +831,9 @@ static int ci_udc_probe(void) head->next = TERMINATE; head->info = 0; - imem = controller.items_mem + ((i >> 1) * ilist_ent_sz); - if (i & 1) - imem += sizeof(struct ept_queue_item); - - controller.items[i] = (struct ept_queue_item *)imem; - if (i & 1) { - ci_flush_qh(i - 1); - ci_flush_qtd(i - 1); + ci_flush_qh(i / 2); + ci_flush_qtd(i / 2); } } @@ -756,7 +841,7 @@ static int ci_udc_probe(void) /* Init EP 0 */ memcpy(&controller.ep[0].ep, &ci_ep_init[0], sizeof(*ci_ep_init)); - controller.ep[0].desc = &ep0_in_desc; + controller.ep[0].desc = &ep0_desc; INIT_LIST_HEAD(&controller.ep[0].queue); controller.ep[0].req_primed = false; controller.gadget.ep0 = &controller.ep[0].ep; @@ -772,6 +857,13 @@ static int ci_udc_probe(void) &controller.gadget.ep_list); } + ci_ep_alloc_request(&controller.ep[0].ep, 0); + if (!controller.ep0_req) { + free(controller.items_mem); + free(controller.epts); + return -ENOMEM; + } + return 0; } @@ -816,5 +908,14 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) { + udc_disconnect(); + + driver->unbind(&controller.gadget); + controller.driver = NULL; + + ci_ep_free_request(&controller.ep[0].ep, &controller.ep0_req->req); + free(controller.items_mem); + free(controller.epts); + return 0; } diff --git a/drivers/usb/gadget/ci_udc.h b/drivers/usb/gadget/ci_udc.h index 23cff56..346164a 100644 --- a/drivers/usb/gadget/ci_udc.h +++ b/drivers/usb/gadget/ci_udc.h @@ -97,10 +97,11 @@ struct ci_ep { struct ci_drv { struct usb_gadget gadget; + struct ci_req *ep0_req; + bool ep0_data_phase; struct usb_gadget_driver *driver; struct ehci_ctrl *ctrl; struct ept_queue_head *epts; - struct ept_queue_item *items[2 * NUM_ENDPOINTS]; uint8_t *items_mem; struct ci_ep ep[NUM_ENDPOINTS]; }; diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 9dd85b6..7a1acb9 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -331,8 +331,11 @@ static void cb_getvar(struct usb_ep *ep, struct usb_request *req) char *cmd = req->buf; char response[RESPONSE_LEN]; const char *s; + size_t chars_left; strcpy(response, "OKAY"); + chars_left = sizeof(response) - strlen(response) - 1; + strsep(&cmd, ":"); if (!cmd) { fastboot_tx_write_str("FAILmissing var"); @@ -340,18 +343,18 @@ static void cb_getvar(struct usb_ep *ep, struct usb_request *req) } if (!strcmp_l1("version", cmd)) { - strncat(response, FASTBOOT_VERSION, sizeof(response)); + strncat(response, FASTBOOT_VERSION, chars_left); } else if (!strcmp_l1("bootloader-version", cmd)) { - strncat(response, U_BOOT_VERSION, sizeof(response)); + strncat(response, U_BOOT_VERSION, chars_left); } else if (!strcmp_l1("downloadsize", cmd)) { char str_num[12]; sprintf(str_num, "%08x", CONFIG_USB_FASTBOOT_BUF_SIZE); - strncat(response, str_num, sizeof(response)); + strncat(response, str_num, chars_left); } else if (!strcmp_l1("serialno", cmd)) { s = getenv("serial#"); if (s) - strncat(response, s, sizeof(response)); + strncat(response, s, chars_left); else strcpy(response, "FAILValue not set"); } else { diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 6374bb9..f274d96 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -2462,12 +2462,12 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, /* Allocate? */ if (!common) { - common = calloc(sizeof *common, 1); + common = calloc(sizeof(*common), 1); if (!common) return ERR_PTR(-ENOMEM); common->free_storage_on_release = 1; } else { - memset(common, 0, sizeof common); + memset(common, 0, sizeof(*common)); common->free_storage_on_release = 0; } diff --git a/drivers/usb/gadget/f_thor.c b/drivers/usb/gadget/f_thor.c index 28f215e..4e06273 100644 --- a/drivers/usb/gadget/f_thor.c +++ b/drivers/usb/gadget/f_thor.c @@ -306,7 +306,6 @@ static int process_data(void) ALLOC_CACHE_ALIGN_BUFFER(struct rqt_box, rqt, sizeof(struct rqt_box)); int ret = -EINVAL; - memset(rqt, 0, sizeof(rqt)); memcpy(rqt, thor_rx_data_buf, sizeof(struct rqt_box)); debug("+RQT: %d, %d\n", rqt->rqt, rqt->rqt_data); diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 7211c6a..04c1a64 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o obj-$(CONFIG_USB_SL811HS) += sl811-hcd.o obj-$(CONFIG_USB_OHCI_S3C24XX) += ohci-s3c24xx.o +obj-$(CONFIG_USB_OHCI_EP93XX) += ohci-ep93xx.o # echi obj-$(CONFIG_USB_EHCI) += ehci-hcd.o diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c new file mode 100644 index 0000000..8fb4aba --- /dev/null +++ b/drivers/usb/host/ohci-ep93xx.c @@ -0,0 +1,38 @@ +/* + * (C) Copyright 2013 + * Sergey Kostanbaev < sergey.kostanbaev <at> fairwaves.ru > + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <config.h> +#include <common.h> + +#if defined(CONFIG_USB_OHCI_NEW) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT) +#include <asm/io.h> +#include <asm/arch/ep93xx.h> + +int usb_cpu_init(void) +{ + struct syscon_regs *syscon = (struct syscon_regs *)SYSCON_BASE; + unsigned long pwr = readl(&syscon->pwrcnt); + writel(pwr | SYSCON_PWRCNT_USH_EN, &syscon->pwrcnt); + + return 0; +} + +int usb_cpu_stop(void) +{ + struct syscon_regs *syscon = (struct syscon_regs *)SYSCON_BASE; + unsigned long pwr = readl(&syscon->pwrcnt); + writel(pwr & ~SYSCON_PWRCNT_USH_EN, &syscon->pwrcnt); + + return 0; +} + +int usb_cpu_init_fail(void) +{ + return usb_cpu_stop(); +} + +#endif /* defined(CONFIG_USB_OHCI) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT) */ diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index dfe5423..5114544 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -164,8 +164,8 @@ static int enable_controller(struct r8a66597 *r8a66597) r8a66597_bset(r8a66597, INTL, SOFCFG); r8a66597_write(r8a66597, 0, INTENB0); - r8a66597_write(r8a66597, 0, INTENB1); - r8a66597_write(r8a66597, 0, INTENB2); + for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) + r8a66597_write(r8a66597, 0, get_intenb_reg(port)); r8a66597_bset(r8a66597, CONFIG_R8A66597_ENDIAN & BIGEND, CFIFOSEL); r8a66597_bset(r8a66597, CONFIG_R8A66597_ENDIAN & BIGEND, D0FIFOSEL); @@ -807,7 +807,7 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) R8A66597_DPRINT("%s\n", __func__); - memset(r8a66597, 0, sizeof(r8a66597)); + memset(r8a66597, 0, sizeof(*r8a66597)); r8a66597->reg = CONFIG_R8A66597_BASE_ADDR; disable_controller(r8a66597); diff --git a/drivers/usb/host/xhci-omap.c b/drivers/usb/host/xhci-omap.c index e667810..912b2bd 100644 --- a/drivers/usb/host/xhci-omap.c +++ b/drivers/usb/host/xhci-omap.c @@ -98,6 +98,7 @@ static int omap_xhci_core_init(struct omap_xhci *omap) { int ret = 0; + usb_phy_power(1); omap_enable_phy(omap); ret = dwc3_core_init(omap->dwc3_reg); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index d1c2e5c..59dc096 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -643,8 +643,8 @@ static int xhci_submit_root(struct usb_device *udev, unsigned long pipe, struct xhci_ctrl *ctrl = udev->controller; struct xhci_hcor *hcor = ctrl->hcor; - if (((req->requesttype & USB_RT_PORT) && - le16_to_cpu(req->index)) > CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS) { + if ((req->requesttype & USB_RT_PORT) && + le16_to_cpu(req->index) > CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS) { printf("The request port(%d) is not configured\n", le16_to_cpu(req->index) - 1); return -EINVAL; diff --git a/drivers/usb/phy/omap_usb_phy.c b/drivers/usb/phy/omap_usb_phy.c index af46db2..f78d532 100644 --- a/drivers/usb/phy/omap_usb_phy.c +++ b/drivers/usb/phy/omap_usb_phy.c @@ -222,7 +222,22 @@ static void am437x_enable_usb2_phy2(struct omap_xhci *omap) void usb_phy_power(int on) { - return; + u32 val; + + /* USB1_CTRL */ + val = readl(USB1_CTRL); + if (on) { + /* + * these bits are re-used on AM437x to power up/down the USB + * CM and OTG PHYs, if we don't toggle them, USB will not be + * functional on newer silicon revisions + */ + val &= ~(USB1_CTRL_CM_PWRDN | USB1_CTRL_OTG_PWRDN); + } else { + val |= USB1_CTRL_CM_PWRDN | USB1_CTRL_OTG_PWRDN; + } + + writel(val, USB1_CTRL); } #endif /* CONFIG_AM437X_USB2PHY2_HOST */ diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c index bb4d7d8..935ae42 100644 --- a/drivers/video/atmel_hlcdfb.c +++ b/drivers/video/atmel_hlcdfb.c @@ -171,6 +171,9 @@ void lcd_ctrl_init(void *lcdbase) | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH; desc->next = (u32)desc; + /* Flush the DMA descriptor if we enabled dcache */ + flush_dcache_range((u32)desc, (u32)desc + sizeof(*desc)); + lcdc_writel(®s->lcdc_baseaddr, desc->address); lcdc_writel(®s->lcdc_basectrl, desc->control); lcdc_writel(®s->lcdc_basenext, desc->next); @@ -194,4 +197,7 @@ void lcd_ctrl_init(void *lcdbase) lcdc_writel(®s->lcdc_lcden, value | LCDC_LCDEN_PWMEN); while (!(lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_PWMSTS)) udelay(1); + + /* Enable flushing if we enabled dcache */ + lcd_set_flush_dcache(1); } diff --git a/drivers/video/mpc8xx_lcd.c b/drivers/video/mpc8xx_lcd.c index fceed87..2bc3ceb 100644 --- a/drivers/video/mpc8xx_lcd.c +++ b/drivers/video/mpc8xx_lcd.c @@ -34,7 +34,7 @@ #define CONFIG_LCD_INFO /* Display Logo, (C) and system info */ #endif -#if defined(CONFIG_V37) || defined(CONFIG_EDT32F10) +#if defined(CONFIG_EDT32F10) #undef CONFIG_LCD_LOGO #undef CONFIG_LCD_INFO #endif @@ -268,11 +268,6 @@ void lcd_ctrl_init (void *lcdbase) * the controller. */ -#ifdef CONFIG_RPXLITE - /* This is special for RPXlite_DW Software Development Platform **[Sam]** */ - panel_info.vl_dp = CONFIG_SYS_LOW; -#endif - lccrtmp = LCDBIT (LCCR_BNUM_BIT, (((panel_info.vl_row * panel_info.vl_col) * (1 << LCD_BPP)) / 128)); @@ -297,9 +292,6 @@ void lcd_ctrl_init (void *lcdbase) /* Initialize LCD controller bus priorities. */ -#ifdef CONFIG_RBC823 - immr->im_siu_conf.sc_sdcr = (immr->im_siu_conf.sc_sdcr & ~0x0f) | 1; /* RAID = 01, LAID = 00 */ -#else immr->im_siu_conf.sc_sdcr &= ~0x0f; /* RAID = LAID = 0 */ /* set SHFT/CLOCK division factor 4 @@ -313,21 +305,7 @@ void lcd_ctrl_init (void *lcdbase) immr->im_clkrst.car_sccr &= ~0x1F; immr->im_clkrst.car_sccr |= LCD_DF; /* was 8 */ -#endif /* CONFIG_RBC823 */ - -#if defined(CONFIG_RBC823) - /* Enable LCD on port D. - */ - immr->im_ioport.iop_pddat &= 0x0300; - immr->im_ioport.iop_pdpar |= 0x1CFF; - immr->im_ioport.iop_pddir |= 0x1CFF; - - /* Configure LCD_ON, VEE_ON, CCFL_ON on port B. - */ - immr->im_cpm.cp_pbdat &= ~0x00005001; - immr->im_cpm.cp_pbpar &= ~0x00005001; - immr->im_cpm.cp_pbdir |= 0x00005001; -#elif !defined(CONFIG_EDT32F10) +#if !defined(CONFIG_EDT32F10) /* Enable LCD on port D. */ immr->im_ioport.iop_pdpar |= 0x1FFF; @@ -432,20 +410,9 @@ void lcd_enable (void) volatile lcd823_t *lcdp = &immr->im_lcd; /* Enable the LCD panel */ -#ifndef CONFIG_RBC823 immr->im_siu_conf.sc_sdcr |= (1 << (31 - 25)); /* LAM = 1 */ -#endif lcdp->lcd_lccr |= LCCR_PON; -#ifdef CONFIG_V37 - /* Turn on display backlight */ - immr->im_cpm.cp_pbpar |= 0x00008000; - immr->im_cpm.cp_pbdir |= 0x00008000; -#elif defined(CONFIG_RBC823) - /* Turn on display backlight */ - immr->im_cpm.cp_pbdat |= 0x00004000; -#endif - #if defined(CONFIG_LWMON) { uchar c = pic_read (0x60); #if defined(CONFIG_LCD) && defined(CONFIG_LWMON) && (CONFIG_POST & CONFIG_SYS_POST_SYSMON) @@ -481,14 +448,6 @@ void lcd_enable (void) r360_i2c_lcd_write(0x40 | ((ctr>>8) & 0xF), ctr & 0xFF); } #endif /* CONFIG_R360MPI */ -#ifdef CONFIG_RBC823 - udelay(200000); /* wait 200ms */ - /* Turn VEE_ON first */ - immr->im_cpm.cp_pbdat |= 0x00000001; - udelay(200000); /* wait 200ms */ - /* Now turn on LCD_ON */ - immr->im_cpm.cp_pbdat |= 0x00001000; -#endif #ifdef CONFIG_RRVISION debug ("PC4->Output(1): enable LVDS\n"); debug ("PC5->Output(0): disable PAL clock\n"); @@ -508,41 +467,6 @@ void lcd_enable (void) #endif } -/*----------------------------------------------------------------------*/ - -#if defined (CONFIG_RBC823) -void lcd_disable (void) -{ - volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR; - volatile lcd823_t *lcdp = &immr->im_lcd; - -#if defined(CONFIG_LWMON) - { uchar c = pic_read (0x60); - c &= ~0x07; /* Power off CCFL, Disable CCFL, Chip Disable LCD */ - pic_write (0x60, c); - } -#elif defined(CONFIG_R360MPI) - { - extern void r360_i2c_lcd_write (uchar data0, uchar data1); - - r360_i2c_lcd_write(0x10, 0x00); - r360_i2c_lcd_write(0x20, 0x00); - r360_i2c_lcd_write(0x30, 0x00); - r360_i2c_lcd_write(0x40, 0x00); - } -#endif /* CONFIG_LWMON */ - /* Disable the LCD panel */ - lcdp->lcd_lccr &= ~LCCR_PON; -#ifdef CONFIG_RBC823 - /* Turn off display backlight, VEE and LCD_ON */ - immr->im_cpm.cp_pbdat &= ~0x00005001; -#else - immr->im_siu_conf.sc_sdcr &= ~(1 << (31 - 25)); /* LAM = 0 */ -#endif /* CONFIG_RBC823 */ -} -#endif /* NOT_USED_SO_FAR || CONFIG_RBC823 */ - - /************************************************************************/ #endif /* CONFIG_LCD */ diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 06ced10..0276a10 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -15,3 +15,4 @@ obj-$(CONFIG_S5P) += s5p_wdt.o obj-$(CONFIG_XILINX_TB_WATCHDOG) += xilinx_tb_wdt.o obj-$(CONFIG_BFIN_WATCHDOG) += bfin_wdt.o obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o +obj-$(CONFIG_DESIGNWARE_WATCHDOG) += designware_wdt.o diff --git a/drivers/watchdog/bfin_wdt.c b/drivers/watchdog/bfin_wdt.c index 7a6756b..6a8db59 100644 --- a/drivers/watchdog/bfin_wdt.c +++ b/drivers/watchdog/bfin_wdt.c @@ -9,6 +9,7 @@ #include <common.h> #include <watchdog.h> #include <asm/blackfin.h> +#include <asm/clock.h> #include <asm/mach-common/bits/watchdog.h> void hw_watchdog_reset(void) diff --git a/drivers/watchdog/designware_wdt.c b/drivers/watchdog/designware_wdt.c new file mode 100644 index 0000000..e788e1b --- /dev/null +++ b/drivers/watchdog/designware_wdt.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2013 Altera Corporation <www.altera.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <watchdog.h> +#include <asm/io.h> +#include <asm/utils.h> + +#define DW_WDT_CR 0x00 +#define DW_WDT_TORR 0x04 +#define DW_WDT_CRR 0x0C + +#define DW_WDT_CR_EN_OFFSET 0x00 +#define DW_WDT_CR_RMOD_OFFSET 0x01 +#define DW_WDT_CR_RMOD_VAL 0x00 +#define DW_WDT_CRR_RESTART_VAL 0x76 + +/* + * Set the watchdog time interval. + * Counter is 32 bit. + */ +static int designware_wdt_settimeout(unsigned int timeout) +{ + signed int i; + + /* calculate the timeout range value */ + i = (log_2_n_round_up(timeout * CONFIG_DW_WDT_CLOCK_KHZ)) - 16; + if (i > 15) + i = 15; + if (i < 0) + i = 0; + + writel((i | (i << 4)), (CONFIG_DW_WDT_BASE + DW_WDT_TORR)); + return 0; +} + +static void designware_wdt_enable(void) +{ + writel(((DW_WDT_CR_RMOD_VAL << DW_WDT_CR_RMOD_OFFSET) | + (0x1 << DW_WDT_CR_EN_OFFSET)), + (CONFIG_DW_WDT_BASE + DW_WDT_CR)); +} + +static unsigned int designware_wdt_is_enabled(void) +{ + unsigned long val; + val = readl((CONFIG_DW_WDT_BASE + DW_WDT_CR)); + return val & 0x1; +} + +#if defined(CONFIG_HW_WATCHDOG) +void hw_watchdog_reset(void) +{ + if (designware_wdt_is_enabled()) + /* restart the watchdog counter */ + writel(DW_WDT_CRR_RESTART_VAL, + (CONFIG_DW_WDT_BASE + DW_WDT_CRR)); +} + +void hw_watchdog_init(void) +{ + /* reset to disable the watchdog */ + hw_watchdog_reset(); + /* set timer in miliseconds */ + designware_wdt_settimeout(CONFIG_HW_WATCHDOG_TIMEOUT_MS); + /* enable the watchdog */ + designware_wdt_enable(); + /* reset the watchdog */ + hw_watchdog_reset(); +} +#endif |