diff options
Diffstat (limited to 'drivers')
72 files changed, 2066 insertions, 815 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index 33227c8bd6d..7683c6139ff 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -21,3 +21,4 @@ obj-y += pwm/ obj-y += input/ # SOC specific infrastructure drivers. obj-y += soc/ +obj-y += thermal/ diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index a93a8e1c04b..c9a3beb79b2 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -730,7 +730,7 @@ static int ata_scsiop_read_write(ccb *pccb, u8 is_write) u16 now_blocks; /* number of blocks per iteration */ u32 transfer_size; /* number of bytes per iteration */ - now_blocks = min(MAX_SATA_BLOCKS_READ_WRITE, blocks); + now_blocks = min((u16)MAX_SATA_BLOCKS_READ_WRITE, blocks); transfer_size = ATA_SECT_SIZE * now_blocks; if (transfer_size > user_buffer_size) { diff --git a/drivers/block/ata_piix.c b/drivers/block/ata_piix.c index 5cf91ade8d2..30426842cc4 100644 --- a/drivers/block/ata_piix.c +++ b/drivers/block/ata_piix.c @@ -192,6 +192,11 @@ int init_sata(int dev) return 0; } +int reset_sata(int dev) +{ + return 0; +} + static inline u8 sata_inb(unsigned long ioaddr) { return inb(ioaddr); diff --git a/drivers/block/dwc_ahsata.c b/drivers/block/dwc_ahsata.c index c68fd2f2565..9a2b547af2d 100644 --- a/drivers/block/dwc_ahsata.c +++ b/drivers/block/dwc_ahsata.c @@ -592,6 +592,27 @@ int init_sata(int dev) return 0; } +int reset_sata(int dev) +{ + struct ahci_probe_ent *probe_ent = + (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct sata_host_regs *host_mmio = + (struct sata_host_regs *)probe_ent->mmio_base; + + if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) { + printf("The sata index %d is out of ranges\n\r", dev); + return -1; + } + + setbits_le32(&host_mmio->ghc, SATA_HOST_GHC_HR); + while (readl(&host_mmio->ghc) & SATA_HOST_GHC_HR) + udelay(100); + + disable_sata_clock(); + + return 0; +} + static void dwc_ahsata_print_info(int dev) { block_dev_desc_t *pdev = &(sata_dev_desc[dev]); diff --git a/drivers/block/fsl_sata.c b/drivers/block/fsl_sata.c index ebd626178d0..71d7cec7bdd 100644 --- a/drivers/block/fsl_sata.c +++ b/drivers/block/fsl_sata.c @@ -255,6 +255,11 @@ int init_sata(int dev) return 0; } +int reset_sata(int dev) +{ + return 0; +} + static void fsl_sata_dump_regs(fsl_sata_reg_t __iomem *reg) { printf("\n\rSATA: %08x\n\r", (u32)reg); diff --git a/drivers/block/pata_bfin.c b/drivers/block/pata_bfin.c index b7fd1cd6344..c2673bd05dc 100644 --- a/drivers/block/pata_bfin.c +++ b/drivers/block/pata_bfin.c @@ -1009,6 +1009,11 @@ int init_sata(int dev) return res; } +int reset_sata(int dev) +{ + return 0; +} + /* Read up to 255 sectors * * Returns sectors read diff --git a/drivers/block/sata_dwc.c b/drivers/block/sata_dwc.c index efca5eaba42..9e8b067cdc8 100644 --- a/drivers/block/sata_dwc.c +++ b/drivers/block/sata_dwc.c @@ -423,6 +423,11 @@ int init_sata(int dev) return rc; } +int reset_sata(int dev) +{ + return 0; +} + static u8 ata_check_altstatus(struct ata_port *ap) { u8 val = 0; diff --git a/drivers/block/sata_sil.c b/drivers/block/sata_sil.c index 1f510cd265c..daff7d4ab57 100644 --- a/drivers/block/sata_sil.c +++ b/drivers/block/sata_sil.c @@ -519,7 +519,7 @@ int init_sata(int dev) u16 word; if (init_done == 1 && dev < sata_info.maxport) - return 1; + return 0; init_done = 1; @@ -571,6 +571,11 @@ int init_sata(int dev) return 0; } +int reset_sata(int dev) +{ + return 0; +} + /* * SATA interface between low level driver and command layer */ diff --git a/drivers/block/sata_sil3114.c b/drivers/block/sata_sil3114.c index 3aa6fc9839e..61ffb66a771 100644 --- a/drivers/block/sata_sil3114.c +++ b/drivers/block/sata_sil3114.c @@ -702,6 +702,11 @@ int init_sata (int dev) return res; } +int reset_sata(int dev) +{ + return 0; +} + /* Check if device is connected to port */ int sata_bus_probe (int portno) { diff --git a/drivers/core/Makefile b/drivers/core/Makefile index 151c2398a4d..f14695b2d6e 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -4,5 +4,6 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-y := device.o lists.o root.o uclass.o util.o +obj-$(CONFIG_DM) += device.o lists.o root.o uclass.o util.o obj-$(CONFIG_OF_CONTROL) += simple-bus.o +obj-$(CONFIG_DM_DEVICE_REMOVE) += device-remove.o diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c new file mode 100644 index 00000000000..8fc6b710842 --- /dev/null +++ b/drivers/core/device-remove.c @@ -0,0 +1,187 @@ +/* + * Device manager + * + * Copyright (c) 2014 Google, Inc + * + * (C) Copyright 2012 + * Pavel Herrmann <morpheus.ibis@gmail.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <errno.h> +#include <malloc.h> +#include <dm/device.h> +#include <dm/device-internal.h> +#include <dm/uclass.h> +#include <dm/uclass-internal.h> +#include <dm/util.h> + +/** + * device_chld_unbind() - Unbind all device's children from the device + * + * On error, the function continues to unbind all children, and reports the + * first error. + * + * @dev: The device that is to be stripped of its children + * @return 0 on success, -ve on error + */ +static int device_chld_unbind(struct udevice *dev) +{ + struct udevice *pos, *n; + int ret, saved_ret = 0; + + assert(dev); + + list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) { + ret = device_unbind(pos); + if (ret && !saved_ret) + saved_ret = ret; + } + + return saved_ret; +} + +/** + * device_chld_remove() - Stop all device's children + * @dev: The device whose children are to be removed + * @return 0 on success, -ve on error + */ +static int device_chld_remove(struct udevice *dev) +{ + struct udevice *pos, *n; + int ret; + + assert(dev); + + list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) { + ret = device_remove(pos); + if (ret) + return ret; + } + + return 0; +} + +int device_unbind(struct udevice *dev) +{ + struct driver *drv; + int ret; + + if (!dev) + return -EINVAL; + + if (dev->flags & DM_FLAG_ACTIVATED) + return -EINVAL; + + drv = dev->driver; + assert(drv); + + if (drv->unbind) { + ret = drv->unbind(dev); + if (ret) + return ret; + } + + ret = device_chld_unbind(dev); + if (ret) + return ret; + + ret = uclass_unbind_device(dev); + if (ret) + return ret; + + if (dev->parent) + list_del(&dev->sibling_node); + free(dev); + + return 0; +} + +/** + * device_free() - Free memory buffers allocated by a device + * @dev: Device that is to be started + */ +void device_free(struct udevice *dev) +{ + int size; + + if (dev->driver->priv_auto_alloc_size) { + free(dev->priv); + dev->priv = NULL; + } + if (dev->flags & DM_FLAG_ALLOC_PDATA) { + free(dev->platdata); + dev->platdata = NULL; + } + size = dev->uclass->uc_drv->per_device_auto_alloc_size; + if (size) { + free(dev->uclass_priv); + dev->uclass_priv = NULL; + } + if (dev->parent) { + size = dev->parent->driver->per_child_auto_alloc_size; + if (size) { + free(dev->parent_priv); + dev->parent_priv = NULL; + } + } +} + +int device_remove(struct udevice *dev) +{ + struct driver *drv; + int ret; + + if (!dev) + return -EINVAL; + + if (!(dev->flags & DM_FLAG_ACTIVATED)) + return 0; + + drv = dev->driver; + assert(drv); + + ret = uclass_pre_remove_device(dev); + if (ret) + return ret; + + ret = device_chld_remove(dev); + if (ret) + goto err; + + if (drv->remove) { + ret = drv->remove(dev); + if (ret) + goto err_remove; + } + + if (dev->parent && dev->parent->driver->child_post_remove) { + ret = dev->parent->driver->child_post_remove(dev); + if (ret) { + dm_warn("%s: Device '%s' failed child_post_remove()", + __func__, dev->name); + } + } + + device_free(dev); + + dev->seq = -1; + dev->flags &= ~DM_FLAG_ACTIVATED; + + return ret; + +err_remove: + /* We can't put the children back */ + dm_warn("%s: Device '%s' failed to remove, but children are gone\n", + __func__, dev->name); +err: + ret = uclass_post_probe_device(dev); + if (ret) { + dm_warn("%s: Device '%s' failed to post_probe on error path\n", + __func__, dev->name); + } + + return ret; +} diff --git a/drivers/core/device.c b/drivers/core/device.c index 49faa29dc1a..6793e1c4f94 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -24,52 +24,6 @@ DECLARE_GLOBAL_DATA_PTR; -/** - * device_chld_unbind() - Unbind all device's children from the device - * - * On error, the function continues to unbind all children, and reports the - * first error. - * - * @dev: The device that is to be stripped of its children - * @return 0 on success, -ve on error - */ -static int device_chld_unbind(struct udevice *dev) -{ - struct udevice *pos, *n; - int ret, saved_ret = 0; - - assert(dev); - - list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) { - ret = device_unbind(pos); - if (ret && !saved_ret) - saved_ret = ret; - } - - return saved_ret; -} - -/** - * device_chld_remove() - Stop all device's children - * @dev: The device whose children are to be removed - * @return 0 on success, -ve on error - */ -static int device_chld_remove(struct udevice *dev) -{ - struct udevice *pos, *n; - int ret; - - assert(dev); - - list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) { - ret = device_remove(pos); - if (ret) - return ret; - } - - return 0; -} - int device_bind(struct udevice *parent, struct driver *drv, const char *name, void *platdata, int of_offset, struct udevice **devp) { @@ -167,71 +121,6 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only, -1, devp); } -int device_unbind(struct udevice *dev) -{ - struct driver *drv; - int ret; - - if (!dev) - return -EINVAL; - - if (dev->flags & DM_FLAG_ACTIVATED) - return -EINVAL; - - drv = dev->driver; - assert(drv); - - if (drv->unbind) { - ret = drv->unbind(dev); - if (ret) - return ret; - } - - ret = device_chld_unbind(dev); - if (ret) - return ret; - - ret = uclass_unbind_device(dev); - if (ret) - return ret; - - if (dev->parent) - list_del(&dev->sibling_node); - free(dev); - - return 0; -} - -/** - * device_free() - Free memory buffers allocated by a device - * @dev: Device that is to be started - */ -static void device_free(struct udevice *dev) -{ - int size; - - if (dev->driver->priv_auto_alloc_size) { - free(dev->priv); - dev->priv = NULL; - } - if (dev->flags & DM_FLAG_ALLOC_PDATA) { - free(dev->platdata); - dev->platdata = NULL; - } - size = dev->uclass->uc_drv->per_device_auto_alloc_size; - if (size) { - free(dev->uclass_priv); - dev->uclass_priv = NULL; - } - if (dev->parent) { - size = dev->parent->driver->per_child_auto_alloc_size; - if (size) { - free(dev->parent_priv); - dev->parent_priv = NULL; - } - } -} - int device_probe_child(struct udevice *dev, void *parent_priv) { struct driver *drv; @@ -342,63 +231,6 @@ int device_probe(struct udevice *dev) return device_probe_child(dev, NULL); } -int device_remove(struct udevice *dev) -{ - struct driver *drv; - int ret; - - if (!dev) - return -EINVAL; - - if (!(dev->flags & DM_FLAG_ACTIVATED)) - return 0; - - drv = dev->driver; - assert(drv); - - ret = uclass_pre_remove_device(dev); - if (ret) - return ret; - - ret = device_chld_remove(dev); - if (ret) - goto err; - - if (drv->remove) { - ret = drv->remove(dev); - if (ret) - goto err_remove; - } - - if (dev->parent && dev->parent->driver->child_post_remove) { - ret = dev->parent->driver->child_post_remove(dev); - if (ret) { - dm_warn("%s: Device '%s' failed child_post_remove()", - __func__, dev->name); - } - } - - device_free(dev); - - dev->seq = -1; - dev->flags &= ~DM_FLAG_ACTIVATED; - - return ret; - -err_remove: - /* We can't put the children back */ - dm_warn("%s: Device '%s' failed to remove, but children are gone\n", - __func__, dev->name); -err: - ret = uclass_post_probe_device(dev); - if (ret) { - dm_warn("%s: Device '%s' failed to post_probe on error path\n", - __func__, dev->name); - } - - return ret; -} - void *dev_get_platdata(struct udevice *dev) { if (!dev) { @@ -548,3 +380,13 @@ int device_find_next_child(struct udevice **devp) return 0; } + +struct udevice *dev_get_parent(struct udevice *child) +{ + return child->parent; +} + +ulong dev_get_of_data(struct udevice *dev) +{ + return dev->of_id->data; +} diff --git a/drivers/core/lists.c b/drivers/core/lists.c index 3a1ea856544..ff115c4723e 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -25,9 +25,6 @@ struct driver *lists_driver_lookup_name(const char *name) const int n_ents = ll_entry_count(struct driver, driver); struct driver *entry; - if (!drv || !n_ents) - return NULL; - for (entry = drv; entry != drv + n_ents; entry++) { if (!strcmp(name, entry->name)) return entry; @@ -44,9 +41,6 @@ struct uclass_driver *lists_uclass_lookup(enum uclass_id id) const int n_ents = ll_entry_count(struct uclass_driver, uclass); struct uclass_driver *entry; - if ((id == UCLASS_INVALID) || !uclass) - return NULL; - for (entry = uclass; entry != uclass + n_ents; entry++) { if (entry->id == id) return entry; @@ -77,34 +71,60 @@ int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only) return result; } +int device_bind_driver(struct udevice *parent, const char *drv_name, + const char *dev_name, struct udevice **devp) +{ + struct driver *drv; + int ret; + + drv = lists_driver_lookup_name(drv_name); + if (!drv) { + printf("Cannot find driver '%s'\n", drv_name); + return -ENOENT; + } + ret = device_bind(parent, drv, dev_name, NULL, -1, devp); + if (ret) { + printf("Cannot create device named '%s' (err=%d)\n", + dev_name, ret); + return ret; + } + + return 0; +} + #ifdef CONFIG_OF_CONTROL /** * driver_check_compatible() - Check if a driver is compatible with this node * * @param blob: Device tree pointer * @param offset: Offset of node in device tree - * @param of_matchL List of compatible strings to match + * @param of_match: List of compatible strings to match + * @param of_idp: Returns the match that was found * @return 0 if there is a match, -ENOENT if no match, -ENODEV if the node * does not have a compatible string, other error <0 if there is a device * tree error */ static int driver_check_compatible(const void *blob, int offset, - const struct udevice_id *of_match) + const struct udevice_id *of_match, + const struct udevice_id **of_idp) { int ret; + *of_idp = NULL; if (!of_match) return -ENOENT; while (of_match->compatible) { ret = fdt_node_check_compatible(blob, offset, of_match->compatible); - if (!ret) + if (!ret) { + *of_idp = of_match; return 0; - else if (ret == -FDT_ERR_NOTFOUND) + } else if (ret == -FDT_ERR_NOTFOUND) { return -ENODEV; - else if (ret < 0) + } else if (ret < 0) { return -EINVAL; + } of_match++; } @@ -116,6 +136,7 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, { struct driver *driver = ll_entry_start(struct driver, driver); const int n_ents = ll_entry_count(struct driver, driver); + const struct udevice_id *id; struct driver *entry; struct udevice *dev; bool found = false; @@ -127,7 +148,8 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, if (devp) *devp = NULL; for (entry = driver; entry != driver + n_ents; entry++) { - ret = driver_check_compatible(blob, offset, entry->of_match); + ret = driver_check_compatible(blob, offset, entry->of_match, + &id); name = fdt_get_name(blob, offset, NULL); if (ret == -ENOENT) { continue; @@ -136,8 +158,7 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, break; } else if (ret) { dm_warn("Device tree error at offset %d\n", offset); - if (!result || ret != -ENOENT) - result = ret; + result = ret; break; } @@ -147,6 +168,7 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, dm_warn("Error binding driver '%s'\n", entry->name); return ret; } else { + dev->of_id = id; found = true; if (devp) *devp = dev; diff --git a/drivers/core/root.c b/drivers/core/root.c index a328a4876f1..47b3acfbe98 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -73,10 +73,8 @@ int dm_scan_platdata(bool pre_reloc_only) dm_warn("Some drivers were not found\n"); ret = 0; } - if (ret) - return ret; - return 0; + return ret; } #ifdef CONFIG_OF_CONTROL diff --git a/drivers/ddr/fsl/ctrl_regs.c b/drivers/ddr/fsl/ctrl_regs.c index 9a156bfd5e1..9e2a4d2f467 100644 --- a/drivers/ddr/fsl/ctrl_regs.c +++ b/drivers/ddr/fsl/ctrl_regs.c @@ -303,7 +303,7 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr, #ifdef CONFIG_SYS_FSL_DDR4 /* tXP=max(4nCK, 6ns) */ - int txp = max(mclk_ps * 4, 6000); /* unit=ps */ + int txp = max((int)mclk_ps * 4, 6000); /* unit=ps */ trwt_mclk = 2; twrt_mclk = 1; act_pd_exit_mclk = picos_to_mclk(txp); @@ -312,7 +312,7 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr, * MRS_CYC = max(tMRD, tMOD) * tMRD = 8nCK, tMOD = max(24nCK, 15ns) */ - tmrd_mclk = max(24, picos_to_mclk(15000)); + tmrd_mclk = max(24U, picos_to_mclk(15000)); #elif defined(CONFIG_SYS_FSL_DDR3) unsigned int data_rate = get_ddr_freq(0); int txp; @@ -325,7 +325,7 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr, * spec has not the tAXPD, we use * tAXPD=1, need design to confirm. */ - txp = max(mclk_ps * 3, (mclk_ps > 1540 ? 7500 : 6000)); + txp = max((int)mclk_ps * 3, (mclk_ps > 1540 ? 7500 : 6000)); tmrd_mclk = 4; /* set the turnaround time */ @@ -511,8 +511,8 @@ static void set_timing_cfg_1(fsl_ddr_cfg_regs_t *ddr, #ifdef CONFIG_SYS_FSL_DDR4 refrec_ctrl = picos_to_mclk(common_dimm->trfc1_ps) - 8; wrrec_mclk = picos_to_mclk(common_dimm->twr_ps); - acttoact_mclk = max(picos_to_mclk(common_dimm->trrds_ps), 4); - wrtord_mclk = max(2, picos_to_mclk(2500)); + acttoact_mclk = max(picos_to_mclk(common_dimm->trrds_ps), 4U); + wrtord_mclk = max(2U, picos_to_mclk(2500)); if ((wrrec_mclk < 1) || (wrrec_mclk > 24)) printf("Error: WRREC doesn't support %d clocks\n", wrrec_mclk); else @@ -627,14 +627,14 @@ static void set_timing_cfg_2(fsl_ddr_cfg_regs_t *ddr, wr_data_delay = popts->write_data_delay; #ifdef CONFIG_SYS_FSL_DDR4 cpo = 0; - cke_pls = max(3, picos_to_mclk(5000)); + cke_pls = max(3U, picos_to_mclk(5000)); #elif defined(CONFIG_SYS_FSL_DDR3) /* * cke pulse = max(3nCK, 7.5ns) for DDR3-800 * max(3nCK, 5.625ns) for DDR3-1066, 1333 * max(3nCK, 5ns) for DDR3-1600, 1866, 2133 */ - cke_pls = max(3, picos_to_mclk(mclk_ps > 1870 ? 7500 : + cke_pls = max(3U, picos_to_mclk(mclk_ps > 1870 ? 7500 : (mclk_ps > 1245 ? 5625 : 5000))); #else cke_pls = FSL_DDR_MIN_TCKE_PULSE_WIDTH_DDR; @@ -1810,9 +1810,9 @@ static void set_timing_cfg_7(fsl_ddr_cfg_regs_t *ddr, unsigned int txpr, tcksre, tcksrx; unsigned int cke_rst, cksre, cksrx, par_lat, cs_to_cmd; - txpr = max(5, picos_to_mclk(common_dimm->trfc1_ps + 10000)); - tcksre = max(5, picos_to_mclk(10000)); - tcksrx = max(5, picos_to_mclk(10000)); + txpr = max(5U, picos_to_mclk(common_dimm->trfc1_ps + 10000)); + tcksre = max(5U, picos_to_mclk(10000)); + tcksrx = max(5U, picos_to_mclk(10000)); par_lat = 0; cs_to_cmd = 0; @@ -1877,7 +1877,7 @@ static void set_timing_cfg_8(fsl_ddr_cfg_regs_t *ddr, } acttoact_bg = picos_to_mclk(common_dimm->trrdl_ps); - wrtord_bg = max(4, picos_to_mclk(7500)); + wrtord_bg = max(4U, picos_to_mclk(7500)); if (popts->otf_burst_chop_en) wrtord_bg += 2; diff --git a/drivers/ddr/fsl/lc_common_dimm_params.c b/drivers/ddr/fsl/lc_common_dimm_params.c index 05a24dd6efd..73db4446153 100644 --- a/drivers/ddr/fsl/lc_common_dimm_params.c +++ b/drivers/ddr/fsl/lc_common_dimm_params.c @@ -289,48 +289,58 @@ compute_lowest_common_dimm_parameters(const dimm_params_t *dimm_params, * Find minimum tckmax_ps to find fastest slow speed, * i.e., this is the slowest the whole system can go. */ - tckmax_ps = min(tckmax_ps, dimm_params[i].tckmax_ps); + tckmax_ps = min(tckmax_ps, + (unsigned int)dimm_params[i].tckmax_ps); #if defined(CONFIG_SYS_FSL_DDR3) || defined(CONFIG_SYS_FSL_DDR4) - taamin_ps = max(taamin_ps, dimm_params[i].taa_ps); + taamin_ps = max(taamin_ps, + (unsigned int)dimm_params[i].taa_ps); #endif - tckmin_x_ps = max(tckmin_x_ps, dimm_params[i].tckmin_x_ps); - trcd_ps = max(trcd_ps, dimm_params[i].trcd_ps); - trp_ps = max(trp_ps, dimm_params[i].trp_ps); - tras_ps = max(tras_ps, dimm_params[i].tras_ps); + tckmin_x_ps = max(tckmin_x_ps, + (unsigned int)dimm_params[i].tckmin_x_ps); + trcd_ps = max(trcd_ps, (unsigned int)dimm_params[i].trcd_ps); + trp_ps = max(trp_ps, (unsigned int)dimm_params[i].trp_ps); + tras_ps = max(tras_ps, (unsigned int)dimm_params[i].tras_ps); #ifdef CONFIG_SYS_FSL_DDR4 - trfc1_ps = max(trfc1_ps, dimm_params[i].trfc1_ps); - trfc2_ps = max(trfc2_ps, dimm_params[i].trfc2_ps); - trfc4_ps = max(trfc4_ps, dimm_params[i].trfc4_ps); - trrds_ps = max(trrds_ps, dimm_params[i].trrds_ps); - trrdl_ps = max(trrdl_ps, dimm_params[i].trrdl_ps); - tccdl_ps = max(tccdl_ps, dimm_params[i].tccdl_ps); + trfc1_ps = max(trfc1_ps, + (unsigned int)dimm_params[i].trfc1_ps); + trfc2_ps = max(trfc2_ps, + (unsigned int)dimm_params[i].trfc2_ps); + trfc4_ps = max(trfc4_ps, + (unsigned int)dimm_params[i].trfc4_ps); + trrds_ps = max(trrds_ps, + (unsigned int)dimm_params[i].trrds_ps); + trrdl_ps = max(trrdl_ps, + (unsigned int)dimm_params[i].trrdl_ps); + tccdl_ps = max(tccdl_ps, + (unsigned int)dimm_params[i].tccdl_ps); #else - twr_ps = max(twr_ps, dimm_params[i].twr_ps); - twtr_ps = max(twtr_ps, dimm_params[i].twtr_ps); - trfc_ps = max(trfc_ps, dimm_params[i].trfc_ps); - trrd_ps = max(trrd_ps, dimm_params[i].trrd_ps); - trtp_ps = max(trtp_ps, dimm_params[i].trtp_ps); + twr_ps = max(twr_ps, (unsigned int)dimm_params[i].twr_ps); + twtr_ps = max(twtr_ps, (unsigned int)dimm_params[i].twtr_ps); + trfc_ps = max(trfc_ps, (unsigned int)dimm_params[i].trfc_ps); + trrd_ps = max(trrd_ps, (unsigned int)dimm_params[i].trrd_ps); + trtp_ps = max(trtp_ps, (unsigned int)dimm_params[i].trtp_ps); #endif - trc_ps = max(trc_ps, dimm_params[i].trc_ps); + trc_ps = max(trc_ps, (unsigned int)dimm_params[i].trc_ps); #if defined(CONFIG_SYS_FSL_DDR1) || defined(CONFIG_SYS_FSL_DDR2) - tis_ps = max(tis_ps, dimm_params[i].tis_ps); - tih_ps = max(tih_ps, dimm_params[i].tih_ps); - tds_ps = max(tds_ps, dimm_params[i].tds_ps); - tdh_ps = max(tdh_ps, dimm_params[i].tdh_ps); - tqhs_ps = max(tqhs_ps, dimm_params[i].tqhs_ps); + tis_ps = max(tis_ps, (unsigned int)dimm_params[i].tis_ps); + tih_ps = max(tih_ps, (unsigned int)dimm_params[i].tih_ps); + tds_ps = max(tds_ps, (unsigned int)dimm_params[i].tds_ps); + tdh_ps = max(tdh_ps, (unsigned int)dimm_params[i].tdh_ps); + tqhs_ps = max(tqhs_ps, (unsigned int)dimm_params[i].tqhs_ps); /* * Find maximum tdqsq_max_ps to find slowest. * * FIXME: is finding the slowest value the correct * strategy for this parameter? */ - tdqsq_max_ps = max(tdqsq_max_ps, dimm_params[i].tdqsq_max_ps); + tdqsq_max_ps = max(tdqsq_max_ps, + (unsigned int)dimm_params[i].tdqsq_max_ps); #endif refresh_rate_ps = max(refresh_rate_ps, - dimm_params[i].refresh_rate_ps); + (unsigned int)dimm_params[i].refresh_rate_ps); /* extended_op_srt is either 0 or 1, 0 having priority */ extended_op_srt = min(extended_op_srt, - dimm_params[i].extended_op_srt); + (unsigned int)dimm_params[i].extended_op_srt); } outpdimm->ndimms_present = number_of_dimms - temp1; diff --git a/drivers/ddr/fsl/main.c b/drivers/ddr/fsl/main.c index b43b669e41f..6f291ebc032 100644 --- a/drivers/ddr/fsl/main.c +++ b/drivers/ddr/fsl/main.c @@ -106,7 +106,8 @@ static void __get_spd(generic_spd_eeprom_t *spd, u8 i2c_address) i2c_write(SPD_SPA1_ADDRESS, 0, 1, &dummy, 1); ret = i2c_read(i2c_address, 0, 1, (uchar *)((ulong)spd + 256), - min(256, sizeof(generic_spd_eeprom_t) - 256)); + min(256, + (int)sizeof(generic_spd_eeprom_t) - 256)); } #else ret = i2c_read(i2c_address, 0, 1, (uchar *)spd, diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c index 55e6a83b9ad..c0aba6e197c 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -289,7 +289,7 @@ static int dfu_read_buffer_fill(struct dfu_entity *dfu, void *buf, int size) readn = 0; while (size > 0) { /* get chunk that can be read */ - chunk = min(size, dfu->b_left); + chunk = min((long)size, dfu->b_left); /* consume */ if (chunk > 0) { memcpy(buf, dfu->i_buf, chunk); diff --git a/drivers/fpga/zynqpl.c b/drivers/fpga/zynqpl.c index 68fe0f3b03a..6a74f896106 100644 --- a/drivers/fpga/zynqpl.c +++ b/drivers/fpga/zynqpl.c @@ -406,8 +406,8 @@ static int zynq_loadfs(xilinx_desc *desc, const void *buf, size_t bsize, unsigned long ts; /* Timestamp */ u32 isr_status, swap; u32 partialbit = 0; - u32 blocksize; - u32 pos = 0; + loff_t blocksize, actread; + loff_t pos = 0; int fstype; char *interface, *dev_part, *filename; @@ -420,7 +420,7 @@ static int zynq_loadfs(xilinx_desc *desc, const void *buf, size_t bsize, if (fs_set_blk_dev(interface, dev_part, fstype)) return FPGA_FAIL; - if (fs_read(filename, (u32) buf, pos, blocksize) < 0) + if (fs_read(filename, (u32) buf, pos, blocksize, &actread) < 0) return FPGA_FAIL; if (zynq_validate_bitstream(desc, buf, bsize, blocksize, &swap, @@ -443,10 +443,10 @@ static int zynq_loadfs(xilinx_desc *desc, const void *buf, size_t bsize, return FPGA_FAIL; if (bsize > blocksize) { - if (fs_read(filename, (u32) buf, pos, blocksize) < 0) + if (fs_read(filename, (u32) buf, pos, blocksize, &actread) < 0) return FPGA_FAIL; } else { - if (fs_read(filename, (u32) buf, pos, bsize) < 0) + if (fs_read(filename, (u32) buf, pos, bsize, &actread) < 0) return FPGA_FAIL; } } while (bsize > blocksize); diff --git a/drivers/gpio/at91_gpio.c b/drivers/gpio/at91_gpio.c index 6517af16281..6129c020ea1 100644 --- a/drivers/gpio/at91_gpio.c +++ b/drivers/gpio/at91_gpio.c @@ -10,11 +10,14 @@ #include <config.h> #include <common.h> +#include <dm.h> #include <asm/io.h> #include <linux/sizes.h> +#include <asm/gpio.h> #include <asm/arch/hardware.h> #include <asm/arch/at91_pio.h> -#include <asm/arch/gpio.h> + +#define GPIO_PER_BANK 32 static struct at91_port *at91_pio_get_port(unsigned port) { @@ -39,19 +42,25 @@ static struct at91_port *at91_pio_get_port(unsigned port) } } +static void at91_set_port_pullup(struct at91_port *at91_port, unsigned offset, + int use_pullup) +{ + u32 mask; + + mask = 1 << offset; + if (use_pullup) + writel(mask, &at91_port->puer); + else + writel(mask, &at91_port->pudr); + writel(mask, &at91_port->per); +} + int at91_set_pio_pullup(unsigned port, unsigned pin, int use_pullup) { struct at91_port *at91_port = at91_pio_get_port(port); - u32 mask; - if (at91_port && (pin < 32)) { - mask = 1 << pin; - if (use_pullup) - writel(1 << pin, &at91_port->puer); - else - writel(1 << pin, &at91_port->pudr); - writel(mask, &at91_port->per); - } + if (at91_port && (pin < GPIO_PER_BANK)) + at91_set_port_pullup(at91_port, pin, use_pullup); return 0; } @@ -64,7 +73,7 @@ int at91_set_pio_periph(unsigned port, unsigned pin, int use_pullup) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; writel(mask, &at91_port->idr); at91_set_pio_pullup(port, pin, use_pullup); @@ -82,7 +91,7 @@ int at91_set_a_periph(unsigned port, unsigned pin, int use_pullup) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; writel(mask, &at91_port->idr); at91_set_pio_pullup(port, pin, use_pullup); @@ -108,7 +117,7 @@ int at91_set_b_periph(unsigned port, unsigned pin, int use_pullup) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; writel(mask, &at91_port->idr); at91_set_pio_pullup(port, pin, use_pullup); @@ -135,7 +144,7 @@ int at91_set_c_periph(unsigned port, unsigned pin, int use_pullup) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; writel(mask, &at91_port->idr); at91_set_pio_pullup(port, pin, use_pullup); @@ -157,7 +166,7 @@ int at91_set_d_periph(unsigned port, unsigned pin, int use_pullup) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; writel(mask, &at91_port->idr); at91_set_pio_pullup(port, pin, use_pullup); @@ -172,6 +181,29 @@ int at91_set_d_periph(unsigned port, unsigned pin, int use_pullup) } #endif +#ifdef CONFIG_DM_GPIO +static bool at91_get_port_output(struct at91_port *at91_port, int offset) +{ + u32 mask, val; + + mask = 1 << offset; + val = readl(&at91_port->osr); + return val & mask; +} +#endif + +static void at91_set_port_input(struct at91_port *at91_port, int offset, + int use_pullup) +{ + u32 mask; + + mask = 1 << offset; + writel(mask, &at91_port->idr); + at91_set_port_pullup(at91_port, offset, use_pullup); + writel(mask, &at91_port->odr); + writel(mask, &at91_port->per); +} + /* * mux the pin to the gpio controller (instead of "A" or "B" peripheral), and * configure it for an input. @@ -179,19 +211,29 @@ int at91_set_d_periph(unsigned port, unsigned pin, int use_pullup) int at91_set_pio_input(unsigned port, u32 pin, int use_pullup) { struct at91_port *at91_port = at91_pio_get_port(port); - u32 mask; - if (at91_port && (pin < 32)) { - mask = 1 << pin; - writel(mask, &at91_port->idr); - at91_set_pio_pullup(port, pin, use_pullup); - writel(mask, &at91_port->odr); - writel(mask, &at91_port->per); - } + if (at91_port && (pin < GPIO_PER_BANK)) + at91_set_port_input(at91_port, pin, use_pullup); return 0; } +static void at91_set_port_output(struct at91_port *at91_port, int offset, + int value) +{ + u32 mask; + + mask = 1 << offset; + writel(mask, &at91_port->idr); + writel(mask, &at91_port->pudr); + if (value) + writel(mask, &at91_port->sodr); + else + writel(mask, &at91_port->codr); + writel(mask, &at91_port->oer); + writel(mask, &at91_port->per); +} + /* * mux the pin to the gpio controller (instead of "A" or "B" peripheral), * and configure it for an output. @@ -199,19 +241,9 @@ int at91_set_pio_input(unsigned port, u32 pin, int use_pullup) int at91_set_pio_output(unsigned port, u32 pin, int value) { struct at91_port *at91_port = at91_pio_get_port(port); - u32 mask; - if (at91_port && (port < ATMEL_PIO_PORTS) && (pin < 32)) { - mask = 1 << pin; - writel(mask, &at91_port->idr); - writel(mask, &at91_port->pudr); - if (value) - writel(mask, &at91_port->sodr); - else - writel(mask, &at91_port->codr); - writel(mask, &at91_port->oer); - writel(mask, &at91_port->per); - } + if (at91_port && (pin < GPIO_PER_BANK)) + at91_set_port_output(at91_port, pin, value); return 0; } @@ -224,7 +256,7 @@ int at91_set_pio_deglitch(unsigned port, unsigned pin, int is_on) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; if (is_on) { #if defined(CPU_HAS_PIO3) @@ -248,7 +280,7 @@ int at91_set_pio_debounce(unsigned port, unsigned pin, int is_on, int div) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; if (is_on) { writel(mask, &at91_port->ifscer); @@ -271,7 +303,7 @@ int at91_set_pio_pulldown(unsigned port, unsigned pin, int is_on) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; writel(mask, &at91_port->pudr); if (is_on) @@ -291,7 +323,7 @@ int at91_set_pio_disable_schmitt_trig(unsigned port, unsigned pin) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; writel(readl(&at91_port->schmitt) | mask, &at91_port->schmitt); @@ -310,7 +342,7 @@ int at91_set_pio_multi_drive(unsigned port, unsigned pin, int is_on) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; if (is_on) writel(mask, &at91_port->mder); @@ -321,41 +353,54 @@ int at91_set_pio_multi_drive(unsigned port, unsigned pin, int is_on) return 0; } +static void at91_set_port_value(struct at91_port *at91_port, int offset, + int value) +{ + u32 mask; + + mask = 1 << offset; + if (value) + writel(mask, &at91_port->sodr); + else + writel(mask, &at91_port->codr); +} + /* * assuming the pin is muxed as a gpio output, set its value. */ int at91_set_pio_value(unsigned port, unsigned pin, int value) { struct at91_port *at91_port = at91_pio_get_port(port); - u32 mask; - if (at91_port && (pin < 32)) { - mask = 1 << pin; - if (value) - writel(mask, &at91_port->sodr); - else - writel(mask, &at91_port->codr); - } + if (at91_port && (pin < GPIO_PER_BANK)) + at91_set_port_value(at91_port, pin, value); return 0; } +static int at91_get_port_value(struct at91_port *at91_port, int offset) +{ + u32 pdsr = 0, mask; + + mask = 1 << offset; + pdsr = readl(&at91_port->pdsr) & mask; + + return pdsr != 0; +} /* * read the pin's value (works even if it's not muxed as a gpio). */ int at91_get_pio_value(unsigned port, unsigned pin) { struct at91_port *at91_port = at91_pio_get_port(port); - u32 pdsr = 0, mask; - if (at91_port && (pin < 32)) { - mask = 1 << pin; - pdsr = readl(&at91_port->pdsr) & mask; - } + if (at91_port && (pin < GPIO_PER_BANK)) + return at91_get_port_value(at91_port, pin); - return pdsr != 0; + return 0; } +#ifndef CONFIG_DM_GPIO /* Common GPIO API */ int gpio_request(unsigned gpio, const char *label) @@ -395,3 +440,91 @@ int gpio_set_value(unsigned gpio, int value) return 0; } +#endif + +#ifdef CONFIG_DM_GPIO + +struct at91_port_priv { + struct at91_port *regs; +}; + +/* set GPIO pin 'gpio' as an input */ +static int at91_gpio_direction_input(struct udevice *dev, unsigned offset) +{ + struct at91_port_priv *port = dev_get_platdata(dev); + + at91_set_port_input(port->regs, offset, 0); + + return 0; +} + +/* set GPIO pin 'gpio' as an output, with polarity 'value' */ +static int at91_gpio_direction_output(struct udevice *dev, unsigned offset, + int value) +{ + struct at91_port_priv *port = dev_get_platdata(dev); + + at91_set_port_output(port->regs, offset, value); + + return 0; +} + +/* read GPIO IN value of pin 'gpio' */ +static int at91_gpio_get_value(struct udevice *dev, unsigned offset) +{ + struct at91_port_priv *port = dev_get_platdata(dev); + + return at91_get_port_value(port->regs, offset); +} + +/* write GPIO OUT value to pin 'gpio' */ +static int at91_gpio_set_value(struct udevice *dev, unsigned offset, + int value) +{ + struct at91_port_priv *port = dev_get_platdata(dev); + + at91_set_port_value(port->regs, offset, value); + + return 0; +} + +static int at91_gpio_get_function(struct udevice *dev, unsigned offset) +{ + struct at91_port_priv *port = dev_get_platdata(dev); + + /* GPIOF_FUNC is not implemented yet */ + if (at91_get_port_output(port->regs, offset)) + return GPIOF_OUTPUT; + else + return GPIOF_INPUT; +} + +static const struct dm_gpio_ops gpio_at91_ops = { + .direction_input = at91_gpio_direction_input, + .direction_output = at91_gpio_direction_output, + .get_value = at91_gpio_get_value, + .set_value = at91_gpio_set_value, + .get_function = at91_gpio_get_function, +}; + +static int at91_gpio_probe(struct udevice *dev) +{ + struct at91_port_priv *port = dev_get_priv(dev); + struct at91_port_platdata *plat = dev_get_platdata(dev); + struct gpio_dev_priv *uc_priv = dev->uclass_priv; + + uc_priv->bank_name = plat->bank_name; + uc_priv->gpio_count = GPIO_PER_BANK; + port->regs = (struct at91_port *)plat->base_addr; + + return 0; +} + +U_BOOT_DRIVER(gpio_at91) = { + .name = "gpio_at91", + .id = UCLASS_GPIO, + .ops = &gpio_at91_ops, + .probe = at91_gpio_probe, + .priv_auto_alloc_size = sizeof(struct at91_port_priv), +}; +#endif diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index 45e9a5ad227..255700ab18d 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -390,6 +390,25 @@ int gpio_get_status(struct udevice *dev, int offset, char *buf, int buffsize) return 0; } +/* + * get a number comprised of multiple GPIO values. gpio_num_array points to + * the array of gpio pin numbers to scan, terminated by -1. + */ +unsigned gpio_get_values_as_int(const int *gpio_num_array) +{ + int gpio; + unsigned bitmask = 1; + unsigned vector = 0; + + while (bitmask && + ((gpio = *gpio_num_array++) != -1)) { + if (gpio_get_value(gpio)) + vector |= bitmask; + bitmask <<= 1; + } + return vector; +} + /* We need to renumber the GPIOs when any driver is probed/removed */ static int gpio_renumber(struct udevice *removed_dev) { diff --git a/drivers/gpio/intel_ich6_gpio.c b/drivers/gpio/intel_ich6_gpio.c index d3381b0369c..b095d17f574 100644 --- a/drivers/gpio/intel_ich6_gpio.c +++ b/drivers/gpio/intel_ich6_gpio.c @@ -33,6 +33,11 @@ #include <pci.h> #include <asm/gpio.h> #include <asm/io.h> +#include <asm/pci.h> +#ifdef CONFIG_X86_RESET_VECTOR +#include <asm/arch/pch.h> +#define SUPPORT_GPIO_SETUP +#endif #define GPIO_PER_BANK 32 @@ -46,6 +51,53 @@ struct ich6_bank_priv { uint32_t lvl; }; +#ifdef SUPPORT_GPIO_SETUP +static void setup_pch_gpios(const struct pch_gpio_map *gpio) +{ + u16 gpiobase = pci_read_config16(PCH_LPC_DEV, GPIO_BASE) & 0xfffc; + + /* GPIO Set 1 */ + if (gpio->set1.level) + outl(*((u32 *)gpio->set1.level), gpiobase + GP_LVL); + if (gpio->set1.mode) + outl(*((u32 *)gpio->set1.mode), gpiobase + GPIO_USE_SEL); + if (gpio->set1.direction) + outl(*((u32 *)gpio->set1.direction), gpiobase + GP_IO_SEL); + if (gpio->set1.reset) + outl(*((u32 *)gpio->set1.reset), gpiobase + GP_RST_SEL1); + if (gpio->set1.invert) + outl(*((u32 *)gpio->set1.invert), gpiobase + GPI_INV); + if (gpio->set1.blink) + outl(*((u32 *)gpio->set1.blink), gpiobase + GPO_BLINK); + + /* GPIO Set 2 */ + if (gpio->set2.level) + outl(*((u32 *)gpio->set2.level), gpiobase + GP_LVL2); + if (gpio->set2.mode) + outl(*((u32 *)gpio->set2.mode), gpiobase + GPIO_USE_SEL2); + if (gpio->set2.direction) + outl(*((u32 *)gpio->set2.direction), gpiobase + GP_IO_SEL2); + if (gpio->set2.reset) + outl(*((u32 *)gpio->set2.reset), gpiobase + GP_RST_SEL2); + + /* GPIO Set 3 */ + if (gpio->set3.level) + outl(*((u32 *)gpio->set3.level), gpiobase + GP_LVL3); + if (gpio->set3.mode) + outl(*((u32 *)gpio->set3.mode), gpiobase + GPIO_USE_SEL3); + if (gpio->set3.direction) + outl(*((u32 *)gpio->set3.direction), gpiobase + GP_IO_SEL3); + if (gpio->set3.reset) + outl(*((u32 *)gpio->set3.reset), gpiobase + GP_RST_SEL3); +} + +/* TODO: Move this to device tree, or platform data */ +void ich_gpio_set_gpio_map(const struct pch_gpio_map *map) +{ + gd->arch.gpio_map = map; +} +#endif /* SUPPORT_GPIO_SETUP */ + static int gpio_ich6_ofdata_to_platdata(struct udevice *dev) { struct ich6_bank_platdata *plat = dev_get_platdata(dev); @@ -60,13 +112,13 @@ static int gpio_ich6_ofdata_to_platdata(struct udevice *dev) pci_dev = PCI_BDF(0, 0x1f, 0); /* Is the device present? */ - pci_read_config_word(pci_dev, PCI_VENDOR_ID, &tmpword); + tmpword = pci_read_config16(pci_dev, PCI_VENDOR_ID); if (tmpword != PCI_VENDOR_ID_INTEL) { debug("%s: wrong VendorID\n", __func__); return -ENODEV; } - pci_read_config_word(pci_dev, PCI_DEVICE_ID, &tmpword); + tmpword = pci_read_config16(pci_dev, PCI_DEVICE_ID); debug("Found %04x:%04x\n", PCI_VENDOR_ID_INTEL, tmpword); /* * We'd like to validate the Device ID too, but pretty much any @@ -76,34 +128,34 @@ static int gpio_ich6_ofdata_to_platdata(struct udevice *dev) */ /* I/O should already be enabled (it's a RO bit). */ - pci_read_config_word(pci_dev, PCI_COMMAND, &tmpword); + tmpword = pci_read_config16(pci_dev, PCI_COMMAND); if (!(tmpword & PCI_COMMAND_IO)) { debug("%s: device IO not enabled\n", __func__); return -ENODEV; } /* Header Type must be normal (bits 6-0 only; see spec.) */ - pci_read_config_byte(pci_dev, PCI_HEADER_TYPE, &tmpbyte); + tmpbyte = pci_read_config8(pci_dev, PCI_HEADER_TYPE); if ((tmpbyte & 0x7f) != PCI_HEADER_TYPE_NORMAL) { debug("%s: invalid Header type\n", __func__); return -ENODEV; } /* Base Class must be a bridge device */ - pci_read_config_byte(pci_dev, PCI_CLASS_CODE, &tmpbyte); + tmpbyte = pci_read_config8(pci_dev, PCI_CLASS_CODE); if (tmpbyte != PCI_CLASS_CODE_BRIDGE) { debug("%s: invalid class\n", __func__); return -ENODEV; } /* Sub Class must be ISA */ - pci_read_config_byte(pci_dev, PCI_CLASS_SUB_CODE, &tmpbyte); + tmpbyte = pci_read_config8(pci_dev, PCI_CLASS_SUB_CODE); if (tmpbyte != PCI_CLASS_SUB_CODE_BRIDGE_ISA) { debug("%s: invalid subclass\n", __func__); return -ENODEV; } /* Programming Interface must be 0x00 (no others exist) */ - pci_read_config_byte(pci_dev, PCI_CLASS_PROG, &tmpbyte); + tmpbyte = pci_read_config8(pci_dev, PCI_CLASS_PROG); if (tmpbyte != 0x00) { debug("%s: invalid interface type\n", __func__); return -ENODEV; @@ -114,7 +166,7 @@ static int gpio_ich6_ofdata_to_platdata(struct udevice *dev) * that it was unused (or undocumented). Check that it looks * okay: not all ones or zeros, and mapped to I/O space (bit 0). */ - pci_read_config_dword(pci_dev, PCI_CFG_GPIOBASE, &tmplong); + tmplong = pci_read_config32(pci_dev, PCI_CFG_GPIOBASE); if (tmplong == 0x00000000 || tmplong == 0xffffffff || !(tmplong & 0x00000001)) { debug("%s: unexpected GPIOBASE value\n", __func__); @@ -140,12 +192,18 @@ static int gpio_ich6_ofdata_to_platdata(struct udevice *dev) return 0; } -int ich6_gpio_probe(struct udevice *dev) +static int ich6_gpio_probe(struct udevice *dev) { struct ich6_bank_platdata *plat = dev_get_platdata(dev); struct gpio_dev_priv *uc_priv = dev->uclass_priv; struct ich6_bank_priv *bank = dev_get_priv(dev); +#ifdef SUPPORT_GPIO_SETUP + if (gd->arch.gpio_map) { + setup_pch_gpios(gd->arch.gpio_map); + gd->arch.gpio_map = NULL; + } +#endif uc_priv->gpio_count = GPIO_PER_BANK; uc_priv->bank_name = plat->bank_name; bank->use_sel = plat->base_addr; @@ -155,7 +213,8 @@ int ich6_gpio_probe(struct udevice *dev) return 0; } -int ich6_gpio_request(struct udevice *dev, unsigned offset, const char *label) +static int ich6_gpio_request(struct udevice *dev, unsigned offset, + const char *label) { struct ich6_bank_priv *bank = dev_get_priv(dev); u32 tmplong; diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index d067897244b..dae3d71d2bb 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -5,7 +5,7 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-$(CONFIG_BFIN_TWI_I2C) += bfin-twi_i2c.o +obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o obj-$(CONFIG_I2C_MV) += mv_i2c.o obj-$(CONFIG_PCA9564_I2C) += pca9564_i2c.o obj-$(CONFIG_TSI108_I2C) += tsi108_i2c.o diff --git a/drivers/i2c/adi_i2c.c b/drivers/i2c/adi_i2c.c new file mode 100644 index 00000000000..20495b1d7f8 --- /dev/null +++ b/drivers/i2c/adi_i2c.c @@ -0,0 +1,305 @@ +/* + * i2c.c - driver for ADI TWI/I2C + * + * Copyright (c) 2006-2014 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include <common.h> +#include <i2c.h> + +#include <asm/clock.h> +#include <asm/twi.h> +#include <asm/io.h> + +static struct twi_regs *i2c_get_base(struct i2c_adapter *adap); + +/* Every register is 32bit aligned, but only 16bits in size */ +#define ureg(name) u16 name; u16 __pad_##name; +struct twi_regs { + ureg(clkdiv); + ureg(control); + ureg(slave_ctl); + ureg(slave_stat); + ureg(slave_addr); + ureg(master_ctl); + ureg(master_stat); + ureg(master_addr); + ureg(int_stat); + ureg(int_mask); + ureg(fifo_ctl); + ureg(fifo_stat); + char __pad[0x50]; + ureg(xmt_data8); + ureg(xmt_data16); + ureg(rcv_data8); + ureg(rcv_data16); +}; +#undef ureg + +#ifdef TWI_CLKDIV +#define TWI0_CLKDIV TWI_CLKDIV +# ifdef CONFIG_SYS_MAX_I2C_BUS +# undef CONFIG_SYS_MAX_I2C_BUS +# endif +#define CONFIG_SYS_MAX_I2C_BUS 1 +#endif + +/* + * The way speed is changed into duty often results in integer truncation + * with 50% duty, so we'll force rounding up to the next duty by adding 1 + * to the max. In practice this will get us a speed of something like + * 385 KHz. The other limit is easy to handle as it is only 8 bits. + */ +#define I2C_SPEED_MAX 400000 +#define I2C_SPEED_TO_DUTY(speed) (5000000 / (speed)) +#define I2C_DUTY_MAX (I2C_SPEED_TO_DUTY(I2C_SPEED_MAX) + 1) +#define I2C_DUTY_MIN 0xff /* 8 bit limited */ +#define SYS_I2C_DUTY I2C_SPEED_TO_DUTY(CONFIG_SYS_I2C_SPEED) +/* Note: duty is inverse of speed, so the comparisons below are correct */ +#if SYS_I2C_DUTY < I2C_DUTY_MAX || SYS_I2C_DUTY > I2C_DUTY_MIN +# error "The I2C hardware can only operate 20KHz - 400KHz" +#endif + +/* All transfers are described by this data structure */ +struct i2c_msg { + u8 flags; +#define I2C_M_COMBO 0x4 +#define I2C_M_STOP 0x2 +#define I2C_M_READ 0x1 + int len; /* msg length */ + u8 *buf; /* pointer to msg data */ + int alen; /* addr length */ + u8 *abuf; /* addr buffer */ +}; + +/* Allow msec timeout per ~byte transfer */ +#define I2C_TIMEOUT 10 + +/** + * wait_for_completion - manage the actual i2c transfer + * @msg: the i2c msg + */ +static int wait_for_completion(struct twi_regs *twi, struct i2c_msg *msg) +{ + u16 int_stat, ctl; + ulong timebase = get_timer(0); + + do { + int_stat = readw(&twi->int_stat); + + if (int_stat & XMTSERV) { + writew(XMTSERV, &twi->int_stat); + if (msg->alen) { + writew(*(msg->abuf++), &twi->xmt_data8); + --msg->alen; + } else if (!(msg->flags & I2C_M_COMBO) && msg->len) { + writew(*(msg->buf++), &twi->xmt_data8); + --msg->len; + } else { + ctl = readw(&twi->master_ctl); + if (msg->flags & I2C_M_COMBO) + writew(ctl | RSTART | MDIR, + &twi->master_ctl); + else + writew(ctl | STOP, &twi->master_ctl); + } + } + if (int_stat & RCVSERV) { + writew(RCVSERV, &twi->int_stat); + if (msg->len) { + *(msg->buf++) = readw(&twi->rcv_data8); + --msg->len; + } else if (msg->flags & I2C_M_STOP) { + ctl = readw(&twi->master_ctl); + writew(ctl | STOP, &twi->master_ctl); + } + } + if (int_stat & MERR) { + writew(MERR, &twi->int_stat); + return msg->len; + } + if (int_stat & MCOMP) { + writew(MCOMP, &twi->int_stat); + if (msg->flags & I2C_M_COMBO && msg->len) { + ctl = readw(&twi->master_ctl); + ctl = (ctl & ~RSTART) | + (min(msg->len, 0xff) << 6) | MEN | MDIR; + writew(ctl, &twi->master_ctl); + } else + break; + } + + /* If we were able to do something, reset timeout */ + if (int_stat) + timebase = get_timer(0); + + } while (get_timer(timebase) < I2C_TIMEOUT); + + return msg->len; +} + +static int i2c_transfer(struct i2c_adapter *adap, uint8_t chip, uint addr, + int alen, uint8_t *buffer, int len, uint8_t flags) +{ + struct twi_regs *twi = i2c_get_base(adap); + int ret; + u16 ctl; + uchar addr_buffer[] = { + (addr >> 0), + (addr >> 8), + (addr >> 16), + }; + struct i2c_msg msg = { + .flags = flags | (len >= 0xff ? I2C_M_STOP : 0), + .buf = buffer, + .len = len, + .abuf = addr_buffer, + .alen = alen, + }; + + /* wait for things to settle */ + while (readw(&twi->master_stat) & BUSBUSY) + if (ctrlc()) + return 1; + + /* Set Transmit device address */ + writew(chip, &twi->master_addr); + + /* Clear the FIFO before starting things */ + writew(XMTFLUSH | RCVFLUSH, &twi->fifo_ctl); + writew(0, &twi->fifo_ctl); + + /* prime the pump */ + if (msg.alen) { + len = (msg.flags & I2C_M_COMBO) ? msg.alen : msg.alen + len; + writew(*(msg.abuf++), &twi->xmt_data8); + --msg.alen; + } else if (!(msg.flags & I2C_M_READ) && msg.len) { + writew(*(msg.buf++), &twi->xmt_data8); + --msg.len; + } + + /* clear int stat */ + writew(-1, &twi->master_stat); + writew(-1, &twi->int_stat); + writew(0, &twi->int_mask); + + /* Master enable */ + ctl = readw(&twi->master_ctl); + ctl = (ctl & FAST) | (min(len, 0xff) << 6) | MEN | + ((msg.flags & I2C_M_READ) ? MDIR : 0); + writew(ctl, &twi->master_ctl); + + /* process the rest */ + ret = wait_for_completion(twi, &msg); + + if (ret) { + ctl = readw(&twi->master_ctl) & ~MEN; + writew(ctl, &twi->master_ctl); + ctl = readw(&twi->control) & ~TWI_ENA; + writew(ctl, &twi->control); + ctl = readw(&twi->control) | TWI_ENA; + writew(ctl, &twi->control); + } + + return ret; +} + +static uint adi_i2c_setspeed(struct i2c_adapter *adap, uint speed) +{ + struct twi_regs *twi = i2c_get_base(adap); + u16 clkdiv = I2C_SPEED_TO_DUTY(speed); + + /* Set TWI interface clock */ + if (clkdiv < I2C_DUTY_MAX || clkdiv > I2C_DUTY_MIN) + return -1; + clkdiv = (clkdiv << 8) | (clkdiv & 0xff); + writew(clkdiv, &twi->clkdiv); + + /* Don't turn it on */ + writew(speed > 100000 ? FAST : 0, &twi->master_ctl); + + return 0; +} + +static void adi_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr) +{ + struct twi_regs *twi = i2c_get_base(adap); + u16 prescale = ((get_i2c_clk() / 1000 / 1000 + 5) / 10) & 0x7F; + + /* Set TWI internal clock as 10MHz */ + writew(prescale, &twi->control); + + /* Set TWI interface clock as specified */ + i2c_set_bus_speed(speed); + + /* Enable it */ + writew(TWI_ENA | prescale, &twi->control); +} + +static int adi_i2c_read(struct i2c_adapter *adap, uint8_t chip, + uint addr, int alen, uint8_t *buffer, int len) +{ + return i2c_transfer(adap, chip, addr, alen, buffer, + len, alen ? I2C_M_COMBO : I2C_M_READ); +} + +static int adi_i2c_write(struct i2c_adapter *adap, uint8_t chip, + uint addr, int alen, uint8_t *buffer, int len) +{ + return i2c_transfer(adap, chip, addr, alen, buffer, len, 0); +} + +static int adi_i2c_probe(struct i2c_adapter *adap, uint8_t chip) +{ + u8 byte; + return adi_i2c_read(adap, chip, 0, 0, &byte, 1); +} + +static struct twi_regs *i2c_get_base(struct i2c_adapter *adap) +{ + switch (adap->hwadapnr) { +#if CONFIG_SYS_MAX_I2C_BUS > 2 + case 2: + return (struct twi_regs *)TWI2_CLKDIV; +#endif +#if CONFIG_SYS_MAX_I2C_BUS > 1 + case 1: + return (struct twi_regs *)TWI1_CLKDIV; +#endif + case 0: + return (struct twi_regs *)TWI0_CLKDIV; + + default: + printf("wrong hwadapnr: %d\n", adap->hwadapnr); + } + + return NULL; +} + +U_BOOT_I2C_ADAP_COMPLETE(adi_i2c0, adi_i2c_init, adi_i2c_probe, + adi_i2c_read, adi_i2c_write, + adi_i2c_setspeed, + CONFIG_SYS_I2C_SPEED, + 0, + 0) + +#if CONFIG_SYS_MAX_I2C_BUS > 1 +U_BOOT_I2C_ADAP_COMPLETE(adi_i2c1, adi_i2c_init, adi_i2c_probe, + adi_i2c_read, adi_i2c_write, + adi_i2c_setspeed, + CONFIG_SYS_I2C_SPEED, + 0, + 1) +#endif + +#if CONFIG_SYS_MAX_I2C_BUS > 2 +U_BOOT_I2C_ADAP_COMPLETE(adi_i2c2, adi_i2c_init, adi_i2c_probe, + adi_i2c_read, adi_i2c_write, + adi_i2c_setspeed, + CONFIG_SYS_I2C_SPEED, + 0, + 2) +#endif diff --git a/drivers/i2c/bfin-twi_i2c.c b/drivers/i2c/bfin-twi_i2c.c deleted file mode 100644 index cfab064dfad..00000000000 --- a/drivers/i2c/bfin-twi_i2c.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - * i2c.c - driver for Blackfin on-chip TWI/I2C - * - * Copyright (c) 2006-2010 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#include <common.h> -#include <i2c.h> - -#include <asm/blackfin.h> -#include <asm/clock.h> -#include <asm/mach-common/bits/twi.h> - -/* Every register is 32bit aligned, but only 16bits in size */ -#define ureg(name) u16 name; u16 __pad_##name; -struct twi_regs { - ureg(clkdiv); - ureg(control); - ureg(slave_ctl); - ureg(slave_stat); - ureg(slave_addr); - ureg(master_ctl); - ureg(master_stat); - ureg(master_addr); - ureg(int_stat); - ureg(int_mask); - ureg(fifo_ctl); - ureg(fifo_stat); - char __pad[0x50]; - ureg(xmt_data8); - ureg(xmt_data16); - ureg(rcv_data8); - ureg(rcv_data16); -}; -#undef ureg - -/* U-Boot I2C framework allows only one active device at a time. */ -#ifdef TWI_CLKDIV -#define TWI0_CLKDIV TWI_CLKDIV -#endif -static volatile struct twi_regs *twi = (void *)TWI0_CLKDIV; - -#ifdef DEBUG -# define dmemset(s, c, n) memset(s, c, n) -#else -# define dmemset(s, c, n) -#endif -#define debugi(fmt, args...) \ - debug( \ - "MSTAT:0x%03x FSTAT:0x%x ISTAT:0x%02x\t%-20s:%-3i: " fmt "\n", \ - twi->master_stat, twi->fifo_stat, twi->int_stat, \ - __func__, __LINE__, ## args) - -#ifdef CONFIG_TWICLK_KHZ -# error do not define CONFIG_TWICLK_KHZ ... use CONFIG_SYS_I2C_SPEED -#endif - -/* - * The way speed is changed into duty often results in integer truncation - * with 50% duty, so we'll force rounding up to the next duty by adding 1 - * to the max. In practice this will get us a speed of something like - * 385 KHz. The other limit is easy to handle as it is only 8 bits. - */ -#define I2C_SPEED_MAX 400000 -#define I2C_SPEED_TO_DUTY(speed) (5000000 / (speed)) -#define I2C_DUTY_MAX (I2C_SPEED_TO_DUTY(I2C_SPEED_MAX) + 1) -#define I2C_DUTY_MIN 0xff /* 8 bit limited */ -#define SYS_I2C_DUTY I2C_SPEED_TO_DUTY(CONFIG_SYS_I2C_SPEED) -/* Note: duty is inverse of speed, so the comparisons below are correct */ -#if SYS_I2C_DUTY < I2C_DUTY_MAX || SYS_I2C_DUTY > I2C_DUTY_MIN -# error "The Blackfin I2C hardware can only operate 20KHz - 400KHz" -#endif - -/* All transfers are described by this data structure */ -struct i2c_msg { - u8 flags; -#define I2C_M_COMBO 0x4 -#define I2C_M_STOP 0x2 -#define I2C_M_READ 0x1 - int len; /* msg length */ - u8 *buf; /* pointer to msg data */ - int alen; /* addr length */ - u8 *abuf; /* addr buffer */ -}; - -/* Allow msec timeout per ~byte transfer */ -#define I2C_TIMEOUT 10 - -/** - * wait_for_completion - manage the actual i2c transfer - * @msg: the i2c msg - */ -static int wait_for_completion(struct i2c_msg *msg) -{ - uint16_t int_stat; - ulong timebase = get_timer(0); - - do { - int_stat = twi->int_stat; - - if (int_stat & XMTSERV) { - debugi("processing XMTSERV"); - twi->int_stat = XMTSERV; - SSYNC(); - if (msg->alen) { - twi->xmt_data8 = *(msg->abuf++); - --msg->alen; - } else if (!(msg->flags & I2C_M_COMBO) && msg->len) { - twi->xmt_data8 = *(msg->buf++); - --msg->len; - } else { - twi->master_ctl |= (msg->flags & I2C_M_COMBO) ? RSTART | MDIR : STOP; - SSYNC(); - } - } - if (int_stat & RCVSERV) { - debugi("processing RCVSERV"); - twi->int_stat = RCVSERV; - SSYNC(); - if (msg->len) { - *(msg->buf++) = twi->rcv_data8; - --msg->len; - } else if (msg->flags & I2C_M_STOP) { - twi->master_ctl |= STOP; - SSYNC(); - } - } - if (int_stat & MERR) { - debugi("processing MERR"); - twi->int_stat = MERR; - SSYNC(); - return msg->len; - } - if (int_stat & MCOMP) { - debugi("processing MCOMP"); - twi->int_stat = MCOMP; - SSYNC(); - if (msg->flags & I2C_M_COMBO && msg->len) { - twi->master_ctl = (twi->master_ctl & ~RSTART) | - (min(msg->len, 0xff) << 6) | MEN | MDIR; - SSYNC(); - } else - break; - } - - /* If we were able to do something, reset timeout */ - if (int_stat) - timebase = get_timer(0); - - } while (get_timer(timebase) < I2C_TIMEOUT); - - return msg->len; -} - -/** - * i2c_transfer - setup an i2c transfer - * @return: 0 if things worked, non-0 if things failed - * - * Here we just get the i2c stuff all prepped and ready, and then tail off - * into wait_for_completion() for all the bits to go. - */ -static int i2c_transfer(uchar chip, uint addr, int alen, uchar *buffer, int len, u8 flags) -{ - uchar addr_buffer[] = { - (addr >> 0), - (addr >> 8), - (addr >> 16), - }; - struct i2c_msg msg = { - .flags = flags | (len >= 0xff ? I2C_M_STOP : 0), - .buf = buffer, - .len = len, - .abuf = addr_buffer, - .alen = alen, - }; - int ret; - - dmemset(buffer, 0xff, len); - debugi("chip=0x%x addr=0x%02x alen=%i buf[0]=0x%02x len=%i flags=0x%02x[%s] ", - chip, addr, alen, buffer[0], len, flags, (flags & I2C_M_READ ? "rd" : "wr")); - - /* wait for things to settle */ - while (twi->master_stat & BUSBUSY) - if (ctrlc()) - return 1; - - /* Set Transmit device address */ - twi->master_addr = chip; - - /* Clear the FIFO before starting things */ - twi->fifo_ctl = XMTFLUSH | RCVFLUSH; - SSYNC(); - twi->fifo_ctl = 0; - SSYNC(); - - /* prime the pump */ - if (msg.alen) { - len = (msg.flags & I2C_M_COMBO) ? msg.alen : msg.alen + len; - debugi("first byte=0x%02x", *msg.abuf); - twi->xmt_data8 = *(msg.abuf++); - --msg.alen; - } else if (!(msg.flags & I2C_M_READ) && msg.len) { - debugi("first byte=0x%02x", *msg.buf); - twi->xmt_data8 = *(msg.buf++); - --msg.len; - } - - /* clear int stat */ - twi->master_stat = -1; - twi->int_stat = -1; - twi->int_mask = 0; - SSYNC(); - - /* Master enable */ - twi->master_ctl = - (twi->master_ctl & FAST) | - (min(len, 0xff) << 6) | MEN | - ((msg.flags & I2C_M_READ) ? MDIR : 0); - SSYNC(); - debugi("CTL=0x%04x", twi->master_ctl); - - /* process the rest */ - ret = wait_for_completion(&msg); - debugi("ret=%d", ret); - - if (ret) { - twi->master_ctl &= ~MEN; - twi->control &= ~TWI_ENA; - SSYNC(); - twi->control |= TWI_ENA; - SSYNC(); - } - - return ret; -} - -/** - * i2c_set_bus_speed - set i2c bus speed - * @speed: bus speed (in HZ) - */ -int i2c_set_bus_speed(unsigned int speed) -{ - u16 clkdiv = I2C_SPEED_TO_DUTY(speed); - - /* Set TWI interface clock */ - if (clkdiv < I2C_DUTY_MAX || clkdiv > I2C_DUTY_MIN) - return -1; - twi->clkdiv = (clkdiv << 8) | (clkdiv & 0xff); - - /* Don't turn it on */ - twi->master_ctl = (speed > 100000 ? FAST : 0); - - return 0; -} - -/** - * i2c_get_bus_speed - get i2c bus speed - * @speed: bus speed (in HZ) - */ -unsigned int i2c_get_bus_speed(void) -{ - /* 10 MHz / (2 * CLKDIV) -> 5 MHz / CLKDIV */ - return 5000000 / (twi->clkdiv & 0xff); -} - -/** - * i2c_init - initialize the i2c bus - * @speed: bus speed (in HZ) - * @slaveaddr: address of device in slave mode (0 - not slave) - * - * Slave mode isn't actually implemented. It'll stay that way until - * we get a real request for it. - */ -void i2c_init(int speed, int slaveaddr) -{ - uint8_t prescale = ((get_i2c_clk() / 1000 / 1000 + 5) / 10) & 0x7F; - - /* Set TWI internal clock as 10MHz */ - twi->control = prescale; - - /* Set TWI interface clock as specified */ - i2c_set_bus_speed(speed); - - /* Enable it */ - twi->control = TWI_ENA | prescale; - SSYNC(); - - debugi("CONTROL:0x%04x CLKDIV:0x%04x", twi->control, twi->clkdiv); - -#if CONFIG_SYS_I2C_SLAVE -# error I2C slave support not tested/supported - /* If they want us as a slave, do it */ - if (slaveaddr) { - twi->slave_addr = slaveaddr; - twi->slave_ctl = SEN; - } -#endif -} - -/** - * i2c_probe - test if a chip exists at a given i2c address - * @chip: i2c chip addr to search for - * @return: 0 if found, non-0 if not found - */ -int i2c_probe(uchar chip) -{ - u8 byte; - return i2c_read(chip, 0, 0, &byte, 1); -} - -/** - * i2c_read - read data from an i2c device - * @chip: i2c chip addr - * @addr: memory (register) address in the chip - * @alen: byte size of address - * @buffer: buffer to store data read from chip - * @len: how many bytes to read - * @return: 0 on success, non-0 on failure - */ -int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) -{ - return i2c_transfer(chip, addr, alen, buffer, len, (alen ? I2C_M_COMBO : I2C_M_READ)); -} - -/** - * i2c_write - write data to an i2c device - * @chip: i2c chip addr - * @addr: memory (register) address in the chip - * @alen: byte size of address - * @buffer: buffer holding data to write to chip - * @len: how many bytes to write - * @return: 0 on success, non-0 on failure - */ -int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) -{ - return i2c_transfer(chip, addr, alen, buffer, len, 0); -} - -/** - * i2c_set_bus_num - change active I2C bus - * @bus: bus index, zero based - * @returns: 0 on success, non-0 on failure - */ -int i2c_set_bus_num(unsigned int bus) -{ - switch (bus) { -#if CONFIG_SYS_MAX_I2C_BUS > 0 - case 0: twi = (void *)TWI0_CLKDIV; return 0; -#endif -#if CONFIG_SYS_MAX_I2C_BUS > 1 - case 1: twi = (void *)TWI1_CLKDIV; return 0; -#endif -#if CONFIG_SYS_MAX_I2C_BUS > 2 - case 2: twi = (void *)TWI2_CLKDIV; return 0; -#endif - default: return -1; - } -} - -/** - * i2c_get_bus_num - returns index of active I2C bus - */ -unsigned int i2c_get_bus_num(void) -{ - switch ((unsigned long)twi) { -#if CONFIG_SYS_MAX_I2C_BUS > 0 - case TWI0_CLKDIV: return 0; -#endif -#if CONFIG_SYS_MAX_I2C_BUS > 1 - case TWI1_CLKDIV: return 1; -#endif -#if CONFIG_SYS_MAX_I2C_BUS > 2 - case TWI2_CLKDIV: return 2; -#endif - default: return -1; - } -} diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c index 7bb1702bba2..ff7f25a0ef7 100644 --- a/drivers/i2c/fsl_i2c.c +++ b/drivers/i2c/fsl_i2c.c @@ -127,7 +127,7 @@ static const struct { static unsigned int set_i2c_bus_speed(const struct fsl_i2c *dev, unsigned int i2c_clk, unsigned int speed) { - unsigned short divider = min(i2c_clk / speed, (unsigned short) -1); + unsigned short divider = min(i2c_clk / speed, (unsigned int)USHRT_MAX); /* * We want to choose an FDR/DFSR that generates an I2C bus speed that diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index 521edfd5de5..9b4effb2fb5 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -701,6 +701,7 @@ static int cros_ec_check_version(struct cros_ec_dev *dev) /* Try sending a version 3 packet */ dev->protocol_version = 3; + req.in_data = 0; if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req), (uint8_t **)&resp, sizeof(*resp)) > 0) { return 0; diff --git a/drivers/misc/cros_ec_spi.c b/drivers/misc/cros_ec_spi.c index e403664bb56..e6dba298b1e 100644 --- a/drivers/misc/cros_ec_spi.c +++ b/drivers/misc/cros_ec_spi.c @@ -143,7 +143,7 @@ int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, return -1; } - len = min(p[1], din_len); + len = min((int)p[1], din_len); cros_ec_dump_data("in", -1, p, len + 3); /* Response code is first byte of message */ diff --git a/drivers/misc/mxc_ocotp.c b/drivers/misc/mxc_ocotp.c index 3de12456996..89737af9b73 100644 --- a/drivers/misc/mxc_ocotp.c +++ b/drivers/misc/mxc_ocotp.c @@ -122,8 +122,8 @@ static void set_timing(struct ocotp_regs *regs) relax = DIV_ROUND_UP(ipg_clk * BV_TIMING_RELAX_NS, 1000000000) - 1; strobe_read = DIV_ROUND_UP(ipg_clk * BV_TIMING_STROBE_READ_NS, 1000000000) + 2 * (relax + 1) - 1; - strobe_prog = DIV_ROUND(ipg_clk * BV_TIMING_STROBE_PROG_US, 1000000) + - 2 * (relax + 1) - 1; + strobe_prog = DIV_ROUND_CLOSEST(ipg_clk * BV_TIMING_STROBE_PROG_US, + 1000000) + 2 * (relax + 1) - 1; timing = BF(strobe_read, TIMING_STROBE_READ) | BF(relax, TIMING_RELAX) | diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index 26406072482..cb46b13cbd3 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -23,6 +23,13 @@ DECLARE_GLOBAL_DATA_PTR; +#define SDHCI_IRQ_EN_BITS (IRQSTATEN_CC | IRQSTATEN_TC | \ + IRQSTATEN_CINT | \ + IRQSTATEN_CTOE | IRQSTATEN_CCE | IRQSTATEN_CEBE | \ + IRQSTATEN_CIE | IRQSTATEN_DTOE | IRQSTATEN_DCE | \ + IRQSTATEN_DEBE | IRQSTATEN_BRR | IRQSTATEN_BWR | \ + IRQSTATEN_DINT) + struct fsl_esdhc { uint dsaddr; /* SDMA system address register */ uint blkattr; /* Block attributes register */ @@ -558,6 +565,7 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) esdhc_setbits32(®s->sysctl, SYSCTL_PEREN | SYSCTL_HCKEN | SYSCTL_IPGEN | SYSCTL_CKEN); + writel(SDHCI_IRQ_EN_BITS, ®s->irqstaten); memset(&cfg->cfg, 0, sizeof(cfg->cfg)); voltage_caps = 0; @@ -610,7 +618,7 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) #endif cfg->cfg.f_min = 400000; - cfg->cfg.f_max = min(gd->arch.sdhc_clk, 52000000); + cfg->cfg.f_max = min(gd->arch.sdhc_clk, (u32)52000000); cfg->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; diff --git a/drivers/mmc/pxa_mmc_gen.c b/drivers/mmc/pxa_mmc_gen.c index 1f297571e56..25ab0b1fc8e 100644 --- a/drivers/mmc/pxa_mmc_gen.c +++ b/drivers/mmc/pxa_mmc_gen.c @@ -197,7 +197,7 @@ static int pxa_mmc_do_read_xfer(struct mmc *mmc, struct mmc_data *data) while (len) { /* The controller has data ready */ if (readl(®s->i_reg) & MMC_I_REG_RXFIFO_RD_REQ) { - size = min(len, PXAMMC_FIFO_SIZE); + size = min(len, (uint32_t)PXAMMC_FIFO_SIZE); len -= size; size /= 4; @@ -233,14 +233,14 @@ static int pxa_mmc_do_write_xfer(struct mmc *mmc, struct mmc_data *data) while (len) { /* The controller is ready to receive data */ if (readl(®s->i_reg) & MMC_I_REG_TXFIFO_WR_REQ) { - size = min(len, PXAMMC_FIFO_SIZE); + size = min(len, (uint32_t)PXAMMC_FIFO_SIZE); len -= size; size /= 4; while (size--) writel(*buf++, ®s->txfifo); - if (min(len, PXAMMC_FIFO_SIZE) < 32) + if (min(len, (uint32_t)PXAMMC_FIFO_SIZE) < 32) writel(MMC_PRTBUF_BUF_PART_FULL, ®s->prtbuf); } diff --git a/drivers/mtd/cfi_mtd.c b/drivers/mtd/cfi_mtd.c index ac805ff1e9c..709a48642d6 100644 --- a/drivers/mtd/cfi_mtd.c +++ b/drivers/mtd/cfi_mtd.c @@ -226,6 +226,7 @@ int cfi_mtd_init(void) mtd->flags = MTD_CAP_NORFLASH; mtd->size = fi->size; mtd->writesize = 1; + mtd->writebufsize = mtd->writesize; mtd->_erase = cfi_mtd_erase; mtd->_read = cfi_mtd_read; diff --git a/drivers/mtd/jedec_flash.c b/drivers/mtd/jedec_flash.c index 593b9b8433a..ce9af8f2541 100644 --- a/drivers/mtd/jedec_flash.c +++ b/drivers/mtd/jedec_flash.c @@ -333,6 +333,57 @@ static const struct amd_flash_info jedec_table[] = { } }, { + .mfr_id = (u16)AMD_MANUFACT, + .dev_id = AM29LV800BT, + .name = "AMD AM29LV800BT", + .uaddr = { + [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = CFI_CMDSET_AMD_LEGACY, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000, 15), + ERASEINFO(0x08000, 1), + ERASEINFO(0x02000, 2), + ERASEINFO(0x04000, 1), + } + }, + { + .mfr_id = (u16)MX_MANUFACT, + .dev_id = AM29LV800BT, + .name = "MXIC MX29LV800BT", + .uaddr = { + [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = CFI_CMDSET_AMD_LEGACY, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000, 15), + ERASEINFO(0x08000, 1), + ERASEINFO(0x02000, 2), + ERASEINFO(0x04000, 1), + } + }, + { + .mfr_id = (u16)EON_ALT_MANU, + .dev_id = AM29LV800BT, + .name = "EON EN29LV800BT", + .uaddr = { + [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = CFI_CMDSET_AMD_LEGACY, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000, 15), + ERASEINFO(0x08000, 1), + ERASEINFO(0x02000, 2), + ERASEINFO(0x04000, 1), + } + }, + { .mfr_id = (u16)STM_MANUFACT, .dev_id = STM29F400BB, .name = "ST Micro M29F400BB", diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 9114a86da2b..620b6e8ff9a 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -18,6 +18,7 @@ #include <malloc.h> #include <nand.h> #include <watchdog.h> +#include <linux/mtd/nand_ecc.h> #ifdef CONFIG_ATMEL_NAND_HWECC @@ -762,6 +763,62 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host, } #endif +#if defined(NO_GALOIS_TABLE_IN_ROM) +static uint16_t *pmecc_galois_table; +static inline int deg(unsigned int poly) +{ + /* polynomial degree is the most-significant bit index */ + return fls(poly) - 1; +} + +static int build_gf_tables(int mm, unsigned int poly, + int16_t *index_of, int16_t *alpha_to) +{ + unsigned int i, x = 1; + const unsigned int k = 1 << deg(poly); + unsigned int nn = (1 << mm) - 1; + + /* primitive polynomial must be of degree m */ + if (k != (1u << mm)) + return -EINVAL; + + for (i = 0; i < nn; i++) { + alpha_to[i] = x; + index_of[x] = i; + if (i && (x == 1)) + /* polynomial is not primitive (a^i=1 with 0<i<2^m-1) */ + return -EINVAL; + x <<= 1; + if (x & k) + x ^= poly; + } + + alpha_to[nn] = 1; + index_of[0] = 0; + + return 0; +} + +static uint16_t *create_lookup_table(int sector_size) +{ + int degree = (sector_size == 512) ? + PMECC_GF_DIMENSION_13 : + PMECC_GF_DIMENSION_14; + unsigned int poly = (sector_size == 512) ? + PMECC_GF_13_PRIMITIVE_POLY : + PMECC_GF_14_PRIMITIVE_POLY; + int table_size = (sector_size == 512) ? + PMECC_INDEX_TABLE_SIZE_512 : + PMECC_INDEX_TABLE_SIZE_1024; + + int16_t *addr = kzalloc(2 * table_size * sizeof(uint16_t), GFP_KERNEL); + if (addr && build_gf_tables(degree, poly, addr, addr + table_size)) + return NULL; + + return (uint16_t *)addr; +} +#endif + static int atmel_pmecc_nand_init_params(struct nand_chip *nand, struct mtd_info *mtd) { @@ -809,11 +866,18 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand, sector_size = host->pmecc_sector_size; /* TODO: need check whether cap & sector_size is validate */ - +#if defined(NO_GALOIS_TABLE_IN_ROM) + /* + * As pmecc_rom_base is the begin of the gallois field table, So the + * index offset just set as 0. + */ + host->pmecc_index_table_offset = 0; +#else if (host->pmecc_sector_size == 512) host->pmecc_index_table_offset = ATMEL_PMECC_INDEX_OFFSET_512; else host->pmecc_index_table_offset = ATMEL_PMECC_INDEX_OFFSET_1024; +#endif MTDDEBUG(MTD_DEBUG_LEVEL1, "Initialize PMECC params, cap: %d, sector: %d\n", @@ -822,7 +886,17 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand, host->pmecc = (struct pmecc_regs __iomem *) ATMEL_BASE_PMECC; host->pmerrloc = (struct pmecc_errloc_regs __iomem *) ATMEL_BASE_PMERRLOC; +#if defined(NO_GALOIS_TABLE_IN_ROM) + pmecc_galois_table = create_lookup_table(host->pmecc_sector_size); + if (!pmecc_galois_table) { + dev_err(host->dev, "out of memory\n"); + return -ENOMEM; + } + + host->pmecc_rom_base = (void __iomem *)pmecc_galois_table; +#else host->pmecc_rom_base = (void __iomem *) ATMEL_BASE_ROM; +#endif /* ECC is calculated for the whole page (1 step) */ nand->ecc.size = mtd->writesize; @@ -1187,7 +1261,7 @@ static int nand_command(int block, int page, uint32_t offs, u8 cmd) void (*hwctrl)(struct mtd_info *mtd, int cmd, unsigned int ctrl) = this->cmd_ctrl; - while (this->dev_ready(&mtd)) + while (!this->dev_ready(&mtd)) ; if (cmd == NAND_CMD_READOOB) { @@ -1212,7 +1286,7 @@ static int nand_command(int block, int page, uint32_t offs, u8 cmd) hwctrl(&mtd, NAND_CMD_READSTART, NAND_CTRL_CLE | NAND_CTRL_CHANGE); hwctrl(&mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - while (this->dev_ready(&mtd)) + while (!this->dev_ready(&mtd)) ; return 0; @@ -1273,6 +1347,39 @@ static int nand_read_page(int block, int page, void *dst) return 0; } + +int spl_nand_erase_one(int block, int page) +{ + struct nand_chip *this = mtd.priv; + void (*hwctrl)(struct mtd_info *mtd, int cmd, + unsigned int ctrl) = this->cmd_ctrl; + int page_addr; + + if (nand_chip.select_chip) + nand_chip.select_chip(&mtd, 0); + + page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT; + hwctrl(&mtd, NAND_CMD_ERASE1, NAND_CTRL_CLE | NAND_CTRL_CHANGE); + /* Row address */ + hwctrl(&mtd, (page_addr & 0xff), NAND_CTRL_ALE | NAND_CTRL_CHANGE); + hwctrl(&mtd, ((page_addr >> 8) & 0xff), + NAND_CTRL_ALE | NAND_CTRL_CHANGE); +#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE + /* One more address cycle for devices > 128MiB */ + hwctrl(&mtd, (page_addr >> 16) & 0x0f, + NAND_CTRL_ALE | NAND_CTRL_CHANGE); +#endif + + hwctrl(&mtd, NAND_CMD_ERASE2, NAND_CTRL_CLE | NAND_CTRL_CHANGE); + udelay(2000); + + while (!this->dev_ready(&mtd)) + ; + + nand_deselect(); + + return 0; +} #else static int nand_read_page(int block, int page, void *dst) { @@ -1319,7 +1426,7 @@ int at91_nand_wait_ready(struct mtd_info *mtd) udelay(this->chip_delay); - return 0; + return 1; } int board_nand_init(struct nand_chip *nand) diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h index 92d4ec59fd2..eac860d13ca 100644 --- a/drivers/mtd/nand/atmel_nand_ecc.h +++ b/drivers/mtd/nand/atmel_nand_ecc.h @@ -141,6 +141,10 @@ struct pmecc_errloc_regs { #define PMECC_GF_DIMENSION_13 13 #define PMECC_GF_DIMENSION_14 14 +/* Primitive Polynomial used by PMECC */ +#define PMECC_GF_13_PRIMITIVE_POLY 0x201b +#define PMECC_GF_14_PRIMITIVE_POLY 0x4443 + #define PMECC_INDEX_TABLE_SIZE_512 0x2000 #define PMECC_INDEX_TABLE_SIZE_1024 0x4000 diff --git a/drivers/mtd/nand/denali_spl.c b/drivers/mtd/nand/denali_spl.c index 65fdde8a652..e98f537c2c3 100644 --- a/drivers/mtd/nand/denali_spl.c +++ b/drivers/mtd/nand/denali_spl.c @@ -203,7 +203,7 @@ int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) if (ret < 0) return ret; - readlen = min(page_size - column, size); + readlen = min(page_size - column, (int)size); memcpy(dst, page_buffer, readlen); column = 0; diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c index 1cf2f98310a..3024b988fef 100644 --- a/drivers/mtd/spi/sandbox.c +++ b/drivers/mtd/spi/sandbox.c @@ -315,7 +315,7 @@ int sandbox_erase_part(struct sandbox_spi_flash *sbsf, int size) int ret; while (size > 0) { - todo = min(size, sizeof(sandbox_sf_0xff)); + todo = min(size, (int)sizeof(sandbox_sf_0xff)); ret = os_write(sbsf->fd, sandbox_sf_0xff, todo); if (ret != todo) return ret; @@ -602,14 +602,14 @@ static int sandbox_sf_bind_bus_cs(struct sandbox_state *state, int busnum, spec, ret); return ret; } - ret = device_find_child_by_seq(bus, cs, true, &slave); + ret = spi_find_chip_select(bus, cs, &slave); if (!ret) { printf("Chip select %d already exists for spec '%s'\n", cs, spec); return -EEXIST; } - ret = spi_bind_device(bus, cs, "spi_flash_std", spec, &slave); + ret = device_bind_driver(bus, "spi_flash_std", spec, &slave); if (ret) return ret; diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index 85cf22d42ec..759231f2e34 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -313,10 +313,11 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, return ret; #endif byte_addr = offset % page_size; - chunk_len = min(len - actual, page_size - byte_addr); + chunk_len = min(len - actual, (size_t)(page_size - byte_addr)); if (flash->spi->max_write_size) - chunk_len = min(chunk_len, flash->spi->max_write_size); + chunk_len = min(chunk_len, + (size_t)flash->spi->max_write_size); spi_flash_addr(write_addr, cmd); diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 375c8a4454a..9c2ff487a70 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -525,6 +525,7 @@ static int macb_phy_init(struct macb_device *macb) return 1; } +static int macb_write_hwaddr(struct eth_device *dev); static int macb_init(struct eth_device *netdev, bd_t *bd) { struct macb_device *macb = to_macb(netdev); @@ -565,7 +566,13 @@ static int macb_init(struct eth_device *netdev, bd_t *bd) macb_writel(macb, TBQP, macb->tx_ring_dma); if (macb_is_gem(macb)) { -#ifdef CONFIG_RGMII + /* + * When the GMAC IP with GE feature, this bit is used to + * select interface between RGMII and GMII. + * When the GMAC IP without GE feature, this bit is used + * to select interface between RMII and MII. + */ +#if defined(CONFIG_RGMII) || defined(CONFIG_RMII) gem_writel(macb, UR, GEM_BIT(RGMII)); #else gem_writel(macb, UR, 0); @@ -587,6 +594,14 @@ static int macb_init(struct eth_device *netdev, bd_t *bd) #endif /* CONFIG_RMII */ } + /* update the ethaddr */ + if (is_valid_ether_addr(netdev->enetaddr)) { + macb_write_hwaddr(netdev); + } else { + printf("%s: mac address is not valid\n", netdev->name); + return -1; + } + if (!macb_phy_init(macb)) return -1; diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 623f7492c75..677c89f0486 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -256,7 +256,7 @@ static void nc_puts(struct stdio_dev *dev, const char *s) len = strlen(s); while (len) { - int send_len = min(len, sizeof(input_buffer)); + int send_len = min(len, (int)sizeof(input_buffer)); nc_send_packet(s, send_len); len -= send_len; s += send_len; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 60c333e2c01..7ee21d1c1d1 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -195,6 +195,9 @@ pci_dev_t pci_find_devices(struct pci_device_id *ids, int index) bdf < PCI_BDF(bus + 1, 0, 0); #endif bdf += PCI_BDF(0, 0, 1)) { + if (pci_skip_dev(hose, bdf)) + continue; + if (!PCI_FUNC(bdf)) { pci_read_config_byte(bdf, PCI_HEADER_TYPE, @@ -662,13 +665,15 @@ int pci_hose_scan_bus(struct pci_controller *hose, int bus) #endif #ifdef CONFIG_PCI_PNP - sub_bus = max(pciauto_config_device(hose, dev), sub_bus); + sub_bus = max((unsigned int)pciauto_config_device(hose, dev), + sub_bus); #else cfg = pci_find_config(hose, class, vendor, device, PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev)); if (cfg) { cfg->config_device(hose, dev, cfg); - sub_bus = max(sub_bus, hose->current_busno); + sub_bus = max(sub_bus, + (unsigned int)hose->current_busno); } #endif diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c index 86ba6b523c1..44470fa812b 100644 --- a/drivers/pci/pci_auto.c +++ b/drivers/pci/pci_auto.c @@ -387,7 +387,7 @@ int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev) n = pci_hose_scan_bus(hose, hose->current_busno); /* figure out the deepest we've gone for this leg */ - sub_bus = max(n, sub_bus); + sub_bus = max((unsigned int)n, sub_bus); pciauto_postscan_setup_bridge(hose, dev, sub_bus); sub_bus = hose->current_busno; diff --git a/drivers/serial/atmel_usart.c b/drivers/serial/atmel_usart.c index 8f0e3489a0e..4fe992bf2bf 100644 --- a/drivers/serial/atmel_usart.c +++ b/drivers/serial/atmel_usart.c @@ -7,11 +7,16 @@ * SPDX-License-Identifier: GPL-2.0+ */ #include <common.h> +#include <dm.h> +#include <errno.h> #include <watchdog.h> #include <serial.h> #include <linux/compiler.h> #include <asm/io.h> +#ifdef CONFIG_DM_SERIAL +#include <asm/arch/atmel_serial.h> +#endif #include <asm/arch/clk.h> #include <asm/arch/hardware.h> @@ -19,9 +24,9 @@ DECLARE_GLOBAL_DATA_PTR; -static void atmel_serial_setbrg(void) +static void atmel_serial_setbrg_internal(atmel_usart3_t *usart, int id, + int baudrate) { - atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE; unsigned long divisor; unsigned long usart_hz; @@ -30,15 +35,13 @@ static void atmel_serial_setbrg(void) * Baud Rate = -------------- * 16 * CD */ - usart_hz = get_usart_clk_rate(CONFIG_USART_ID); - divisor = (usart_hz / 16 + gd->baudrate / 2) / gd->baudrate; + usart_hz = get_usart_clk_rate(id); + divisor = (usart_hz / 16 + baudrate / 2) / baudrate; writel(USART3_BF(CD, divisor), &usart->brgr); } -static int atmel_serial_init(void) +static void atmel_serial_init_internal(atmel_usart3_t *usart) { - atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE; - /* * Just in case: drain transmitter register * 1000us is enough for baudrate >= 9600 @@ -47,9 +50,10 @@ static int atmel_serial_init(void) __udelay(1000); writel(USART3_BIT(RSTRX) | USART3_BIT(RSTTX), &usart->cr); +} - serial_setbrg(); - +static void atmel_serial_activate(atmel_usart3_t *usart) +{ writel((USART3_BF(USART_MODE, USART3_USART_MODE_NORMAL) | USART3_BF(USCLKS, USART3_USCLKS_MCK) | USART3_BF(CHRL, USART3_CHRL_8) @@ -59,6 +63,22 @@ static int atmel_serial_init(void) writel(USART3_BIT(RXEN) | USART3_BIT(TXEN), &usart->cr); /* 100us is enough for the new settings to be settled */ __udelay(100); +} + +#ifndef CONFIG_DM_SERIAL +static void atmel_serial_setbrg(void) +{ + atmel_serial_setbrg_internal((atmel_usart3_t *)CONFIG_USART_BASE, + CONFIG_USART_ID, gd->baudrate); +} + +static int atmel_serial_init(void) +{ + atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE; + + atmel_serial_init_internal(usart); + serial_setbrg(); + atmel_serial_activate(usart); return 0; } @@ -109,3 +129,81 @@ __weak struct serial_device *default_serial_console(void) { return &atmel_serial_drv; } +#endif + +#ifdef CONFIG_DM_SERIAL + +struct atmel_serial_priv { + atmel_usart3_t *usart; +}; + +int atmel_serial_setbrg(struct udevice *dev, int baudrate) +{ + struct atmel_serial_priv *priv = dev_get_priv(dev); + + atmel_serial_setbrg_internal(priv->usart, 0 /* ignored */, baudrate); + atmel_serial_activate(priv->usart); + + return 0; +} + +static int atmel_serial_getc(struct udevice *dev) +{ + struct atmel_serial_priv *priv = dev_get_priv(dev); + + if (!(readl(&priv->usart->csr) & USART3_BIT(RXRDY))) + return -EAGAIN; + + return readl(&priv->usart->rhr); +} + +static int atmel_serial_putc(struct udevice *dev, const char ch) +{ + struct atmel_serial_priv *priv = dev_get_priv(dev); + + if (!(readl(&priv->usart->csr) & USART3_BIT(TXRDY))) + return -EAGAIN; + + writel(ch, &priv->usart->thr); + + return 0; +} + +static int atmel_serial_pending(struct udevice *dev, bool input) +{ + struct atmel_serial_priv *priv = dev_get_priv(dev); + uint32_t csr = readl(&priv->usart->csr); + + if (input) + return csr & USART3_BIT(RXRDY) ? 1 : 0; + else + return csr & USART3_BIT(TXEMPTY) ? 0 : 1; +} + +static const struct dm_serial_ops atmel_serial_ops = { + .putc = atmel_serial_putc, + .pending = atmel_serial_pending, + .getc = atmel_serial_getc, + .setbrg = atmel_serial_setbrg, +}; + +static int atmel_serial_probe(struct udevice *dev) +{ + struct atmel_serial_platdata *plat = dev->platdata; + struct atmel_serial_priv *priv = dev_get_priv(dev); + + priv->usart = (atmel_usart3_t *)plat->base_addr; + atmel_serial_init_internal(priv->usart); + + return 0; +} + +U_BOOT_DRIVER(serial_atmel) = { + .name = "serial_atmel", + .id = UCLASS_SERIAL, + .probe = atmel_serial_probe, + .ops = &atmel_serial_ops, + .flags = DM_FLAG_PRE_RELOC, + .priv_auto_alloc_size = sizeof(struct atmel_serial_priv), +}; +#endif diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index 71f1a5cb910..b09053f1402 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -6,6 +6,7 @@ #include <common.h> #include <dm.h> +#include <environment.h> #include <errno.h> #include <fdtdec.h> #include <os.h> @@ -19,8 +20,10 @@ DECLARE_GLOBAL_DATA_PTR; -/* The currently-selected console serial device */ -struct udevice *cur_dev __attribute__ ((section(".data"))); +/* + * Table with supported baudrates (defined in config_xyz.h) + */ +static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE; #ifndef CONFIG_SYS_MALLOC_F_LEN #error "Serial is required before relocation - define CONFIG_SYS_MALLOC_F_LEN to make this work" @@ -28,6 +31,8 @@ struct udevice *cur_dev __attribute__ ((section(".data"))); static void serial_find_console_or_panic(void) { + struct udevice *dev; + #ifdef CONFIG_OF_CONTROL int node; @@ -35,18 +40,21 @@ static void serial_find_console_or_panic(void) node = fdtdec_get_chosen_node(gd->fdt_blob, "stdout-path"); if (node < 0) node = fdtdec_get_alias_node(gd->fdt_blob, "console"); - if (!uclass_get_device_by_of_offset(UCLASS_SERIAL, node, &cur_dev)) + if (!uclass_get_device_by_of_offset(UCLASS_SERIAL, node, &dev)) { + gd->cur_serial_dev = dev; return; + } /* * If the console is not marked to be bound before relocation, bind * it anyway. */ if (node > 0 && - !lists_bind_fdt(gd->dm_root, gd->fdt_blob, node, &cur_dev)) { - if (!device_probe(cur_dev)) + !lists_bind_fdt(gd->dm_root, gd->fdt_blob, node, &dev)) { + if (!device_probe(dev)) { + gd->cur_serial_dev = dev; return; - cur_dev = NULL; + } } #endif /* @@ -61,11 +69,12 @@ static void serial_find_console_or_panic(void) #else #define INDEX 0 #endif - if (uclass_get_device_by_seq(UCLASS_SERIAL, INDEX, &cur_dev) && - uclass_get_device(UCLASS_SERIAL, INDEX, &cur_dev) && - (uclass_first_device(UCLASS_SERIAL, &cur_dev) || !cur_dev)) + if (uclass_get_device_by_seq(UCLASS_SERIAL, INDEX, &dev) && + uclass_get_device(UCLASS_SERIAL, INDEX, &dev) && + (uclass_first_device(UCLASS_SERIAL, &dev) || !dev)) panic("No serial driver found"); #undef INDEX + gd->cur_serial_dev = dev; } /* Called prior to relocation */ @@ -127,40 +136,42 @@ static int _serial_tstc(struct udevice *dev) void serial_putc(char ch) { - _serial_putc(cur_dev, ch); + _serial_putc(gd->cur_serial_dev, ch); } void serial_puts(const char *str) { - _serial_puts(cur_dev, str); + _serial_puts(gd->cur_serial_dev, str); } int serial_getc(void) { - return _serial_getc(cur_dev); + return _serial_getc(gd->cur_serial_dev); } int serial_tstc(void) { - return _serial_tstc(cur_dev); + return _serial_tstc(gd->cur_serial_dev); } void serial_setbrg(void) { - struct dm_serial_ops *ops = serial_get_ops(cur_dev); + struct dm_serial_ops *ops = serial_get_ops(gd->cur_serial_dev); if (ops->setbrg) - ops->setbrg(cur_dev, gd->baudrate); + ops->setbrg(gd->cur_serial_dev, gd->baudrate); } void serial_stdio_init(void) { } +#ifdef CONFIG_DM_STDIO static void serial_stub_putc(struct stdio_dev *sdev, const char ch) { _serial_putc(sdev->priv, ch); } +#endif void serial_stub_puts(struct stdio_dev *sdev, const char *str) { @@ -177,11 +188,74 @@ int serial_stub_tstc(struct stdio_dev *sdev) return _serial_tstc(sdev->priv); } +/** + * on_baudrate() - Update the actual baudrate when the env var changes + * + * This will check for a valid baudrate and only apply it if valid. + */ +static int on_baudrate(const char *name, const char *value, enum env_op op, + int flags) +{ + int i; + int baudrate; + + switch (op) { + case env_op_create: + case env_op_overwrite: + /* + * Switch to new baudrate if new baudrate is supported + */ + baudrate = simple_strtoul(value, NULL, 10); + + /* Not actually changing */ + if (gd->baudrate == baudrate) + return 0; + + for (i = 0; i < ARRAY_SIZE(baudrate_table); ++i) { + if (baudrate == baudrate_table[i]) + break; + } + if (i == ARRAY_SIZE(baudrate_table)) { + if ((flags & H_FORCE) == 0) + printf("## Baudrate %d bps not supported\n", + baudrate); + return 1; + } + if ((flags & H_INTERACTIVE) != 0) { + printf("## Switch baudrate to %d bps and press ENTER ...\n", + baudrate); + udelay(50000); + } + + gd->baudrate = baudrate; + + serial_setbrg(); + + udelay(50000); + + if ((flags & H_INTERACTIVE) != 0) + while (1) { + if (getc() == '\r') + break; + } + + return 0; + case env_op_delete: + printf("## Baudrate may not be deleted\n"); + return 1; + default: + return 0; + } +} +U_BOOT_ENV_CALLBACK(baudrate, on_baudrate); + static int serial_post_probe(struct udevice *dev) { - struct stdio_dev sdev; struct dm_serial_ops *ops = serial_get_ops(dev); +#ifdef CONFIG_DM_STDIO struct serial_dev_priv *upriv = dev->uclass_priv; + struct stdio_dev sdev; +#endif int ret; /* Set the baud rate */ @@ -191,9 +265,9 @@ static int serial_post_probe(struct udevice *dev) return ret; } +#ifdef CONFIG_DM_STDIO if (!(gd->flags & GD_FLG_RELOC)) return 0; - memset(&sdev, '\0', sizeof(sdev)); strncpy(sdev.name, dev->name, sizeof(sdev.name)); @@ -204,7 +278,7 @@ static int serial_post_probe(struct udevice *dev) sdev.getc = serial_stub_getc; sdev.tstc = serial_stub_tstc; stdio_register_dev(&sdev, &upriv->sdev); - +#endif return 0; } diff --git a/drivers/serial/serial_sh.h b/drivers/serial/serial_sh.h index 53406e58554..ef88c8f2733 100644 --- a/drivers/serial/serial_sh.h +++ b/drivers/serial/serial_sh.h @@ -433,7 +433,7 @@ static inline void sci_##name##_out(struct uart_port *port,\ SCI_OUT(sci_size, sci_offset, value);\ } -#if defined(CONFIG_SH3) || \ +#if defined(CONFIG_CPU_SH3) || \ defined(CONFIG_ARCH_SH7367) || \ defined(CONFIG_ARCH_SH7377) || \ defined(CONFIG_ARCH_SH7372) || \ diff --git a/drivers/serial/serial_tegra.c b/drivers/serial/serial_tegra.c index 7eb70e1de13..b9227f05633 100644 --- a/drivers/serial/serial_tegra.c +++ b/drivers/serial/serial_tegra.c @@ -9,6 +9,7 @@ #include <ns16550.h> #include <serial.h> +#ifdef CONFIG_OF_CONTROL static const struct udevice_id tegra_serial_ids[] = { { .compatible = "nvidia,tegra20-uart" }, { } @@ -26,13 +27,28 @@ static int tegra_serial_ofdata_to_platdata(struct udevice *dev) return 0; } +#else +struct ns16550_platdata tegra_serial = { + .base = CONFIG_SYS_NS16550_COM1, + .reg_shift = 2, + .clock = V_NS16550_CLK, +}; + +U_BOOT_DEVICE(ns16550_serial) = { + "serial_tegra20", &tegra_serial +}; +#endif + U_BOOT_DRIVER(serial_ns16550) = { .name = "serial_tegra20", .id = UCLASS_SERIAL, +#ifdef CONFIG_OF_CONTROL .of_match = tegra_serial_ids, .ofdata_to_platdata = tegra_serial_ofdata_to_platdata, .platdata_auto_alloc_size = sizeof(struct ns16550_platdata), +#endif .priv_auto_alloc_size = sizeof(struct NS16550), .probe = ns16550_serial_probe, .ops = &ns16550_serial_ops, + .flags = DM_FLAG_PRE_RELOC, }; diff --git a/drivers/serial/usbtty.c b/drivers/serial/usbtty.c index 7fb0b92078d..75f0ec31bbf 100644 --- a/drivers/serial/usbtty.c +++ b/drivers/serial/usbtty.c @@ -882,7 +882,7 @@ static int write_buffer (circbuf_t * buf) space_avail = current_urb->buffer_length - current_urb->actual_length; - popnum = min(space_avail, buf->size); + popnum = min(space_avail, (int)buf->size); if (popnum == 0) break; diff --git a/drivers/spi/atmel_spi.h b/drivers/spi/atmel_spi.h index d2409454f9f..1538a235a5f 100644 --- a/drivers/spi/atmel_spi.h +++ b/drivers/spi/atmel_spi.h @@ -94,3 +94,7 @@ static inline struct atmel_spi_slave *to_atmel_spi(struct spi_slave *slave) readl(as->regs + ATMEL_SPI_##reg) #define spi_writel(as, reg, value) \ writel(value, as->regs + ATMEL_SPI_##reg) + +#if !defined(CONFIG_SYS_SPI_WRITE_TOUT) +#define CONFIG_SYS_SPI_WRITE_TOUT (5 * CONFIG_SYS_HZ) +#endif diff --git a/drivers/spi/fsl_espi.c b/drivers/spi/fsl_espi.c index ae0fe58f2c0..375dc07f5f4 100644 --- a/drivers/spi/fsl_espi.c +++ b/drivers/spi/fsl_espi.c @@ -273,7 +273,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *data_out, spi_cs_deactivate(slave); return 0; } - buf_len = 2 * cmd_len + min(data_len, max_tran_len); + buf_len = 2 * cmd_len + min(data_len, (size_t)max_tran_len); len = cmd_len + data_len; rx_offset = cmd_len; buffer = (unsigned char *)malloc(buf_len); @@ -306,7 +306,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *data_out, if (data_in) din = buffer + rx_offset; dout = buffer; - tran_len = min(data_len , max_tran_len); + tran_len = min(data_len, (size_t)max_tran_len); num_blks = DIV_ROUND_UP(tran_len + cmd_len, 4); num_bytes = (tran_len + cmd_len) % 4; fsl->data_len = tran_len + cmd_len; diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index 23f2ba6223d..08815994fe5 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -315,7 +315,7 @@ int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen, tmp = reg_read(®s->rxdata); data = cpu_to_be32(tmp); debug("SPI Rx: 0x%x 0x%x\n", tmp, data); - cnt = min(nbytes, sizeof(data)); + cnt = min_t(u32, nbytes, sizeof(data)); if (din) { memcpy(din, &data, cnt); din += cnt; diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index 13c6b77d73d..7a57bceb260 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -57,7 +57,7 @@ int spi_claim_bus(struct spi_slave *slave) speed = slave->max_hz; if (spi->max_hz) { if (speed) - speed = min(speed, spi->max_hz); + speed = min(speed, (int)spi->max_hz); else speed = spi->max_hz; } @@ -115,16 +115,7 @@ int spi_chip_select(struct udevice *dev) return slave ? slave->cs : -ENOENT; } -/** - * spi_find_chip_select() - Find the slave attached to chip select - * - * @bus: SPI bus to search - * @cs: Chip select to look for - * @devp: Returns the slave device if found - * @return 0 if found, -ENODEV on error - */ -static int spi_find_chip_select(struct udevice *bus, int cs, - struct udevice **devp) +int spi_find_chip_select(struct udevice *bus, int cs, struct udevice **devp) { struct udevice *dev; @@ -197,27 +188,6 @@ int spi_cs_info(struct udevice *bus, uint cs, struct spi_cs_info *info) return -ENODEV; } -int spi_bind_device(struct udevice *bus, int cs, const char *drv_name, - const char *dev_name, struct udevice **devp) -{ - struct driver *drv; - int ret; - - drv = lists_driver_lookup_name(drv_name); - if (!drv) { - printf("Cannot find driver '%s'\n", drv_name); - return -ENOENT; - } - ret = device_bind(bus, drv, dev_name, NULL, -1, devp); - if (ret) { - printf("Cannot create device named '%s' (err=%d)\n", - dev_name, ret); - return ret; - } - - return 0; -} - int spi_find_bus_and_cs(int busnum, int cs, struct udevice **busp, struct udevice **devp) { @@ -264,7 +234,7 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, if (ret == -ENODEV && drv_name) { debug("%s: Binding new device '%s', busnum=%d, cs=%d, driver=%s\n", __func__, dev_name, busnum, cs, drv_name); - ret = spi_bind_device(bus, cs, drv_name, dev_name, &dev); + ret = device_bind_driver(bus, drv_name, dev_name, &dev); if (ret) return ret; created = true; diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile new file mode 100644 index 00000000000..6d4cacdcf7f --- /dev/null +++ b/drivers/thermal/Makefile @@ -0,0 +1,9 @@ +# +# (C) Copyright 2014 Freescale Semiconductor, Inc. +# Author: Nitin Garg <nitin.garg@freescale.com> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_DM_THERMAL) += thermal-uclass.o +obj-$(CONFIG_IMX6_THERMAL) += imx_thermal.o diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c new file mode 100644 index 00000000000..116158511db --- /dev/null +++ b/drivers/thermal/imx_thermal.c @@ -0,0 +1,177 @@ +/* + * (C) Copyright 2014 Freescale Semiconductor, Inc. + * Author: Nitin Garg <nitin.garg@freescale.com> + * Ye Li <Ye.Li@freescale.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <config.h> +#include <common.h> +#include <div64.h> +#include <fuse.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <dm.h> +#include <errno.h> +#include <malloc.h> +#include <thermal.h> +#include <imx_thermal.h> + +#define TEMPERATURE_MIN -40 +#define TEMPERATURE_HOT 80 +#define TEMPERATURE_MAX 125 +#define FACTOR0 10000000 +#define FACTOR1 15976 +#define FACTOR2 4297157 +#define MEASURE_FREQ 327 + +#define TEMPSENSE0_TEMP_CNT_SHIFT 8 +#define TEMPSENSE0_TEMP_CNT_MASK (0xfff << TEMPSENSE0_TEMP_CNT_SHIFT) +#define TEMPSENSE0_FINISHED (1 << 2) +#define TEMPSENSE0_MEASURE_TEMP (1 << 1) +#define TEMPSENSE0_POWER_DOWN (1 << 0) +#define MISC0_REFTOP_SELBIASOFF (1 << 3) +#define TEMPSENSE1_MEASURE_FREQ 0xffff + +static int read_cpu_temperature(struct udevice *dev) +{ + int temperature; + unsigned int reg, n_meas; + const struct imx_thermal_plat *pdata = dev_get_platdata(dev); + struct anatop_regs *anatop = (struct anatop_regs *)pdata->regs; + unsigned int *priv = dev_get_priv(dev); + u32 fuse = *priv; + int t1, n1; + u32 c1, c2; + u64 temp64; + + /* + * Sensor data layout: + * [31:20] - sensor value @ 25C + * We use universal formula now and only need sensor value @ 25C + * slope = 0.4297157 - (0.0015976 * 25C fuse) + */ + n1 = fuse >> 20; + t1 = 25; /* t1 always 25C */ + + /* + * Derived from linear interpolation: + * slope = 0.4297157 - (0.0015976 * 25C fuse) + * slope = (FACTOR2 - FACTOR1 * n1) / FACTOR0 + * (Nmeas - n1) / (Tmeas - t1) = slope + * We want to reduce this down to the minimum computation necessary + * for each temperature read. Also, we want Tmeas in millicelsius + * and we don't want to lose precision from integer division. So... + * Tmeas = (Nmeas - n1) / slope + t1 + * milli_Tmeas = 1000 * (Nmeas - n1) / slope + 1000 * t1 + * milli_Tmeas = -1000 * (n1 - Nmeas) / slope + 1000 * t1 + * Let constant c1 = (-1000 / slope) + * milli_Tmeas = (n1 - Nmeas) * c1 + 1000 * t1 + * Let constant c2 = n1 *c1 + 1000 * t1 + * milli_Tmeas = c2 - Nmeas * c1 + */ + temp64 = FACTOR0; + temp64 *= 1000; + do_div(temp64, FACTOR1 * n1 - FACTOR2); + c1 = temp64; + c2 = n1 * c1 + 1000 * t1; + + /* + * now we only use single measure, every time we read + * the temperature, we will power on/down anadig thermal + * module + */ + writel(TEMPSENSE0_POWER_DOWN, &anatop->tempsense0_clr); + writel(MISC0_REFTOP_SELBIASOFF, &anatop->ana_misc0_set); + + /* setup measure freq */ + reg = readl(&anatop->tempsense1); + reg &= ~TEMPSENSE1_MEASURE_FREQ; + reg |= MEASURE_FREQ; + writel(reg, &anatop->tempsense1); + + /* start the measurement process */ + writel(TEMPSENSE0_MEASURE_TEMP, &anatop->tempsense0_clr); + writel(TEMPSENSE0_FINISHED, &anatop->tempsense0_clr); + writel(TEMPSENSE0_MEASURE_TEMP, &anatop->tempsense0_set); + + /* make sure that the latest temp is valid */ + while ((readl(&anatop->tempsense0) & + TEMPSENSE0_FINISHED) == 0) + udelay(10000); + + /* read temperature count */ + reg = readl(&anatop->tempsense0); + n_meas = (reg & TEMPSENSE0_TEMP_CNT_MASK) + >> TEMPSENSE0_TEMP_CNT_SHIFT; + writel(TEMPSENSE0_FINISHED, &anatop->tempsense0_clr); + + /* milli_Tmeas = c2 - Nmeas * c1 */ + temperature = (c2 - n_meas * c1)/1000; + + /* power down anatop thermal sensor */ + writel(TEMPSENSE0_POWER_DOWN, &anatop->tempsense0_set); + writel(MISC0_REFTOP_SELBIASOFF, &anatop->ana_misc0_clr); + + return temperature; +} + +int imx_thermal_get_temp(struct udevice *dev, int *temp) +{ + int cpu_tmp = 0; + + cpu_tmp = read_cpu_temperature(dev); + while (cpu_tmp > TEMPERATURE_MIN && cpu_tmp < TEMPERATURE_MAX) { + if (cpu_tmp >= TEMPERATURE_HOT) { + printf("CPU Temperature is %d C, too hot to boot, waiting...\n", + cpu_tmp); + udelay(5000000); + cpu_tmp = read_cpu_temperature(dev); + } else { + break; + } + } + + *temp = cpu_tmp; + + return 0; +} + +static const struct dm_thermal_ops imx_thermal_ops = { + .get_temp = imx_thermal_get_temp, +}; + +static int imx_thermal_probe(struct udevice *dev) +{ + unsigned int fuse = ~0; + + const struct imx_thermal_plat *pdata = dev_get_platdata(dev); + unsigned int *priv = dev_get_priv(dev); + + /* Read Temperature calibration data fuse */ + fuse_read(pdata->fuse_bank, pdata->fuse_word, &fuse); + + /* Check for valid fuse */ + if (fuse == 0 || fuse == ~0) { + printf("CPU: Thermal invalid data, fuse: 0x%x\n", fuse); + return -EPERM; + } else { + printf("CPU: Thermal calibration data: 0x%x\n", fuse); + } + + *priv = fuse; + + enable_thermal_clk(); + + return 0; +} + +U_BOOT_DRIVER(imx_thermal) = { + .name = "imx_thermal", + .id = UCLASS_THERMAL, + .ops = &imx_thermal_ops, + .probe = imx_thermal_probe, + .priv_auto_alloc_size = sizeof(unsigned int), + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/thermal/thermal-uclass.c b/drivers/thermal/thermal-uclass.c new file mode 100644 index 00000000000..3bee1a7dc7a --- /dev/null +++ b/drivers/thermal/thermal-uclass.c @@ -0,0 +1,30 @@ +/* + * (C) Copyright 2014 Freescale Semiconductor, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <thermal.h> +#include <errno.h> +#include <fdtdec.h> +#include <malloc.h> +#include <asm/io.h> +#include <linux/list.h> + + +int thermal_get_temp(struct udevice *dev, int *temp) +{ + const struct dm_thermal_ops *ops = device_get_ops(dev); + + if (!ops->get_temp) + return -ENOSYS; + + return ops->get_temp(dev, temp); +} + +UCLASS_DRIVER(thermal) = { + .id = UCLASS_THERMAL, + .name = "thermal", +}; diff --git a/drivers/tpm/tpm_tis_lpc.c b/drivers/tpm/tpm_tis_lpc.c index eecf18cbf92..d09f8cee05b 100644 --- a/drivers/tpm/tpm_tis_lpc.c +++ b/drivers/tpm/tpm_tis_lpc.c @@ -274,7 +274,7 @@ static u32 tis_senddata(const u8 * const data, u32 len) * changes to zero exactly after the last byte is fed into the * FIFO. */ - count = min(burst, len - offset - 1); + count = min((u32)burst, len - offset - 1); while (count--) tpm_write_byte(data[offset++], &lpc_tpm_dev[locality].data); diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 7bd25629c8c..a4c5606527a 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -743,8 +743,8 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) if (!gadget_is_dualspeed(gadget)) break; device_qual(cdev); - value = min(w_length, - sizeof(struct usb_qualifier_descriptor)); + value = min_t(int, w_length, + sizeof(struct usb_qualifier_descriptor)); break; case USB_DT_OTHER_SPEED_CONFIG: if (!gadget_is_dualspeed(gadget)) diff --git a/drivers/usb/gadget/designware_udc.c b/drivers/usb/gadget/designware_udc.c index 3559400b284..0db7a3b6c15 100644 --- a/drivers/usb/gadget/designware_udc.c +++ b/drivers/usb/gadget/designware_udc.c @@ -269,8 +269,8 @@ static void dw_write_noniso_tx_fifo(struct usb_endpoint_instance UDCDBGA("urb->buffer %p, buffer_length %d, actual_length %d", urb->buffer, urb->buffer_length, urb->actual_length); - last = min(urb->actual_length - endpoint->sent, - endpoint->tx_packetSize); + last = min_t(u32, urb->actual_length - endpoint->sent, + endpoint->tx_packetSize); if (last) { u8 *cp = urb->buffer + endpoint->sent; diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index efd5c7fda14..94235552808 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -65,7 +65,8 @@ static int udc_write_urb(struct usb_endpoint_instance *endpoint) if (!urb || !urb->actual_length) return -1; - n = min(urb->actual_length - endpoint->sent, endpoint->tx_packetSize); + n = min_t(unsigned int, urb->actual_length - endpoint->sent, + endpoint->tx_packetSize); if (n <= 0) return -1; diff --git a/drivers/usb/gadget/s3c_udc_otg_xfer_dma.c b/drivers/usb/gadget/s3c_udc_otg_xfer_dma.c index 9c54b462c4e..7e7a2c2d906 100644 --- a/drivers/usb/gadget/s3c_udc_otg_xfer_dma.c +++ b/drivers/usb/gadget/s3c_udc_otg_xfer_dma.c @@ -97,8 +97,8 @@ static int setdma_rx(struct s3c_ep *ep, struct s3c_request *req) u32 ep_num = ep_index(ep); buf = req->req.buf + req->req.actual; - length = min(req->req.length - req->req.actual, - ep_num ? DMA_BUFFER_SIZE : ep->ep.maxpacket); + length = min_t(u32, req->req.length - req->req.actual, + ep_num ? DMA_BUFFER_SIZE : ep->ep.maxpacket); ep->len = length; ep->dma_buf = buf; diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c index 2a5bbf5ac0e..e8142ac0922 100644 --- a/drivers/usb/host/dwc2.c +++ b/drivers/usb/host/dwc2.c @@ -503,23 +503,23 @@ static int dwc_otg_submit_rh_msg_in_descriptor(struct usb_device *dev, case 0: switch (wValue & 0xff00) { case 0x0100: /* device descriptor */ - len = min3(txlen, sizeof(root_hub_dev_des), wLength); + len = min3(txlen, (int)sizeof(root_hub_dev_des), (int)wLength); memcpy(buffer, root_hub_dev_des, len); break; case 0x0200: /* configuration descriptor */ - len = min3(txlen, sizeof(root_hub_config_des), wLength); + len = min3(txlen, (int)sizeof(root_hub_config_des), (int)wLength); memcpy(buffer, root_hub_config_des, len); break; case 0x0300: /* string descriptors */ switch (wValue & 0xff) { case 0x00: - len = min3(txlen, sizeof(root_hub_str_index0), - wLength); + len = min3(txlen, (int)sizeof(root_hub_str_index0), + (int)wLength); memcpy(buffer, root_hub_str_index0, len); break; case 0x01: - len = min3(txlen, sizeof(root_hub_str_index1), - wLength); + len = min3(txlen, (int)sizeof(root_hub_str_index1), + (int)wLength); memcpy(buffer, root_hub_str_index1, len); break; } @@ -556,7 +556,7 @@ static int dwc_otg_submit_rh_msg_in_descriptor(struct usb_device *dev, data[10] = data[9]; } - len = min3(txlen, data[0], wLength); + len = min3(txlen, (int)data[0], (int)wLength); memcpy(buffer, data, len); break; default: diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index c671c72cb1c..5520805af37 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -910,7 +910,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, } mdelay(1); - len = min3(srclen, le16_to_cpu(req->length), length); + len = min3(srclen, (int)le16_to_cpu(req->length), length); if (srcptr != NULL && len > 0) memcpy(buffer, srcptr, len); else diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 46e4cee1d04..0556f328e45 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -103,12 +103,6 @@ static int rh_devnum; /* address of Root Hub endpoint */ /* ------------------------------------------------------------------------- */ -#define ALIGN(x,a) (((x)+(a)-1UL)&~((a)-1UL)) -#define min_t(type,x,y) \ - ({ type __x = (x); type __y = (y); __x < __y ? __x : __y; }) - -/* ------------------------------------------------------------------------- */ - static int isp116x_reset(struct isp116x *isp116x); /* --- Debugging functions ------------------------------------------------- */ diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index dc0a4e31796..97a7edeb539 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -47,7 +47,7 @@ #include <asm/arch/hardware.h> /* needed for AT91_USB_HOST_BASE */ #endif -#if defined(CONFIG_ARM920T) || \ +#if defined(CONFIG_CPU_ARM920T) || \ defined(CONFIG_S3C24X0) || \ defined(CONFIG_440EP) || \ defined(CONFIG_PCI_OHCI) || \ @@ -65,9 +65,6 @@ #define OHCI_CONTROL_INIT \ (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE -#define min_t(type, x, y) \ - ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; }) - #ifdef CONFIG_PCI_OHCI static struct pci_device_id ohci_pci_ids[] = { {0x10b9, 0x5237}, /* ULI1575 PCI OHCI module ids */ diff --git a/drivers/usb/host/ohci-s3c24xx.c b/drivers/usb/host/ohci-s3c24xx.c index 3c659c60c97..8bb2275c094 100644 --- a/drivers/usb/host/ohci-s3c24xx.c +++ b/drivers/usb/host/ohci-s3c24xx.c @@ -35,9 +35,6 @@ #define OHCI_CONTROL_INIT \ (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE -#define min_t(type, x, y) \ - ({ type __x = (x); type __y = (y); __x < __y ? __x : __y; }) - #undef DEBUG #ifdef DEBUG #define dbg(format, arg...) printf("DEBUG: " format "\n", ## arg) diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 511454479b1..6f33456c90d 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -550,9 +550,6 @@ static int check_usb_device_connecting(struct r8a66597 *r8a66597) return -1; /* fail */ } -/* based on usb_ohci.c */ -#define min_t(type, x, y) \ - ({ type __x = (x); type __y = (y); __x < __y ? __x : __y; }) /*-------------------------------------------------------------------------* * Virtual Root Hub *-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 19c3ec62118..b5aade988d4 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -511,7 +511,7 @@ static void record_transfer_result(struct usb_device *udev, union xhci_trb *event, int length) { udev->act_len = min(length, length - - EVENT_TRB_LEN(le32_to_cpu(event->trans_event.transfer_len))); + (int)EVENT_TRB_LEN(le32_to_cpu(event->trans_event.transfer_len))); switch (GET_COMP_CODE(le32_to_cpu(event->trans_event.transfer_len))) { case COMP_SUCCESS: diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 59dc096b0c3..87f2972cb26 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -829,7 +829,7 @@ static int xhci_submit_root(struct usb_device *udev, unsigned long pipe, debug("scrlen = %d\n req->length = %d\n", srclen, le16_to_cpu(req->length)); - len = min(srclen, le16_to_cpu(req->length)); + len = min(srclen, (int)le16_to_cpu(req->length)); if (srcptr != NULL && len > 0) memcpy(buffer, srcptr, len); diff --git a/drivers/usb/musb/musb_hcd.h b/drivers/usb/musb/musb_hcd.h index 02b9adcbe4e..0c8e75d46c1 100644 --- a/drivers/usb/musb/musb_hcd.h +++ b/drivers/usb/musb/musb_hcd.h @@ -37,9 +37,6 @@ extern unsigned char new[]; ((readb(&musbr->power) & MUSB_POWER_HSMODE) \ >> MUSB_POWER_HSMODE_SHIFT) -#define min_t(type, x, y) \ - ({ type __x = (x); type __y = (y); __x < __y ? __x : __y; }) - /* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */ /* destination of request */ diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 14a6781edca..7301be39554 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_VIDEO_SANDBOX_SDL) += sandbox_sdl.o obj-$(CONFIG_VIDEO_SED13806) += sed13806.o obj-$(CONFIG_VIDEO_SM501) += sm501.o obj-$(CONFIG_VIDEO_SMI_LYNXEM) += smiLynxEM.o videomodes.o +obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o obj-$(CONFIG_VIDEO_TEGRA) += tegra.o obj-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o obj-$(CONFIG_FORMIKE) += formike.o diff --git a/drivers/video/ati_radeon_fb.c b/drivers/video/ati_radeon_fb.c index 38d2eb107ec..618f5d93b6d 100644 --- a/drivers/video/ati_radeon_fb.c +++ b/drivers/video/ati_radeon_fb.c @@ -39,11 +39,6 @@ #define DPRINT(x...) do{}while(0) #endif -#ifndef min_t -#define min_t(type,x,y) \ - ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; }) -#endif - #define MAX_MAPPED_VRAM (2048*2048*4) #define MIN_MAPPED_VRAM (1024*768*1) diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c index a347e13d7de..a653bb41685 100644 --- a/drivers/video/cfb_console.c +++ b/drivers/video/cfb_console.c @@ -1541,14 +1541,14 @@ int video_display_bitmap(ulong bmp_image, int x, int y) #ifdef CONFIG_SPLASH_SCREEN_ALIGN if (x == BMP_ALIGN_CENTER) - x = max(0, (VIDEO_VISIBLE_COLS - width) / 2); + x = max(0, (int)(VIDEO_VISIBLE_COLS - width) / 2); else if (x < 0) - x = max(0, VIDEO_VISIBLE_COLS - width + x + 1); + x = max(0, (int)(VIDEO_VISIBLE_COLS - width + x + 1)); if (y == BMP_ALIGN_CENTER) - y = max(0, (VIDEO_VISIBLE_ROWS - height) / 2); + y = max(0, (int)(VIDEO_VISIBLE_ROWS - height) / 2); else if (y < 0) - y = max(0, VIDEO_VISIBLE_ROWS - height + y + 1); + y = max(0, (int)(VIDEO_VISIBLE_ROWS - height + y + 1)); #endif /* CONFIG_SPLASH_SCREEN_ALIGN */ /* @@ -1874,14 +1874,14 @@ static void plot_logo_or_black(void *screen, int width, int x, int y, int black) #ifdef CONFIG_SPLASH_SCREEN_ALIGN if (x == BMP_ALIGN_CENTER) - x = max(0, (VIDEO_VISIBLE_COLS - VIDEO_LOGO_WIDTH) / 2); + x = max(0, (int)(VIDEO_VISIBLE_COLS - VIDEO_LOGO_WIDTH) / 2); else if (x < 0) - x = max(0, VIDEO_VISIBLE_COLS - VIDEO_LOGO_WIDTH + x + 1); + x = max(0, (int)(VIDEO_VISIBLE_COLS - VIDEO_LOGO_WIDTH + x + 1)); if (y == BMP_ALIGN_CENTER) - y = max(0, (VIDEO_VISIBLE_ROWS - VIDEO_LOGO_HEIGHT) / 2); + y = max(0, (int)(VIDEO_VISIBLE_ROWS - VIDEO_LOGO_HEIGHT) / 2); else if (y < 0) - y = max(0, VIDEO_VISIBLE_ROWS - VIDEO_LOGO_HEIGHT + y + 1); + y = max(0, (int)(VIDEO_VISIBLE_ROWS - VIDEO_LOGO_HEIGHT + y + 1)); #endif /* CONFIG_SPLASH_SCREEN_ALIGN */ dest = (unsigned char *)screen + (y * width + x) * VIDEO_PIXEL_SIZE; @@ -2028,7 +2028,7 @@ static void *video_logo(void) * we need to adjust the logo height */ if (video_logo_ypos == BMP_ALIGN_CENTER) - video_logo_height += max(0, (VIDEO_VISIBLE_ROWS - \ + video_logo_height += max(0, (int)(VIDEO_VISIBLE_ROWS - VIDEO_LOGO_HEIGHT) / 2); else if (video_logo_ypos > 0) video_logo_height += video_logo_ypos; diff --git a/drivers/video/sunxi_display.c b/drivers/video/sunxi_display.c new file mode 100644 index 00000000000..d2413971c07 --- /dev/null +++ b/drivers/video/sunxi_display.c @@ -0,0 +1,451 @@ +/* + * Display driver for Allwinner SoCs. + * + * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be> + * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> + +#include <asm/arch/clock.h> +#include <asm/arch/display.h> +#include <asm/global_data.h> +#include <asm/io.h> +#include <fdtdec.h> +#include <fdt_support.h> +#include <linux/fb.h> +#include <video_fb.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct sunxi_display { + GraphicDevice graphic_device; + bool enabled; +} sunxi_display; + +static int sunxi_hdmi_hpd_detect(void) +{ + struct sunxi_ccm_reg * const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + struct sunxi_hdmi_reg * const hdmi = + (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE; + + /* Set pll3 to 300MHz */ + clock_set_pll3(300000000); + + /* Set hdmi parent to pll3 */ + clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK, + CCM_HDMI_CTRL_PLL3); + + /* Set ahb gating to pass */ +#ifdef CONFIG_MACH_SUN6I + setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI); +#endif + setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI); + + /* Clock on */ + setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE); + + writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl); + writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0); + + udelay(1000); + + if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT) + return 1; + + /* No need to keep these running */ + clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE); + clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE); + clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI); +#ifdef CONFIG_MACH_SUN6I + clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI); +#endif + clock_set_pll3(0); + + return 0; +} + +/* + * This is the entity that mixes and matches the different layers and inputs. + * Allwinner calls it the back-end, but i like composer better. + */ +static void sunxi_composer_init(void) +{ + struct sunxi_ccm_reg * const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + struct sunxi_de_be_reg * const de_be = + (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE; + int i; + +#ifdef CONFIG_MACH_SUN6I + /* Reset off */ + setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0); +#endif + + /* Clocks on */ + setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0); + setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0); + clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000); + + /* Engine bug, clear registers after reset */ + for (i = 0x0800; i < 0x1000; i += 4) + writel(0, SUNXI_DE_BE0_BASE + i); + + setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE); +} + +static void sunxi_composer_mode_set(struct fb_videomode *mode, + unsigned int address) +{ + struct sunxi_de_be_reg * const de_be = + (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE; + + writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres), + &de_be->disp_size); + writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres), + &de_be->layer0_size); + writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride); + writel(address << 3, &de_be->layer0_addr_low32b); + writel(address >> 29, &de_be->layer0_addr_high4b); + writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl); + + setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE); +} + +/* + * LCDC, what allwinner calls a CRTC, so timing controller and serializer. + */ +static void sunxi_lcdc_pll_set(int dotclock, int *clk_div, int *clk_double) +{ + struct sunxi_ccm_reg * const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + int value, n, m, diff; + int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF; + int best_double = 0; + + /* + * Find the lowest divider resulting in a matching clock, if there + * is no match, pick the closest lower clock, as monitors tend to + * not sync to higher frequencies. + */ + for (m = 15; m > 0; m--) { + n = (m * dotclock) / 3000; + + if ((n >= 9) && (n <= 127)) { + value = (3000 * n) / m; + diff = dotclock - value; + if (diff < best_diff) { + best_diff = diff; + best_m = m; + best_n = n; + best_double = 0; + } + } + + /* These are just duplicates */ + if (!(m & 1)) + continue; + + n = (m * dotclock) / 6000; + if ((n >= 9) && (n <= 127)) { + value = (6000 * n) / m; + diff = dotclock - value; + if (diff < best_diff) { + best_diff = diff; + best_m = m; + best_n = n; + best_double = 1; + } + } + } + + debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n", + dotclock, (best_double + 1) * 3000 * best_n / best_m, + best_double + 1, best_n, best_m); + + clock_set_pll3(best_n * 3000000); + + writel(CCM_LCD_CH1_CTRL_GATE | + (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X : CCM_LCD_CH1_CTRL_PLL3) | + CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg); + + *clk_div = best_m; + *clk_double = best_double; +} + +static void sunxi_lcdc_init(void) +{ + struct sunxi_ccm_reg * const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + struct sunxi_lcdc_reg * const lcdc = + (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE; + + /* Reset off */ +#ifdef CONFIG_MACH_SUN6I + setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0); +#else + setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST); +#endif + + /* Clock on */ + setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0); + + /* Init lcdc */ + writel(0, &lcdc->ctrl); /* Disable tcon */ + writel(0, &lcdc->int0); /* Disable all interrupts */ + + /* Disable tcon0 dot clock */ + clrbits_le32(&lcdc->tcon0_dclk, SUNXI_LCDC_TCON0_DCLK_ENABLE); + + /* Set all io lines to tristate */ + writel(0xffffffff, &lcdc->tcon0_io_tristate); + writel(0xffffffff, &lcdc->tcon1_io_tristate); +} + +static void sunxi_lcdc_mode_set(struct fb_videomode *mode, + int *clk_div, int *clk_double) +{ + struct sunxi_lcdc_reg * const lcdc = + (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE; + int bp, total; + + /* Use tcon1 */ + clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK, + SUNXI_LCDC_CTRL_IO_MAP_TCON1); + + /* Enabled, 0x1e start delay */ + writel(SUNXI_LCDC_TCON1_CTRL_ENABLE | + SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(0x1e), &lcdc->tcon1_ctrl); + + writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres), + &lcdc->tcon1_timing_source); + writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres), + &lcdc->tcon1_timing_scale); + writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres), + &lcdc->tcon1_timing_out); + + bp = mode->hsync_len + mode->left_margin; + total = mode->xres + mode->right_margin + bp; + writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) | + SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h); + + bp = mode->vsync_len + mode->upper_margin; + total = mode->yres + mode->lower_margin + bp; + writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) | + SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v); + + writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len), + &lcdc->tcon1_timing_sync); + + sunxi_lcdc_pll_set(mode->pixclock, clk_div, clk_double); +} + +#ifdef CONFIG_MACH_SUN6I +static void sunxi_drc_init(void) +{ + struct sunxi_ccm_reg * const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + + /* On sun6i the drc must be clocked even when in pass-through mode */ + setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0); + clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000); +} +#endif + +static void sunxi_hdmi_mode_set(struct fb_videomode *mode, + int clk_div, int clk_double) +{ + struct sunxi_hdmi_reg * const hdmi = + (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE; + int x, y; + + /* Write clear interrupt status bits */ + writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq); + + /* Init various registers, select pll3 as clock source */ + writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity); + writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0); + writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1); + writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl); + writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0); + + /* Setup clk div and doubler */ + clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK, + SUNXI_HDMI_PLL_CTRL_DIV(clk_div)); + if (!clk_double) + setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE); + + /* Setup timing registers */ + writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres), + &hdmi->video_size); + + x = mode->hsync_len + mode->left_margin; + y = mode->vsync_len + mode->upper_margin; + writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp); + + x = mode->right_margin; + y = mode->lower_margin; + writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp); + + x = mode->hsync_len; + y = mode->vsync_len; + writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw); + + if (mode->sync & FB_SYNC_HOR_HIGH_ACT) + setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR); + + if (mode->sync & FB_SYNC_VERT_HIGH_ACT) + setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER); +} + +static void sunxi_engines_init(void) +{ + sunxi_composer_init(); + sunxi_lcdc_init(); +#ifdef CONFIG_MACH_SUN6I + sunxi_drc_init(); +#endif +} + +static void sunxi_mode_set(struct fb_videomode *mode, unsigned int address) +{ + struct sunxi_de_be_reg * const de_be = + (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE; + struct sunxi_lcdc_reg * const lcdc = + (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE; + struct sunxi_hdmi_reg * const hdmi = + (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE; + int clk_div, clk_double; + int retries = 3; + +retry: + clrbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE); + clrbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE); + clrbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START); + + sunxi_composer_mode_set(mode, address); + sunxi_lcdc_mode_set(mode, &clk_div, &clk_double); + sunxi_hdmi_mode_set(mode, clk_div, clk_double); + + setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS); + setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START); + + udelay(1000000 / mode->refresh + 500); + + setbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE); + + udelay(1000000 / mode->refresh + 500); + + setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE); + + udelay(1000000 / mode->refresh + 500); + + /* + * Sometimes the display pipeline does not sync up properly, if + * this happens the hdmi fifo underrun or overrun bits are set. + */ + if (readl(&hdmi->irq) & + (SUNXI_HDMI_IRQ_STATUS_FIFO_UF | SUNXI_HDMI_IRQ_STATUS_FIFO_OF)) { + if (retries--) + goto retry; + printf("HDMI fifo under or overrun\n"); + } +} + +void *video_hw_init(void) +{ + static GraphicDevice *graphic_device = &sunxi_display.graphic_device; + /* + * Vesa standard 1024x768@60 + * 65.0 1024 1048 1184 1344 768 771 777 806 -hsync -vsync + */ + struct fb_videomode mode = { + .name = "1024x768", + .refresh = 60, + .xres = 1024, + .yres = 768, + .pixclock = 65000, + .left_margin = 160, + .right_margin = 24, + .upper_margin = 29, + .lower_margin = 3, + .hsync_len = 136, + .vsync_len = 6, + .sync = 0, + .vmode = 0, + .flag = 0, + }; + int ret; + + memset(&sunxi_display, 0, sizeof(struct sunxi_display)); + + printf("Reserved %dkB of RAM for Framebuffer.\n", + CONFIG_SUNXI_FB_SIZE >> 10); + gd->fb_base = gd->ram_top; + + ret = sunxi_hdmi_hpd_detect(); + if (!ret) + return NULL; + + printf("HDMI connected.\n"); + sunxi_display.enabled = true; + + printf("Setting up a %s console.\n", mode.name); + sunxi_engines_init(); + sunxi_mode_set(&mode, gd->fb_base - CONFIG_SYS_SDRAM_BASE); + + /* + * These are the only members of this structure that are used. All the + * others are driver specific. There is nothing to decribe pitch or + * stride, but we are lucky with our hw. + */ + graphic_device->frameAdrs = gd->fb_base; + graphic_device->gdfIndex = GDF_32BIT_X888RGB; + graphic_device->gdfBytesPP = 4; + graphic_device->winSizeX = mode.xres; + graphic_device->winSizeY = mode.yres; + + return graphic_device; +} + +/* + * Simplefb support. + */ +#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB) +int sunxi_simplefb_setup(void *blob) +{ + static GraphicDevice *graphic_device = &sunxi_display.graphic_device; + int offset, ret; + + if (!sunxi_display.enabled) + return 0; + + /* Find a framebuffer node, with pipeline == "de_be0-lcd0-hdmi" */ + offset = fdt_node_offset_by_compatible(blob, -1, + "allwinner,simple-framebuffer"); + while (offset >= 0) { + ret = fdt_find_string(blob, offset, "allwinner,pipeline", + "de_be0-lcd0-hdmi"); + if (ret == 0) + break; + offset = fdt_node_offset_by_compatible(blob, offset, + "allwinner,simple-framebuffer"); + } + if (offset < 0) { + eprintf("Cannot setup simplefb: node not found\n"); + return 0; /* Keep older kernels working */ + } + + ret = fdt_setup_simplefb_node(blob, offset, gd->fb_base, + graphic_device->winSizeX, graphic_device->winSizeY, + graphic_device->winSizeX * graphic_device->gdfBytesPP, + "x8r8g8b8"); + if (ret) + eprintf("Cannot setup simplefb: Error setting properties\n"); + + return ret; +} +#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */ |