summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bios_emulator/atibios.c2
-rw-r--r--drivers/block/Kconfig1
-rw-r--r--drivers/core/uclass.c9
-rw-r--r--drivers/gpio/intel_broadwell_gpio.c7
-rw-r--r--drivers/i2c/intel_i2c.c6
-rw-r--r--drivers/misc/cros_ec.c385
-rw-r--r--drivers/misc/fsl_sec_mon.c240
-rw-r--r--drivers/mmc/Kconfig1
-rw-r--r--drivers/mmc/mmc-uclass.c1
-rw-r--r--drivers/mmc/mmc_private.h4
-rw-r--r--drivers/mmc/mmc_write.c10
-rw-r--r--drivers/pci/pci_rom.c62
-rw-r--r--drivers/power/pmic/Kconfig14
-rw-r--r--drivers/power/pmic/Makefile2
-rw-r--r--drivers/power/pmic/lp873x.c86
-rw-r--r--drivers/power/pmic/palmas.c104
-rw-r--r--drivers/power/regulator/Kconfig24
-rw-r--r--drivers/power/regulator/Makefile3
-rw-r--r--drivers/power/regulator/fixed.c21
-rw-r--r--drivers/power/regulator/gpio-regulator.c137
-rw-r--r--drivers/power/regulator/lp873x_regulator.c357
-rw-r--r--drivers/power/regulator/palmas_regulator.c453
-rw-r--r--drivers/reset/Kconfig9
-rw-r--r--drivers/reset/Makefile1
-rw-r--r--drivers/reset/reset-uniphier.c376
-rw-r--r--drivers/rtc/mc146818.c2
-rw-r--r--drivers/spi/fsl_qspi.c10
-rw-r--r--drivers/tpm/tpm_tis_lpc.c4
-rw-r--r--drivers/usb/host/ehci-pci.c4
-rw-r--r--drivers/video/Kconfig23
-rw-r--r--drivers/video/Makefile5
-rw-r--r--drivers/video/broadwell_igd.c39
-rw-r--r--drivers/video/coreboot.c79
-rw-r--r--drivers/video/coreboot_fb.c108
-rw-r--r--drivers/video/ivybridge_igd.c843
-rw-r--r--drivers/video/simple_panel.c2
-rw-r--r--drivers/video/vesa.c34
-rw-r--r--drivers/video/vesa_fb.c63
-rw-r--r--drivers/video/video-uclass.c3
39 files changed, 2847 insertions, 687 deletions
diff --git a/drivers/bios_emulator/atibios.c b/drivers/bios_emulator/atibios.c
index 7717246..2d5b5dc 100644
--- a/drivers/bios_emulator/atibios.c
+++ b/drivers/bios_emulator/atibios.c
@@ -599,7 +599,7 @@ int biosemu_run(pci_dev_t pcidev, uchar *bios_rom, int bios_len,
if (clean_up) {
BE_exit();
if (vga_info->BIOSImage &&
- (u32)(vga_info->BIOSImage) != 0xc0000)
+ (ulong)(vga_info->BIOSImage) != 0xc0000)
free(vga_info->BIOSImage);
free(vga_info);
vga_info = NULL;
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 80eea84..fe5aa07 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -1,6 +1,7 @@
config BLK
bool "Support block devices"
depends on DM
+ default y if DM_MMC
help
Enable support for block devices, such as SCSI, MMC and USB
flash sticks. These provide a block-level interface which permits
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index de602ae..60610e5 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -148,6 +148,15 @@ int uclass_get(enum uclass_id id, struct uclass **ucp)
return 0;
}
+const char *uclass_get_name(enum uclass_id id)
+{
+ struct uclass *uc;
+
+ if (uclass_get(id, &uc))
+ return NULL;
+ return uc->uc_drv->name;
+}
+
int uclass_find_device(enum uclass_id id, int index, struct udevice **devp)
{
struct uclass *uc;
diff --git a/drivers/gpio/intel_broadwell_gpio.c b/drivers/gpio/intel_broadwell_gpio.c
index 8b50900..81ce446 100644
--- a/drivers/gpio/intel_broadwell_gpio.c
+++ b/drivers/gpio/intel_broadwell_gpio.c
@@ -9,6 +9,7 @@
#include <fdtdec.h>
#include <pch.h>
#include <pci.h>
+#include <syscon.h>
#include <asm/cpu.h>
#include <asm/gpio.h>
#include <asm/io.h>
@@ -118,6 +119,12 @@ static int broadwell_gpio_probe(struct udevice *dev)
struct broadwell_bank_platdata *plat = dev_get_platdata(dev);
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
struct broadwell_bank_priv *priv = dev_get_priv(dev);
+ struct udevice *pinctrl;
+ int ret;
+
+ /* Set up pin control if available */
+ ret = syscon_get_by_driver_data(X86_SYSCON_PINCONF, &pinctrl);
+ debug("%s, pinctrl=%p, ret=%d\n", __func__, pinctrl, ret);
uc_priv->gpio_count = GPIO_PER_BANK;
uc_priv->bank_name = plat->bank_name;
diff --git a/drivers/i2c/intel_i2c.c b/drivers/i2c/intel_i2c.c
index a0182dc..550a728 100644
--- a/drivers/i2c/intel_i2c.c
+++ b/drivers/i2c/intel_i2c.c
@@ -248,11 +248,11 @@ static int intel_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
static int intel_i2c_probe(struct udevice *dev)
{
struct intel_i2c *priv = dev_get_priv(dev);
- u32 base;
+ ulong base;
/* Save base address from PCI BAR */
- priv->base = (u32)dm_pci_map_bar(dev, PCI_BASE_ADDRESS_4,
- PCI_REGION_IO);
+ priv->base = (ulong)dm_pci_map_bar(dev, PCI_BASE_ADDRESS_4,
+ PCI_REGION_IO);
base = priv->base;
/* Set SMBus enable. */
diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c
index 5225cdb..8073730 100644
--- a/drivers/misc/cros_ec.c
+++ b/drivers/misc/cros_ec.c
@@ -43,9 +43,6 @@ enum {
DECLARE_GLOBAL_DATA_PTR;
-/* Note: depends on enum ec_current_image */
-static const char * const ec_current_image_name[] = {"unknown", "RO", "RW"};
-
void cros_ec_dump_data(const char *name, int cmd, const uint8_t *data, int len)
{
#ifdef DEBUG
@@ -750,15 +747,24 @@ int cros_ec_flash_erase(struct cros_ec_dev *dev, uint32_t offset, uint32_t size)
static int cros_ec_flash_write_block(struct cros_ec_dev *dev,
const uint8_t *data, uint32_t offset, uint32_t size)
{
- struct ec_params_flash_write p;
+ struct ec_params_flash_write *p;
+ int ret;
- p.offset = offset;
- p.size = size;
- assert(data && p.size <= EC_FLASH_WRITE_VER0_SIZE);
- memcpy(&p + 1, data, p.size);
+ p = malloc(sizeof(*p) + size);
+ if (!p)
+ return -ENOMEM;
+
+ p->offset = offset;
+ p->size = size;
+ assert(data && p->size <= EC_FLASH_WRITE_VER0_SIZE);
+ memcpy(p + 1, data, p->size);
+
+ ret = ec_command_inptr(dev, EC_CMD_FLASH_WRITE, 0,
+ p, sizeof(*p) + size, NULL, 0) >= 0 ? 0 : -1;
- return ec_command_inptr(dev, EC_CMD_FLASH_WRITE, 0,
- &p, sizeof(p), NULL, 0) >= 0 ? 0 : -1;
+ free(p);
+
+ return ret;
}
/**
@@ -790,6 +796,27 @@ static int cros_ec_data_is_erased(const uint32_t *data, int size)
return 1;
}
+/**
+ * Read back flash parameters
+ *
+ * This function reads back parameters of the flash as reported by the EC
+ *
+ * @param dev Pointer to device
+ * @param info Pointer to output flash info struct
+ */
+int cros_ec_read_flashinfo(struct cros_ec_dev *dev,
+ struct ec_response_flash_info *info)
+{
+ int ret;
+
+ ret = ec_command(dev, EC_CMD_FLASH_INFO, 0,
+ NULL, 0, info, sizeof(*info));
+ if (ret < 0)
+ return ret;
+
+ return ret < sizeof(*info) ? -1 : 0;
+}
+
int cros_ec_flash_write(struct cros_ec_dev *dev, const uint8_t *data,
uint32_t offset, uint32_t size)
{
@@ -1134,344 +1161,6 @@ int cros_ec_i2c_tunnel(struct udevice *dev, int port, struct i2c_msg *in,
return 0;
}
-#ifdef CONFIG_CMD_CROS_EC
-
-/**
- * Perform a flash read or write command
- *
- * @param dev CROS-EC device to read/write
- * @param is_write 1 do to a write, 0 to do a read
- * @param argc Number of arguments
- * @param argv Arguments (2 is region, 3 is address)
- * @return 0 for ok, 1 for a usage error or -ve for ec command error
- * (negative EC_RES_...)
- */
-static int do_read_write(struct cros_ec_dev *dev, int is_write, int argc,
- char * const argv[])
-{
- uint32_t offset, size = -1U, region_size;
- unsigned long addr;
- char *endp;
- int region;
- int ret;
-
- region = cros_ec_decode_region(argc - 2, argv + 2);
- if (region == -1)
- return 1;
- if (argc < 4)
- return 1;
- addr = simple_strtoul(argv[3], &endp, 16);
- if (*argv[3] == 0 || *endp != 0)
- return 1;
- if (argc > 4) {
- size = simple_strtoul(argv[4], &endp, 16);
- if (*argv[4] == 0 || *endp != 0)
- return 1;
- }
-
- ret = cros_ec_flash_offset(dev, region, &offset, &region_size);
- if (ret) {
- debug("%s: Could not read region info\n", __func__);
- return ret;
- }
- if (size == -1U)
- size = region_size;
-
- ret = is_write ?
- cros_ec_flash_write(dev, (uint8_t *)addr, offset, size) :
- cros_ec_flash_read(dev, (uint8_t *)addr, offset, size);
- if (ret) {
- debug("%s: Could not %s region\n", __func__,
- is_write ? "write" : "read");
- return ret;
- }
-
- return 0;
-}
-
-static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
-{
- struct cros_ec_dev *dev;
- struct udevice *udev;
- const char *cmd;
- int ret = 0;
-
- if (argc < 2)
- return CMD_RET_USAGE;
-
- cmd = argv[1];
- if (0 == strcmp("init", cmd)) {
- /* Remove any existing device */
- ret = uclass_find_device(UCLASS_CROS_EC, 0, &udev);
- if (!ret)
- device_remove(udev);
- ret = uclass_get_device(UCLASS_CROS_EC, 0, &udev);
- if (ret) {
- printf("Could not init cros_ec device (err %d)\n", ret);
- return 1;
- }
- return 0;
- }
-
- ret = uclass_get_device(UCLASS_CROS_EC, 0, &udev);
- if (ret) {
- printf("Cannot get cros-ec device (err=%d)\n", ret);
- return 1;
- }
- dev = dev_get_uclass_priv(udev);
- if (0 == strcmp("id", cmd)) {
- char id[MSG_BYTES];
-
- if (cros_ec_read_id(dev, id, sizeof(id))) {
- debug("%s: Could not read KBC ID\n", __func__);
- return 1;
- }
- printf("%s\n", id);
- } else if (0 == strcmp("info", cmd)) {
- struct ec_response_mkbp_info info;
-
- if (cros_ec_info(dev, &info)) {
- debug("%s: Could not read KBC info\n", __func__);
- return 1;
- }
- printf("rows = %u\n", info.rows);
- printf("cols = %u\n", info.cols);
- printf("switches = %#x\n", info.switches);
- } else if (0 == strcmp("curimage", cmd)) {
- enum ec_current_image image;
-
- if (cros_ec_read_current_image(dev, &image)) {
- debug("%s: Could not read KBC image\n", __func__);
- return 1;
- }
- printf("%d\n", image);
- } else if (0 == strcmp("hash", cmd)) {
- struct ec_response_vboot_hash hash;
- int i;
-
- if (cros_ec_read_hash(dev, &hash)) {
- debug("%s: Could not read KBC hash\n", __func__);
- return 1;
- }
-
- if (hash.hash_type == EC_VBOOT_HASH_TYPE_SHA256)
- printf("type: SHA-256\n");
- else
- printf("type: %d\n", hash.hash_type);
-
- printf("offset: 0x%08x\n", hash.offset);
- printf("size: 0x%08x\n", hash.size);
-
- printf("digest: ");
- for (i = 0; i < hash.digest_size; i++)
- printf("%02x", hash.hash_digest[i]);
- printf("\n");
- } else if (0 == strcmp("reboot", cmd)) {
- int region;
- enum ec_reboot_cmd cmd;
-
- if (argc >= 3 && !strcmp(argv[2], "cold"))
- cmd = EC_REBOOT_COLD;
- else {
- region = cros_ec_decode_region(argc - 2, argv + 2);
- if (region == EC_FLASH_REGION_RO)
- cmd = EC_REBOOT_JUMP_RO;
- else if (region == EC_FLASH_REGION_RW)
- cmd = EC_REBOOT_JUMP_RW;
- else
- return CMD_RET_USAGE;
- }
-
- if (cros_ec_reboot(dev, cmd, 0)) {
- debug("%s: Could not reboot KBC\n", __func__);
- return 1;
- }
- } else if (0 == strcmp("events", cmd)) {
- uint32_t events;
-
- if (cros_ec_get_host_events(dev, &events)) {
- debug("%s: Could not read host events\n", __func__);
- return 1;
- }
- printf("0x%08x\n", events);
- } else if (0 == strcmp("clrevents", cmd)) {
- uint32_t events = 0x7fffffff;
-
- if (argc >= 3)
- events = simple_strtol(argv[2], NULL, 0);
-
- if (cros_ec_clear_host_events(dev, events)) {
- debug("%s: Could not clear host events\n", __func__);
- return 1;
- }
- } else if (0 == strcmp("read", cmd)) {
- ret = do_read_write(dev, 0, argc, argv);
- if (ret > 0)
- return CMD_RET_USAGE;
- } else if (0 == strcmp("write", cmd)) {
- ret = do_read_write(dev, 1, argc, argv);
- if (ret > 0)
- return CMD_RET_USAGE;
- } else if (0 == strcmp("erase", cmd)) {
- int region = cros_ec_decode_region(argc - 2, argv + 2);
- uint32_t offset, size;
-
- if (region == -1)
- return CMD_RET_USAGE;
- if (cros_ec_flash_offset(dev, region, &offset, &size)) {
- debug("%s: Could not read region info\n", __func__);
- ret = -1;
- } else {
- ret = cros_ec_flash_erase(dev, offset, size);
- if (ret) {
- debug("%s: Could not erase region\n",
- __func__);
- }
- }
- } else if (0 == strcmp("regioninfo", cmd)) {
- int region = cros_ec_decode_region(argc - 2, argv + 2);
- uint32_t offset, size;
-
- if (region == -1)
- return CMD_RET_USAGE;
- ret = cros_ec_flash_offset(dev, region, &offset, &size);
- if (ret) {
- debug("%s: Could not read region info\n", __func__);
- } else {
- printf("Region: %s\n", region == EC_FLASH_REGION_RO ?
- "RO" : "RW");
- printf("Offset: %x\n", offset);
- printf("Size: %x\n", size);
- }
- } else if (0 == strcmp("vbnvcontext", cmd)) {
- uint8_t block[EC_VBNV_BLOCK_SIZE];
- char buf[3];
- int i, len;
- unsigned long result;
-
- if (argc <= 2) {
- ret = cros_ec_read_vbnvcontext(dev, block);
- if (!ret) {
- printf("vbnv_block: ");
- for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++)
- printf("%02x", block[i]);
- putc('\n');
- }
- } else {
- /*
- * TODO(clchiou): Move this to a utility function as
- * cmd_spi might want to call it.
- */
- memset(block, 0, EC_VBNV_BLOCK_SIZE);
- len = strlen(argv[2]);
- buf[2] = '\0';
- for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++) {
- if (i * 2 >= len)
- break;
- buf[0] = argv[2][i * 2];
- if (i * 2 + 1 >= len)
- buf[1] = '0';
- else
- buf[1] = argv[2][i * 2 + 1];
- strict_strtoul(buf, 16, &result);
- block[i] = result;
- }
- ret = cros_ec_write_vbnvcontext(dev, block);
- }
- if (ret) {
- debug("%s: Could not %s VbNvContext\n", __func__,
- argc <= 2 ? "read" : "write");
- }
- } else if (0 == strcmp("test", cmd)) {
- int result = cros_ec_test(dev);
-
- if (result)
- printf("Test failed with error %d\n", result);
- else
- puts("Test passed\n");
- } else if (0 == strcmp("version", cmd)) {
- struct ec_response_get_version *p;
- char *build_string;
-
- ret = cros_ec_read_version(dev, &p);
- if (!ret) {
- /* Print versions */
- printf("RO version: %1.*s\n",
- (int)sizeof(p->version_string_ro),
- p->version_string_ro);
- printf("RW version: %1.*s\n",
- (int)sizeof(p->version_string_rw),
- p->version_string_rw);
- printf("Firmware copy: %s\n",
- (p->current_image <
- ARRAY_SIZE(ec_current_image_name) ?
- ec_current_image_name[p->current_image] :
- "?"));
- ret = cros_ec_read_build_info(dev, &build_string);
- if (!ret)
- printf("Build info: %s\n", build_string);
- }
- } else if (0 == strcmp("ldo", cmd)) {
- uint8_t index, state;
- char *endp;
-
- if (argc < 3)
- return CMD_RET_USAGE;
- index = simple_strtoul(argv[2], &endp, 10);
- if (*argv[2] == 0 || *endp != 0)
- return CMD_RET_USAGE;
- if (argc > 3) {
- state = simple_strtoul(argv[3], &endp, 10);
- if (*argv[3] == 0 || *endp != 0)
- return CMD_RET_USAGE;
- ret = cros_ec_set_ldo(udev, index, state);
- } else {
- ret = cros_ec_get_ldo(udev, index, &state);
- if (!ret) {
- printf("LDO%d: %s\n", index,
- state == EC_LDO_STATE_ON ?
- "on" : "off");
- }
- }
-
- if (ret) {
- debug("%s: Could not access LDO%d\n", __func__, index);
- return ret;
- }
- } else {
- return CMD_RET_USAGE;
- }
-
- if (ret < 0) {
- printf("Error: CROS-EC command failed (error %d)\n", ret);
- ret = 1;
- }
-
- return ret;
-}
-
-U_BOOT_CMD(
- crosec, 6, 1, do_cros_ec,
- "CROS-EC utility command",
- "init Re-init CROS-EC (done on startup automatically)\n"
- "crosec id Read CROS-EC ID\n"
- "crosec info Read CROS-EC info\n"
- "crosec curimage Read CROS-EC current image\n"
- "crosec hash Read CROS-EC hash\n"
- "crosec reboot [rw | ro | cold] Reboot CROS-EC\n"
- "crosec events Read CROS-EC host events\n"
- "crosec clrevents [mask] Clear CROS-EC host events\n"
- "crosec regioninfo <ro|rw> Read image info\n"
- "crosec erase <ro|rw> Erase EC image\n"
- "crosec read <ro|rw> <addr> [<size>] Read EC image\n"
- "crosec write <ro|rw> <addr> [<size>] Write EC image\n"
- "crosec vbnvcontext [hexstring] Read [write] VbNvContext from EC\n"
- "crosec ldo <idx> [<state>] Switch/Read LDO state\n"
- "crosec test run tests on cros_ec\n"
- "crosec version Read CROS-EC version"
-);
-#endif
-
UCLASS_DRIVER(cros_ec) = {
.id = UCLASS_CROS_EC,
.name = "cros_ec",
diff --git a/drivers/misc/fsl_sec_mon.c b/drivers/misc/fsl_sec_mon.c
index d482a7d..415232e 100644
--- a/drivers/misc/fsl_sec_mon.c
+++ b/drivers/misc/fsl_sec_mon.c
@@ -7,140 +7,158 @@
#include <common.h>
#include <fsl_sec_mon.h>
-int change_sec_mon_state(u32 initial_state, u32 final_state)
+static u32 get_sec_mon_state(void)
{
struct ccsr_sec_mon_regs *sec_mon_regs = (void *)
(CONFIG_SYS_SEC_MON_ADDR);
- u32 sts = sec_mon_in32(&sec_mon_regs->hp_stat);
+ return sec_mon_in32(&sec_mon_regs->hp_stat) & HPSR_SSM_ST_MASK;
+}
+
+static int set_sec_mon_state_non_sec(void)
+{
+ u32 sts;
int timeout = 10;
+ struct ccsr_sec_mon_regs *sec_mon_regs = (void *)
+ (CONFIG_SYS_SEC_MON_ADDR);
- if ((sts & HPSR_SSM_ST_MASK) != initial_state)
- return -1;
+ sts = get_sec_mon_state();
- if (initial_state == HPSR_SSM_ST_TRUST) {
- switch (final_state) {
- case HPSR_SSM_ST_NON_SECURE:
- printf("SEC_MON state transitioning to Soft Fail.\n");
- sec_mon_setbits32(&sec_mon_regs->hp_com, HPCOMR_SW_SV);
-
- /*
- * poll till SEC_MON is in
- * Soft Fail state
- */
- while (((sts & HPSR_SSM_ST_MASK) !=
- HPSR_SSM_ST_SOFT_FAIL)) {
- while (timeout) {
- sts = sec_mon_in32
- (&sec_mon_regs->hp_stat);
-
- if ((sts & HPSR_SSM_ST_MASK) ==
- HPSR_SSM_ST_SOFT_FAIL)
- break;
-
- udelay(10);
- timeout--;
- }
- }
+ switch (sts) {
+ /*
+ * If initial state is check or Non-Secure, then set the Software
+ * Security Violation Bit and transition to Non-Secure State.
+ */
+ case HPSR_SSM_ST_CHECK:
+ printf("SEC_MON state transitioning to Non Secure.\n");
+ sec_mon_setbits32(&sec_mon_regs->hp_com, HPCOMR_SW_SV);
- if (timeout == 0) {
- printf("SEC_MON state transition timeout.\n");
- return -1;
- }
+ /* polling loop till SEC_MON is in Non Secure state */
+ while (timeout) {
+ sts = get_sec_mon_state();
+
+ if ((sts & HPSR_SSM_ST_MASK) ==
+ HPSR_SSM_ST_NON_SECURE)
+ break;
+
+ udelay(10);
+ timeout--;
+ }
- timeout = 10;
+ if (timeout == 0) {
+ printf("SEC_MON state transition timeout.\n");
+ return -1;
+ }
+ break;
+
+ /*
+ * If initial state is Trusted, Secure or Soft-Fail, then first set
+ * the Software Security Violation Bit and transition to Soft-Fail
+ * State.
+ */
+ case HPSR_SSM_ST_TRUST:
+ case HPSR_SSM_ST_SECURE:
+ case HPSR_SSM_ST_SOFT_FAIL:
+ printf("SEC_MON state transitioning to Soft Fail.\n");
+ sec_mon_setbits32(&sec_mon_regs->hp_com, HPCOMR_SW_SV);
+
+ /* polling loop till SEC_MON is in Soft-Fail state */
+ while (timeout) {
+ sts = get_sec_mon_state();
+
+ if ((sts & HPSR_SSM_ST_MASK) ==
+ HPSR_SSM_ST_SOFT_FAIL)
+ break;
+
+ udelay(10);
+ timeout--;
+ }
+
+ if (timeout == 0) {
+ printf("SEC_MON state transition timeout.\n");
+ return -1;
+ }
+
+ timeout = 10;
+ /*
+ * If SSM Soft Fail to Non-Secure State Transition
+ * disable is not set, then set SSM_ST bit and
+ * transition to Non-Secure State.
+ */
+ if ((sec_mon_in32(&sec_mon_regs->hp_com) &
+ HPCOMR_SSM_SFNS_DIS) == 0) {
printf("SEC_MON state transitioning to Non Secure.\n");
sec_mon_setbits32(&sec_mon_regs->hp_com, HPCOMR_SSM_ST);
- /*
- * poll till SEC_MON is in
- * Non Secure state
- */
- while (((sts & HPSR_SSM_ST_MASK) !=
- HPSR_SSM_ST_NON_SECURE)) {
- while (timeout) {
- sts = sec_mon_in32
- (&sec_mon_regs->hp_stat);
-
- if ((sts & HPSR_SSM_ST_MASK) ==
- HPSR_SSM_ST_NON_SECURE)
- break;
-
- udelay(10);
- timeout--;
- }
- }
+ /* polling loop till SEC_MON is in Non Secure*/
+ while (timeout) {
+ sts = get_sec_mon_state();
- if (timeout == 0) {
- printf("SEC_MON state transition timeout.\n");
- return -1;
- }
- break;
- case HPSR_SSM_ST_SOFT_FAIL:
- printf("SEC_MON state transitioning to Soft Fail.\n");
- sec_mon_setbits32(&sec_mon_regs->hp_com, HPCOMR_SW_FSV);
-
- /*
- * polling loop till SEC_MON is in
- * Soft Fail state
- */
- while (((sts & HPSR_SSM_ST_MASK) !=
- HPSR_SSM_ST_SOFT_FAIL)) {
- while (timeout) {
- sts = sec_mon_in32
- (&sec_mon_regs->hp_stat);
-
- if ((sts & HPSR_SSM_ST_MASK) ==
- HPSR_SSM_ST_SOFT_FAIL)
- break;
-
- udelay(10);
- timeout--;
- }
+ if ((sts & HPSR_SSM_ST_MASK) ==
+ HPSR_SSM_ST_NON_SECURE)
+ break;
+
+ udelay(10);
+ timeout--;
}
if (timeout == 0) {
printf("SEC_MON state transition timeout.\n");
return -1;
}
- break;
- default:
- return -1;
}
- } else if (initial_state == HPSR_SSM_ST_NON_SECURE) {
- switch (final_state) {
- case HPSR_SSM_ST_SOFT_FAIL:
- printf("SEC_MON state transitioning to Soft Fail.\n");
- sec_mon_setbits32(&sec_mon_regs->hp_com, HPCOMR_SW_FSV);
-
- /*
- * polling loop till SEC_MON is in
- * Soft Fail state
- */
- while (((sts & HPSR_SSM_ST_MASK) !=
- HPSR_SSM_ST_SOFT_FAIL)) {
- while (timeout) {
- sts = sec_mon_in32
- (&sec_mon_regs->hp_stat);
-
- if ((sts & HPSR_SSM_ST_MASK) ==
- HPSR_SSM_ST_SOFT_FAIL)
- break;
-
- udelay(10);
- timeout--;
- }
- }
+ break;
+ default:
+ printf("SEC_MON already in Non Secure state.\n");
+ return 0;
+ }
+ return 0;
+}
- if (timeout == 0) {
- printf("SEC_MON state transition timeout.\n");
- return -1;
- }
+static int set_sec_mon_state_soft_fail(void)
+{
+ u32 sts;
+ int timeout = 10;
+ struct ccsr_sec_mon_regs *sec_mon_regs = (void *)
+ (CONFIG_SYS_SEC_MON_ADDR);
+
+ printf("SEC_MON state transitioning to Soft Fail.\n");
+ sec_mon_setbits32(&sec_mon_regs->hp_com, HPCOMR_SW_FSV);
+
+ /* polling loop till SEC_MON is in Soft-Fail state */
+ while (timeout) {
+ sts = get_sec_mon_state();
+
+ if ((sts & HPSR_SSM_ST_MASK) ==
+ HPSR_SSM_ST_SOFT_FAIL)
break;
- default:
- return -1;
- }
+
+ udelay(10);
+ timeout--;
}
+ if (timeout == 0) {
+ printf("SEC_MON state transition timeout.\n");
+ return -1;
+ }
return 0;
}
+
+int set_sec_mon_state(u32 state)
+{
+ int ret = -1;
+
+ switch (state) {
+ case HPSR_SSM_ST_NON_SECURE:
+ ret = set_sec_mon_state_non_sec();
+ break;
+ case HPSR_SSM_ST_SOFT_FAIL:
+ ret = set_sec_mon_state_soft_fail();
+ break;
+ default:
+ printf("SEC_MON state transition not supported.\n");
+ return 0;
+ }
+
+ return ret;
+}
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index ba9a723..24f4b28 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -19,6 +19,7 @@ config DM_MMC
config DM_MMC_OPS
bool "Support MMC controller operations using Driver Model"
depends on DM_MMC
+ default y if DM_MMC
help
Driver model provides a means of supporting device operations. This
option moves MMC operations under the control of driver model. The
diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c
index 425abb1..77424cd 100644
--- a/drivers/mmc/mmc-uclass.c
+++ b/drivers/mmc/mmc-uclass.c
@@ -262,6 +262,7 @@ static const struct blk_ops mmc_blk_ops = {
.read = mmc_bread,
#ifndef CONFIG_SPL_BUILD
.write = mmc_bwrite,
+ .erase = mmc_berase,
#endif
.select_hwpart = mmc_select_hwpart,
};
diff --git a/drivers/mmc/mmc_private.h b/drivers/mmc/mmc_private.h
index d8b399e..03bf24d 100644
--- a/drivers/mmc/mmc_private.h
+++ b/drivers/mmc/mmc_private.h
@@ -29,15 +29,15 @@ ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
#endif
#if !(defined(CONFIG_SPL_BUILD) && !defined(CONFIG_SPL_SAVEENV))
-unsigned long mmc_berase(struct blk_desc *block_dev, lbaint_t start,
- lbaint_t blkcnt);
#ifdef CONFIG_BLK
ulong mmc_bwrite(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
const void *src);
+ulong mmc_berase(struct udevice *dev, lbaint_t start, lbaint_t blkcnt);
#else
ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
const void *src);
+ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt);
#endif
#else /* CONFIG_SPL_BUILD and CONFIG_SPL_SAVEENV is not defined */
diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c
index 2289640..54acbf7 100644
--- a/drivers/mmc/mmc_write.c
+++ b/drivers/mmc/mmc_write.c
@@ -66,9 +66,15 @@ err_out:
return err;
}
-unsigned long mmc_berase(struct blk_desc *block_dev, lbaint_t start,
- lbaint_t blkcnt)
+#ifdef CONFIG_BLK
+ulong mmc_berase(struct udevice *dev, lbaint_t start, lbaint_t blkcnt)
+#else
+ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt)
+#endif
{
+#ifdef CONFIG_BLK
+ struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
+#endif
int dev_num = block_dev->devnum;
int err = 0;
u32 start_rem, blkcnt_rem;
diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c
index 399055b..cd083f7 100644
--- a/drivers/pci/pci_rom.c
+++ b/drivers/pci/pci_rom.c
@@ -31,6 +31,7 @@
#include <pci.h>
#include <pci_rom.h>
#include <vbe.h>
+#include <video.h>
#include <video_fb.h>
#include <linux/screen_info.h>
@@ -348,3 +349,64 @@ err:
free(ram);
return ret;
}
+
+#ifdef CONFIG_DM_VIDEO
+int vbe_setup_video_priv(struct vesa_mode_info *vesa,
+ struct video_priv *uc_priv,
+ struct video_uc_platdata *plat)
+{
+ if (!vesa->x_resolution)
+ return -ENXIO;
+ uc_priv->xsize = vesa->x_resolution;
+ uc_priv->ysize = vesa->y_resolution;
+ switch (vesa->bits_per_pixel) {
+ case 32:
+ case 24:
+ uc_priv->bpix = VIDEO_BPP32;
+ break;
+ case 16:
+ uc_priv->bpix = VIDEO_BPP16;
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+ plat->base = vesa->phys_base_ptr;
+ plat->size = vesa->bytes_per_scanline * vesa->y_resolution;
+
+ return 0;
+}
+
+int vbe_setup_video(struct udevice *dev, int (*int15_handler)(void))
+{
+ struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
+ struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+ int ret;
+
+ printf("Video: ");
+
+ /* If we are running from EFI or coreboot, this can't work */
+ if (!ll_boot_init()) {
+ printf("Not available (previous bootloader prevents it)\n");
+ return -EPERM;
+ }
+ bootstage_start(BOOTSTAGE_ID_ACCUM_LCD, "vesa display");
+ ret = dm_pci_run_vga_bios(dev, int15_handler, PCI_ROM_USE_NATIVE |
+ PCI_ROM_ALLOW_FALLBACK);
+ bootstage_accum(BOOTSTAGE_ID_ACCUM_LCD);
+ if (ret) {
+ debug("failed to run video BIOS: %d\n", ret);
+ return ret;
+ }
+
+ ret = vbe_setup_video_priv(&mode_info.vesa, uc_priv, plat);
+ if (ret) {
+ debug("No video mode configured\n");
+ return ret;
+ }
+
+ printf("%dx%dx%d\n", uc_priv->xsize, uc_priv->ysize,
+ mode_info.vesa.bits_per_pixel);
+
+ return 0;
+}
+#endif
diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig
index 13d293a..ce204b3 100644
--- a/drivers/power/pmic/Kconfig
+++ b/drivers/power/pmic/Kconfig
@@ -143,3 +143,17 @@ config PMIC_TPS65090
FETs and a battery charger. This driver provides register access
only, and you can enable the regulator/charger drivers separately if
required.
+
+config PMIC_PALMAS
+ bool "Enable driver for Texas Instruments PALMAS PMIC"
+ depends on DM_PMIC
+ ---help---
+ The PALMAS is a PMIC containing several LDOs, SMPS.
+ This driver binds the pmic children.
+
+config PMIC_LP873X
+ bool "Enable driver for Texas Instruments LP873X PMIC"
+ depends on DM_PMIC
+ ---help---
+ The LP873X is a PMIC containing couple of LDOs and couple of SMPS.
+ This driver binds the pmic children.
diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile
index 37d9eb5..cd1c694 100644
--- a/drivers/power/pmic/Makefile
+++ b/drivers/power/pmic/Makefile
@@ -16,6 +16,8 @@ obj-$(CONFIG_PMIC_RK808) += rk808.o
obj-$(CONFIG_PMIC_RN5T567) += rn5t567.o
obj-$(CONFIG_PMIC_TPS65090) += tps65090.o
obj-$(CONFIG_PMIC_S5M8767) += s5m8767.o
+obj-$(CONFIG_$(SPL_)PMIC_PALMAS) += palmas.o
+obj-$(CONFIG_$(SPL_)PMIC_LP873X) += lp873x.o
obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o
obj-$(CONFIG_POWER_MAX77696) += pmic_max77696.o
diff --git a/drivers/power/pmic/lp873x.c b/drivers/power/pmic/lp873x.c
new file mode 100644
index 0000000..307f96b
--- /dev/null
+++ b/drivers/power/pmic/lp873x.c
@@ -0,0 +1,86 @@
+/*
+ * (C) Copyright 2016 Texas Instruments Incorporated, <www.ti.com>
+ * Keerthy <j-keerthy@ti.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#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>
+#include <dm/device.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const struct pmic_child_info pmic_children_info[] = {
+ { .prefix = "ldo", .driver = LP873X_LDO_DRIVER },
+ { .prefix = "buck", .driver = LP873X_BUCK_DRIVER },
+ { },
+};
+
+static int lp873x_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ if (dm_i2c_write(dev, reg, buff, len)) {
+ error("write error to device: %p register: %#x!", 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)) {
+ error("read error from device: %p register: %#x!", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int lp873x_bind(struct udevice *dev)
+{
+ int regulators_node;
+ const void *blob = gd->fdt_blob;
+ int children;
+ int node = dev->of_offset;
+
+ regulators_node = fdt_subnode_offset(blob, node, "regulators");
+
+ if (regulators_node <= 0) {
+ printf("%s: %s reg subnode not found!", __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 lp873x_ids[] = {
+ { .compatible = "ti,lp8732", .data = LP8732 },
+ { .compatible = "ti,lp8733" , .data = LP8733 },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_lp873x) = {
+ .name = "lp873x_pmic",
+ .id = UCLASS_PMIC,
+ .of_match = lp873x_ids,
+ .bind = lp873x_bind,
+ .ops = &lp873x_ops,
+};
diff --git a/drivers/power/pmic/palmas.c b/drivers/power/pmic/palmas.c
new file mode 100644
index 0000000..6c79a93
--- /dev/null
+++ b/drivers/power/pmic/palmas.c
@@ -0,0 +1,104 @@
+/*
+ * (C) Copyright 2016 Texas Instruments Incorporated, <www.ti.com>
+ * Keerthy <j-keerthy@ti.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#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/palmas.h>
+#include <dm/device.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const struct pmic_child_info pmic_children_info[] = {
+ { .prefix = "ldo", .driver = PALMAS_LDO_DRIVER },
+ { .prefix = "smps", .driver = PALMAS_SMPS_DRIVER },
+ { },
+};
+
+static int palmas_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ if (dm_i2c_write(dev, reg, buff, len)) {
+ error("write error to device: %p register: %#x!", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int palmas_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ if (dm_i2c_read(dev, reg, buff, len)) {
+ error("read error from device: %p register: %#x!", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int palmas_bind(struct udevice *dev)
+{
+ int pmic_node = -1, regulators_node;
+ const void *blob = gd->fdt_blob;
+ int children;
+ int node = dev->of_offset;
+ int subnode, len;
+
+ fdt_for_each_subnode(blob, subnode, node) {
+ const char *name;
+ char *temp;
+
+ name = fdt_get_name(blob, subnode, &len);
+ temp = strstr(name, "pmic");
+ if (temp) {
+ pmic_node = subnode;
+ break;
+ }
+ }
+
+ if (pmic_node <= 0) {
+ debug("%s: %s pmic subnode not found!", __func__, dev->name);
+ return -ENXIO;
+ }
+
+ regulators_node = fdt_subnode_offset(blob, pmic_node, "regulators");
+
+ if (regulators_node <= 0) {
+ debug("%s: %s reg subnode not found!", __func__, dev->name);
+ return -ENXIO;
+ }
+
+ children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+ if (!children)
+ debug("%s: %s - no child found\n", __func__, dev->name);
+
+ /* Always return success for this device */
+ return 0;
+}
+
+static struct dm_pmic_ops palmas_ops = {
+ .read = palmas_read,
+ .write = palmas_write,
+};
+
+static const struct udevice_id palmas_ids[] = {
+ { .compatible = "ti,tps659038", .data = TPS659038 },
+ { .compatible = "ti,tps65917" , .data = TPS65917 },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_palmas) = {
+ .name = "palmas_pmic",
+ .id = UCLASS_PMIC,
+ .of_match = palmas_ids,
+ .bind = palmas_bind,
+ .ops = &palmas_ops,
+};
diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig
index c7e88c0..f870e8b 100644
--- a/drivers/power/regulator/Kconfig
+++ b/drivers/power/regulator/Kconfig
@@ -68,6 +68,14 @@ config DM_REGULATOR_FIXED
features for fixed value regulators. The driver implements get/set api
for enable and get only for voltage value.
+config DM_REGULATOR_GPIO
+ bool "Enable Driver Model for GPIO REGULATOR"
+ depends on DM_REGULATOR
+ ---help---
+ This config enables implementation of driver-model regulator uclass
+ features for gpio regulators. The driver implements get/set for
+ voltage value.
+
config REGULATOR_RK808
bool "Enable driver for RK808 regulators"
depends on DM_REGULATOR && PMIC_RK808
@@ -125,3 +133,19 @@ config REGULATOR_TPS65090
regulators, one for each FET. The standard regulator interface is
supported, but it is only possible to turn the regulators on or off.
There is no voltage/current control.
+
+config DM_REGULATOR_PALMAS
+ bool "Enable driver for PALMAS PMIC regulators"
+ depends on PMIC_PALMAS
+ ---help---
+ This enables implementation of driver-model regulator uclass
+ features for REGULATOR PALMAS and the family of PALMAS PMICs.
+ The driver implements get/set api for: value and enable.
+
+config DM_REGULATOR_LP873X
+ bool "Enable driver for LP873X PMIC regulators"
+ depends on PMIC_LP873X
+ ---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.
diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile
index ab461ec..6002c88 100644
--- a/drivers/power/regulator/Makefile
+++ b/drivers/power/regulator/Makefile
@@ -11,7 +11,10 @@ obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o
obj-$(CONFIG_DM_REGULATOR_PFUZE100) += pfuze100.o
obj-$(CONFIG_REGULATOR_PWM) += pwm_regulator.o
obj-$(CONFIG_$(SPL_)DM_REGULATOR_FIXED) += fixed.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_GPIO) += gpio-regulator.o
obj-$(CONFIG_REGULATOR_RK808) += rk808.o
obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
obj-$(CONFIG_DM_REGULATOR_SANDBOX) += sandbox.o
obj-$(CONFIG_REGULATOR_TPS65090) += tps65090_regulator.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_PALMAS) += palmas_regulator.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP873X) += lp873x_regulator.o
diff --git a/drivers/power/regulator/fixed.c b/drivers/power/regulator/fixed.c
index 37b8400..62dc47f 100644
--- a/drivers/power/regulator/fixed.c
+++ b/drivers/power/regulator/fixed.c
@@ -37,11 +37,15 @@ static int fixed_regulator_ofdata_to_platdata(struct udevice *dev)
/* Set type to fixed */
uc_pdata->type = REGULATOR_TYPE_FIXED;
- /* Get fixed regulator gpio desc */
+ /* Get fixed regulator optional enable GPIO desc */
gpio = &dev_pdata->gpio;
ret = gpio_request_by_name(dev, "gpio", 0, gpio, GPIOD_IS_OUT);
- if (ret)
- debug("Fixed regulator gpio - not found! Error: %d", ret);
+ if (ret) {
+ debug("Fixed regulator optional enable GPIO - not found! Error: %d\n",
+ ret);
+ if (ret != -ENOENT)
+ return ret;
+ }
/* Get optional ramp up delay */
dev_pdata->startup_delay_us = fdtdec_get_uint(gd->fdt_blob,
@@ -87,8 +91,9 @@ static bool fixed_regulator_get_enable(struct udevice *dev)
{
struct fixed_regulator_platdata *dev_pdata = dev_get_platdata(dev);
+ /* Enable GPIO is optional */
if (!dev_pdata->gpio.dev)
- return false;
+ return true;
return dm_gpio_get_value(&dev_pdata->gpio);
}
@@ -98,8 +103,12 @@ static int fixed_regulator_set_enable(struct udevice *dev, bool enable)
struct fixed_regulator_platdata *dev_pdata = dev_get_platdata(dev);
int ret;
- if (!dev_pdata->gpio.dev)
- return -ENOSYS;
+ /* Enable GPIO is optional */
+ if (!dev_pdata->gpio.dev) {
+ if (!enable)
+ return -ENOSYS;
+ return 0;
+ }
ret = dm_gpio_set_value(&dev_pdata->gpio, enable);
if (ret) {
diff --git a/drivers/power/regulator/gpio-regulator.c b/drivers/power/regulator/gpio-regulator.c
new file mode 100644
index 0000000..0a60a9c
--- /dev/null
+++ b/drivers/power/regulator/gpio-regulator.c
@@ -0,0 +1,137 @@
+/*
+ * (C) Copyright 2016 Texas Instruments Incorporated, <www.ti.com>
+ * Keerthy <j-keerthy@ti.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <asm/gpio.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+
+#define GPIO_REGULATOR_MAX_STATES 2
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct gpio_regulator_platdata {
+ struct gpio_desc gpio; /* GPIO for regulator voltage control */
+ int states[GPIO_REGULATOR_MAX_STATES];
+ int voltages[GPIO_REGULATOR_MAX_STATES];
+};
+
+static int gpio_regulator_ofdata_to_platdata(struct udevice *dev)
+{
+ struct dm_regulator_uclass_platdata *uc_pdata;
+ struct gpio_regulator_platdata *dev_pdata;
+ struct gpio_desc *gpio;
+ const void *blob = gd->fdt_blob;
+ int node = dev->of_offset;
+ int ret, count, i, j;
+ u32 states_array[8];
+
+ dev_pdata = dev_get_platdata(dev);
+ uc_pdata = dev_get_uclass_platdata(dev);
+ if (!uc_pdata)
+ return -ENXIO;
+
+ /* Set type to gpio */
+ uc_pdata->type = REGULATOR_TYPE_GPIO;
+
+ /*
+ * Get gpio regulator gpio desc
+ * Assuming one GPIO per regulator.
+ * Can be extended later to multiple GPIOs
+ * per gpio-regulator. As of now no instance with multiple
+ * gpios is presnt
+ */
+ gpio = &dev_pdata->gpio;
+ ret = gpio_request_by_name(dev, "gpios", 0, gpio, GPIOD_IS_OUT);
+ if (ret)
+ debug("regulator gpio - not found! Error: %d", ret);
+
+ count = fdtdec_get_int_array_count(blob, node, "states",
+ states_array, 8);
+
+ if (!count)
+ return -EINVAL;
+
+ for (i = 0, j = 0; i < count; i += 2) {
+ dev_pdata->voltages[j] = states_array[i];
+ dev_pdata->states[j] = states_array[i + 1];
+ j++;
+ }
+
+ return 0;
+}
+
+static int gpio_regulator_get_value(struct udevice *dev)
+{
+ struct dm_regulator_uclass_platdata *uc_pdata;
+ struct gpio_regulator_platdata *dev_pdata = dev_get_platdata(dev);
+ int enable;
+
+ if (!dev_pdata->gpio.dev)
+ return -ENOSYS;
+
+ uc_pdata = dev_get_uclass_platdata(dev);
+ if (uc_pdata->min_uV > uc_pdata->max_uV) {
+ debug("Invalid constraints for: %s\n", uc_pdata->name);
+ return -EINVAL;
+ }
+
+ enable = dm_gpio_get_value(&dev_pdata->gpio);
+ if (enable == dev_pdata->states[0])
+ return dev_pdata->voltages[0];
+ else
+ return dev_pdata->voltages[1];
+}
+
+static int gpio_regulator_set_value(struct udevice *dev, int uV)
+{
+ struct gpio_regulator_platdata *dev_pdata = dev_get_platdata(dev);
+ int ret;
+ bool enable;
+
+ if (!dev_pdata->gpio.dev)
+ return -ENOSYS;
+
+ if (uV == dev_pdata->voltages[0])
+ enable = dev_pdata->states[0];
+ else if (uV == dev_pdata->voltages[1])
+ enable = dev_pdata->states[1];
+ else
+ return -EINVAL;
+
+ ret = dm_gpio_set_value(&dev_pdata->gpio, enable);
+ if (ret) {
+ error("Can't set regulator : %s gpio to: %d\n", dev->name,
+ enable);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct dm_regulator_ops gpio_regulator_ops = {
+ .get_value = gpio_regulator_get_value,
+ .set_value = gpio_regulator_set_value,
+};
+
+static const struct udevice_id gpio_regulator_ids[] = {
+ { .compatible = "regulator-gpio" },
+ { },
+};
+
+U_BOOT_DRIVER(gpio_regulator) = {
+ .name = "gpio regulator",
+ .id = UCLASS_REGULATOR,
+ .ops = &gpio_regulator_ops,
+ .of_match = gpio_regulator_ids,
+ .ofdata_to_platdata = gpio_regulator_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct gpio_regulator_platdata),
+};
diff --git a/drivers/power/regulator/lp873x_regulator.c b/drivers/power/regulator/lp873x_regulator.c
new file mode 100644
index 0000000..dcb19ff
--- /dev/null
+++ b/drivers/power/regulator/lp873x_regulator.c
@@ -0,0 +1,357 @@
+/*
+ * (C) Copyright 2016
+ * Texas Instruments Incorporated, <www.ti.com>
+ *
+ * Keerthy <j-keerthy@ti.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#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>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const char lp873x_buck_ctrl[LP873X_BUCK_NUM] = {0x2, 0x4};
+static const char lp873x_buck_volt[LP873X_BUCK_NUM] = {0x6, 0x7};
+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_buck_enable(struct udevice *dev, int op, bool *enable)
+{
+ int ret;
+ unsigned int adr;
+ struct dm_regulator_uclass_platdata *uc_pdata;
+
+ uc_pdata = dev_get_uclass_platdata(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_BUCK_MODE_MASK;
+
+ if (ret)
+ *enable = true;
+ else
+ *enable = false;
+
+ return 0;
+ } else if (op == PMIC_OP_SET) {
+ if (*enable)
+ ret |= LP873X_BUCK_MODE_MASK;
+ else
+ ret &= ~(LP873X_BUCK_MODE_MASK);
+ ret = pmic_reg_write(dev->parent, adr, ret);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int lp873x_buck_volt2hex(int uV)
+{
+ if (uV > LP873X_BUCK_VOLT_MAX)
+ return -EINVAL;
+ else if (uV > 1400000)
+ return (uV - 1420000) / 20000 + 0x9E;
+ else if (uV > 730000)
+ return (uV - 735000) / 5000 + 0x18;
+ else if (uV >= 700000)
+ return (uV - 700000) / 10000 + 0x1;
+ else
+ return -EINVAL;
+}
+
+static int lp873x_buck_hex2volt(int hex)
+{
+ if (hex > LP873X_BUCK_VOLT_MAX_HEX)
+ return -EINVAL;
+ else if (hex > 0x9D)
+ return 1400000 + (hex - 0x9D) * 20000;
+ else if (hex > 0x17)
+ return 730000 + (hex - 0x17) * 5000;
+ else if (hex >= 0x14)
+ return 700000 + (hex - 0x14) * 10000;
+ else
+ return -EINVAL;
+}
+
+static int lp873x_buck_val(struct udevice *dev, int op, int *uV)
+{
+ unsigned int hex, adr;
+ int ret;
+ struct dm_regulator_uclass_platdata *uc_pdata;
+
+ uc_pdata = dev_get_uclass_platdata(dev);
+
+ if (op == PMIC_OP_GET)
+ *uV = 0;
+
+ adr = uc_pdata->volt_reg;
+
+ ret = pmic_reg_read(dev->parent, adr);
+ if (ret < 0)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ ret &= LP873X_BUCK_VOLT_MASK;
+ ret = lp873x_buck_hex2volt(ret);
+ if (ret < 0)
+ return ret;
+ *uV = ret;
+
+ return 0;
+ }
+
+ hex = lp873x_buck_volt2hex(*uV);
+ if (hex < 0)
+ return hex;
+
+ ret &= 0x0;
+ ret |= hex;
+
+ ret = pmic_reg_write(dev->parent, adr, ret);
+
+ return ret;
+}
+
+static int lp873x_ldo_enable(struct udevice *dev, int op, bool *enable)
+{
+ int ret;
+ unsigned int adr;
+ struct dm_regulator_uclass_platdata *uc_pdata;
+
+ uc_pdata = dev_get_uclass_platdata(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_platdata *uc_pdata;
+
+ if (op == PMIC_OP_GET)
+ *uV = 0;
+
+ uc_pdata = dev_get_uclass_platdata(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_platdata *uc_pdata;
+
+ uc_pdata = dev_get_uclass_platdata(dev);
+ uc_pdata->type = REGULATOR_TYPE_LDO;
+
+ int idx = dev->driver_data;
+ if (idx >= LP873X_LDO_NUM) {
+ printf("Wrong ID for regulator\n");
+ 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 bool 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 int lp873x_buck_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_platdata *uc_pdata;
+ int idx;
+
+ uc_pdata = dev_get_uclass_platdata(dev);
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+
+ idx = dev->driver_data;
+ if (idx >= LP873X_BUCK_NUM) {
+ printf("Wrong ID for regulator\n");
+ return -1;
+ }
+
+ uc_pdata->ctrl_reg = lp873x_buck_ctrl[idx];
+ uc_pdata->volt_reg = lp873x_buck_volt[idx];
+
+ return 0;
+}
+
+static int buck_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = lp873x_buck_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int buck_set_value(struct udevice *dev, int uV)
+{
+ return lp873x_buck_val(dev, PMIC_OP_SET, &uV);
+}
+
+static bool buck_get_enable(struct udevice *dev)
+{
+ bool enable = false;
+ int ret;
+
+
+ ret = lp873x_buck_enable(dev, PMIC_OP_GET, &enable);
+ if (ret)
+ return ret;
+
+ return enable;
+}
+
+static int buck_set_enable(struct udevice *dev, bool enable)
+{
+ return lp873x_buck_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,
+};
+
+static const struct dm_regulator_ops lp873x_buck_ops = {
+ .get_value = buck_get_value,
+ .set_value = buck_set_value,
+ .get_enable = buck_get_enable,
+ .set_enable = buck_set_enable,
+};
+
+U_BOOT_DRIVER(lp873x_buck) = {
+ .name = LP873X_BUCK_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &lp873x_buck_ops,
+ .probe = lp873x_buck_probe,
+};
diff --git a/drivers/power/regulator/palmas_regulator.c b/drivers/power/regulator/palmas_regulator.c
new file mode 100644
index 0000000..cce7cd2
--- /dev/null
+++ b/drivers/power/regulator/palmas_regulator.c
@@ -0,0 +1,453 @@
+/*
+ * (C) Copyright 2016
+ * Texas Instruments Incorporated, <www.ti.com>
+ *
+ * Keerthy <j-keerthy@ti.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#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/palmas.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define REGULATOR_ON 0x1
+#define REGULATOR_OFF 0x0
+
+#define SMPS_MODE_MASK 0x3
+#define SMPS_MODE_SHIFT 0x0
+#define LDO_MODE_MASK 0x1
+#define LDO_MODE_SHIFT 0x0
+
+static const char palmas_smps_ctrl[][PALMAS_SMPS_NUM] = {
+ {0x20, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38, 0x3c},
+ {0x20, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38},
+ {0x20, 0x24, 0x2c, 0x30, 0x38},
+};
+
+static const char palmas_smps_volt[][PALMAS_SMPS_NUM] = {
+ {0x23, 0x27, 0x2b, 0x2f, 0x33, 0x37, 0x3b, 0x3c},
+ {0x23, 0x27, 0x2b, 0x2f, 0x33, 0x37, 0x3b},
+ {0x23, 0x27, 0x2f, 0x33, 0x3B}
+};
+
+static const char palmas_ldo_ctrl[][PALMAS_LDO_NUM] = {
+ {0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64},
+ {0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64},
+ {0x50, 0x52, 0x54, 0x5e, 0x62}
+};
+
+static const char palmas_ldo_volt[][PALMAS_LDO_NUM] = {
+ {0x51, 0x53, 0x55, 0x57, 0x59, 0x5b, 0x5d, 0x5f, 0x61, 0x63, 0x65},
+ {0x51, 0x53, 0x55, 0x57, 0x59, 0x5b, 0x5d, 0x5f, 0x61, 0x63, 0x65},
+ {0x51, 0x53, 0x55, 0x5f, 0x63}
+};
+
+static int palmas_smps_enable(struct udevice *dev, int op, bool *enable)
+{
+ int ret;
+ unsigned int adr;
+ struct dm_regulator_uclass_platdata *uc_pdata;
+
+ uc_pdata = dev_get_uclass_platdata(dev);
+ adr = uc_pdata->ctrl_reg;
+
+ ret = pmic_reg_read(dev->parent, adr);
+ if (ret < 0)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ ret &= PALMAS_SMPS_STATUS_MASK;
+
+ if (ret)
+ *enable = true;
+ else
+ *enable = false;
+
+ return 0;
+ } else if (op == PMIC_OP_SET) {
+ if (*enable)
+ ret |= PALMAS_SMPS_MODE_MASK;
+ else
+ ret &= ~(PALMAS_SMPS_MODE_MASK);
+
+ ret = pmic_reg_write(dev->parent, adr, ret);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int palmas_smps_volt2hex(int uV)
+{
+ if (uV > PALMAS_LDO_VOLT_MAX)
+ return -EINVAL;
+
+ if (uV > 1650000)
+ return (uV - 1000000) / 20000 + 0x6;
+
+ if (uV == 500000)
+ return 0x6;
+ else
+ return 0x6 + ((uV - 500000) / 10000);
+}
+
+static int palmas_smps_hex2volt(int hex, bool range)
+{
+ unsigned int uV = 0;
+
+ if (hex > PALMAS_SMPS_VOLT_MAX_HEX)
+ return -EINVAL;
+
+ if (hex < 0x7)
+ uV = 500000;
+ else
+ uV = 500000 + (hex - 0x6) * 10000;
+
+ if (range)
+ uV *= 2;
+
+ return uV;
+}
+
+static int palmas_smps_val(struct udevice *dev, int op, int *uV)
+{
+ unsigned int hex, adr;
+ int ret;
+ bool range;
+ struct dm_regulator_uclass_platdata *uc_pdata;
+
+ uc_pdata = dev_get_uclass_platdata(dev);
+
+ if (op == PMIC_OP_GET)
+ *uV = 0;
+
+ adr = uc_pdata->volt_reg;
+
+ ret = pmic_reg_read(dev->parent, adr);
+ if (ret < 0)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ if (ret & PALMAS_SMPS_RANGE_MASK)
+ range = true;
+ else
+ range = false;
+
+ ret &= PALMAS_SMPS_VOLT_MASK;
+ ret = palmas_smps_hex2volt(ret, range);
+ if (ret < 0)
+ return ret;
+ *uV = ret;
+
+ return 0;
+ }
+
+ hex = palmas_smps_volt2hex(*uV);
+ if (hex < 0)
+ return hex;
+
+ ret &= ~PALMAS_SMPS_VOLT_MASK;
+ ret |= hex;
+ if (*uV > 1650000)
+ ret |= PALMAS_SMPS_RANGE_MASK;
+
+ return pmic_reg_write(dev->parent, adr, ret);
+}
+
+static int palmas_ldo_enable(struct udevice *dev, int op, bool *enable)
+{
+ int ret;
+ unsigned int adr;
+ struct dm_regulator_uclass_platdata *uc_pdata;
+
+ uc_pdata = dev_get_uclass_platdata(dev);
+ adr = uc_pdata->ctrl_reg;
+
+ ret = pmic_reg_read(dev->parent, adr);
+ if (ret < 0)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ ret &= PALMAS_LDO_STATUS_MASK;
+
+ if (ret)
+ *enable = true;
+ else
+ *enable = false;
+
+ return 0;
+ } else if (op == PMIC_OP_SET) {
+ if (*enable)
+ ret |= PALMAS_LDO_MODE_MASK;
+ else
+ ret &= ~(PALMAS_LDO_MODE_MASK);
+
+ ret = pmic_reg_write(dev->parent, adr, ret);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int palmas_ldo_volt2hex(int uV)
+{
+ if (uV > PALMAS_LDO_VOLT_MAX)
+ return -EINVAL;
+
+ return (uV - 850000) / 50000;
+}
+
+static int palmas_ldo_hex2volt(int hex)
+{
+ if (hex > PALMAS_LDO_VOLT_MAX_HEX)
+ return -EINVAL;
+
+ if (!hex)
+ return 0;
+
+ return (hex * 50000) + 850000;
+}
+
+static int palmas_ldo_val(struct udevice *dev, int op, int *uV)
+{
+ unsigned int hex, adr;
+ int ret;
+
+ struct dm_regulator_uclass_platdata *uc_pdata;
+
+ if (op == PMIC_OP_GET)
+ *uV = 0;
+
+ uc_pdata = dev_get_uclass_platdata(dev);
+
+ adr = uc_pdata->volt_reg;
+
+ ret = pmic_reg_read(dev->parent, adr);
+ if (ret < 0)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ ret &= PALMAS_LDO_VOLT_MASK;
+ ret = palmas_ldo_hex2volt(ret);
+ if (ret < 0)
+ return ret;
+ *uV = ret;
+ return 0;
+ }
+
+ hex = palmas_ldo_volt2hex(*uV);
+ if (hex < 0)
+ return hex;
+
+ ret &= ~PALMAS_LDO_VOLT_MASK;
+ ret |= hex;
+ if (*uV > 1650000)
+ ret |= 0x80;
+
+ return pmic_reg_write(dev->parent, adr, ret);
+}
+
+static int palmas_ldo_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_platdata *uc_pdata;
+ struct udevice *parent;
+
+ uc_pdata = dev_get_uclass_platdata(dev);
+
+ parent = dev_get_parent(dev);
+ int type = dev_get_driver_data(parent);
+
+ uc_pdata->type = REGULATOR_TYPE_LDO;
+
+ if (dev->driver_data) {
+ u8 idx = dev->driver_data - 1;
+ uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][idx];
+ uc_pdata->volt_reg = palmas_ldo_volt[type][idx];
+ } else {
+ /* check for ldoln and ldousb cases */
+ if (!strcmp("ldoln", dev->name)) {
+ uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][9];
+ uc_pdata->volt_reg = palmas_ldo_volt[type][9];
+ } else if (!strcmp("ldousb", dev->name)) {
+ uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][10];
+ uc_pdata->volt_reg = palmas_ldo_volt[type][10];
+ }
+ }
+
+ return 0;
+}
+
+static int ldo_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = palmas_ldo_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int ldo_set_value(struct udevice *dev, int uV)
+{
+ return palmas_ldo_val(dev, PMIC_OP_SET, &uV);
+}
+
+static bool ldo_get_enable(struct udevice *dev)
+{
+ bool enable = false;
+ int ret;
+
+ ret = palmas_ldo_enable(dev, PMIC_OP_GET, &enable);
+ if (ret)
+ return ret;
+
+ return enable;
+}
+
+static int ldo_set_enable(struct udevice *dev, bool enable)
+{
+ return palmas_ldo_enable(dev, PMIC_OP_SET, &enable);
+}
+
+static int palmas_smps_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_platdata *uc_pdata;
+ struct udevice *parent;
+ int idx;
+
+ uc_pdata = dev_get_uclass_platdata(dev);
+
+ parent = dev_get_parent(dev);
+ int type = dev_get_driver_data(parent);
+
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+
+ switch (type) {
+ case PALMAS:
+ case TPS659038:
+ switch (dev->driver_data) {
+ case 123:
+ case 12:
+ uc_pdata->ctrl_reg = palmas_smps_ctrl[type][0];
+ uc_pdata->volt_reg = palmas_smps_volt[type][0];
+ break;
+ case 3:
+ uc_pdata->ctrl_reg = palmas_smps_ctrl[type][1];
+ uc_pdata->volt_reg = palmas_smps_volt[type][1];
+ break;
+ case 45:
+ uc_pdata->ctrl_reg = palmas_smps_ctrl[type][2];
+ uc_pdata->volt_reg = palmas_smps_volt[type][2];
+ break;
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ idx = dev->driver_data - 4;
+ uc_pdata->ctrl_reg = palmas_smps_ctrl[type][idx];
+ uc_pdata->volt_reg = palmas_smps_volt[type][idx];
+ break;
+
+ default:
+ printf("Wrong ID for regulator\n");
+ }
+ break;
+
+ case TPS65917:
+ switch (dev->driver_data) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ idx = dev->driver_data - 1;
+ uc_pdata->ctrl_reg = palmas_smps_ctrl[type][idx];
+ uc_pdata->volt_reg = palmas_smps_volt[type][idx];
+ break;
+
+ default:
+ printf("Wrong ID for regulator\n");
+ }
+ break;
+
+ default:
+ printf("Invalid PMIC ID\n");
+ }
+
+ return 0;
+}
+
+static int smps_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = palmas_smps_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int smps_set_value(struct udevice *dev, int uV)
+{
+ return palmas_smps_val(dev, PMIC_OP_SET, &uV);
+}
+
+static bool smps_get_enable(struct udevice *dev)
+{
+ bool enable = false;
+ int ret;
+
+ ret = palmas_smps_enable(dev, PMIC_OP_GET, &enable);
+ if (ret)
+ return ret;
+
+ return enable;
+}
+
+static int smps_set_enable(struct udevice *dev, bool enable)
+{
+ return palmas_smps_enable(dev, PMIC_OP_SET, &enable);
+}
+
+static const struct dm_regulator_ops palmas_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(palmas_ldo) = {
+ .name = PALMAS_LDO_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &palmas_ldo_ops,
+ .probe = palmas_ldo_probe,
+};
+
+static const struct dm_regulator_ops palmas_smps_ops = {
+ .get_value = smps_get_value,
+ .set_value = smps_set_value,
+ .get_enable = smps_get_enable,
+ .set_enable = smps_set_enable,
+};
+
+U_BOOT_DRIVER(palmas_smps) = {
+ .name = PALMAS_SMPS_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &palmas_smps_ops,
+ .probe = palmas_smps_probe,
+};
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 4fcc0d9..c42b0bc 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -34,4 +34,13 @@ config TEGRA186_RESET
Enable support for manipulating Tegra's on-SoC reset signals via IPC
requests to the BPMP (Boot and Power Management Processor).
+config RESET_UNIPHIER
+ bool "Reset controller driver for UniPhier SoCs"
+ depends on ARCH_UNIPHIER
+ default y
+ help
+ Support for reset controllers on UniPhier SoCs.
+ Say Y if you want to control reset signals provided by System Control
+ block, Media I/O block, Peripheral Block.
+
endmenu
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 5d4ea3d..5c4305c 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_SANDBOX_MBOX) += sandbox-reset.o
obj-$(CONFIG_SANDBOX_MBOX) += sandbox-reset-test.o
obj-$(CONFIG_TEGRA_CAR_RESET) += tegra-car-reset.o
obj-$(CONFIG_TEGRA186_RESET) += tegra186-reset.o
+obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
diff --git a/drivers/reset/reset-uniphier.c b/drivers/reset/reset-uniphier.c
new file mode 100644
index 0000000..29c4d4d
--- /dev/null
+++ b/drivers/reset/reset-uniphier.c
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <reset-uclass.h>
+#include <dm/device.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/sizes.h>
+
+struct uniphier_reset_data {
+ unsigned int id;
+ unsigned int reg;
+ unsigned int bit;
+ unsigned int flags;
+#define UNIPHIER_RESET_ACTIVE_LOW BIT(0)
+};
+
+#define UNIPHIER_RESET_ID_END (unsigned int)(-1)
+
+#define UNIPHIER_RESET_END \
+ { .id = UNIPHIER_RESET_ID_END }
+
+#define UNIPHIER_RESET(_id, _reg, _bit) \
+ { \
+ .id = (_id), \
+ .reg = (_reg), \
+ .bit = (_bit), \
+ }
+
+#define UNIPHIER_RESETX(_id, _reg, _bit) \
+ { \
+ .id = (_id), \
+ .reg = (_reg), \
+ .bit = (_bit), \
+ .flags = UNIPHIER_RESET_ACTIVE_LOW, \
+ }
+
+/* System reset data */
+#define UNIPHIER_SLD3_SYS_RESET_STDMAC(id) \
+ UNIPHIER_RESETX((id), 0x2000, 10)
+
+#define UNIPHIER_LD11_SYS_RESET_STDMAC(id) \
+ UNIPHIER_RESETX((id), 0x200c, 8)
+
+#define UNIPHIER_PRO4_SYS_RESET_GIO(id) \
+ UNIPHIER_RESETX((id), 0x2000, 6)
+
+#define UNIPHIER_LD20_SYS_RESET_GIO(id) \
+ UNIPHIER_RESETX((id), 0x200c, 5)
+
+#define UNIPHIER_PRO4_SYS_RESET_USB3(id, ch) \
+ UNIPHIER_RESETX((id), 0x2000 + 0x4 * (ch), 17)
+
+const struct uniphier_reset_data uniphier_sld3_sys_reset_data[] = {
+ UNIPHIER_SLD3_SYS_RESET_STDMAC(8), /* Ether, HSC, MIO */
+ UNIPHIER_RESET_END,
+};
+
+const struct uniphier_reset_data uniphier_pro4_sys_reset_data[] = {
+ UNIPHIER_SLD3_SYS_RESET_STDMAC(8), /* HSC, MIO, RLE */
+ UNIPHIER_PRO4_SYS_RESET_GIO(12), /* Ether, SATA, USB3 */
+ UNIPHIER_PRO4_SYS_RESET_USB3(14, 0),
+ UNIPHIER_PRO4_SYS_RESET_USB3(15, 1),
+ UNIPHIER_RESET_END,
+};
+
+const struct uniphier_reset_data uniphier_pro5_sys_reset_data[] = {
+ UNIPHIER_SLD3_SYS_RESET_STDMAC(8), /* HSC */
+ UNIPHIER_PRO4_SYS_RESET_GIO(12), /* PCIe, USB3 */
+ UNIPHIER_PRO4_SYS_RESET_USB3(14, 0),
+ UNIPHIER_PRO4_SYS_RESET_USB3(15, 1),
+ UNIPHIER_RESET_END,
+};
+
+const struct uniphier_reset_data uniphier_pxs2_sys_reset_data[] = {
+ UNIPHIER_SLD3_SYS_RESET_STDMAC(8), /* HSC, RLE */
+ UNIPHIER_PRO4_SYS_RESET_USB3(14, 0),
+ UNIPHIER_PRO4_SYS_RESET_USB3(15, 1),
+ UNIPHIER_RESETX(16, 0x2014, 4), /* USB30-PHY0 */
+ UNIPHIER_RESETX(17, 0x2014, 0), /* USB30-PHY1 */
+ UNIPHIER_RESETX(18, 0x2014, 2), /* USB30-PHY2 */
+ UNIPHIER_RESETX(20, 0x2014, 5), /* USB31-PHY0 */
+ UNIPHIER_RESETX(21, 0x2014, 1), /* USB31-PHY1 */
+ UNIPHIER_RESETX(28, 0x2014, 12), /* SATA */
+ UNIPHIER_RESET(29, 0x2014, 8), /* SATA-PHY (active high) */
+ UNIPHIER_RESET_END,
+};
+
+const struct uniphier_reset_data uniphier_ld11_sys_reset_data[] = {
+ UNIPHIER_LD11_SYS_RESET_STDMAC(8), /* HSC, MIO */
+ UNIPHIER_RESET_END,
+};
+
+const struct uniphier_reset_data uniphier_ld20_sys_reset_data[] = {
+ UNIPHIER_LD11_SYS_RESET_STDMAC(8), /* HSC */
+ UNIPHIER_LD20_SYS_RESET_GIO(12), /* PCIe, USB3 */
+ UNIPHIER_RESETX(16, 0x200c, 12), /* USB30-PHY0 */
+ UNIPHIER_RESETX(17, 0x200c, 13), /* USB30-PHY1 */
+ UNIPHIER_RESETX(18, 0x200c, 14), /* USB30-PHY2 */
+ UNIPHIER_RESETX(19, 0x200c, 15), /* USB30-PHY3 */
+ UNIPHIER_RESET_END,
+};
+
+/* Media I/O reset data */
+#define UNIPHIER_MIO_RESET_SD(id, ch) \
+ UNIPHIER_RESETX((id), 0x110 + 0x200 * (ch), 0)
+
+#define UNIPHIER_MIO_RESET_SD_BRIDGE(id, ch) \
+ UNIPHIER_RESETX((id), 0x110 + 0x200 * (ch), 26)
+
+#define UNIPHIER_MIO_RESET_EMMC_HW_RESET(id, ch) \
+ UNIPHIER_RESETX((id), 0x80 + 0x200 * (ch), 0)
+
+#define UNIPHIER_MIO_RESET_USB2(id, ch) \
+ UNIPHIER_RESETX((id), 0x114 + 0x200 * (ch), 0)
+
+#define UNIPHIER_MIO_RESET_USB2_BRIDGE(id, ch) \
+ UNIPHIER_RESETX((id), 0x110 + 0x200 * (ch), 24)
+
+#define UNIPHIER_MIO_RESET_DMAC(id) \
+ UNIPHIER_RESETX((id), 0x110, 17)
+
+const struct uniphier_reset_data uniphier_mio_reset_data[] = {
+ UNIPHIER_MIO_RESET_SD(0, 0),
+ UNIPHIER_MIO_RESET_SD(1, 1),
+ UNIPHIER_MIO_RESET_SD(2, 2),
+ UNIPHIER_MIO_RESET_SD_BRIDGE(3, 0),
+ UNIPHIER_MIO_RESET_SD_BRIDGE(4, 1),
+ UNIPHIER_MIO_RESET_SD_BRIDGE(5, 2),
+ UNIPHIER_MIO_RESET_EMMC_HW_RESET(6, 1),
+ UNIPHIER_MIO_RESET_DMAC(7),
+ UNIPHIER_MIO_RESET_USB2(8, 0),
+ UNIPHIER_MIO_RESET_USB2(9, 1),
+ UNIPHIER_MIO_RESET_USB2(10, 2),
+ UNIPHIER_MIO_RESET_USB2(11, 3),
+ UNIPHIER_MIO_RESET_USB2_BRIDGE(12, 0),
+ UNIPHIER_MIO_RESET_USB2_BRIDGE(13, 1),
+ UNIPHIER_MIO_RESET_USB2_BRIDGE(14, 2),
+ UNIPHIER_MIO_RESET_USB2_BRIDGE(15, 3),
+ UNIPHIER_RESET_END,
+};
+
+/* Peripheral reset data */
+#define UNIPHIER_PERI_RESET_UART(id, ch) \
+ UNIPHIER_RESETX((id), 0x114, 19 + (ch))
+
+#define UNIPHIER_PERI_RESET_I2C(id, ch) \
+ UNIPHIER_RESETX((id), 0x114, 5 + (ch))
+
+#define UNIPHIER_PERI_RESET_FI2C(id, ch) \
+ UNIPHIER_RESETX((id), 0x114, 24 + (ch))
+
+const struct uniphier_reset_data uniphier_ld4_peri_reset_data[] = {
+ UNIPHIER_PERI_RESET_UART(0, 0),
+ UNIPHIER_PERI_RESET_UART(1, 1),
+ UNIPHIER_PERI_RESET_UART(2, 2),
+ UNIPHIER_PERI_RESET_UART(3, 3),
+ UNIPHIER_PERI_RESET_I2C(4, 0),
+ UNIPHIER_PERI_RESET_I2C(5, 1),
+ UNIPHIER_PERI_RESET_I2C(6, 2),
+ UNIPHIER_PERI_RESET_I2C(7, 3),
+ UNIPHIER_PERI_RESET_I2C(8, 4),
+ UNIPHIER_RESET_END,
+};
+
+const struct uniphier_reset_data uniphier_pro4_peri_reset_data[] = {
+ UNIPHIER_PERI_RESET_UART(0, 0),
+ UNIPHIER_PERI_RESET_UART(1, 1),
+ UNIPHIER_PERI_RESET_UART(2, 2),
+ UNIPHIER_PERI_RESET_UART(3, 3),
+ UNIPHIER_PERI_RESET_FI2C(4, 0),
+ UNIPHIER_PERI_RESET_FI2C(5, 1),
+ UNIPHIER_PERI_RESET_FI2C(6, 2),
+ UNIPHIER_PERI_RESET_FI2C(7, 3),
+ UNIPHIER_PERI_RESET_FI2C(8, 4),
+ UNIPHIER_PERI_RESET_FI2C(9, 5),
+ UNIPHIER_PERI_RESET_FI2C(10, 6),
+ UNIPHIER_RESET_END,
+};
+
+/* core implementaton */
+struct uniphier_reset_priv {
+ void __iomem *base;
+ const struct uniphier_reset_data *data;
+};
+
+static int uniphier_reset_request(struct reset_ctl *reset_ctl)
+{
+ return 0;
+}
+
+static int uniphier_reset_free(struct reset_ctl *reset_ctl)
+{
+ return 0;
+}
+
+static int uniphier_reset_update(struct reset_ctl *reset_ctl, int assert)
+{
+ struct uniphier_reset_priv *priv = dev_get_priv(reset_ctl->dev);
+ unsigned long id = reset_ctl->id;
+ const struct uniphier_reset_data *p;
+
+ for (p = priv->data; p->id != UNIPHIER_RESET_ID_END; p++) {
+ u32 mask, val;
+
+ if (p->id != id)
+ continue;
+
+ val = readl(priv->base + p->reg);
+
+ if (p->flags & UNIPHIER_RESET_ACTIVE_LOW)
+ assert = !assert;
+
+ mask = BIT(p->bit);
+
+ if (assert)
+ val |= mask;
+ else
+ val &= ~mask;
+
+ writel(val, priv->base + p->reg);
+
+ return 0;
+ }
+
+ dev_err(priv->dev, "reset_id=%lu was not handled\n", id);
+ return -EINVAL;
+}
+
+static int uniphier_reset_assert(struct reset_ctl *reset_ctl)
+{
+ return uniphier_reset_update(reset_ctl, 1);
+}
+
+static int uniphier_reset_deassert(struct reset_ctl *reset_ctl)
+{
+ return uniphier_reset_update(reset_ctl, 0);
+}
+
+static const struct reset_ops uniphier_reset_ops = {
+ .request = uniphier_reset_request,
+ .free = uniphier_reset_free,
+ .rst_assert = uniphier_reset_assert,
+ .rst_deassert = uniphier_reset_deassert,
+};
+
+static int uniphier_reset_probe(struct udevice *dev)
+{
+ struct uniphier_reset_priv *priv = dev_get_priv(dev);
+ fdt_addr_t addr;
+
+ addr = dev_get_addr(dev->parent);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->base = devm_ioremap(dev, addr, SZ_4K);
+ if (!priv->base)
+ return -ENOMEM;
+
+ priv->data = (void *)dev_get_driver_data(dev);
+
+ return 0;
+}
+
+static const struct udevice_id uniphier_reset_match[] = {
+ /* System reset */
+ {
+ .compatible = "socionext,uniphier-sld3-reset",
+ .data = (ulong)uniphier_sld3_sys_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-ld4-reset",
+ .data = (ulong)uniphier_sld3_sys_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-pro4-reset",
+ .data = (ulong)uniphier_pro4_sys_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-sld8-reset",
+ .data = (ulong)uniphier_sld3_sys_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-pro5-reset",
+ .data = (ulong)uniphier_pro5_sys_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-pxs2-reset",
+ .data = (ulong)uniphier_pxs2_sys_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-ld11-reset",
+ .data = (ulong)uniphier_ld11_sys_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-ld20-reset",
+ .data = (ulong)uniphier_ld20_sys_reset_data,
+ },
+ /* Media I/O reset */
+ {
+ .compatible = "socionext,uniphier-sld3-mio-clock",
+ .data = (ulong)uniphier_mio_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-ld4-mio-reset",
+ .data = (ulong)uniphier_mio_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-pro4-mio-reset",
+ .data = (ulong)uniphier_mio_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-sld8-mio-reset",
+ .data = (ulong)uniphier_mio_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-pro5-mio-reset",
+ .data = (ulong)uniphier_mio_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-pxs2-mio-reset",
+ .data = (ulong)uniphier_mio_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-ld11-mio-reset",
+ .data = (ulong)uniphier_mio_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-ld20-mio-reset",
+ .data = (ulong)uniphier_mio_reset_data,
+ },
+ /* Peripheral reset */
+ {
+ .compatible = "socionext,uniphier-ld4-peri-reset",
+ .data = (ulong)uniphier_ld4_peri_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-pro4-peri-reset",
+ .data = (ulong)uniphier_pro4_peri_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-sld8-peri-reset",
+ .data = (ulong)uniphier_ld4_peri_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-pro5-peri-reset",
+ .data = (ulong)uniphier_pro4_peri_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-pxs2-peri-reset",
+ .data = (ulong)uniphier_pro4_peri_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-ld11-peri-reset",
+ .data = (ulong)uniphier_pro4_peri_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-ld20-peri-reset",
+ .data = (ulong)uniphier_pro4_peri_reset_data,
+ },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(uniphier_reset) = {
+ .name = "uniphier-reset",
+ .id = UCLASS_RESET,
+ .of_match = uniphier_reset_match,
+ .probe = uniphier_reset_probe,
+ .priv_auto_alloc_size = sizeof(struct uniphier_reset_priv),
+ .ops = &uniphier_reset_ops,
+};
diff --git a/drivers/rtc/mc146818.c b/drivers/rtc/mc146818.c
index da804d5..4df9eda 100644
--- a/drivers/rtc/mc146818.c
+++ b/drivers/rtc/mc146818.c
@@ -14,7 +14,7 @@
#include <dm.h>
#include <rtc.h>
-#if defined(__I386__) || defined(CONFIG_MALTA)
+#if defined(CONFIG_X86) || defined(CONFIG_MALTA)
#include <asm/io.h>
#define in8(p) inb(p)
#define out8(p, v) outb(v, p)
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
index 2144fca..729ded9 100644
--- a/drivers/spi/fsl_qspi.c
+++ b/drivers/spi/fsl_qspi.c
@@ -865,6 +865,7 @@ static inline struct fsl_qspi *to_qspi_spi(struct spi_slave *slave)
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int mode)
{
+ u32 mcr_val;
struct fsl_qspi *qspi;
struct fsl_qspi_regs *regs;
u32 total_size;
@@ -896,8 +897,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
qspi->slave.max_write_size = TX_BUFFER_SIZE;
+ mcr_val = qspi_read32(qspi->priv.flags, &regs->mcr);
qspi_write32(qspi->priv.flags, &regs->mcr,
- QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK);
+ QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK |
+ (mcr_val & QSPI_MCR_END_CFD_MASK));
qspi_cfg_smpr(&qspi->priv,
~(QSPI_SMPR_FSDLY_MASK | QSPI_SMPR_DDRSMP_MASK |
@@ -975,6 +978,7 @@ static int fsl_qspi_child_pre_probe(struct udevice *dev)
static int fsl_qspi_probe(struct udevice *bus)
{
+ u32 mcr_val;
u32 amba_size_per_chip;
struct fsl_qspi_platdata *plat = dev_get_platdata(bus);
struct fsl_qspi_priv *priv = dev_get_priv(bus);
@@ -999,8 +1003,10 @@ static int fsl_qspi_probe(struct udevice *bus)
priv->flash_num = plat->flash_num;
priv->num_chipselect = plat->num_chipselect;
+ mcr_val = qspi_read32(priv->flags, &priv->regs->mcr);
qspi_write32(priv->flags, &priv->regs->mcr,
- QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK);
+ QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK |
+ (mcr_val & QSPI_MCR_END_CFD_MASK));
qspi_cfg_smpr(priv, ~(QSPI_SMPR_FSDLY_MASK | QSPI_SMPR_DDRSMP_MASK |
QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK), 0);
diff --git a/drivers/tpm/tpm_tis_lpc.c b/drivers/tpm/tpm_tis_lpc.c
index 257d035..b4efbb5 100644
--- a/drivers/tpm/tpm_tis_lpc.c
+++ b/drivers/tpm/tpm_tis_lpc.c
@@ -204,7 +204,7 @@ static int tis_senddata(struct udevice *dev, const u8 *data, size_t len)
/* Wait till the device is ready to accept more data. */
while (!burst) {
if (max_cycles++ == MAX_DELAY_US) {
- printf("%s:%d failed to feed %d bytes of %d\n",
+ printf("%s:%d failed to feed %zd bytes of %zd\n",
__FILE__, __LINE__, len - offset, len);
return -ETIMEDOUT;
}
@@ -224,7 +224,7 @@ static int tis_senddata(struct udevice *dev, const u8 *data, size_t len)
* changes to zero exactly after the last byte is fed into the
* FIFO.
*/
- count = min((u32)burst, len - offset - 1);
+ count = min((size_t)burst, len - offset - 1);
while (count--)
tpm_write_byte(priv, data[offset++],
&regs[locality].data);
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 6fc2479..f20fc33 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -32,8 +32,8 @@ static void ehci_pci_init(struct udevice *dev, struct ehci_hccr **ret_hccr,
hcor = (struct ehci_hcor *)((uintptr_t) hccr +
HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
- debug("EHCI-PCI init hccr 0x%x and hcor 0x%x hc_length %d\n",
- (u32)hccr, (u32)hcor,
+ debug("EHCI-PCI init hccr %#lx and hcor %#lx hc_length %d\n",
+ (ulong)hccr, (ulong)hcor,
(u32)HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
*ret_hccr = hccr;
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 8361a71..86db0da 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -101,6 +101,15 @@ config VIDCONSOLE_AS_LCD
to update the environment, the breakage may be confusing for users.
This option will be removed around the end of 2016.
+config VIDEO_COREBOOT
+ bool "Enable coreboot framebuffer driver support"
+ depends on X86 && SYS_COREBOOT
+ help
+ Turn on this option to enable a framebuffer driver when U-Boot is
+ loaded by coreboot where the graphics device is configured by
+ coreboot already. This can in principle be used with any platform
+ that coreboot supports.
+
config VIDEO_VESA
bool "Enable VESA video driver support"
default n
@@ -366,7 +375,19 @@ config VIDEO_BROADWELL_IGD
bool "Enable Intel Broadwell integrated graphics device"
depends on X86
help
- This enabled support for integrated graphics on Intel broadwell
+ This enables support for integrated graphics on Intel broadwell
+ devices. Initialisation is mostly performed by a VGA boot ROM, with
+ some setup handled by U-Boot itself. The graphics adaptor works as
+ a VESA device and supports LCD panels, eDP and LVDS outputs.
+ Configuration of most aspects of device operation is performed using
+ a special tool which configures the VGA ROM, but the graphics
+ resolution can be selected in U-Boot.
+
+config VIDEO_IVYBRIDGE_IGD
+ bool "Enable Intel Ivybridge integration graphics support"
+ depends on X86
+ help
+ This enables support for integrated graphics on Intel ivybridge
devices. Initialisation is mostly performed by a VGA boot ROM, with
some setup handled by U-Boot itself. The graphics adaptor works as
a VESA device and supports LCD panels, eDP and LVDS outputs.
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 3f045fe..4a42417 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_CONSOLE_TRUETYPE) += console_truetype.o fonts/
endif
obj-$(CONFIG_VIDEO_BROADWELL_IGD) += broadwell_igd.o
+obj-$(CONFIG_VIDEO_IVYBRIDGE_IGD) += ivybridge_igd.o
obj-$(CONFIG_ATI_RADEON_FB) += ati_radeon_fb.o videomodes.o
obj-$(CONFIG_ATMEL_HLCD) += atmel_hlcdfb.o
@@ -36,7 +37,7 @@ obj-$(CONFIG_S6E63D6) += s6e63d6.o
obj-$(CONFIG_LD9040) += ld9040.o
obj-$(CONFIG_SED156X) += sed156x.o
obj-$(CONFIG_VIDEO_BCM2835) += bcm2835.o
-obj-$(CONFIG_VIDEO_COREBOOT) += coreboot_fb.o
+obj-$(CONFIG_VIDEO_COREBOOT) += coreboot.o
obj-$(CONFIG_VIDEO_CT69000) += ct69000.o videomodes.o
obj-$(CONFIG_VIDEO_DA8XX) += da8xx-fb.o videomodes.o
obj-$(CONFIG_VIDEO_IMX25LCDC) += imx25lcdc.o videomodes.o
@@ -57,7 +58,7 @@ obj-$(CONFIG_VIDEO_SMI_LYNXEM) += smiLynxEM.o videomodes.o
obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o videomodes.o
obj-$(CONFIG_VIDEO_TEGRA20) += tegra.o
obj-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o
-obj-$(CONFIG_VIDEO_VESA) += vesa_fb.o
+obj-$(CONFIG_VIDEO_VESA) += vesa.o
obj-$(CONFIG_FORMIKE) += formike.o
obj-$(CONFIG_LG4573) += lg4573.o
obj-$(CONFIG_AM335X_LCD) += am335x-fb.o
diff --git a/drivers/video/broadwell_igd.c b/drivers/video/broadwell_igd.c
index 4286fd0..beef770 100644
--- a/drivers/video/broadwell_igd.c
+++ b/drivers/video/broadwell_igd.c
@@ -9,10 +9,8 @@
#include <common.h>
#include <bios_emul.h>
#include <dm.h>
-#include <pci_rom.h>
#include <vbe.h>
#include <video.h>
-#include <video_fb.h>
#include <asm/cpu.h>
#include <asm/intel_regs.h>
#include <asm/io.h>
@@ -20,11 +18,9 @@
#include <asm/arch/cpu.h>
#include <asm/arch/iomap.h>
#include <asm/arch/pch.h>
-#include <linux/log2.h>
#include "i915_reg.h"
struct broadwell_igd_priv {
- GraphicDevice ctfb;
u8 *regs;
};
@@ -664,10 +660,7 @@ static int broadwell_igd_probe(struct udevice *dev)
{
struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
struct video_priv *uc_priv = dev_get_uclass_priv(dev);
- struct broadwell_igd_priv *priv = dev_get_priv(dev);
bool is_broadwell;
- GraphicDevice *gdev = &priv->ctfb;
- int bits_per_pixel;
int ret;
if (!ll_boot_init()) {
@@ -683,13 +676,9 @@ static int broadwell_igd_probe(struct udevice *dev)
debug("%s: is_broadwell=%d\n", __func__, is_broadwell);
ret = igd_pre_init(dev, is_broadwell);
if (!ret) {
- ret = dm_pci_run_vga_bios(dev, broadwell_igd_int15_handler,
- PCI_ROM_USE_NATIVE |
- PCI_ROM_ALLOW_FALLBACK);
- if (ret) {
- printf("failed to run video BIOS: %d\n", ret);
- ret = -EIO;
- }
+ ret = vbe_setup_video(dev, broadwell_igd_int15_handler);
+ if (ret)
+ debug("failed to run video BIOS: %d\n", ret);
}
if (!ret)
ret = igd_post_init(dev, is_broadwell);
@@ -697,13 +686,8 @@ static int broadwell_igd_probe(struct udevice *dev)
if (ret)
return ret;
- if (vbe_get_video_info(gdev)) {
- printf("No video mode configured\n");
- return -ENXIO;
- }
-
- /* Use write-through for the graphics memory, 256MB */
- ret = mtrr_add_request(MTRR_TYPE_WRTHROUGH, gdev->pciBase, 256 << 20);
+ /* Use write-combining for the graphics memory, 256MB */
+ ret = mtrr_add_request(MTRR_TYPE_WRCOMB, plat->base, 256 << 20);
if (!ret)
ret = mtrr_commit(true);
if (ret && ret != -ENOSYS) {
@@ -711,17 +695,8 @@ static int broadwell_igd_probe(struct udevice *dev)
ret);
}
- bits_per_pixel = gdev->gdfBytesPP * 8;
- sprintf(gdev->modeIdent, "%dx%dx%d", gdev->winSizeX, gdev->winSizeY,
- bits_per_pixel);
- printf("%s\n", gdev->modeIdent);
- uc_priv->xsize = gdev->winSizeX;
- uc_priv->ysize = gdev->winSizeY;
- uc_priv->bpix = ilog2(bits_per_pixel);
- plat->base = gdev->pciBase;
- plat->size = gdev->memSize;
- debug("fb=%x, size %x, display size=%d %d %d\n", gdev->pciBase,
- gdev->memSize, uc_priv->xsize, uc_priv->ysize, uc_priv->bpix);
+ debug("fb=%lx, size %x, display size=%d %d %d\n", plat->base,
+ plat->size, uc_priv->xsize, uc_priv->ysize, uc_priv->bpix);
return 0;
}
diff --git a/drivers/video/coreboot.c b/drivers/video/coreboot.c
new file mode 100644
index 0000000..3a94aa1
--- /dev/null
+++ b/drivers/video/coreboot.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2016, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <vbe.h>
+#include <video.h>
+#include <asm/arch/sysinfo.h>
+
+static int save_vesa_mode(struct cb_framebuffer *fb,
+ struct vesa_mode_info *vesa)
+{
+ /*
+ * If there is no framebuffer structure, bail out and keep
+ * running on the serial console.
+ */
+ if (!fb)
+ return -ENXIO;
+
+ vesa->x_resolution = fb->x_resolution;
+ vesa->y_resolution = fb->y_resolution;
+ vesa->bits_per_pixel = fb->bits_per_pixel;
+ vesa->bytes_per_scanline = fb->bytes_per_line;
+ vesa->phys_base_ptr = fb->physical_address;
+ vesa->red_mask_size = fb->red_mask_size;
+ vesa->red_mask_pos = fb->red_mask_pos;
+ vesa->green_mask_size = fb->green_mask_size;
+ vesa->green_mask_pos = fb->green_mask_pos;
+ vesa->blue_mask_size = fb->blue_mask_size;
+ vesa->blue_mask_pos = fb->blue_mask_pos;
+ vesa->reserved_mask_size = fb->reserved_mask_size;
+ vesa->reserved_mask_pos = fb->reserved_mask_pos;
+
+ return 0;
+}
+
+static int coreboot_video_probe(struct udevice *dev)
+{
+ struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
+ struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct cb_framebuffer *fb = lib_sysinfo.framebuffer;
+ struct vesa_mode_info *vesa = &mode_info.vesa;
+ int ret;
+
+ printf("Video: ");
+
+ /* Initialize vesa_mode_info structure */
+ ret = save_vesa_mode(fb, vesa);
+ if (ret)
+ goto err;
+
+ ret = vbe_setup_video_priv(vesa, uc_priv, plat);
+ if (ret)
+ goto err;
+
+ printf("%dx%dx%d\n", uc_priv->xsize, uc_priv->ysize,
+ vesa->bits_per_pixel);
+
+ return 0;
+
+err:
+ printf("No video mode configured in coreboot!\n");
+ return ret;
+}
+
+static const struct udevice_id coreboot_video_ids[] = {
+ { .compatible = "coreboot-fb" },
+ { }
+};
+
+U_BOOT_DRIVER(coreboot_video) = {
+ .name = "coreboot_video",
+ .id = UCLASS_VIDEO,
+ .of_match = coreboot_video_ids,
+ .probe = coreboot_video_probe,
+};
diff --git a/drivers/video/coreboot_fb.c b/drivers/video/coreboot_fb.c
deleted file mode 100644
index feb5463..0000000
--- a/drivers/video/coreboot_fb.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * coreboot Framebuffer driver.
- *
- * Copyright (C) 2011 The Chromium OS authors
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <asm/arch/sysinfo.h>
-#include <vbe.h>
-#include <video_fb.h>
-#include "videomodes.h"
-
-/*
- * The Graphic Device
- */
-GraphicDevice ctfb;
-
-static void save_vesa_mode(void)
-{
- struct vesa_mode_info *vesa = &mode_info.vesa;
- struct cb_framebuffer *fb = lib_sysinfo.framebuffer;
-
- vesa->x_resolution = fb->x_resolution;
- vesa->y_resolution = fb->y_resolution;
- vesa->bits_per_pixel = fb->bits_per_pixel;
- vesa->bytes_per_scanline = fb->bytes_per_line;
- vesa->phys_base_ptr = fb->physical_address;
- vesa->red_mask_size = fb->red_mask_size;
- vesa->red_mask_pos = fb->red_mask_pos;
- vesa->green_mask_size = fb->green_mask_size;
- vesa->green_mask_pos = fb->green_mask_pos;
- vesa->blue_mask_size = fb->blue_mask_size;
- vesa->blue_mask_pos = fb->blue_mask_pos;
- vesa->reserved_mask_size = fb->reserved_mask_size;
- vesa->reserved_mask_pos = fb->reserved_mask_pos;
-}
-
-static int parse_coreboot_table_fb(GraphicDevice *gdev)
-{
- struct cb_framebuffer *fb = lib_sysinfo.framebuffer;
-
- /* If there is no framebuffer structure, bail out and keep
- * running on the serial console.
- */
- if (!fb)
- return 0;
-
- gdev->winSizeX = fb->x_resolution;
- gdev->winSizeY = fb->y_resolution;
-
- gdev->plnSizeX = fb->x_resolution;
- gdev->plnSizeY = fb->y_resolution;
-
- gdev->gdfBytesPP = fb->bits_per_pixel / 8;
-
- switch (fb->bits_per_pixel) {
- case 24:
- gdev->gdfIndex = GDF_32BIT_X888RGB;
- break;
- case 16:
- gdev->gdfIndex = GDF_16BIT_565RGB;
- break;
- default:
- gdev->gdfIndex = GDF__8BIT_INDEX;
- break;
- }
-
- gdev->isaBase = CONFIG_SYS_ISA_IO_BASE_ADDRESS;
- gdev->pciBase = (unsigned int)fb->physical_address;
-
- gdev->frameAdrs = (unsigned int)fb->physical_address;
- gdev->memSize = fb->bytes_per_line * fb->y_resolution;
-
- gdev->vprBase = (unsigned int)fb->physical_address;
- gdev->cprBase = (unsigned int)fb->physical_address;
-
- return 1;
-}
-
-void *video_hw_init(void)
-{
- GraphicDevice *gdev = &ctfb;
- int bits_per_pixel;
-
- printf("Video: ");
-
- if (!parse_coreboot_table_fb(gdev)) {
- printf("No video mode configured in coreboot!\n");
- return NULL;
- }
-
- bits_per_pixel = gdev->gdfBytesPP * 8;
-
- /* fill in Graphic device struct */
- sprintf(gdev->modeIdent, "%dx%dx%d", gdev->winSizeX, gdev->winSizeY,
- bits_per_pixel);
- printf("%s\n", gdev->modeIdent);
-
- memset((void *)gdev->pciBase, 0,
- gdev->winSizeX * gdev->winSizeY * gdev->gdfBytesPP);
-
- /* Initialize vesa_mode_info structure */
- save_vesa_mode();
-
- return (void *)gdev;
-}
diff --git a/drivers/video/ivybridge_igd.c b/drivers/video/ivybridge_igd.c
new file mode 100644
index 0000000..94db3dd
--- /dev/null
+++ b/drivers/video/ivybridge_igd.c
@@ -0,0 +1,843 @@
+/*
+ * Copyright (C) 2016 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <bios_emul.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <pci_rom.h>
+#include <vbe.h>
+#include <asm/intel_regs.h>
+#include <asm/io.h>
+#include <asm/mtrr.h>
+#include <asm/pci.h>
+#include <asm/arch/pch.h>
+#include <asm/arch/sandybridge.h>
+
+struct gt_powermeter {
+ u16 reg;
+ u32 value;
+};
+
+/* These are magic values - unfortunately the meaning is unknown */
+static const struct gt_powermeter snb_pm_gt1[] = {
+ { 0xa200, 0xcc000000 },
+ { 0xa204, 0x07000040 },
+ { 0xa208, 0x0000fe00 },
+ { 0xa20c, 0x00000000 },
+ { 0xa210, 0x17000000 },
+ { 0xa214, 0x00000021 },
+ { 0xa218, 0x0817fe19 },
+ { 0xa21c, 0x00000000 },
+ { 0xa220, 0x00000000 },
+ { 0xa224, 0xcc000000 },
+ { 0xa228, 0x07000040 },
+ { 0xa22c, 0x0000fe00 },
+ { 0xa230, 0x00000000 },
+ { 0xa234, 0x17000000 },
+ { 0xa238, 0x00000021 },
+ { 0xa23c, 0x0817fe19 },
+ { 0xa240, 0x00000000 },
+ { 0xa244, 0x00000000 },
+ { 0xa248, 0x8000421e },
+ { 0 }
+};
+
+static const struct gt_powermeter snb_pm_gt2[] = {
+ { 0xa200, 0x330000a6 },
+ { 0xa204, 0x402d0031 },
+ { 0xa208, 0x00165f83 },
+ { 0xa20c, 0xf1000000 },
+ { 0xa210, 0x00000000 },
+ { 0xa214, 0x00160016 },
+ { 0xa218, 0x002a002b },
+ { 0xa21c, 0x00000000 },
+ { 0xa220, 0x00000000 },
+ { 0xa224, 0x330000a6 },
+ { 0xa228, 0x402d0031 },
+ { 0xa22c, 0x00165f83 },
+ { 0xa230, 0xf1000000 },
+ { 0xa234, 0x00000000 },
+ { 0xa238, 0x00160016 },
+ { 0xa23c, 0x002a002b },
+ { 0xa240, 0x00000000 },
+ { 0xa244, 0x00000000 },
+ { 0xa248, 0x8000421e },
+ { 0 }
+};
+
+static const struct gt_powermeter ivb_pm_gt1[] = {
+ { 0xa800, 0x00000000 },
+ { 0xa804, 0x00021c00 },
+ { 0xa808, 0x00000403 },
+ { 0xa80c, 0x02001700 },
+ { 0xa810, 0x05000200 },
+ { 0xa814, 0x00000000 },
+ { 0xa818, 0x00690500 },
+ { 0xa81c, 0x0000007f },
+ { 0xa820, 0x01002501 },
+ { 0xa824, 0x00000300 },
+ { 0xa828, 0x01000331 },
+ { 0xa82c, 0x0000000c },
+ { 0xa830, 0x00010016 },
+ { 0xa834, 0x01100101 },
+ { 0xa838, 0x00010103 },
+ { 0xa83c, 0x00041300 },
+ { 0xa840, 0x00000b30 },
+ { 0xa844, 0x00000000 },
+ { 0xa848, 0x7f000000 },
+ { 0xa84c, 0x05000008 },
+ { 0xa850, 0x00000001 },
+ { 0xa854, 0x00000004 },
+ { 0xa858, 0x00000007 },
+ { 0xa85c, 0x00000000 },
+ { 0xa860, 0x00010000 },
+ { 0xa248, 0x0000221e },
+ { 0xa900, 0x00000000 },
+ { 0xa904, 0x00001c00 },
+ { 0xa908, 0x00000000 },
+ { 0xa90c, 0x06000000 },
+ { 0xa910, 0x09000200 },
+ { 0xa914, 0x00000000 },
+ { 0xa918, 0x00590000 },
+ { 0xa91c, 0x00000000 },
+ { 0xa920, 0x04002501 },
+ { 0xa924, 0x00000100 },
+ { 0xa928, 0x03000410 },
+ { 0xa92c, 0x00000000 },
+ { 0xa930, 0x00020000 },
+ { 0xa934, 0x02070106 },
+ { 0xa938, 0x00010100 },
+ { 0xa93c, 0x00401c00 },
+ { 0xa940, 0x00000000 },
+ { 0xa944, 0x00000000 },
+ { 0xa948, 0x10000e00 },
+ { 0xa94c, 0x02000004 },
+ { 0xa950, 0x00000001 },
+ { 0xa954, 0x00000004 },
+ { 0xa960, 0x00060000 },
+ { 0xaa3c, 0x00001c00 },
+ { 0xaa54, 0x00000004 },
+ { 0xaa60, 0x00060000 },
+ { 0 }
+};
+
+static const struct gt_powermeter ivb_pm_gt2[] = {
+ { 0xa800, 0x10000000 },
+ { 0xa804, 0x00033800 },
+ { 0xa808, 0x00000902 },
+ { 0xa80c, 0x0c002f00 },
+ { 0xa810, 0x12000400 },
+ { 0xa814, 0x00000000 },
+ { 0xa818, 0x00d20800 },
+ { 0xa81c, 0x00000002 },
+ { 0xa820, 0x03004b02 },
+ { 0xa824, 0x00000600 },
+ { 0xa828, 0x07000773 },
+ { 0xa82c, 0x00000000 },
+ { 0xa830, 0x00010032 },
+ { 0xa834, 0x1520040d },
+ { 0xa838, 0x00020105 },
+ { 0xa83c, 0x00083700 },
+ { 0xa840, 0x0000151d },
+ { 0xa844, 0x00000000 },
+ { 0xa848, 0x20001b00 },
+ { 0xa84c, 0x0a000010 },
+ { 0xa850, 0x00000000 },
+ { 0xa854, 0x00000008 },
+ { 0xa858, 0x00000008 },
+ { 0xa85c, 0x00000000 },
+ { 0xa860, 0x00020000 },
+ { 0xa248, 0x0000221e },
+ { 0xa900, 0x00000000 },
+ { 0xa904, 0x00003500 },
+ { 0xa908, 0x00000000 },
+ { 0xa90c, 0x0c000000 },
+ { 0xa910, 0x12000500 },
+ { 0xa914, 0x00000000 },
+ { 0xa918, 0x00b20000 },
+ { 0xa91c, 0x00000000 },
+ { 0xa920, 0x08004b02 },
+ { 0xa924, 0x00000200 },
+ { 0xa928, 0x07000820 },
+ { 0xa92c, 0x00000000 },
+ { 0xa930, 0x00030000 },
+ { 0xa934, 0x050f020d },
+ { 0xa938, 0x00020300 },
+ { 0xa93c, 0x00903900 },
+ { 0xa940, 0x00000000 },
+ { 0xa944, 0x00000000 },
+ { 0xa948, 0x20001b00 },
+ { 0xa94c, 0x0a000010 },
+ { 0xa950, 0x00000000 },
+ { 0xa954, 0x00000008 },
+ { 0xa960, 0x00110000 },
+ { 0xaa3c, 0x00003900 },
+ { 0xaa54, 0x00000008 },
+ { 0xaa60, 0x00110000 },
+ { 0 }
+};
+
+static const struct gt_powermeter ivb_pm_gt2_17w[] = {
+ { 0xa800, 0x20000000 },
+ { 0xa804, 0x000e3800 },
+ { 0xa808, 0x00000806 },
+ { 0xa80c, 0x0c002f00 },
+ { 0xa810, 0x0c000800 },
+ { 0xa814, 0x00000000 },
+ { 0xa818, 0x00d20d00 },
+ { 0xa81c, 0x000000ff },
+ { 0xa820, 0x03004b02 },
+ { 0xa824, 0x00000600 },
+ { 0xa828, 0x07000773 },
+ { 0xa82c, 0x00000000 },
+ { 0xa830, 0x00020032 },
+ { 0xa834, 0x1520040d },
+ { 0xa838, 0x00020105 },
+ { 0xa83c, 0x00083700 },
+ { 0xa840, 0x000016ff },
+ { 0xa844, 0x00000000 },
+ { 0xa848, 0xff000000 },
+ { 0xa84c, 0x0a000010 },
+ { 0xa850, 0x00000002 },
+ { 0xa854, 0x00000008 },
+ { 0xa858, 0x0000000f },
+ { 0xa85c, 0x00000000 },
+ { 0xa860, 0x00020000 },
+ { 0xa248, 0x0000221e },
+ { 0xa900, 0x00000000 },
+ { 0xa904, 0x00003800 },
+ { 0xa908, 0x00000000 },
+ { 0xa90c, 0x0c000000 },
+ { 0xa910, 0x12000800 },
+ { 0xa914, 0x00000000 },
+ { 0xa918, 0x00b20000 },
+ { 0xa91c, 0x00000000 },
+ { 0xa920, 0x08004b02 },
+ { 0xa924, 0x00000300 },
+ { 0xa928, 0x01000820 },
+ { 0xa92c, 0x00000000 },
+ { 0xa930, 0x00030000 },
+ { 0xa934, 0x15150406 },
+ { 0xa938, 0x00020300 },
+ { 0xa93c, 0x00903900 },
+ { 0xa940, 0x00000000 },
+ { 0xa944, 0x00000000 },
+ { 0xa948, 0x20001b00 },
+ { 0xa94c, 0x0a000010 },
+ { 0xa950, 0x00000000 },
+ { 0xa954, 0x00000008 },
+ { 0xa960, 0x00110000 },
+ { 0xaa3c, 0x00003900 },
+ { 0xaa54, 0x00000008 },
+ { 0xaa60, 0x00110000 },
+ { 0 }
+};
+
+static const struct gt_powermeter ivb_pm_gt2_35w[] = {
+ { 0xa800, 0x00000000 },
+ { 0xa804, 0x00030400 },
+ { 0xa808, 0x00000806 },
+ { 0xa80c, 0x0c002f00 },
+ { 0xa810, 0x0c000300 },
+ { 0xa814, 0x00000000 },
+ { 0xa818, 0x00d20d00 },
+ { 0xa81c, 0x000000ff },
+ { 0xa820, 0x03004b02 },
+ { 0xa824, 0x00000600 },
+ { 0xa828, 0x07000773 },
+ { 0xa82c, 0x00000000 },
+ { 0xa830, 0x00020032 },
+ { 0xa834, 0x1520040d },
+ { 0xa838, 0x00020105 },
+ { 0xa83c, 0x00083700 },
+ { 0xa840, 0x000016ff },
+ { 0xa844, 0x00000000 },
+ { 0xa848, 0xff000000 },
+ { 0xa84c, 0x0a000010 },
+ { 0xa850, 0x00000001 },
+ { 0xa854, 0x00000008 },
+ { 0xa858, 0x00000008 },
+ { 0xa85c, 0x00000000 },
+ { 0xa860, 0x00020000 },
+ { 0xa248, 0x0000221e },
+ { 0xa900, 0x00000000 },
+ { 0xa904, 0x00003800 },
+ { 0xa908, 0x00000000 },
+ { 0xa90c, 0x0c000000 },
+ { 0xa910, 0x12000800 },
+ { 0xa914, 0x00000000 },
+ { 0xa918, 0x00b20000 },
+ { 0xa91c, 0x00000000 },
+ { 0xa920, 0x08004b02 },
+ { 0xa924, 0x00000300 },
+ { 0xa928, 0x01000820 },
+ { 0xa92c, 0x00000000 },
+ { 0xa930, 0x00030000 },
+ { 0xa934, 0x15150406 },
+ { 0xa938, 0x00020300 },
+ { 0xa93c, 0x00903900 },
+ { 0xa940, 0x00000000 },
+ { 0xa944, 0x00000000 },
+ { 0xa948, 0x20001b00 },
+ { 0xa94c, 0x0a000010 },
+ { 0xa950, 0x00000000 },
+ { 0xa954, 0x00000008 },
+ { 0xa960, 0x00110000 },
+ { 0xaa3c, 0x00003900 },
+ { 0xaa54, 0x00000008 },
+ { 0xaa60, 0x00110000 },
+ { 0 }
+};
+
+static inline u32 gtt_read(void *bar, u32 reg)
+{
+ return readl(bar + reg);
+}
+
+static inline void gtt_write(void *bar, u32 reg, u32 data)
+{
+ writel(data, bar + reg);
+}
+
+static void gtt_write_powermeter(void *bar, const struct gt_powermeter *pm)
+{
+ for (; pm && pm->reg; pm++)
+ gtt_write(bar, pm->reg, pm->value);
+}
+
+#define GTT_RETRY 1000
+static int gtt_poll(void *bar, u32 reg, u32 mask, u32 value)
+{
+ unsigned try = GTT_RETRY;
+ u32 data;
+
+ while (try--) {
+ data = gtt_read(bar, reg);
+ if ((data & mask) == value)
+ return 1;
+ udelay(10);
+ }
+
+ printf("GT init timeout\n");
+ return 0;
+}
+
+static int gma_pm_init_pre_vbios(void *gtt_bar, int rev)
+{
+ u32 reg32;
+
+ debug("GT Power Management Init, silicon = %#x\n", rev);
+
+ if (rev < IVB_STEP_C0) {
+ /* 1: Enable force wake */
+ gtt_write(gtt_bar, 0xa18c, 0x00000001);
+ gtt_poll(gtt_bar, 0x130090, (1 << 0), (1 << 0));
+ } else {
+ gtt_write(gtt_bar, 0xa180, 1 << 5);
+ gtt_write(gtt_bar, 0xa188, 0xffff0001);
+ gtt_poll(gtt_bar, 0x130040, (1 << 0), (1 << 0));
+ }
+
+ if ((rev & BASE_REV_MASK) == BASE_REV_SNB) {
+ /* 1d: Set GTT+0x42004 [15:14]=11 (SnB C1+) */
+ reg32 = gtt_read(gtt_bar, 0x42004);
+ reg32 |= (1 << 14) | (1 << 15);
+ gtt_write(gtt_bar, 0x42004, reg32);
+ }
+
+ if (rev >= IVB_STEP_A0) {
+ /* Display Reset Acknowledge Settings */
+ reg32 = gtt_read(gtt_bar, 0x45010);
+ reg32 |= (1 << 1) | (1 << 0);
+ gtt_write(gtt_bar, 0x45010, reg32);
+ }
+
+ /* 2: Get GT SKU from GTT+0x911c[13] */
+ reg32 = gtt_read(gtt_bar, 0x911c);
+ if ((rev & BASE_REV_MASK) == BASE_REV_SNB) {
+ if (reg32 & (1 << 13)) {
+ debug("SNB GT1 Power Meter Weights\n");
+ gtt_write_powermeter(gtt_bar, snb_pm_gt1);
+ } else {
+ debug("SNB GT2 Power Meter Weights\n");
+ gtt_write_powermeter(gtt_bar, snb_pm_gt2);
+ }
+ } else {
+ u32 unit = readl(MCHBAR_REG(0x5938)) & 0xf;
+
+ if (reg32 & (1 << 13)) {
+ /* GT1 SKU */
+ debug("IVB GT1 Power Meter Weights\n");
+ gtt_write_powermeter(gtt_bar, ivb_pm_gt1);
+ } else {
+ /* GT2 SKU */
+ u32 tdp = readl(MCHBAR_REG(0x5930)) & 0x7fff;
+ tdp /= (1 << unit);
+
+ if (tdp <= 17) {
+ /* <=17W ULV */
+ debug("IVB GT2 17W Power Meter Weights\n");
+ gtt_write_powermeter(gtt_bar, ivb_pm_gt2_17w);
+ } else if ((tdp >= 25) && (tdp <= 35)) {
+ /* 25W-35W */
+ debug("IVB GT2 25W-35W Power Meter Weights\n");
+ gtt_write_powermeter(gtt_bar, ivb_pm_gt2_35w);
+ } else {
+ /* All others */
+ debug("IVB GT2 35W Power Meter Weights\n");
+ gtt_write_powermeter(gtt_bar, ivb_pm_gt2_35w);
+ }
+ }
+ }
+
+ /* 3: Gear ratio map */
+ gtt_write(gtt_bar, 0xa004, 0x00000010);
+
+ /* 4: GFXPAUSE */
+ gtt_write(gtt_bar, 0xa000, 0x00070020);
+
+ /* 5: Dynamic EU trip control */
+ gtt_write(gtt_bar, 0xa080, 0x00000004);
+
+ /* 6: ECO bits */
+ reg32 = gtt_read(gtt_bar, 0xa180);
+ reg32 |= (1 << 26) | (1 << 31);
+ /* (bit 20=1 for SNB step D1+ / IVB A0+) */
+ if (rev >= SNB_STEP_D1)
+ reg32 |= (1 << 20);
+ gtt_write(gtt_bar, 0xa180, reg32);
+
+ /* 6a: for SnB step D2+ only */
+ if (((rev & BASE_REV_MASK) == BASE_REV_SNB) &&
+ (rev >= SNB_STEP_D2)) {
+ reg32 = gtt_read(gtt_bar, 0x9400);
+ reg32 |= (1 << 7);
+ gtt_write(gtt_bar, 0x9400, reg32);
+
+ reg32 = gtt_read(gtt_bar, 0x941c);
+ reg32 &= 0xf;
+ reg32 |= (1 << 1);
+ gtt_write(gtt_bar, 0x941c, reg32);
+ gtt_poll(gtt_bar, 0x941c, (1 << 1), (0 << 1));
+ }
+
+ if ((rev & BASE_REV_MASK) == BASE_REV_IVB) {
+ reg32 = gtt_read(gtt_bar, 0x907c);
+ reg32 |= (1 << 16);
+ gtt_write(gtt_bar, 0x907c, reg32);
+
+ /* 6b: Clocking reset controls */
+ gtt_write(gtt_bar, 0x9424, 0x00000001);
+ } else {
+ /* 6b: Clocking reset controls */
+ gtt_write(gtt_bar, 0x9424, 0x00000000);
+ }
+
+ /* 7 */
+ if (gtt_poll(gtt_bar, 0x138124, (1 << 31), (0 << 31))) {
+ gtt_write(gtt_bar, 0x138128, 0x00000029); /* Mailbox Data */
+ /* Mailbox Cmd for RC6 VID */
+ gtt_write(gtt_bar, 0x138124, 0x80000004);
+ if (gtt_poll(gtt_bar, 0x138124, (1 << 31), (0 << 31)))
+ gtt_write(gtt_bar, 0x138124, 0x8000000a);
+ gtt_poll(gtt_bar, 0x138124, (1 << 31), (0 << 31));
+ }
+
+ /* 8 */
+ gtt_write(gtt_bar, 0xa090, 0x00000000); /* RC Control */
+ gtt_write(gtt_bar, 0xa098, 0x03e80000); /* RC1e Wake Rate Limit */
+ gtt_write(gtt_bar, 0xa09c, 0x0028001e); /* RC6/6p Wake Rate Limit */
+ gtt_write(gtt_bar, 0xa0a0, 0x0000001e); /* RC6pp Wake Rate Limit */
+ gtt_write(gtt_bar, 0xa0a8, 0x0001e848); /* RC Evaluation Interval */
+ gtt_write(gtt_bar, 0xa0ac, 0x00000019); /* RC Idle Hysteresis */
+
+ /* 9 */
+ gtt_write(gtt_bar, 0x2054, 0x0000000a); /* Render Idle Max Count */
+ gtt_write(gtt_bar, 0x12054, 0x0000000a); /* Video Idle Max Count */
+ gtt_write(gtt_bar, 0x22054, 0x0000000a); /* Blitter Idle Max Count */
+
+ /* 10 */
+ gtt_write(gtt_bar, 0xa0b0, 0x00000000); /* Unblock Ack to Busy */
+ gtt_write(gtt_bar, 0xa0b4, 0x000003e8); /* RC1e Threshold */
+ gtt_write(gtt_bar, 0xa0b8, 0x0000c350); /* RC6 Threshold */
+ gtt_write(gtt_bar, 0xa0bc, 0x000186a0); /* RC6p Threshold */
+ gtt_write(gtt_bar, 0xa0c0, 0x0000fa00); /* RC6pp Threshold */
+
+ /* 11 */
+ gtt_write(gtt_bar, 0xa010, 0x000f4240); /* RP Down Timeout */
+ gtt_write(gtt_bar, 0xa014, 0x12060000); /* RP Interrupt Limits */
+ gtt_write(gtt_bar, 0xa02c, 0x00015f90); /* RP Up Threshold */
+ gtt_write(gtt_bar, 0xa030, 0x000186a0); /* RP Down Threshold */
+ gtt_write(gtt_bar, 0xa068, 0x000186a0); /* RP Up EI */
+ gtt_write(gtt_bar, 0xa06c, 0x000493e0); /* RP Down EI */
+ gtt_write(gtt_bar, 0xa070, 0x0000000a); /* RP Idle Hysteresis */
+
+ /* 11a: Enable Render Standby (RC6) */
+ if ((rev & BASE_REV_MASK) == BASE_REV_IVB) {
+ /*
+ * IvyBridge should also support DeepRenderStandby.
+ *
+ * Unfortunately it does not work reliably on all SKUs so
+ * disable it here and it can be enabled by the kernel.
+ */
+ gtt_write(gtt_bar, 0xa090, 0x88040000); /* HW RC Control */
+ } else {
+ gtt_write(gtt_bar, 0xa090, 0x88040000); /* HW RC Control */
+ }
+
+ /* 12: Normal Frequency Request */
+ /* RPNFREQ_VAL comes from MCHBAR 0x5998 23:16 (8 bits!? use 7) */
+ reg32 = readl(MCHBAR_REG(0x5998));
+ reg32 >>= 16;
+ reg32 &= 0xef;
+ reg32 <<= 25;
+ gtt_write(gtt_bar, 0xa008, reg32);
+
+ /* 13: RP Control */
+ gtt_write(gtt_bar, 0xa024, 0x00000592);
+
+ /* 14: Enable PM Interrupts */
+ gtt_write(gtt_bar, 0x4402c, 0x03000076);
+
+ /* Clear 0x6c024 [8:6] */
+ reg32 = gtt_read(gtt_bar, 0x6c024);
+ reg32 &= ~0x000001c0;
+ gtt_write(gtt_bar, 0x6c024, reg32);
+
+ return 0;
+}
+
+static int gma_pm_init_post_vbios(struct udevice *dev, int rev, void *gtt_bar)
+{
+ const void *blob = gd->fdt_blob;
+ int node = dev->of_offset;
+ u32 reg32, cycle_delay;
+
+ debug("GT Power Management Init (post VBIOS)\n");
+
+ /* 15: Deassert Force Wake */
+ if (rev < IVB_STEP_C0) {
+ gtt_write(gtt_bar, 0xa18c, gtt_read(gtt_bar, 0xa18c) & ~1);
+ gtt_poll(gtt_bar, 0x130090, (1 << 0), (0 << 0));
+ } else {
+ gtt_write(gtt_bar, 0xa188, 0x1fffe);
+ if (gtt_poll(gtt_bar, 0x130040, (1 << 0), (0 << 0))) {
+ gtt_write(gtt_bar, 0xa188,
+ gtt_read(gtt_bar, 0xa188) | 1);
+ }
+ }
+
+ /* 16: SW RC Control */
+ gtt_write(gtt_bar, 0xa094, 0x00060000);
+
+ /* Setup Digital Port Hotplug */
+ reg32 = gtt_read(gtt_bar, 0xc4030);
+ if (!reg32) {
+ u32 dp_hotplug[3];
+
+ if (fdtdec_get_int_array(blob, node, "intel,dp_hotplug",
+ dp_hotplug, ARRAY_SIZE(dp_hotplug)))
+ return -EINVAL;
+
+ reg32 = (dp_hotplug[0] & 0x7) << 2;
+ reg32 |= (dp_hotplug[0] & 0x7) << 10;
+ reg32 |= (dp_hotplug[0] & 0x7) << 18;
+ gtt_write(gtt_bar, 0xc4030, reg32);
+ }
+
+ /* Setup Panel Power On Delays */
+ reg32 = gtt_read(gtt_bar, 0xc7208);
+ if (!reg32) {
+ reg32 = (unsigned)fdtdec_get_int(blob, node,
+ "panel-port-select", 0) << 30;
+ reg32 |= fdtdec_get_int(blob, node, "panel-power-up-delay", 0)
+ << 16;
+ reg32 |= fdtdec_get_int(blob, node,
+ "panel-power-backlight-on-delay", 0);
+ gtt_write(gtt_bar, 0xc7208, reg32);
+ }
+
+ /* Setup Panel Power Off Delays */
+ reg32 = gtt_read(gtt_bar, 0xc720c);
+ if (!reg32) {
+ reg32 = fdtdec_get_int(blob, node, "panel-power-down-delay", 0)
+ << 16;
+ reg32 |= fdtdec_get_int(blob, node,
+ "panel-power-backlight-off-delay", 0);
+ gtt_write(gtt_bar, 0xc720c, reg32);
+ }
+
+ /* Setup Panel Power Cycle Delay */
+ cycle_delay = fdtdec_get_int(blob, node,
+ "intel,panel-power-cycle-delay", 0);
+ if (cycle_delay) {
+ reg32 = gtt_read(gtt_bar, 0xc7210);
+ reg32 &= ~0xff;
+ reg32 |= cycle_delay;
+ gtt_write(gtt_bar, 0xc7210, reg32);
+ }
+
+ /* Enable Backlight if needed */
+ reg32 = fdtdec_get_int(blob, node, "intel,cpu-backlight", 0);
+ if (reg32) {
+ gtt_write(gtt_bar, 0x48250, (1 << 31));
+ gtt_write(gtt_bar, 0x48254, reg32);
+ }
+ reg32 = fdtdec_get_int(blob, node, "intel,pch-backlight", 0);
+ if (reg32) {
+ gtt_write(gtt_bar, 0xc8250, (1 << 31));
+ gtt_write(gtt_bar, 0xc8254, reg32);
+ }
+
+ return 0;
+}
+
+/*
+ * Some vga option roms are used for several chipsets but they only have one
+ * PCI ID in their header. If we encounter such an option rom, we need to do
+ * the mapping ourselves.
+ */
+
+uint32_t board_map_oprom_vendev(uint32_t vendev)
+{
+ switch (vendev) {
+ case 0x80860102: /* GT1 Desktop */
+ case 0x8086010a: /* GT1 Server */
+ case 0x80860112: /* GT2 Desktop */
+ case 0x80860116: /* GT2 Mobile */
+ case 0x80860122: /* GT2 Desktop >=1.3GHz */
+ case 0x80860126: /* GT2 Mobile >=1.3GHz */
+ case 0x80860156: /* IVB */
+ case 0x80860166: /* IVB */
+ return 0x80860106; /* GT1 Mobile */
+ }
+
+ return vendev;
+}
+
+static int int15_handler(void)
+{
+ int res = 0;
+
+ debug("%s: INT15 function %04x!\n", __func__, M.x86.R_AX);
+
+ switch (M.x86.R_AX) {
+ case 0x5f34:
+ /*
+ * Set Panel Fitting Hook:
+ * bit 2 = Graphics Stretching
+ * bit 1 = Text Stretching
+ * bit 0 = Centering (do not set with bit1 or bit2)
+ * 0 = video bios default
+ */
+ M.x86.R_AX = 0x005f;
+ M.x86.R_CL = 0x00; /* Use video bios default */
+ res = 1;
+ break;
+ case 0x5f35:
+ /*
+ * Boot Display Device Hook:
+ * bit 0 = CRT
+ * bit 1 = TV (eDP)
+ * bit 2 = EFP
+ * bit 3 = LFP
+ * bit 4 = CRT2
+ * bit 5 = TV2 (eDP)
+ * bit 6 = EFP2
+ * bit 7 = LFP2
+ */
+ M.x86.R_AX = 0x005f;
+ M.x86.R_CX = 0x0000; /* Use video bios default */
+ res = 1;
+ break;
+ case 0x5f51:
+ /*
+ * Hook to select active LFP configuration:
+ * 00h = No LVDS, VBIOS does not enable LVDS
+ * 01h = Int-LVDS, LFP driven by integrated LVDS decoder
+ * 02h = SVDO-LVDS, LFP driven by SVDO decoder
+ * 03h = eDP, LFP Driven by Int-DisplayPort encoder
+ */
+ M.x86.R_AX = 0x005f;
+ M.x86.R_CX = 0x0003; /* eDP */
+ res = 1;
+ break;
+ case 0x5f70:
+ switch (M.x86.R_CH) {
+ case 0:
+ /* Get Mux */
+ M.x86.R_AX = 0x005f;
+ M.x86.R_CX = 0x0000;
+ res = 1;
+ break;
+ case 1:
+ /* Set Mux */
+ M.x86.R_AX = 0x005f;
+ M.x86.R_CX = 0x0000;
+ res = 1;
+ break;
+ case 2:
+ /* Get SG/Non-SG mode */
+ M.x86.R_AX = 0x005f;
+ M.x86.R_CX = 0x0000;
+ res = 1;
+ break;
+ default:
+ /* Interrupt was not handled */
+ debug("Unknown INT15 5f70 function: 0x%02x\n",
+ M.x86.R_CH);
+ break;
+ }
+ break;
+ case 0x5fac:
+ res = 1;
+ break;
+ default:
+ debug("Unknown INT15 function %04x!\n", M.x86.R_AX);
+ break;
+ }
+ return res;
+}
+
+static void sandybridge_setup_graphics(struct udevice *dev,
+ struct udevice *video_dev)
+{
+ u32 reg32;
+ u16 reg16;
+ u8 reg8;
+
+ dm_pci_read_config16(video_dev, PCI_DEVICE_ID, &reg16);
+ switch (reg16) {
+ case 0x0102: /* GT1 Desktop */
+ case 0x0106: /* GT1 Mobile */
+ case 0x010a: /* GT1 Server */
+ case 0x0112: /* GT2 Desktop */
+ case 0x0116: /* GT2 Mobile */
+ case 0x0122: /* GT2 Desktop >=1.3GHz */
+ case 0x0126: /* GT2 Mobile >=1.3GHz */
+ case 0x0156: /* IvyBridge */
+ case 0x0166: /* IvyBridge */
+ break;
+ default:
+ debug("Graphics not supported by this CPU/chipset\n");
+ return;
+ }
+
+ debug("Initialising Graphics\n");
+
+ /* Setup IGD memory by setting GGC[7:3] = 1 for 32MB */
+ dm_pci_read_config16(dev, GGC, &reg16);
+ reg16 &= ~0x00f8;
+ reg16 |= 1 << 3;
+ /* Program GTT memory by setting GGC[9:8] = 2MB */
+ reg16 &= ~0x0300;
+ reg16 |= 2 << 8;
+ /* Enable VGA decode */
+ reg16 &= ~0x0002;
+ dm_pci_write_config16(dev, GGC, reg16);
+
+ /* Enable 256MB aperture */
+ dm_pci_read_config8(video_dev, MSAC, &reg8);
+ reg8 &= ~0x06;
+ reg8 |= 0x02;
+ dm_pci_write_config8(video_dev, MSAC, reg8);
+
+ /* Erratum workarounds */
+ reg32 = readl(MCHBAR_REG(0x5f00));
+ reg32 |= (1 << 9) | (1 << 10);
+ writel(reg32, MCHBAR_REG(0x5f00));
+
+ /* Enable SA Clock Gating */
+ reg32 = readl(MCHBAR_REG(0x5f00));
+ writel(reg32 | 1, MCHBAR_REG(0x5f00));
+
+ /* GPU RC6 workaround for sighting 366252 */
+ reg32 = readl(MCHBAR_REG(0x5d14));
+ reg32 |= (1 << 31);
+ writel(reg32, MCHBAR_REG(0x5d14));
+
+ /* VLW */
+ reg32 = readl(MCHBAR_REG(0x6120));
+ reg32 &= ~(1 << 0);
+ writel(reg32, MCHBAR_REG(0x6120));
+
+ reg32 = readl(MCHBAR_REG(0x5418));
+ reg32 |= (1 << 4) | (1 << 5);
+ writel(reg32, MCHBAR_REG(0x5418));
+}
+
+static int gma_func0_init(struct udevice *dev)
+{
+ struct udevice *nbridge;
+ void *gtt_bar;
+ ulong base;
+ u32 reg32;
+ int ret;
+ int rev;
+
+ /* Enable PCH Display Port */
+ writew(0x0010, RCB_REG(DISPBDF));
+ setbits_le32(RCB_REG(FD2), PCH_ENABLE_DBDF);
+
+ ret = uclass_first_device_err(UCLASS_NORTHBRIDGE, &nbridge);
+ if (ret)
+ return ret;
+ rev = bridge_silicon_revision(nbridge);
+ sandybridge_setup_graphics(nbridge, dev);
+
+ /* IGD needs to be Bus Master */
+ dm_pci_read_config32(dev, PCI_COMMAND, &reg32);
+ reg32 |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+ dm_pci_write_config32(dev, PCI_COMMAND, reg32);
+
+ /* Use write-combining for the graphics memory, 256MB */
+ base = dm_pci_read_bar32(dev, 2);
+ mtrr_add_request(MTRR_TYPE_WRCOMB, base, 256 << 20);
+ mtrr_commit(true);
+
+ gtt_bar = (void *)dm_pci_read_bar32(dev, 0);
+ debug("GT bar %p\n", gtt_bar);
+ ret = gma_pm_init_pre_vbios(gtt_bar, rev);
+ if (ret)
+ return ret;
+
+ return rev;
+}
+
+static int bd82x6x_video_probe(struct udevice *dev)
+{
+ void *gtt_bar;
+ int ret, rev;
+
+ rev = gma_func0_init(dev);
+ if (rev < 0)
+ return rev;
+ ret = vbe_setup_video(dev, int15_handler);
+ if (ret)
+ return ret;
+
+ /* Post VBIOS init */
+ gtt_bar = (void *)dm_pci_read_bar32(dev, 0);
+ ret = gma_pm_init_post_vbios(dev, rev, gtt_bar);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct udevice_id bd82x6x_video_ids[] = {
+ { .compatible = "intel,gma" },
+ { }
+};
+
+U_BOOT_DRIVER(bd82x6x_video) = {
+ .name = "bd82x6x_video",
+ .id = UCLASS_VIDEO,
+ .of_match = bd82x6x_video_ids,
+ .probe = bd82x6x_video_probe,
+};
diff --git a/drivers/video/simple_panel.c b/drivers/video/simple_panel.c
index b2fe345..baa95f6 100644
--- a/drivers/video/simple_panel.c
+++ b/drivers/video/simple_panel.c
@@ -42,7 +42,7 @@ static int simple_panel_ofdata_to_platdata(struct udevice *dev)
ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
"power-supply", &priv->reg);
if (ret) {
- debug("%s: Warning: cnnot get power supply: ret=%d\n",
+ debug("%s: Warning: cannot get power supply: ret=%d\n",
__func__, ret);
if (ret != -ENOENT)
return ret;
diff --git a/drivers/video/vesa.c b/drivers/video/vesa.c
new file mode 100644
index 0000000..ddf8df8
--- /dev/null
+++ b/drivers/video/vesa.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <pci.h>
+#include <vbe.h>
+
+static int vesa_video_probe(struct udevice *dev)
+{
+ return vbe_setup_video(dev, NULL);
+}
+
+static const struct udevice_id vesa_video_ids[] = {
+ { .compatible = "vesa-fb" },
+ { }
+};
+
+U_BOOT_DRIVER(vesa_video) = {
+ .name = "vesa_video",
+ .id = UCLASS_VIDEO,
+ .of_match = vesa_video_ids,
+ .probe = vesa_video_probe,
+};
+
+static struct pci_device_id vesa_video_supported[] = {
+ { PCI_DEVICE_CLASS(PCI_CLASS_DISPLAY_VGA << 8, ~0) },
+ { },
+};
+
+U_BOOT_PCI_DEVICE(vesa_video, vesa_video_supported);
diff --git a/drivers/video/vesa_fb.c b/drivers/video/vesa_fb.c
deleted file mode 100644
index 021c1d6..0000000
--- a/drivers/video/vesa_fb.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * VESA frame buffer driver
- *
- * Copyright (C) 2014 Google, Inc
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <pci_rom.h>
-#include <video_fb.h>
-#include <vbe.h>
-
-/*
- * The Graphic Device
- */
-GraphicDevice ctfb;
-
-void *video_hw_init(void)
-{
- GraphicDevice *gdev = &ctfb;
- struct udevice *dev;
- int bits_per_pixel;
- int ret;
-
- printf("Video: ");
- if (!ll_boot_init()) {
- /*
- * If we are running from EFI or coreboot, this driver can't
- * work.
- */
- printf("Not available (previous bootloader prevents it)\n");
- return NULL;
- }
- if (vbe_get_video_info(gdev)) {
- ret = dm_pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, 0, &dev);
- if (ret) {
- printf("no card detected\n");
- return NULL;
- }
- bootstage_start(BOOTSTAGE_ID_ACCUM_LCD, "vesa display");
- ret = dm_pci_run_vga_bios(dev, NULL, PCI_ROM_USE_NATIVE |
- PCI_ROM_ALLOW_FALLBACK);
- bootstage_accum(BOOTSTAGE_ID_ACCUM_LCD);
- if (ret) {
- printf("failed to run video BIOS: %d\n", ret);
- return NULL;
- }
- }
-
- if (vbe_get_video_info(gdev)) {
- printf("No video mode configured\n");
- return NULL;
- }
-
- bits_per_pixel = gdev->gdfBytesPP * 8;
- sprintf(gdev->modeIdent, "%dx%dx%d", gdev->winSizeX, gdev->winSizeY,
- bits_per_pixel);
- printf("%s\n", gdev->modeIdent);
- debug("Frame buffer at %x\n", gdev->pciBase);
-
- return (void *)gdev;
-}
diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c
index b6dd0f5..11ca793 100644
--- a/drivers/video/video-uclass.c
+++ b/drivers/video/video-uclass.c
@@ -54,6 +54,9 @@ static ulong alloc_fb(struct udevice *dev, ulong *addrp)
struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
ulong base, align, size;
+ if (!plat->size)
+ return 0;
+
align = plat->align ? plat->align : 1 << 20;
base = *addrp - plat->size;
base &= ~(align - 1);