summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2023-01-13 09:56:19 -0500
committerTom Rini <[email protected]>2023-01-13 09:56:19 -0500
commitfe4c21de4fbf5756d354d2473ffc675e7596ccfb (patch)
tree8778bb160f68af9551d31a904af939f093235131 /drivers
parentb3f6e0ff1fe48fe56809ff85dc22c555bfc81035 (diff)
parent0e86f813f474ea6f46c6055b579eba10930dffd6 (diff)
Merge tag 'u-boot-stm32-20230113' of https://source.denx.de/u-boot/custodians/u-boot-stm
Add driver to manage onboard hub supplies Add calibration support for stm32-adc Linux kernel v6.1 DT synchronization for stm32mp151.dtsi stm32mp157a-dk1-scmi-u-boot.dtsi update Add support of OP-TEE and STM32MP13x in bsec driver ECDSA various fixes for stm32mp
Diffstat (limited to 'drivers')
-rw-r--r--drivers/adc/stm32-adc.c134
-rw-r--r--drivers/usb/Kconfig10
-rw-r--r--drivers/usb/host/usb-uclass.c16
3 files changed, 136 insertions, 24 deletions
diff --git a/drivers/adc/stm32-adc.c b/drivers/adc/stm32-adc.c
index 85efc119dbf..1fba707c6f7 100644
--- a/drivers/adc/stm32-adc.c
+++ b/drivers/adc/stm32-adc.c
@@ -33,8 +33,11 @@
#define STM32H7_ADRDY BIT(0)
/* STM32H7_ADC_CR - bit fields */
+#define STM32H7_ADCAL BIT(31)
+#define STM32H7_ADCALDIF BIT(30)
#define STM32H7_DEEPPWD BIT(29)
#define STM32H7_ADVREGEN BIT(28)
+#define STM32H7_ADCALLIN BIT(16)
#define STM32H7_BOOST BIT(8)
#define STM32H7_ADSTART BIT(2)
#define STM32H7_ADDIS BIT(1)
@@ -65,47 +68,72 @@ struct stm32_adc {
const struct stm32_adc_cfg *cfg;
};
-static int stm32_adc_stop(struct udevice *dev)
+static void stm32_adc_enter_pwr_down(struct udevice *dev)
{
struct stm32_adc *adc = dev_get_priv(dev);
- setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADDIS);
clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST);
/* Setting DEEPPWD disables ADC vreg and clears ADVREGEN */
setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_DEEPPWD);
- adc->active_channel = -1;
-
- return 0;
}
-static int stm32_adc_start_channel(struct udevice *dev, int channel)
+static int stm32_adc_exit_pwr_down(struct udevice *dev)
{
- struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
struct stm32_adc_common *common = dev_get_priv(dev_get_parent(dev));
struct stm32_adc *adc = dev_get_priv(dev);
int ret;
u32 val;
+ /* return immediately if ADC is not in deep power down mode */
+ if (!(readl(adc->regs + STM32H7_ADC_CR) & STM32H7_DEEPPWD))
+ return 0;
+
/* Exit deep power down, then enable ADC voltage regulator */
clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_DEEPPWD);
setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADVREGEN);
+
if (common->rate > STM32H7_BOOST_CLKRATE)
setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST);
/* Wait for startup time */
if (!adc->cfg->has_vregready) {
udelay(20);
- } else {
- ret = readl_poll_timeout(adc->regs + STM32H7_ADC_ISR, val,
- val & STM32MP1_VREGREADY,
- STM32_ADC_TIMEOUT_US);
- if (ret < 0) {
- stm32_adc_stop(dev);
- dev_err(dev, "Failed to enable vreg: %d\n", ret);
- return ret;
- }
+ return 0;
+ }
+
+ ret = readl_poll_timeout(adc->regs + STM32H7_ADC_ISR, val,
+ val & STM32MP1_VREGREADY,
+ STM32_ADC_TIMEOUT_US);
+ if (ret < 0) {
+ stm32_adc_enter_pwr_down(dev);
+ dev_err(dev, "Failed to enable vreg: %d\n", ret);
}
+ return ret;
+}
+
+static int stm32_adc_stop(struct udevice *dev)
+{
+ struct stm32_adc *adc = dev_get_priv(dev);
+
+ setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADDIS);
+ stm32_adc_enter_pwr_down(dev);
+ adc->active_channel = -1;
+
+ return 0;
+}
+
+static int stm32_adc_start_channel(struct udevice *dev, int channel)
+{
+ struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
+ struct stm32_adc *adc = dev_get_priv(dev);
+ int ret;
+ u32 val;
+
+ ret = stm32_adc_exit_pwr_down(dev);
+ if (ret < 0)
+ return ret;
+
/* Only use single ended channels */
writel(0, adc->regs + STM32H7_ADC_DIFSEL);
@@ -162,6 +190,64 @@ static int stm32_adc_channel_data(struct udevice *dev, int channel,
return 0;
}
+/**
+ * Fixed timeout value for ADC calibration.
+ * worst cases:
+ * - low clock frequency (0.12 MHz min)
+ * - maximum prescalers
+ * Calibration requires:
+ * - 16384 ADC clock cycle for the linear calibration
+ * - 20 ADC clock cycle for the offset calibration
+ *
+ * Set to 100ms for now
+ */
+#define STM32H7_ADC_CALIB_TIMEOUT_US 100000
+
+static int stm32_adc_selfcalib(struct udevice *dev)
+{
+ struct stm32_adc *adc = dev_get_priv(dev);
+ int ret;
+ u32 val;
+
+ /*
+ * Select calibration mode:
+ * - Offset calibration for single ended inputs
+ * - No linearity calibration. Done in next step.
+ */
+ clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADCALDIF | STM32H7_ADCALLIN);
+
+ /* Start calibration, then wait for completion */
+ setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADCAL);
+ ret = readl_poll_sleep_timeout(adc->regs + STM32H7_ADC_CR, val,
+ !(val & STM32H7_ADCAL), 100,
+ STM32H7_ADC_CALIB_TIMEOUT_US);
+ if (ret) {
+ dev_err(dev, "calibration failed\n");
+ goto out;
+ }
+
+ /*
+ * Select calibration mode, then start calibration:
+ * - Offset calibration for differential input
+ * - Linearity calibration (needs to be done only once for single/diff)
+ * will run simultaneously with offset calibration.
+ */
+ setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADCALDIF | STM32H7_ADCALLIN);
+
+ /* Start calibration, then wait for completion */
+ setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADCAL);
+ ret = readl_poll_sleep_timeout(adc->regs + STM32H7_ADC_CR, val,
+ !(val & STM32H7_ADCAL), 100,
+ STM32H7_ADC_CALIB_TIMEOUT_US);
+ if (ret)
+ dev_err(dev, "calibration failed\n");
+
+out:
+ clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADCALDIF | STM32H7_ADCALLIN);
+
+ return ret;
+}
+
static int stm32_adc_get_legacy_chan_count(struct udevice *dev)
{
int ret;
@@ -272,7 +358,7 @@ static int stm32_adc_probe(struct udevice *dev)
struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
struct stm32_adc_common *common = dev_get_priv(dev_get_parent(dev));
struct stm32_adc *adc = dev_get_priv(dev);
- int offset;
+ int offset, ret;
offset = dev_read_u32_default(dev, "reg", -ENODATA);
if (offset < 0) {
@@ -287,7 +373,19 @@ static int stm32_adc_probe(struct udevice *dev)
uc_pdata->vdd_microvolts = common->vref_uv;
uc_pdata->vss_microvolts = 0;
- return stm32_adc_chan_of_init(dev);
+ ret = stm32_adc_chan_of_init(dev);
+ if (ret < 0)
+ return ret;
+
+ ret = stm32_adc_exit_pwr_down(dev);
+ if (ret < 0)
+ return ret;
+
+ ret = stm32_adc_selfcalib(dev);
+ if (ret)
+ stm32_adc_enter_pwr_down(dev);
+
+ return ret;
}
static const struct adc_ops stm32_adc_ops = {
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 8efd4614573..ebe6bf94981 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -105,6 +105,16 @@ config USB_KEYBOARD
Say Y here if you want to use a USB keyboard for U-Boot command line
input.
+config USB_ONBOARD_HUB
+ bool "Onboard USB hub support"
+ depends on DM_USB
+ ---help---
+ Say Y here if you want to support discrete onboard USB hubs that
+ don't require an additional control bus for initialization, but
+ need some non-trivial form of initialization, such as enabling a
+ power regulator. An example for such a hub is the Microchip
+ USB2514B.
+
if USB_KEYBOARD
config USB_KEYBOARD_FN_KEYS
diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c
index 956e2a4e8e4..93c318c3d1d 100644
--- a/drivers/usb/host/usb-uclass.c
+++ b/drivers/usb/host/usb-uclass.c
@@ -271,19 +271,23 @@ int usb_init(void)
/* init low_level USB */
printf("Bus %s: ", bus->name);
-#ifdef CONFIG_SANDBOX
/*
* For Sandbox, we need scan the device tree each time when we
* start the USB stack, in order to re-create the emulated USB
* devices and bind drivers for them before we actually do the
* driver probe.
+ *
+ * For USB onboard HUB, we need to do some non-trivial init
+ * like enabling a power regulator, before enumeration.
*/
- ret = dm_scan_fdt_dev(bus);
- if (ret) {
- printf("Sandbox USB device scan failed (%d)\n", ret);
- continue;
+ if (IS_ENABLED(CONFIG_SANDBOX) ||
+ IS_ENABLED(CONFIG_USB_ONBOARD_HUB)) {
+ ret = dm_scan_fdt_dev(bus);
+ if (ret) {
+ printf("USB device scan from fdt failed (%d)", ret);
+ continue;
+ }
}
-#endif
ret = device_probe(bus);
if (ret == -ENODEV) { /* No such device. */