summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/core/Kconfig9
-rw-r--r--drivers/core/device-remove.c4
-rw-r--r--drivers/core/device.c103
-rw-r--r--drivers/core/root.c14
-rw-r--r--drivers/core/uclass.c122
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/mvgpio.h6
-rw-r--r--drivers/gpio/mvmfp.c14
-rw-r--r--drivers/gpio/stm32_gpio.c199
-rw-r--r--drivers/misc/status_led.c14
-rw-r--r--drivers/serial/Kconfig10
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/ns16550.c36
-rw-r--r--drivers/serial/serial-uclass.c2
-rw-r--r--drivers/serial/serial.c2
-rw-r--r--drivers/serial/serial_stm32.c117
-rw-r--r--drivers/usb/emul/sandbox_hub.c1
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/ehci-vf.c164
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;
+}