diff options
author | keith.zhao <keith.zhao@starfivetech.com> | 2023-02-16 14:43:17 +0300 |
---|---|---|
committer | keith.zhao <keith.zhao@starfivetech.com> | 2023-02-17 06:56:53 +0300 |
commit | f042c1ea252e3dfc955db03b0e95e0b322a7afca (patch) | |
tree | 51a2ea9864e7fdb41dee896fe0862b45cec41f0c /drivers/power | |
parent | a6d99b2bd03f952b22958779b423de7ba237657a (diff) | |
download | u-boot-f042c1ea252e3dfc955db03b0e95e0b322a7afca.tar.xz |
power: add power subsystem driver in uboot
add power subsystem in driver,include pmu pmic and regulator
pmu : dc8200 power
pmic : mipi power
regulator : entend power
Signed-off-by:keith.zhao<keith.zhao@statfivetech.com>
Diffstat (limited to 'drivers/power')
-rw-r--r-- | drivers/power/domain/Kconfig | 7 | ||||
-rw-r--r-- | drivers/power/domain/Makefile | 1 | ||||
-rw-r--r-- | drivers/power/domain/starfive-power-domain.c | 155 | ||||
-rw-r--r-- | drivers/power/pmic/Kconfig | 7 | ||||
-rw-r--r-- | drivers/power/pmic/Makefile | 1 | ||||
-rw-r--r-- | drivers/power/pmic/pmic_starfive.c | 98 | ||||
-rw-r--r-- | drivers/power/regulator/Kconfig | 8 | ||||
-rw-r--r-- | drivers/power/regulator/Makefile | 1 | ||||
-rw-r--r-- | drivers/power/regulator/starfive_regulator.c | 181 |
9 files changed, 459 insertions, 0 deletions
diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig index 99b3f9ae71..0b8bbcab03 100644 --- a/drivers/power/domain/Kconfig +++ b/drivers/power/domain/Kconfig @@ -30,6 +30,13 @@ config IMX8M_POWER_DOMAIN Enable support for manipulating NXP i.MX8M on-SoC power domains via requests to the ATF. +config STARFIVE_POWER_DOMAIN + bool "Enable starfive power domain driver" + depends on POWER_DOMAIN + help + Enable support for pwoer up on-SoC power domains via + requests to the ATF. + config MTK_POWER_DOMAIN bool "Enable the MediaTek power domain driver" depends on POWER_DOMAIN && ARCH_MEDIATEK diff --git a/drivers/power/domain/Makefile b/drivers/power/domain/Makefile index 3d1e5f073c..9e7cdc5fa0 100644 --- a/drivers/power/domain/Makefile +++ b/drivers/power/domain/Makefile @@ -15,3 +15,4 @@ obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain-test.o obj-$(CONFIG_TEGRA186_POWER_DOMAIN) += tegra186-power-domain.o obj-$(CONFIG_TI_SCI_POWER_DOMAIN) += ti-sci-power-domain.o obj-$(CONFIG_TI_POWER_DOMAIN) += ti-power-domain.o +obj-$(CONFIG_STARFIVE_POWER_DOMAIN) += starfive-power-domain.o diff --git a/drivers/power/domain/starfive-power-domain.c b/drivers/power/domain/starfive-power-domain.c new file mode 100644 index 0000000000..d33c9a5c46 --- /dev/null +++ b/drivers/power/domain/starfive-power-domain.c @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com> + */ +#include <asm/io.h> +#include <common.h> +#include <dm.h> +#include <linux/bitops.h> +#include <linux/iopoll.h> +#include <malloc.h> +#include <power-domain-uclass.h> + +#define usleep_range(a, b) udelay((b)) + +#define MAX_DOMAINS 64 +#define TIMEOUT_US 100000 + +/* register define */ +#define HW_EVENT_TURN_ON_MASK 0x04 +#define HW_EVENT_TURN_OFF_MASK 0x08 +#define SW_TURN_ON_POWER_MODE 0x0C +#define SW_TURN_OFF_POWER_MODE 0x10 +#define SW_ENCOURAGE 0x44 +#define PMU_INT_MASK 0x48 +#define PCH_BYPASS 0x4C +#define PCH_PSTATE 0x50 +#define PCH_TIMEOUT 0x54 +#define LP_TIMEOUT 0x58 +#define HW_TURN_ON_MODE 0x5C +#define CURR_POWER_MODE 0x80 +#define PMU_EVENT_STATUS 0x88 +#define PMU_INT_STATUS 0x8C + +/* sw encourage cfg */ +#define SW_MODE_ENCOURAGE_EN_LO 0x05 +#define SW_MODE_ENCOURAGE_EN_HI 0x50 +#define SW_MODE_ENCOURAGE_DIS_LO 0x0A +#define SW_MODE_ENCOURAGE_DIS_HI 0xA0 +#define SW_MODE_ENCOURAGE_ON 0xFF + +struct sf_power_domain { + void __iomem *regs; +}; + +static int sf_power_domain_request(struct power_domain *power_domain) +{ + if (power_domain->id >= MAX_DOMAINS) + return -EINVAL; + + return 0; +} + +static int sf_power_domain_free(struct power_domain *power_domain) +{ + return 0; +} + +static int sf_power_domain_on(struct power_domain *power_domain) +{ + struct sf_power_domain *priv = dev_get_priv(power_domain->dev); + uint32_t mode; + uint32_t val; + uint32_t encourage_lo; + uint32_t encourage_hi; + int ret; + mode = SW_TURN_ON_POWER_MODE; + encourage_lo = SW_MODE_ENCOURAGE_EN_LO; + encourage_hi = SW_MODE_ENCOURAGE_EN_HI; + + /* write SW_ENCOURAGE to make the configuration take effect */ + val = __raw_readl(priv->regs + mode) | BIT(power_domain->id); + + __raw_writel(val, priv->regs + mode); + __raw_writel(SW_MODE_ENCOURAGE_ON, priv->regs + SW_ENCOURAGE); + __raw_writel(encourage_lo, priv->regs + SW_ENCOURAGE); + __raw_writel(encourage_hi, priv->regs + SW_ENCOURAGE); + + ret = readl_poll_timeout(priv->regs + CURR_POWER_MODE, val, + val & BIT(power_domain->id), + TIMEOUT_US); + if (ret) { + pr_err("power_on failed"); + return -ETIMEDOUT; + } + + + return 0; +} + +static int sf_power_domain_off(struct power_domain *power_domain) +{ + struct sf_power_domain *priv = dev_get_priv(power_domain->dev); + uint32_t mode; + uint32_t val; + uint32_t encourage_lo; + uint32_t encourage_hi; + int ret; + mode = SW_TURN_OFF_POWER_MODE; + encourage_lo = SW_MODE_ENCOURAGE_DIS_LO; + encourage_hi = SW_MODE_ENCOURAGE_DIS_HI; + + val = __raw_readl(priv->regs + mode) & ~(BIT(power_domain->id)); + + __raw_writel(val, priv->regs + mode); + __raw_writel(SW_MODE_ENCOURAGE_ON, priv->regs + SW_ENCOURAGE); + __raw_writel(encourage_lo, priv->regs + SW_ENCOURAGE); + __raw_writel(encourage_hi, priv->regs + SW_ENCOURAGE); + + ret = readl_poll_timeout(priv->regs + CURR_POWER_MODE, val, + !(val & BIT(power_domain->id)), + TIMEOUT_US); + if (ret) { + pr_err("power_off failed"); + return -ETIMEDOUT; + } + + + return 0; +} + + +static int sf_power_domain_probe(struct udevice *dev) +{ + struct sf_power_domain *priv = dev_get_priv(dev); + + fdt_addr_t addr; + addr = dev_read_addr_index(dev, 0); + priv->regs = (void __iomem *)addr; + + if (!priv->regs) + return -EINVAL; + + return 0; +} + +static const struct udevice_id sf_power_domain_ids[] = { + { .compatible = "starfive,jh7110-pmu" }, + { /* sentinel */ } +}; + +struct power_domain_ops sf_power_domain_ops = { + .rfree = sf_power_domain_free, + .off = sf_power_domain_off, + .on = sf_power_domain_on, + .request = sf_power_domain_request, +}; + +U_BOOT_DRIVER(sf_power_domain) = { + .name = "sf_power_domain", + .id = UCLASS_POWER_DOMAIN, + .of_match = sf_power_domain_ids, + .ops = &sf_power_domain_ops, + .priv_auto = sizeof(struct sf_power_domain), + .probe = sf_power_domain_probe, +}; diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index fd6648b313..693576d0a8 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -342,3 +342,10 @@ config PMIC_TPS65941 help The TPS65941 is a PMIC containing a bunch of SMPS & LDOs. This driver binds the pmic children. + +config PMIC_STARFIVE + bool "Enable driver for STARFIVE PMIC" + depends on DM_PMIC + help + The PMIC contains a bunch of SMPS & LDOs. + This driver binds the pmic children. diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 5d1a97e5f6..f447328201 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -42,3 +42,4 @@ obj-$(CONFIG_POWER_TPS65910) += pmic_tps65910.o obj-$(CONFIG_POWER_HI6553) += pmic_hi6553.o obj-$(CONFIG_POWER_MC34VR500) += pmic_mc34vr500.o obj-$(CONFIG_PMIC_TPS65941) += tps65941.o +obj-$(CONFIG_PMIC_STARFIVE) += pmic_starfive.o diff --git a/drivers/power/pmic/pmic_starfive.c b/drivers/power/pmic/pmic_starfive.c new file mode 100644 index 0000000000..71e4d2c519 --- /dev/null +++ b/drivers/power/pmic/pmic_starfive.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2023 Starfive, Inc. + * Author: keith.zhao<keith.zhao@statfivetech.com> + */ + +#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <log.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <dm/device.h> + +#define LP8732 0x0 +#define LP8733 0x1 + +#define LP873X_LDO_NUM 8 + +/* Drivers name */ +#define LP873X_LDO_DRIVER "lp873x_ldo" +#define LP873X_BUCK_DRIVER "lp873x_buck" + +#define LP873X_BUCK_VOLT_MASK 0xFF +#define LP873X_BUCK_VOLT_MAX_HEX 0xFF +#define LP873X_BUCK_VOLT_MAX 3360000 +#define LP873X_BUCK_MODE_MASK 0x1 + +#define LP873X_LDO_VOLT_MASK 0x1F +#define LP873X_LDO_VOLT_MAX_HEX 0x19 +#define LP873X_LDO_VOLT_MAX 3300000 +#define LP873X_LDO_MODE_MASK 0x1 + +static const struct pmic_child_info pmic_children_info[] = { + { .prefix = "ldo", .driver = LP873X_LDO_DRIVER }, + { }, +}; + +static int lp873x_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + if (dm_i2c_write(dev, reg, buff, len)) { + pr_err("write error to device: %p register: %#x!\n", dev, reg); + return -EIO; + } + + return 0; +} + +static int lp873x_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + if (dm_i2c_read(dev, reg, buff, len)) { + pr_err("read error from device: %p register: %#x!\n", dev, reg); + return -EIO; + } + + return 0; +} + +static int starfive_bind(struct udevice *dev) +{ + ofnode regulators_node; + int children; + + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { + printf("%s: %s regulators subnode not found!\n", __func__, + dev->name); + return -ENXIO; + } + + children = pmic_bind_children(dev, regulators_node, pmic_children_info); + if (!children) + printf("%s: %s - no child found\n", __func__, dev->name); + + /* Always return success for this device */ + return 0; +} + +static struct dm_pmic_ops lp873x_ops = { + .read = lp873x_read, + .write = lp873x_write, +}; + +static const struct udevice_id starfive_ids[] = { + { .compatible = "starfive,jh7110-evb-regulator", .data = LP8732 }, + { } +}; + +U_BOOT_DRIVER(pmic_starfive) = { + .name = "pmic_starfive", + .id = UCLASS_PMIC, + .of_match = starfive_ids, + .bind = starfive_bind, + .ops = &lp873x_ops, +}; diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index cd253b95f2..fc5b1062f4 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -266,6 +266,14 @@ config DM_REGULATOR_LP873X features for REGULATOR LP873X and the family of LP873X PMICs. The driver implements get/set api for: value and enable. +config DM_REGULATOR_STARFIVE + bool "Enable driver for STARFIVE PMIC regulators" + depends on PMIC_STARFIVE + ---help--- + This enables implementation of driver-model regulator uclass + features for REGULATOR LP873X and the family of LP873X PMICs. + The driver implements get/set api for: value and enable. + config DM_REGULATOR_LP87565 bool "Enable driver for LP87565 PMIC regulators" depends on PMIC_LP87565 diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index 677134c822..b3085c6a1a 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_$(SPL_)DM_REGULATOR_PALMAS) += palmas_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_PBIAS) += pbias_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP873X) += lp873x_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP87565) += lp87565_regulator.o +obj-$(CONFIG_$(SPL_)DM_REGULATOR_STARFIVE) += starfive_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o obj-$(CONFIG_DM_REGULATOR_TPS65910) += tps65910_regulator.o obj-$(CONFIG_DM_REGULATOR_TPS62360) += tps62360_regulator.o diff --git a/drivers/power/regulator/starfive_regulator.c b/drivers/power/regulator/starfive_regulator.c new file mode 100644 index 0000000000..548accd5b1 --- /dev/null +++ b/drivers/power/regulator/starfive_regulator.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2023 Starfive, Inc. + * Author: keith.zhao<keith.zhao@statfivetech.com> + */ + + +#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/lp873x.h> + +static const char lp873x_ldo_ctrl[LP873X_LDO_NUM] = {0x8, 0x9}; +static const char lp873x_ldo_volt[LP873X_LDO_NUM] = {0xA, 0xB}; + + +static int lp873x_ldo_enable(struct udevice *dev, int op, bool *enable) +{ + int ret; + unsigned int adr; + struct dm_regulator_uclass_plat *uc_pdata; + + uc_pdata = dev_get_uclass_plat(dev); + adr = uc_pdata->ctrl_reg; + + ret = pmic_reg_read(dev->parent, adr); + if (ret < 0) + return ret; + + if (op == PMIC_OP_GET) { + ret &= LP873X_LDO_MODE_MASK; + + if (ret) + *enable = true; + else + *enable = false; + + return 0; + } else if (op == PMIC_OP_SET) { + if (*enable) + ret |= LP873X_LDO_MODE_MASK; + else + ret &= ~(LP873X_LDO_MODE_MASK); + + ret = pmic_reg_write(dev->parent, adr, ret); + if (ret) + return ret; + } + + return 0; +} + +static int lp873x_ldo_volt2hex(int uV) +{ + if (uV > LP873X_LDO_VOLT_MAX) + return -EINVAL; + + return (uV - 800000) / 100000; +} + +static int lp873x_ldo_hex2volt(int hex) +{ + if (hex > LP873X_LDO_VOLT_MAX_HEX) + return -EINVAL; + + if (!hex) + return 0; + + return (hex * 100000) + 800000; +} + +static int lp873x_ldo_val(struct udevice *dev, int op, int *uV) +{ + unsigned int hex, adr; + int ret; + + struct dm_regulator_uclass_plat *uc_pdata; + + if (op == PMIC_OP_GET) + *uV = 0; + + uc_pdata = dev_get_uclass_plat(dev); + + adr = uc_pdata->volt_reg; + + ret = pmic_reg_read(dev->parent, adr); + if (ret < 0) + return ret; + + if (op == PMIC_OP_GET) { + ret &= LP873X_LDO_VOLT_MASK; + ret = lp873x_ldo_hex2volt(ret); + if (ret < 0) + return ret; + *uV = ret; + return 0; + } + + hex = lp873x_ldo_volt2hex(*uV); + if (hex < 0) + return hex; + + ret &= ~LP873X_LDO_VOLT_MASK; + ret |= hex; + if (*uV > 1650000) + ret |= 0x80; + ret = pmic_reg_write(dev->parent, adr, ret); + + return ret; +} + +static int lp873x_ldo_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_plat *uc_pdata; + + uc_pdata = dev_get_uclass_plat(dev); + uc_pdata->type = REGULATOR_TYPE_LDO; + + int idx = dev->driver_data; + if (idx >= LP873X_LDO_NUM) { + return -1; + } + + uc_pdata->ctrl_reg = lp873x_ldo_ctrl[idx]; + uc_pdata->volt_reg = lp873x_ldo_volt[idx]; + + return 0; +} + +static int ldo_get_value(struct udevice *dev) +{ + int uV; + int ret; + + ret = lp873x_ldo_val(dev, PMIC_OP_GET, &uV); + if (ret) + return ret; + + return uV; +} + +static int ldo_set_value(struct udevice *dev, int uV) +{ + return lp873x_ldo_val(dev, PMIC_OP_SET, &uV); +} + +static int ldo_get_enable(struct udevice *dev) +{ + bool enable = false; + int ret; + + ret = lp873x_ldo_enable(dev, PMIC_OP_GET, &enable); + if (ret) + return ret; + + return enable; +} + +static int ldo_set_enable(struct udevice *dev, bool enable) +{ + return lp873x_ldo_enable(dev, PMIC_OP_SET, &enable); +} + +static const struct dm_regulator_ops lp873x_ldo_ops = { + .get_value = ldo_get_value, + .set_value = ldo_set_value, + .get_enable = ldo_get_enable, + .set_enable = ldo_set_enable, +}; + +U_BOOT_DRIVER(lp873x_ldo) = { + .name = LP873X_LDO_DRIVER, + .id = UCLASS_REGULATOR, + .ops = &lp873x_ldo_ops, + .probe = lp873x_ldo_probe, +}; + |