diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/core/Kconfig | 9 | ||||
-rw-r--r-- | drivers/core/device-remove.c | 4 | ||||
-rw-r--r-- | drivers/core/device.c | 103 | ||||
-rw-r--r-- | drivers/core/root.c | 14 | ||||
-rw-r--r-- | drivers/core/uclass.c | 122 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpio/mvgpio.h | 6 | ||||
-rw-r--r-- | drivers/gpio/mvmfp.c | 14 | ||||
-rw-r--r-- | drivers/gpio/stm32_gpio.c | 199 | ||||
-rw-r--r-- | drivers/misc/status_led.c | 14 | ||||
-rw-r--r-- | drivers/serial/Kconfig | 10 | ||||
-rw-r--r-- | drivers/serial/Makefile | 1 | ||||
-rw-r--r-- | drivers/serial/ns16550.c | 36 | ||||
-rw-r--r-- | drivers/serial/serial-uclass.c | 2 | ||||
-rw-r--r-- | drivers/serial/serial.c | 2 | ||||
-rw-r--r-- | drivers/serial/serial_stm32.c | 117 | ||||
-rw-r--r-- | drivers/usb/emul/sandbox_hub.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/host/ehci-vf.c | 164 |
19 files changed, 716 insertions, 104 deletions
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig index 75d182d..2861b43 100644 --- a/drivers/core/Kconfig +++ b/drivers/core/Kconfig @@ -46,3 +46,12 @@ config DM_STDIO Normally serial drivers register with stdio so that they can be used as normal output devices. In SPL we don't normally use stdio, so we can omit this feature. + +config DM_SEQ_ALIAS + bool "Support numbered aliases in device tree" + depends on DM + default y + help + Most boards will have a '/aliases' node containing the path to + numbered devices (e.g. serial0 = &serial0). This feature can be + disabled if it is not required, to save code space in SPL. diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c index 7fee1c0..6a16b4f 100644 --- a/drivers/core/device-remove.c +++ b/drivers/core/device-remove.c @@ -92,6 +92,10 @@ int device_unbind(struct udevice *dev) free(dev->platdata); dev->platdata = NULL; } + if (dev->flags & DM_FLAG_ALLOC_UCLASS_PDATA) { + free(dev->uclass_platdata); + dev->uclass_platdata = NULL; + } if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) { free(dev->parent_platdata); dev->parent_platdata = NULL; diff --git a/drivers/core/device.c b/drivers/core/device.c index ccaa99c..3b77d23 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -30,7 +30,7 @@ int device_bind(struct udevice *parent, const struct driver *drv, { struct udevice *dev; struct uclass *uc; - int ret = 0; + int size, ret = 0; *devp = NULL; if (!name) @@ -56,21 +56,23 @@ int device_bind(struct udevice *parent, const struct driver *drv, dev->seq = -1; dev->req_seq = -1; -#ifdef CONFIG_OF_CONTROL - /* - * Some devices, such as a SPI bus, I2C bus and serial ports are - * numbered using aliases. - * - * This is just a 'requested' sequence, and will be - * resolved (and ->seq updated) when the device is probed. - */ - if (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS) { - if (uc->uc_drv->name && of_offset != -1) { - fdtdec_get_alias_seq(gd->fdt_blob, uc->uc_drv->name, - of_offset, &dev->req_seq); + if (IS_ENABLED(CONFIG_OF_CONTROL) && IS_ENABLED(CONFIG_DM_SEQ_ALIAS)) { + /* + * Some devices, such as a SPI bus, I2C bus and serial ports + * are numbered using aliases. + * + * This is just a 'requested' sequence, and will be + * resolved (and ->seq updated) when the device is probed. + */ + if (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS) { + if (uc->uc_drv->name && of_offset != -1) { + fdtdec_get_alias_seq(gd->fdt_blob, + uc->uc_drv->name, of_offset, + &dev->req_seq); + } } } -#endif + if (!dev->platdata && drv->platdata_auto_alloc_size) { dev->flags |= DM_FLAG_ALLOC_PDATA; dev->platdata = calloc(1, drv->platdata_auto_alloc_size); @@ -79,9 +81,19 @@ int device_bind(struct udevice *parent, const struct driver *drv, goto fail_alloc1; } } - if (parent) { - int size = parent->driver->per_child_platdata_auto_alloc_size; + size = uc->uc_drv->per_device_platdata_auto_alloc_size; + if (size) { + dev->flags |= DM_FLAG_ALLOC_UCLASS_PDATA; + dev->uclass_platdata = calloc(1, size); + if (!dev->uclass_platdata) { + ret = -ENOMEM; + goto fail_alloc2; + } + } + + if (parent) { + size = parent->driver->per_child_platdata_auto_alloc_size; if (!size) { size = parent->uclass->uc_drv-> per_child_platdata_auto_alloc_size; @@ -91,7 +103,7 @@ int device_bind(struct udevice *parent, const struct driver *drv, dev->parent_platdata = calloc(1, size); if (!dev->parent_platdata) { ret = -ENOMEM; - goto fail_alloc2; + goto fail_alloc3; } } } @@ -123,21 +135,32 @@ int device_bind(struct udevice *parent, const struct driver *drv, return 0; fail_child_post_bind: - if (drv->unbind && drv->unbind(dev)) { - dm_warn("unbind() method failed on dev '%s' on error path\n", - dev->name); + if (IS_ENABLED(DM_DEVICE_REMOVE)) { + if (drv->unbind && drv->unbind(dev)) { + dm_warn("unbind() method failed on dev '%s' on error path\n", + dev->name); + } } fail_bind: - if (uclass_unbind_device(dev)) { - dm_warn("Failed to unbind dev '%s' on error path\n", - dev->name); + if (IS_ENABLED(DM_DEVICE_REMOVE)) { + if (uclass_unbind_device(dev)) { + dm_warn("Failed to unbind dev '%s' on error path\n", + dev->name); + } } fail_uclass_bind: - list_del(&dev->sibling_node); - if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) { - free(dev->parent_platdata); - dev->parent_platdata = NULL; + if (IS_ENABLED(DM_DEVICE_REMOVE)) { + list_del(&dev->sibling_node); + if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) { + free(dev->parent_platdata); + dev->parent_platdata = NULL; + } + } +fail_alloc3: + if (dev->flags & DM_FLAG_ALLOC_UCLASS_PDATA) { + free(dev->uclass_platdata); + dev->uclass_platdata = NULL; } fail_alloc2: if (dev->flags & DM_FLAG_ALLOC_PDATA) { @@ -314,6 +337,16 @@ void *dev_get_parent_platdata(struct udevice *dev) return dev->parent_platdata; } +void *dev_get_uclass_platdata(struct udevice *dev) +{ + if (!dev) { + dm_warn("%s: null device", __func__); + return NULL; + } + + return dev->uclass_platdata; +} + void *dev_get_priv(struct udevice *dev) { if (!dev) { @@ -474,11 +507,27 @@ ulong dev_get_driver_data(struct udevice *dev) return dev->driver_data; } +const void *dev_get_driver_ops(struct udevice *dev) +{ + if (!dev || !dev->driver->ops) + return NULL; + + return dev->driver->ops; +} + enum uclass_id device_get_uclass_id(struct udevice *dev) { return dev->uclass->uc_drv->id; } +const char *dev_get_uclass_name(struct udevice *dev) +{ + if (!dev) + return NULL; + + return dev->uclass->uc_drv->name; +} + #ifdef CONFIG_OF_CONTROL fdt_addr_t dev_get_addr(struct udevice *dev) { diff --git a/drivers/core/root.c b/drivers/core/root.c index 9b5c6bb..12d0460 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -197,13 +197,15 @@ int dm_init_and_scan(bool pre_reloc_only) debug("dm_scan_platdata() failed: %d\n", ret); return ret; } -#ifdef CONFIG_OF_CONTROL - ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only); - if (ret) { - debug("dm_scan_fdt() failed: %d\n", ret); - return ret; + + if (OF_CONTROL) { + ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only); + if (ret) { + debug("dm_scan_fdt() failed: %d\n", ret); + return ret; + } } -#endif + ret = dm_scan_other(pre_reloc_only); if (ret) return ret; diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 98c15e5..04e939d 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -99,10 +99,18 @@ fail_mem: int uclass_destroy(struct uclass *uc) { struct uclass_driver *uc_drv; - struct udevice *dev, *tmp; + struct udevice *dev; int ret; - list_for_each_entry_safe(dev, tmp, &uc->dev_head, uclass_node) { + /* + * We cannot use list_for_each_entry_safe() here. If a device in this + * uclass has a child device also in this uclass, it will be also be + * unbound (by the recursion in the call to device_unbind() below). + * We can loop until the list is empty. + */ + while (!list_empty(&uc->dev_head)) { + dev = list_first_entry(&uc->dev_head, struct udevice, + uclass_node); ret = device_remove(dev); if (ret) return ret; @@ -156,6 +164,60 @@ int uclass_find_device(enum uclass_id id, int index, struct udevice **devp) return -ENODEV; } +int uclass_find_first_device(enum uclass_id id, struct udevice **devp) +{ + struct uclass *uc; + int ret; + + *devp = NULL; + ret = uclass_get(id, &uc); + if (ret) + return ret; + if (list_empty(&uc->dev_head)) + return 0; + + *devp = list_first_entry(&uc->dev_head, struct udevice, uclass_node); + + return 0; +} + +int uclass_find_next_device(struct udevice **devp) +{ + struct udevice *dev = *devp; + + *devp = NULL; + if (list_is_last(&dev->uclass_node, &dev->uclass->dev_head)) + return 0; + + *devp = list_entry(dev->uclass_node.next, struct udevice, uclass_node); + + return 0; +} + +int uclass_find_device_by_name(enum uclass_id id, const char *name, + struct udevice **devp) +{ + struct uclass *uc; + struct udevice *dev; + int ret; + + *devp = NULL; + if (!name) + return -EINVAL; + ret = uclass_get(id, &uc); + if (ret) + return ret; + + list_for_each_entry(dev, &uc->dev_head, uclass_node) { + if (!strncmp(dev->name, name, strlen(name))) { + *devp = dev; + return 0; + } + } + + return -ENODEV; +} + int uclass_find_device_by_seq(enum uclass_id id, int seq_or_req_seq, bool find_req_seq, struct udevice **devp) { @@ -209,17 +271,7 @@ static int uclass_find_device_by_of_offset(enum uclass_id id, int node, return -ENODEV; } -/** - * uclass_get_device_tail() - handle the end of a get_device call - * - * This handles returning an error or probing a device as needed. - * - * @dev: Device that needs to be probed - * @ret: Error to return. If non-zero then the device is not probed - * @devp: Returns the value of 'dev' if there is no error - * @return ret, if non-zero, else the result of the device_probe() call - */ -static int uclass_get_device_tail(struct udevice *dev, int ret, +int uclass_get_device_tail(struct udevice *dev, int ret, struct udevice **devp) { if (ret) @@ -244,6 +296,17 @@ int uclass_get_device(enum uclass_id id, int index, struct udevice **devp) return uclass_get_device_tail(dev, ret, devp); } +int uclass_get_device_by_name(enum uclass_id id, const char *name, + struct udevice **devp) +{ + struct udevice *dev; + int ret; + + *devp = NULL; + ret = uclass_find_device_by_name(id, name, &dev); + return uclass_get_device_tail(dev, ret, devp); +} + int uclass_get_device_by_seq(enum uclass_id id, int seq, struct udevice **devp) { struct udevice *dev; @@ -274,24 +337,12 @@ int uclass_get_device_by_of_offset(enum uclass_id id, int node, int uclass_first_device(enum uclass_id id, struct udevice **devp) { - struct uclass *uc; struct udevice *dev; int ret; *devp = NULL; - ret = uclass_get(id, &uc); - if (ret) - return ret; - if (list_empty(&uc->dev_head)) - return 0; - - dev = list_first_entry(&uc->dev_head, struct udevice, uclass_node); - ret = device_probe(dev); - if (ret) - return ret; - *devp = dev; - - return 0; + ret = uclass_find_first_device(id, &dev); + return uclass_get_device_tail(dev, ret, devp); } int uclass_next_device(struct udevice **devp) @@ -300,17 +351,8 @@ int uclass_next_device(struct udevice **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 udevice, - uclass_node); - ret = device_probe(dev); - if (ret) - return ret; - *devp = dev; - - return 0; + ret = uclass_find_next_device(&dev); + return uclass_get_device_tail(dev, ret, devp); } int uclass_bind_device(struct udevice *dev) @@ -344,6 +386,7 @@ err: return ret; } +#ifdef CONFIG_DM_DEVICE_REMOVE int uclass_unbind_device(struct udevice *dev) { struct uclass *uc; @@ -359,6 +402,7 @@ int uclass_unbind_device(struct udevice *dev) list_del(&dev->uclass_node); return 0; } +#endif int uclass_resolve_seq(struct udevice *dev) { @@ -422,6 +466,7 @@ int uclass_post_probe_device(struct udevice *dev) return 0; } +#ifdef CONFIG_DM_DEVICE_REMOVE int uclass_pre_remove_device(struct udevice *dev) { struct uclass_driver *uc_drv; @@ -443,3 +488,4 @@ int uclass_pre_remove_device(struct udevice *dev) return 0; } +#endif diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 85f71c5..8ca8b05 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -42,3 +42,4 @@ obj-$(CONFIG_TCA642X) += tca642x.o oby-$(CONFIG_SX151X) += sx151x.o obj-$(CONFIG_SUNXI_GPIO) += sunxi_gpio.o obj-$(CONFIG_LPC32XX_GPIO) += lpc32xx_gpio.o +obj-$(CONFIG_STM32_GPIO) += stm32_gpio.o diff --git a/drivers/gpio/mvgpio.h b/drivers/gpio/mvgpio.h index a3f17a0..1de7395 100644 --- a/drivers/gpio/mvgpio.h +++ b/drivers/gpio/mvgpio.h @@ -14,9 +14,8 @@ #include <common.h> -#ifdef CONFIG_SHEEVA_88SV331xV5 /* - * GPIO Register map for SHEEVA 88SV331xV5 + * GPIO Register map for Marvell SOCs */ struct gpio_reg { u32 gplr; /* Pin Level Register - 0x0000 */ @@ -51,8 +50,5 @@ struct gpio_reg { u32 pad12[2]; u32 apmask; /* Bitwise Mask of Edge Detect Register - 0x009C */ }; -#else -#error "CPU core subversion not defined" -#endif #endif /* __MVGPIO_H__ */ diff --git a/drivers/gpio/mvmfp.c b/drivers/gpio/mvmfp.c index 97bbe99..43ecf66 100644 --- a/drivers/gpio/mvmfp.c +++ b/drivers/gpio/mvmfp.c @@ -43,18 +43,8 @@ void mfp_config(u32 *mfp_cfgs) /* Write a mfg register as per configuration */ val = 0; - if (cfg_val & MFP_AF_FLAG) - /* Abstract and program Afternate-Func Selection */ - val |= cfg_val & MFP_AF_MASK; - if (cfg_val & MFP_EDGE_FLAG) - /* Abstract and program Edge configuration */ - val |= cfg_val & MFP_LPM_EDGE_MASK; - if (cfg_val & MFP_DRIVE_FLAG) - /* Abstract and program Drive configuration */ - val |= cfg_val & MFP_DRIVE_MASK; - if (cfg_val & MFP_PULL_FLAG) - /* Abstract and program Pullup/down configuration */ - val |= cfg_val & MFP_PULL_MASK; + if (cfg_val & MFP_VALUE_MASK) + val |= cfg_val & MFP_VALUE_MASK; writel(val, p_mfpr); } while (1); diff --git a/drivers/gpio/stm32_gpio.c b/drivers/gpio/stm32_gpio.c new file mode 100644 index 0000000..d3497e9 --- /dev/null +++ b/drivers/gpio/stm32_gpio.c @@ -0,0 +1,199 @@ +/* + * (C) Copyright 2011 + * Yuri Tikhonov, Emcraft Systems, yur@emcraft.com + * + * (C) Copyright 2015 + * Kamil Lulko, <rev13@wp.pl> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/errno.h> +#include <asm/arch/stm32.h> +#include <asm/arch/gpio.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define STM32_GPIOA_BASE (STM32_AHB1PERIPH_BASE + 0x0000) +#define STM32_GPIOB_BASE (STM32_AHB1PERIPH_BASE + 0x0400) +#define STM32_GPIOC_BASE (STM32_AHB1PERIPH_BASE + 0x0800) +#define STM32_GPIOD_BASE (STM32_AHB1PERIPH_BASE + 0x0C00) +#define STM32_GPIOE_BASE (STM32_AHB1PERIPH_BASE + 0x1000) +#define STM32_GPIOF_BASE (STM32_AHB1PERIPH_BASE + 0x1400) +#define STM32_GPIOG_BASE (STM32_AHB1PERIPH_BASE + 0x1800) +#define STM32_GPIOH_BASE (STM32_AHB1PERIPH_BASE + 0x1C00) +#define STM32_GPIOI_BASE (STM32_AHB1PERIPH_BASE + 0x2000) + +static const unsigned long io_base[] = { + STM32_GPIOA_BASE, STM32_GPIOB_BASE, STM32_GPIOC_BASE, + STM32_GPIOD_BASE, STM32_GPIOE_BASE, STM32_GPIOF_BASE, + STM32_GPIOG_BASE, STM32_GPIOH_BASE, STM32_GPIOI_BASE +}; + +struct stm32_gpio_regs { + u32 moder; /* GPIO port mode */ + u32 otyper; /* GPIO port output type */ + u32 ospeedr; /* GPIO port output speed */ + u32 pupdr; /* GPIO port pull-up/pull-down */ + u32 idr; /* GPIO port input data */ + u32 odr; /* GPIO port output data */ + u32 bsrr; /* GPIO port bit set/reset */ + u32 lckr; /* GPIO port configuration lock */ + u32 afr[2]; /* GPIO alternate function */ +}; + +#define CHECK_DSC(x) (!x || x->port > 8 || x->pin > 15) +#define CHECK_CTL(x) (!x || x->af > 15 || x->mode > 3 || x->otype > 1 || \ + x->pupd > 2 || x->speed > 3) + +int stm32_gpio_config(const struct stm32_gpio_dsc *dsc, + const struct stm32_gpio_ctl *ctl) +{ + struct stm32_gpio_regs *gpio_regs; + u32 i; + int rv; + + if (CHECK_DSC(dsc)) { + rv = -EINVAL; + goto out; + } + if (CHECK_CTL(ctl)) { + rv = -EINVAL; + goto out; + } + + gpio_regs = (struct stm32_gpio_regs *)io_base[dsc->port]; + + setbits_le32(&STM32_RCC->ahb1enr, 1 << dsc->port); + + i = (dsc->pin & 0x07) * 4; + clrbits_le32(&gpio_regs->afr[dsc->pin >> 3], (0xF << i)); + setbits_le32(&gpio_regs->afr[dsc->pin >> 3], ctl->af << i); + + i = dsc->pin * 2; + + clrbits_le32(&gpio_regs->moder, (0x3 << i)); + setbits_le32(&gpio_regs->moder, ctl->mode << i); + + clrbits_le32(&gpio_regs->otyper, (0x3 << i)); + setbits_le32(&gpio_regs->otyper, ctl->otype << i); + + clrbits_le32(&gpio_regs->ospeedr, (0x3 << i)); + setbits_le32(&gpio_regs->ospeedr, ctl->speed << i); + + clrbits_le32(&gpio_regs->pupdr, (0x3 << i)); + setbits_le32(&gpio_regs->pupdr, ctl->pupd << i); + + rv = 0; +out: + return rv; +} + +int stm32_gpout_set(const struct stm32_gpio_dsc *dsc, int state) +{ + struct stm32_gpio_regs *gpio_regs; + int rv; + + if (CHECK_DSC(dsc)) { + rv = -EINVAL; + goto out; + } + + gpio_regs = (struct stm32_gpio_regs *)io_base[dsc->port]; + + if (state) + writel(1 << dsc->pin, &gpio_regs->bsrr); + else + writel(1 << (dsc->pin + 16), &gpio_regs->bsrr); + + rv = 0; +out: + return rv; +} + +int stm32_gpin_get(const struct stm32_gpio_dsc *dsc) +{ + struct stm32_gpio_regs *gpio_regs; + int rv; + + if (CHECK_DSC(dsc)) { + rv = -EINVAL; + goto out; + } + + gpio_regs = (struct stm32_gpio_regs *)io_base[dsc->port]; + rv = readl(&gpio_regs->idr) & (1 << dsc->pin); +out: + return rv; +} + +/* Common GPIO API */ + +int gpio_request(unsigned gpio, const char *label) +{ + return 0; +} + +int gpio_free(unsigned gpio) +{ + return 0; +} + +int gpio_direction_input(unsigned gpio) +{ + struct stm32_gpio_dsc dsc; + struct stm32_gpio_ctl ctl; + + dsc.port = stm32_gpio_to_port(gpio); + dsc.pin = stm32_gpio_to_pin(gpio); + ctl.af = STM32_GPIO_AF0; + ctl.mode = STM32_GPIO_MODE_IN; + ctl.pupd = STM32_GPIO_PUPD_NO; + ctl.speed = STM32_GPIO_SPEED_50M; + + return stm32_gpio_config(&dsc, &ctl); +} + +int gpio_direction_output(unsigned gpio, int value) +{ + struct stm32_gpio_dsc dsc; + struct stm32_gpio_ctl ctl; + int res; + + dsc.port = stm32_gpio_to_port(gpio); + dsc.pin = stm32_gpio_to_pin(gpio); + ctl.af = STM32_GPIO_AF0; + ctl.mode = STM32_GPIO_MODE_OUT; + ctl.otype = STM32_GPIO_OTYPE_PP; + ctl.pupd = STM32_GPIO_PUPD_NO; + ctl.speed = STM32_GPIO_SPEED_50M; + + res = stm32_gpio_config(&dsc, &ctl); + if (res < 0) + goto out; + res = stm32_gpout_set(&dsc, value); +out: + return res; +} + +int gpio_get_value(unsigned gpio) +{ + struct stm32_gpio_dsc dsc; + + dsc.port = stm32_gpio_to_port(gpio); + dsc.pin = stm32_gpio_to_pin(gpio); + + return stm32_gpin_get(&dsc); +} + +int gpio_set_value(unsigned gpio, int value) +{ + struct stm32_gpio_dsc dsc; + + dsc.port = stm32_gpio_to_port(gpio); + dsc.pin = stm32_gpio_to_pin(gpio); + + return stm32_gpout_set(&dsc, value); +} diff --git a/drivers/misc/status_led.c b/drivers/misc/status_led.c index ed9adb2..9869d98 100644 --- a/drivers/misc/status_led.c +++ b/drivers/misc/status_led.c @@ -53,6 +53,20 @@ led_dev_t led_dev[] = { 0, }, #endif +#if defined(STATUS_LED_BIT4) + { STATUS_LED_BIT4, + STATUS_LED_STATE4, + STATUS_LED_PERIOD4, + 0, + }, +#endif +#if defined(STATUS_LED_BIT5) + { STATUS_LED_BIT5, + STATUS_LED_STATE5, + STATUS_LED_PERIOD5, + 0, + }, +#endif }; #define MAX_LED_DEV (sizeof(led_dev)/sizeof(led_dev_t)) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 1686a1f..54e6f26 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -66,6 +66,16 @@ config DEBUG_UART_CLOCK A default should be provided by your board, but if not you will need to use the correct value here. +config DEBUG_UART_SHIFT + int "UART register shift" + depends on DEBUG_UART + default 0 if DEBUG_UART + help + Some UARTs (notably ns16550) support different register layouts + where the registers are spaced either as bytes, words or some other + value. Use this value to specify the shift to use, where 0=byte + registers, 2=32-bit word registers, etc. + config UNIPHIER_SERIAL bool "UniPhier on-chip UART support" depends on ARCH_UNIPHIER && DM_SERIAL diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index b385852..d183eed 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_TEGRA_SERIAL) += serial_tegra.o obj-$(CONFIG_UNIPHIER_SERIAL) += serial_uniphier.o obj-$(CONFIG_OMAP_SERIAL) += serial_omap.o obj-$(CONFIG_X86_SERIAL) += serial_x86.o +obj-$(CONFIG_STM32_SERIAL) += serial_stm32.o ifndef CONFIG_SPL_BUILD obj-$(CONFIG_USB_TTY) += usbtty.o diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 67b1d60..fd110b3 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -57,7 +57,7 @@ DECLARE_GLOBAL_DATA_PTR; #ifdef CONFIG_DM_SERIAL -static inline void serial_out_shift(unsigned char *addr, int shift, int value) +static inline void serial_out_shift(void *addr, int shift, int value) { #ifdef CONFIG_SYS_NS16550_PORT_MAPPED outb(value, (ulong)addr); @@ -72,7 +72,7 @@ static inline void serial_out_shift(unsigned char *addr, int shift, int value) #endif } -static inline int serial_in_shift(unsigned char *addr, int shift) +static inline int serial_in_shift(void *addr, int shift) { #ifdef CONFIG_SYS_NS16550_PORT_MAPPED return inb((ulong)addr); @@ -114,9 +114,11 @@ static int ns16550_readb(NS16550_t port, int offset) /* We can clean these up once everything is moved to driver model */ #define serial_out(value, addr) \ - ns16550_writeb(com_port, addr - (unsigned char *)com_port, value) + ns16550_writeb(com_port, \ + (unsigned char *)addr - (unsigned char *)com_port, value) #define serial_in(addr) \ - ns16550_readb(com_port, addr - (unsigned char *)com_port) + ns16550_readb(com_port, \ + (unsigned char *)addr - (unsigned char *)com_port) #endif static inline int calc_divisor(NS16550_t port, int clock, int baudrate) @@ -173,7 +175,6 @@ void NS16550_init(NS16550_t com_port, int baud_divisor) defined(CONFIG_TI81XX) || defined(CONFIG_AM43XX) serial_out(0x7, &com_port->mdr1); /* mode select reset TL16C750*/ #endif - NS16550_setbrg(com_port, 0); serial_out(UART_MCRVAL, &com_port->mcr); serial_out(UART_FCRVAL, &com_port->fcr); if (baud_divisor != -1) @@ -254,15 +255,20 @@ void debug_uart_init(void) */ baud_divisor = calc_divisor(com_port, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE); - - serial_out_shift(&com_port->ier, 0, CONFIG_SYS_NS16550_IER); - serial_out_shift(&com_port->mcr, 0, UART_MCRVAL); - serial_out_shift(&com_port->fcr, 0, UART_FCRVAL); - - serial_out_shift(&com_port->lcr, 0, UART_LCR_BKSE | UART_LCRVAL); - serial_out_shift(&com_port->dll, 0, baud_divisor & 0xff); - serial_out_shift(&com_port->dlm, 0, (baud_divisor >> 8) & 0xff); - serial_out_shift(&com_port->lcr, 0, UART_LCRVAL); + baud_divisor = 13; + serial_out_shift(&com_port->ier, CONFIG_DEBUG_UART_SHIFT, + CONFIG_SYS_NS16550_IER); + serial_out_shift(&com_port->mcr, CONFIG_DEBUG_UART_SHIFT, UART_MCRVAL); + serial_out_shift(&com_port->fcr, CONFIG_DEBUG_UART_SHIFT, UART_FCRVAL); + + serial_out_shift(&com_port->lcr, CONFIG_DEBUG_UART_SHIFT, + UART_LCR_BKSE | UART_LCRVAL); + serial_out_shift(&com_port->dll, CONFIG_DEBUG_UART_SHIFT, + baud_divisor & 0xff); + serial_out_shift(&com_port->dlm, CONFIG_DEBUG_UART_SHIFT, + (baud_divisor >> 8) & 0xff); + serial_out_shift(&com_port->lcr, CONFIG_DEBUG_UART_SHIFT, + UART_LCRVAL); } static inline void _debug_uart_putc(int ch) @@ -271,7 +277,7 @@ static inline void _debug_uart_putc(int ch) while (!(serial_in_shift(&com_port->lsr, 0) & UART_LSR_THRE)) ; - serial_out_shift(&com_port->thr, 0, ch); + serial_out_shift(&com_port->thr, CONFIG_DEBUG_UART_SHIFT, ch); } DEBUG_UART_FUNCS diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index b239691..b8c2f48 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -70,7 +70,7 @@ static void serial_find_console_or_panic(void) if (uclass_get_device_by_seq(UCLASS_SERIAL, INDEX, &dev) && uclass_get_device(UCLASS_SERIAL, INDEX, &dev) && (uclass_first_device(UCLASS_SERIAL, &dev) || !dev)) - panic("No serial driver found"); + panic_str("No serial driver found"); #undef INDEX gd->cur_serial_dev = dev; } diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index 9f78492..699c410 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -154,6 +154,7 @@ serial_initfunc(sa1100_serial_initialize); serial_initfunc(sandbox_serial_initialize); serial_initfunc(sconsole_serial_initialize); serial_initfunc(sh_serial_initialize); +serial_initfunc(stm32_serial_initialize); serial_initfunc(uartlite_serial_initialize); serial_initfunc(zynq_serial_initialize); @@ -246,6 +247,7 @@ void serial_initialize(void) sandbox_serial_initialize(); sconsole_serial_initialize(); sh_serial_initialize(); + stm32_serial_initialize(); uartlite_serial_initialize(); zynq_serial_initialize(); diff --git a/drivers/serial/serial_stm32.c b/drivers/serial/serial_stm32.c new file mode 100644 index 0000000..3c80096 --- /dev/null +++ b/drivers/serial/serial_stm32.c @@ -0,0 +1,117 @@ +/* + * (C) Copyright 2015 + * Kamil Lulko, <rev13@wp.pl> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <serial.h> +#include <asm/arch/stm32.h> + +#define STM32_USART1_BASE (STM32_APB2PERIPH_BASE + 0x1000) +#define RCC_APB2ENR_USART1EN (1 << 4) + +#define USART_BASE STM32_USART1_BASE +#define RCC_USART_ENABLE RCC_APB2ENR_USART1EN + +struct stm32_serial { + u32 sr; + u32 dr; + u32 brr; + u32 cr1; + u32 cr2; + u32 cr3; + u32 gtpr; +}; + +#define USART_CR1_RE (1 << 2) +#define USART_CR1_TE (1 << 3) +#define USART_CR1_UE (1 << 13) + +#define USART_SR_FLAG_RXNE (1 << 5) +#define USART_SR_FLAG_TXE (1 << 7) + +#define USART_BRR_F_MASK 0xF +#define USART_BRR_M_SHIFT 4 +#define USART_BRR_M_MASK 0xFFF0 + +DECLARE_GLOBAL_DATA_PTR; + +static void stm32_serial_setbrg(void) +{ + serial_init(); +} + +static int stm32_serial_init(void) +{ + struct stm32_serial *usart = (struct stm32_serial *)USART_BASE; + u32 clock, int_div, frac_div, tmp; + + if ((USART_BASE & STM32_BUS_MASK) == STM32_APB1PERIPH_BASE) { + setbits_le32(&STM32_RCC->apb1enr, RCC_USART_ENABLE); + clock = clock_get(CLOCK_APB1); + } else if ((USART_BASE & STM32_BUS_MASK) == STM32_APB2PERIPH_BASE) { + setbits_le32(&STM32_RCC->apb2enr, RCC_USART_ENABLE); + clock = clock_get(CLOCK_APB2); + } else { + return -1; + } + + int_div = (25 * clock) / (4 * gd->baudrate); + tmp = ((int_div / 100) << USART_BRR_M_SHIFT) & USART_BRR_M_MASK; + frac_div = int_div - (100 * (tmp >> USART_BRR_M_SHIFT)); + tmp |= (((frac_div * 16) + 50) / 100) & USART_BRR_F_MASK; + + writel(tmp, &usart->brr); + setbits_le32(&usart->cr1, USART_CR1_RE | USART_CR1_TE | USART_CR1_UE); + + return 0; +} + +static int stm32_serial_getc(void) +{ + struct stm32_serial *usart = (struct stm32_serial *)USART_BASE; + while ((readl(&usart->sr) & USART_SR_FLAG_RXNE) == 0) + ; + return readl(&usart->dr); +} + +static void stm32_serial_putc(const char c) +{ + struct stm32_serial *usart = (struct stm32_serial *)USART_BASE; + while ((readl(&usart->sr) & USART_SR_FLAG_TXE) == 0) + ; + writel(c, &usart->dr); +} + +static int stm32_serial_tstc(void) +{ + struct stm32_serial *usart = (struct stm32_serial *)USART_BASE; + u8 ret; + + ret = readl(&usart->sr) & USART_SR_FLAG_RXNE; + return ret; +} + +static struct serial_device stm32_serial_drv = { + .name = "stm32_serial", + .start = stm32_serial_init, + .stop = NULL, + .setbrg = stm32_serial_setbrg, + .putc = stm32_serial_putc, + .puts = default_serial_puts, + .getc = stm32_serial_getc, + .tstc = stm32_serial_tstc, +}; + +void stm32_serial_initialize(void) +{ + serial_register(&stm32_serial_drv); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &stm32_serial_drv; +} diff --git a/drivers/usb/emul/sandbox_hub.c b/drivers/usb/emul/sandbox_hub.c index 280c708..baf8bdc 100644 --- a/drivers/usb/emul/sandbox_hub.c +++ b/drivers/usb/emul/sandbox_hub.c @@ -32,6 +32,7 @@ static struct usb_string hub_strings[] = { {STRING_MANUFACTURER, "sandbox"}, {STRING_PRODUCT, "hub"}, {STRING_SERIAL, "2345"}, + {}, }; static struct usb_device_descriptor hub_device_desc = { diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 7658f87..3b57e56 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_USB_EHCI_SUNXI) += ehci-sunxi.o obj-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o obj-$(CONFIG_USB_EHCI_UNIPHIER) += ehci-uniphier.o obj-$(CONFIG_USB_EHCI_VCT) += ehci-vct.o +obj-$(CONFIG_USB_EHCI_VF) += ehci-vf.o obj-$(CONFIG_USB_EHCI_RMOBILE) += ehci-rmobile.o obj-$(CONFIG_USB_EHCI_ZYNQ) += ehci-zynq.o diff --git a/drivers/usb/host/ehci-vf.c b/drivers/usb/host/ehci-vf.c new file mode 100644 index 0000000..5454855 --- /dev/null +++ b/drivers/usb/host/ehci-vf.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2015 Sanchayan Maity <sanchayan.maity@toradex.com> + * Copyright (C) 2015 Toradex AG + * + * Based on ehci-mx6 driver + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <usb.h> +#include <errno.h> +#include <linux/compiler.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/imx-regs.h> +#include <asm/arch/crm_regs.h> +#include <asm/imx-common/iomux-v3.h> +#include <asm/imx-common/regs-usbphy.h> +#include <usb/ehci-fsl.h> + +#include "ehci.h" + +#define USB_NC_REG_OFFSET 0x00000800 + +#define ANADIG_PLL_CTRL_EN_USB_CLKS (1 << 6) + +#define UCTRL_OVER_CUR_POL (1 << 8) /* OTG Polarity of Overcurrent */ +#define UCTRL_OVER_CUR_DIS (1 << 7) /* Disable OTG Overcurrent Detection */ + +/* USBCMD */ +#define UCMD_RUN_STOP (1 << 0) /* controller run/stop */ +#define UCMD_RESET (1 << 1) /* controller reset */ + +static const unsigned phy_bases[] = { + USB_PHY0_BASE_ADDR, + USB_PHY1_BASE_ADDR, +}; + +static const unsigned nc_reg_bases[] = { + USBC0_BASE_ADDR, + USBC1_BASE_ADDR, +}; + +static void usb_internal_phy_clock_gate(int index) +{ + void __iomem *phy_reg; + + phy_reg = (void __iomem *)phy_bases[index]; + clrbits_le32(phy_reg + USBPHY_CTRL, USBPHY_CTRL_CLKGATE); +} + +static void usb_power_config(int index) +{ + struct anadig_reg __iomem *anadig = + (struct anadig_reg __iomem *)ANADIG_BASE_ADDR; + void __iomem *pll_ctrl; + + switch (index) { + case 0: + pll_ctrl = &anadig->pll3_ctrl; + clrbits_le32(pll_ctrl, ANADIG_PLL3_CTRL_BYPASS); + setbits_le32(pll_ctrl, ANADIG_PLL3_CTRL_ENABLE + | ANADIG_PLL3_CTRL_POWERDOWN + | ANADIG_PLL_CTRL_EN_USB_CLKS); + break; + case 1: + pll_ctrl = &anadig->pll7_ctrl; + clrbits_le32(pll_ctrl, ANADIG_PLL7_CTRL_BYPASS); + setbits_le32(pll_ctrl, ANADIG_PLL7_CTRL_ENABLE + | ANADIG_PLL7_CTRL_POWERDOWN + | ANADIG_PLL_CTRL_EN_USB_CLKS); + break; + default: + return; + } +} + +static void usb_phy_enable(int index, struct usb_ehci *ehci) +{ + void __iomem *phy_reg; + void __iomem *phy_ctrl; + void __iomem *usb_cmd; + + phy_reg = (void __iomem *)phy_bases[index]; + phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL); + usb_cmd = (void __iomem *)&ehci->usbcmd; + + /* Stop then Reset */ + clrbits_le32(usb_cmd, UCMD_RUN_STOP); + while (readl(usb_cmd) & UCMD_RUN_STOP) + ; + + setbits_le32(usb_cmd, UCMD_RESET); + while (readl(usb_cmd) & UCMD_RESET) + ; + + /* Reset USBPHY module */ + setbits_le32(phy_ctrl, USBPHY_CTRL_SFTRST); + udelay(10); + + /* Remove CLKGATE and SFTRST */ + clrbits_le32(phy_ctrl, USBPHY_CTRL_CLKGATE | USBPHY_CTRL_SFTRST); + udelay(10); + + /* Power up the PHY */ + writel(0, phy_reg + USBPHY_PWD); + + /* Enable FS/LS device */ + setbits_le32(phy_ctrl, USBPHY_CTRL_ENUTMILEVEL2 | + USBPHY_CTRL_ENUTMILEVEL3); +} + +static void usb_oc_config(int index) +{ + void __iomem *ctrl; + + ctrl = (void __iomem *)(nc_reg_bases[index] + USB_NC_REG_OFFSET); + + setbits_le32(ctrl, UCTRL_OVER_CUR_POL); + setbits_le32(ctrl, UCTRL_OVER_CUR_DIS); +} + +int ehci_hcd_init(int index, enum usb_init_type init, + struct ehci_hccr **hccr, struct ehci_hcor **hcor) +{ + struct usb_ehci *ehci; + + if (index >= ARRAY_SIZE(nc_reg_bases)) + return -EINVAL; + + if (init == USB_INIT_DEVICE && index == 1) + return -ENODEV; + if (init == USB_INIT_HOST && index == 0) + return -ENODEV; + + ehci = (struct usb_ehci *)nc_reg_bases[index]; + + usb_power_config(index); + usb_oc_config(index); + usb_internal_phy_clock_gate(index); + usb_phy_enable(index, ehci); + + *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); + *hcor = (struct ehci_hcor *)((uint32_t)*hccr + + HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); + + if (init == USB_INIT_DEVICE) { + setbits_le32(&ehci->usbmode, CM_DEVICE); + writel((PORT_PTS_UTMI | PORT_PTS_PTW), &ehci->portsc); + setbits_le32(&ehci->portsc, USB_EN); + } else if (init == USB_INIT_HOST) { + setbits_le32(&ehci->usbmode, CM_HOST); + writel((PORT_PTS_UTMI | PORT_PTS_PTW), &ehci->portsc); + setbits_le32(&ehci->portsc, USB_EN); + } + + return 0; +} + +int ehci_hcd_stop(int index) +{ + return 0; +} |