Merge git://git.denx.de/u-boot-dm
This commit is contained in:
@@ -36,6 +36,8 @@ obj-$(CONFIG_SPL_WATCHDOG_SUPPORT) += watchdog/
|
||||
obj-$(CONFIG_SPL_USB_HOST_SUPPORT) += usb/host/
|
||||
obj-$(CONFIG_OMAP_USB_PHY) += usb/phy/
|
||||
obj-$(CONFIG_SPL_SATA_SUPPORT) += block/
|
||||
obj-$(CONFIG_SPL_USB_HOST_SUPPORT) += block/
|
||||
obj-$(CONFIG_SPL_MMC_SUPPORT) += block/
|
||||
|
||||
else
|
||||
|
||||
|
||||
@@ -9,10 +9,9 @@ config BLK
|
||||
be partitioned into several areas, called 'partitions' in U-Boot.
|
||||
A filesystem can be placed in each partition.
|
||||
|
||||
config DISK
|
||||
bool "Support disk controllers with driver model"
|
||||
config AHCI
|
||||
bool "Support SATA controllers with driver model"
|
||||
depends on DM
|
||||
default y if DM
|
||||
help
|
||||
This enables a uclass for disk controllers in U-Boot. Various driver
|
||||
types can use this, such as AHCI/SATA. It does not provide any standard
|
||||
|
||||
@@ -7,7 +7,11 @@
|
||||
|
||||
obj-$(CONFIG_BLK) += blk-uclass.o
|
||||
|
||||
obj-$(CONFIG_DISK) += disk-uclass.o
|
||||
ifndef CONFIG_BLK
|
||||
obj-y += blk_legacy.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_AHCI) += ahci-uclass.o
|
||||
obj-$(CONFIG_SCSI_AHCI) += ahci.o
|
||||
obj-$(CONFIG_DWC_AHSATA) += dwc_ahsata.o
|
||||
obj-$(CONFIG_FSL_SATA) += fsl_sata.o
|
||||
@@ -22,7 +26,7 @@ obj-$(CONFIG_SATA_MV) += sata_mv.o
|
||||
obj-$(CONFIG_SATA_SIL3114) += sata_sil3114.o
|
||||
obj-$(CONFIG_SATA_SIL) += sata_sil.o
|
||||
obj-$(CONFIG_IDE_SIL680) += sil680.o
|
||||
obj-$(CONFIG_SANDBOX) += sandbox.o
|
||||
obj-$(CONFIG_SANDBOX) += sandbox.o sandbox_scsi.o sata_sandbox.o
|
||||
obj-$(CONFIG_SCSI_SYM53C8XX) += sym53c8xx.o
|
||||
obj-$(CONFIG_SYSTEMACE) += systemace.o
|
||||
obj-$(CONFIG_BLOCK_CACHE) += blkcache.o
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
|
||||
UCLASS_DRIVER(disk) = {
|
||||
.id = UCLASS_DISK,
|
||||
.name = "disk",
|
||||
UCLASS_DRIVER(ahci) = {
|
||||
.id = UCLASS_AHCI,
|
||||
.name = "ahci",
|
||||
};
|
||||
@@ -11,6 +11,315 @@
|
||||
#include <dm/device-internal.h>
|
||||
#include <dm/lists.h>
|
||||
|
||||
static const char *if_typename_str[IF_TYPE_COUNT] = {
|
||||
[IF_TYPE_IDE] = "ide",
|
||||
[IF_TYPE_SCSI] = "scsi",
|
||||
[IF_TYPE_ATAPI] = "atapi",
|
||||
[IF_TYPE_USB] = "usb",
|
||||
[IF_TYPE_DOC] = "doc",
|
||||
[IF_TYPE_MMC] = "mmc",
|
||||
[IF_TYPE_SD] = "sd",
|
||||
[IF_TYPE_SATA] = "sata",
|
||||
[IF_TYPE_HOST] = "host",
|
||||
[IF_TYPE_SYSTEMACE] = "ace",
|
||||
};
|
||||
|
||||
static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
|
||||
[IF_TYPE_IDE] = UCLASS_INVALID,
|
||||
[IF_TYPE_SCSI] = UCLASS_INVALID,
|
||||
[IF_TYPE_ATAPI] = UCLASS_INVALID,
|
||||
[IF_TYPE_USB] = UCLASS_MASS_STORAGE,
|
||||
[IF_TYPE_DOC] = UCLASS_INVALID,
|
||||
[IF_TYPE_MMC] = UCLASS_MMC,
|
||||
[IF_TYPE_SD] = UCLASS_INVALID,
|
||||
[IF_TYPE_SATA] = UCLASS_AHCI,
|
||||
[IF_TYPE_HOST] = UCLASS_ROOT,
|
||||
[IF_TYPE_SYSTEMACE] = UCLASS_INVALID,
|
||||
};
|
||||
|
||||
static enum if_type if_typename_to_iftype(const char *if_typename)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IF_TYPE_COUNT; i++) {
|
||||
if (if_typename_str[i] &&
|
||||
!strcmp(if_typename, if_typename_str[i]))
|
||||
return i;
|
||||
}
|
||||
|
||||
return IF_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
static enum uclass_id if_type_to_uclass_id(enum if_type if_type)
|
||||
{
|
||||
return if_type_uclass_id[if_type];
|
||||
}
|
||||
|
||||
struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum)
|
||||
{
|
||||
struct blk_desc *desc;
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
ret = blk_get_device(if_type, devnum, &dev);
|
||||
if (ret)
|
||||
return NULL;
|
||||
desc = dev_get_uclass_platdata(dev);
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is complicated with driver model. We look up the interface
|
||||
* name in a local table. This gives us an interface type which we can match
|
||||
* against the uclass of the block device's parent.
|
||||
*/
|
||||
struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum)
|
||||
{
|
||||
enum uclass_id uclass_id;
|
||||
enum if_type if_type;
|
||||
struct udevice *dev;
|
||||
struct uclass *uc;
|
||||
int ret;
|
||||
|
||||
if_type = if_typename_to_iftype(if_typename);
|
||||
if (if_type == IF_TYPE_UNKNOWN) {
|
||||
debug("%s: Unknown interface type '%s'\n", __func__,
|
||||
if_typename);
|
||||
return NULL;
|
||||
}
|
||||
uclass_id = if_type_to_uclass_id(if_type);
|
||||
if (uclass_id == UCLASS_INVALID) {
|
||||
debug("%s: Unknown uclass for interface type'\n",
|
||||
if_typename_str[if_type]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = uclass_get(UCLASS_BLK, &uc);
|
||||
if (ret)
|
||||
return NULL;
|
||||
uclass_foreach_dev(dev, uc) {
|
||||
struct blk_desc *desc = dev_get_uclass_platdata(dev);
|
||||
|
||||
debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
|
||||
if_type, devnum, dev->name, desc->if_type, desc->devnum);
|
||||
if (desc->devnum != devnum)
|
||||
continue;
|
||||
|
||||
/* Find out the parent device uclass */
|
||||
if (device_get_uclass_id(dev->parent) != uclass_id) {
|
||||
debug("%s: parent uclass %d, this dev %d\n", __func__,
|
||||
device_get_uclass_id(dev->parent), uclass_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (device_probe(dev))
|
||||
return NULL;
|
||||
|
||||
debug("%s: Device desc %p\n", __func__, desc);
|
||||
return desc;
|
||||
}
|
||||
debug("%s: No device found\n", __func__);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_desc() - Get the block device descriptor for the given device number
|
||||
*
|
||||
* @if_type: Interface type
|
||||
* @devnum: Device number (0 = first)
|
||||
* @descp: Returns block device descriptor on success
|
||||
* @return 0 on success, -ENODEV if there is no such device and no device
|
||||
* with a higher device number, -ENOENT if there is no such device but there
|
||||
* is one with a higher number, or other -ve on other error.
|
||||
*/
|
||||
static int get_desc(enum if_type if_type, int devnum, struct blk_desc **descp)
|
||||
{
|
||||
bool found_more = false;
|
||||
struct udevice *dev;
|
||||
struct uclass *uc;
|
||||
int ret;
|
||||
|
||||
*descp = NULL;
|
||||
ret = uclass_get(UCLASS_BLK, &uc);
|
||||
if (ret)
|
||||
return ret;
|
||||
uclass_foreach_dev(dev, uc) {
|
||||
struct blk_desc *desc = dev_get_uclass_platdata(dev);
|
||||
|
||||
debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
|
||||
if_type, devnum, dev->name, desc->if_type, desc->devnum);
|
||||
if (desc->if_type == if_type) {
|
||||
if (desc->devnum == devnum) {
|
||||
ret = device_probe(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
} else if (desc->devnum > devnum) {
|
||||
found_more = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found_more ? -ENOENT : -ENODEV;
|
||||
}
|
||||
|
||||
int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart)
|
||||
{
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
ret = blk_get_device(if_type, devnum, &dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return blk_select_hwpart(dev, hwpart);
|
||||
}
|
||||
|
||||
int blk_list_part(enum if_type if_type)
|
||||
{
|
||||
struct blk_desc *desc;
|
||||
int devnum, ok;
|
||||
int ret;
|
||||
|
||||
for (ok = 0, devnum = 0;; ++devnum) {
|
||||
ret = get_desc(if_type, devnum, &desc);
|
||||
if (ret == -ENODEV)
|
||||
break;
|
||||
else if (ret)
|
||||
continue;
|
||||
if (desc->part_type != PART_TYPE_UNKNOWN) {
|
||||
++ok;
|
||||
if (devnum)
|
||||
putc('\n');
|
||||
part_print(desc);
|
||||
}
|
||||
}
|
||||
if (!ok)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blk_print_part_devnum(enum if_type if_type, int devnum)
|
||||
{
|
||||
struct blk_desc *desc;
|
||||
int ret;
|
||||
|
||||
ret = get_desc(if_type, devnum, &desc);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (desc->type == DEV_TYPE_UNKNOWN)
|
||||
return -ENOENT;
|
||||
part_print(desc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void blk_list_devices(enum if_type if_type)
|
||||
{
|
||||
struct blk_desc *desc;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
for (i = 0;; ++i) {
|
||||
ret = get_desc(if_type, i, &desc);
|
||||
if (ret == -ENODEV)
|
||||
break;
|
||||
else if (ret)
|
||||
continue;
|
||||
if (desc->type == DEV_TYPE_UNKNOWN)
|
||||
continue; /* list only known devices */
|
||||
printf("Device %d: ", i);
|
||||
dev_print(desc);
|
||||
}
|
||||
}
|
||||
|
||||
int blk_print_device_num(enum if_type if_type, int devnum)
|
||||
{
|
||||
struct blk_desc *desc;
|
||||
int ret;
|
||||
|
||||
ret = get_desc(if_type, devnum, &desc);
|
||||
if (ret)
|
||||
return ret;
|
||||
printf("\nIDE device %d: ", devnum);
|
||||
dev_print(desc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blk_show_device(enum if_type if_type, int devnum)
|
||||
{
|
||||
struct blk_desc *desc;
|
||||
int ret;
|
||||
|
||||
printf("\nDevice %d: ", devnum);
|
||||
ret = get_desc(if_type, devnum, &desc);
|
||||
if (ret == -ENODEV || ret == -ENOENT) {
|
||||
printf("unknown device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
dev_print(desc);
|
||||
|
||||
if (desc->type == DEV_TYPE_UNKNOWN)
|
||||
return -ENOENT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start,
|
||||
lbaint_t blkcnt, void *buffer)
|
||||
{
|
||||
struct blk_desc *desc;
|
||||
ulong n;
|
||||
int ret;
|
||||
|
||||
ret = get_desc(if_type, devnum, &desc);
|
||||
if (ret)
|
||||
return ret;
|
||||
n = blk_dread(desc, start, blkcnt, buffer);
|
||||
if (IS_ERR_VALUE(n))
|
||||
return n;
|
||||
|
||||
/* flush cache after read */
|
||||
flush_cache((ulong)buffer, blkcnt * desc->blksz);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start,
|
||||
lbaint_t blkcnt, const void *buffer)
|
||||
{
|
||||
struct blk_desc *desc;
|
||||
int ret;
|
||||
|
||||
ret = get_desc(if_type, devnum, &desc);
|
||||
if (ret)
|
||||
return ret;
|
||||
return blk_dwrite(desc, start, blkcnt, buffer);
|
||||
}
|
||||
|
||||
int blk_select_hwpart(struct udevice *dev, int hwpart)
|
||||
{
|
||||
const struct blk_ops *ops = blk_get_ops(dev);
|
||||
|
||||
if (!ops)
|
||||
return -ENOSYS;
|
||||
if (!ops->select_hwpart)
|
||||
return 0;
|
||||
|
||||
return ops->select_hwpart(dev, hwpart);
|
||||
}
|
||||
|
||||
int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
|
||||
{
|
||||
return blk_select_hwpart(desc->bdev, hwpart);
|
||||
}
|
||||
|
||||
int blk_first_device(int if_type, struct udevice **devp)
|
||||
{
|
||||
struct blk_desc *desc;
|
||||
@@ -131,6 +440,26 @@ int blk_prepare_device(struct udevice *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blk_find_max_devnum(enum if_type if_type)
|
||||
{
|
||||
struct udevice *dev;
|
||||
int max_devnum = -ENODEV;
|
||||
struct uclass *uc;
|
||||
int ret;
|
||||
|
||||
ret = uclass_get(UCLASS_BLK, &uc);
|
||||
if (ret)
|
||||
return ret;
|
||||
uclass_foreach_dev(dev, uc) {
|
||||
struct blk_desc *desc = dev_get_uclass_platdata(dev);
|
||||
|
||||
if (desc->if_type == if_type && desc->devnum > max_devnum)
|
||||
max_devnum = desc->devnum;
|
||||
}
|
||||
|
||||
return max_devnum;
|
||||
}
|
||||
|
||||
int blk_create_device(struct udevice *parent, const char *drv_name,
|
||||
const char *name, int if_type, int devnum, int blksz,
|
||||
lbaint_t size, struct udevice **devp)
|
||||
@@ -139,6 +468,15 @@ int blk_create_device(struct udevice *parent, const char *drv_name,
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
if (devnum == -1) {
|
||||
ret = blk_find_max_devnum(if_type);
|
||||
if (ret == -ENODEV)
|
||||
devnum = 0;
|
||||
else if (ret < 0)
|
||||
return ret;
|
||||
else
|
||||
devnum = ret + 1;
|
||||
}
|
||||
ret = device_bind_driver(parent, drv_name, name, &dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -154,6 +492,29 @@ int blk_create_device(struct udevice *parent, const char *drv_name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blk_create_devicef(struct udevice *parent, const char *drv_name,
|
||||
const char *name, int if_type, int devnum, int blksz,
|
||||
lbaint_t size, struct udevice **devp)
|
||||
{
|
||||
char dev_name[30], *str;
|
||||
int ret;
|
||||
|
||||
snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
|
||||
str = strdup(dev_name);
|
||||
if (!str)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = blk_create_device(parent, drv_name, str, if_type, devnum,
|
||||
blksz, size, devp);
|
||||
if (ret) {
|
||||
free(str);
|
||||
return ret;
|
||||
}
|
||||
device_set_name_alloced(*devp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int blk_unbind_all(int if_type)
|
||||
{
|
||||
struct uclass *uc;
|
||||
|
||||
261
drivers/block/blk_legacy.c
Normal file
261
drivers/block/blk_legacy.c
Normal file
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Google, Inc
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
struct blk_driver *blk_driver_lookup_type(int if_type)
|
||||
{
|
||||
struct blk_driver *drv = ll_entry_start(struct blk_driver, blk_driver);
|
||||
const int n_ents = ll_entry_count(struct blk_driver, blk_driver);
|
||||
struct blk_driver *entry;
|
||||
|
||||
for (entry = drv; entry != drv + n_ents; entry++) {
|
||||
if (if_type == entry->if_type)
|
||||
return entry;
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct blk_driver *blk_driver_lookup_typename(const char *if_typename)
|
||||
{
|
||||
struct blk_driver *drv = ll_entry_start(struct blk_driver, blk_driver);
|
||||
const int n_ents = ll_entry_count(struct blk_driver, blk_driver);
|
||||
struct blk_driver *entry;
|
||||
|
||||
for (entry = drv; entry != drv + n_ents; entry++) {
|
||||
if (!strcmp(if_typename, entry->if_typename))
|
||||
return entry;
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_desc() - Get the block device descriptor for the given device number
|
||||
*
|
||||
* @drv: Legacy block driver
|
||||
* @devnum: Device number (0 = first)
|
||||
* @descp: Returns block device descriptor on success
|
||||
* @return 0 on success, -ENODEV if there is no such device, -ENOSYS if the
|
||||
* driver does not provide a way to find a device, or other -ve on other
|
||||
* error.
|
||||
*/
|
||||
static int get_desc(struct blk_driver *drv, int devnum, struct blk_desc **descp)
|
||||
{
|
||||
if (drv->desc) {
|
||||
if (devnum < 0 || devnum >= drv->max_devs)
|
||||
return -ENODEV;
|
||||
*descp = &drv->desc[devnum];
|
||||
return 0;
|
||||
}
|
||||
if (!drv->get_dev)
|
||||
return -ENOSYS;
|
||||
|
||||
return drv->get_dev(devnum, descp);
|
||||
}
|
||||
|
||||
#ifdef HAVE_BLOCK_DEVICE
|
||||
int blk_list_part(enum if_type if_type)
|
||||
{
|
||||
struct blk_driver *drv;
|
||||
struct blk_desc *desc;
|
||||
int devnum, ok;
|
||||
bool first = true;
|
||||
|
||||
drv = blk_driver_lookup_type(if_type);
|
||||
if (!drv)
|
||||
return -ENOSYS;
|
||||
for (ok = 0, devnum = 0; devnum < drv->max_devs; ++devnum) {
|
||||
if (get_desc(drv, devnum, &desc))
|
||||
continue;
|
||||
if (desc->part_type != PART_TYPE_UNKNOWN) {
|
||||
++ok;
|
||||
if (!first)
|
||||
putc('\n');
|
||||
part_print(desc);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
if (!ok)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blk_print_part_devnum(enum if_type if_type, int devnum)
|
||||
{
|
||||
struct blk_driver *drv = blk_driver_lookup_type(if_type);
|
||||
struct blk_desc *desc;
|
||||
int ret;
|
||||
|
||||
if (!drv)
|
||||
return -ENOSYS;
|
||||
ret = get_desc(drv, devnum, &desc);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (desc->type == DEV_TYPE_UNKNOWN)
|
||||
return -ENOENT;
|
||||
part_print(desc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void blk_list_devices(enum if_type if_type)
|
||||
{
|
||||
struct blk_driver *drv = blk_driver_lookup_type(if_type);
|
||||
struct blk_desc *desc;
|
||||
int i;
|
||||
|
||||
if (!drv)
|
||||
return;
|
||||
for (i = 0; i < drv->max_devs; ++i) {
|
||||
if (get_desc(drv, i, &desc))
|
||||
continue;
|
||||
if (desc->type == DEV_TYPE_UNKNOWN)
|
||||
continue; /* list only known devices */
|
||||
printf("Device %d: ", i);
|
||||
dev_print(desc);
|
||||
}
|
||||
}
|
||||
|
||||
int blk_print_device_num(enum if_type if_type, int devnum)
|
||||
{
|
||||
struct blk_driver *drv = blk_driver_lookup_type(if_type);
|
||||
struct blk_desc *desc;
|
||||
int ret;
|
||||
|
||||
if (!drv)
|
||||
return -ENOSYS;
|
||||
ret = get_desc(drv, devnum, &desc);
|
||||
if (ret)
|
||||
return ret;
|
||||
printf("\n%s device %d: ", drv->if_typename, devnum);
|
||||
dev_print(desc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blk_show_device(enum if_type if_type, int devnum)
|
||||
{
|
||||
struct blk_driver *drv = blk_driver_lookup_type(if_type);
|
||||
struct blk_desc *desc;
|
||||
int ret;
|
||||
|
||||
if (!drv)
|
||||
return -ENOSYS;
|
||||
printf("\nDevice %d: ", devnum);
|
||||
if (devnum >= drv->max_devs) {
|
||||
puts("unknown device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
ret = get_desc(drv, devnum, &desc);
|
||||
if (ret)
|
||||
return ret;
|
||||
dev_print(desc);
|
||||
|
||||
if (desc->type == DEV_TYPE_UNKNOWN)
|
||||
return -ENOENT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* HAVE_BLOCK_DEVICE */
|
||||
|
||||
struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum)
|
||||
{
|
||||
struct blk_driver *drv = blk_driver_lookup_type(if_type);
|
||||
struct blk_desc *desc;
|
||||
|
||||
if (!drv)
|
||||
return NULL;
|
||||
|
||||
if (get_desc(drv, devnum, &desc))
|
||||
return NULL;
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
|
||||
{
|
||||
struct blk_driver *drv = blk_driver_lookup_type(desc->if_type);
|
||||
|
||||
if (!drv)
|
||||
return -ENOSYS;
|
||||
if (drv->select_hwpart)
|
||||
return drv->select_hwpart(desc, hwpart);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum)
|
||||
{
|
||||
struct blk_driver *drv = blk_driver_lookup_typename(if_typename);
|
||||
struct blk_desc *desc;
|
||||
|
||||
if (!drv)
|
||||
return NULL;
|
||||
|
||||
if (get_desc(drv, devnum, &desc))
|
||||
return NULL;
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start,
|
||||
lbaint_t blkcnt, void *buffer)
|
||||
{
|
||||
struct blk_driver *drv = blk_driver_lookup_type(if_type);
|
||||
struct blk_desc *desc;
|
||||
ulong n;
|
||||
int ret;
|
||||
|
||||
if (!drv)
|
||||
return -ENOSYS;
|
||||
ret = get_desc(drv, devnum, &desc);
|
||||
if (ret)
|
||||
return ret;
|
||||
n = desc->block_read(desc, start, blkcnt, buffer);
|
||||
if (IS_ERR_VALUE(n))
|
||||
return n;
|
||||
|
||||
/* flush cache after read */
|
||||
flush_cache((ulong)buffer, blkcnt * desc->blksz);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start,
|
||||
lbaint_t blkcnt, const void *buffer)
|
||||
{
|
||||
struct blk_driver *drv = blk_driver_lookup_type(if_type);
|
||||
struct blk_desc *desc;
|
||||
int ret;
|
||||
|
||||
if (!drv)
|
||||
return -ENOSYS;
|
||||
ret = get_desc(drv, devnum, &desc);
|
||||
if (ret)
|
||||
return ret;
|
||||
return desc->block_write(desc, start, blkcnt, buffer);
|
||||
}
|
||||
|
||||
int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart)
|
||||
{
|
||||
struct blk_driver *drv = blk_driver_lookup_type(if_type);
|
||||
struct blk_desc *desc;
|
||||
int ret;
|
||||
|
||||
if (!drv)
|
||||
return -ENOSYS;
|
||||
ret = get_desc(drv, devnum, &desc);
|
||||
if (ret)
|
||||
return ret;
|
||||
return drv->select_hwpart(desc, hwpart);
|
||||
}
|
||||
@@ -17,6 +17,19 @@
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#ifndef CONFIG_BLK
|
||||
static struct host_block_dev host_devices[CONFIG_HOST_MAX_DEVICES];
|
||||
|
||||
static struct host_block_dev *find_host_device(int dev)
|
||||
{
|
||||
if (dev >= 0 && dev < CONFIG_HOST_MAX_DEVICES)
|
||||
return &host_devices[dev];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BLK
|
||||
static unsigned long host_block_read(struct udevice *dev,
|
||||
unsigned long start, lbaint_t blkcnt,
|
||||
void *buffer)
|
||||
@@ -24,6 +37,18 @@ static unsigned long host_block_read(struct udevice *dev,
|
||||
struct host_block_dev *host_dev = dev_get_priv(dev);
|
||||
struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
|
||||
|
||||
#else
|
||||
static unsigned long host_block_read(struct blk_desc *block_dev,
|
||||
unsigned long start, lbaint_t blkcnt,
|
||||
void *buffer)
|
||||
{
|
||||
int dev = block_dev->devnum;
|
||||
struct host_block_dev *host_dev = find_host_device(dev);
|
||||
|
||||
if (!host_dev)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
if (os_lseek(host_dev->fd, start * block_dev->blksz, OS_SEEK_SET) ==
|
||||
-1) {
|
||||
printf("ERROR: Invalid block %lx\n", start);
|
||||
@@ -35,12 +60,21 @@ static unsigned long host_block_read(struct udevice *dev,
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLK
|
||||
static unsigned long host_block_write(struct udevice *dev,
|
||||
unsigned long start, lbaint_t blkcnt,
|
||||
const void *buffer)
|
||||
{
|
||||
struct host_block_dev *host_dev = dev_get_priv(dev);
|
||||
struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
|
||||
#else
|
||||
static unsigned long host_block_write(struct blk_desc *block_dev,
|
||||
unsigned long start, lbaint_t blkcnt,
|
||||
const void *buffer)
|
||||
{
|
||||
int dev = block_dev->devnum;
|
||||
struct host_block_dev *host_dev = find_host_device(dev);
|
||||
#endif
|
||||
|
||||
if (os_lseek(host_dev->fd, start * block_dev->blksz, OS_SEEK_SET) ==
|
||||
-1) {
|
||||
@@ -53,6 +87,7 @@ static unsigned long host_block_write(struct udevice *dev,
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLK
|
||||
int host_dev_bind(int devnum, char *filename)
|
||||
{
|
||||
struct host_block_dev *host_dev;
|
||||
@@ -115,9 +150,51 @@ err:
|
||||
free(str);
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
int host_dev_bind(int dev, char *filename)
|
||||
{
|
||||
struct host_block_dev *host_dev = find_host_device(dev);
|
||||
|
||||
if (!host_dev)
|
||||
return -1;
|
||||
if (host_dev->blk_dev.priv) {
|
||||
os_close(host_dev->fd);
|
||||
host_dev->blk_dev.priv = NULL;
|
||||
}
|
||||
if (host_dev->filename)
|
||||
free(host_dev->filename);
|
||||
if (filename && *filename) {
|
||||
host_dev->filename = strdup(filename);
|
||||
} else {
|
||||
host_dev->filename = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
host_dev->fd = os_open(host_dev->filename, OS_O_RDWR);
|
||||
if (host_dev->fd == -1) {
|
||||
printf("Failed to access host backing file '%s'\n",
|
||||
host_dev->filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct blk_desc *blk_dev = &host_dev->blk_dev;
|
||||
blk_dev->if_type = IF_TYPE_HOST;
|
||||
blk_dev->priv = host_dev;
|
||||
blk_dev->blksz = 512;
|
||||
blk_dev->lba = os_lseek(host_dev->fd, 0, OS_SEEK_END) / blk_dev->blksz;
|
||||
blk_dev->block_read = host_block_read;
|
||||
blk_dev->block_write = host_block_write;
|
||||
blk_dev->devnum = dev;
|
||||
blk_dev->part_type = PART_TYPE_UNKNOWN;
|
||||
part_init(blk_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int host_get_dev_err(int devnum, struct blk_desc **blk_devp)
|
||||
{
|
||||
#ifdef CONFIG_BLK
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
@@ -125,20 +202,22 @@ int host_get_dev_err(int devnum, struct blk_desc **blk_devp)
|
||||
if (ret)
|
||||
return ret;
|
||||
*blk_devp = dev_get_uclass_platdata(dev);
|
||||
#else
|
||||
struct host_block_dev *host_dev = find_host_device(devnum);
|
||||
|
||||
if (!host_dev)
|
||||
return -ENODEV;
|
||||
|
||||
if (!host_dev->blk_dev.priv)
|
||||
return -ENOENT;
|
||||
|
||||
*blk_devp = &host_dev->blk_dev;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct blk_desc *host_get_dev(int dev)
|
||||
{
|
||||
struct blk_desc *blk_dev;
|
||||
|
||||
if (host_get_dev_err(dev, &blk_dev))
|
||||
return NULL;
|
||||
|
||||
return blk_dev;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLK
|
||||
static const struct blk_ops sandbox_host_blk_ops = {
|
||||
.read = host_block_read,
|
||||
.write = host_block_write,
|
||||
@@ -150,3 +229,11 @@ U_BOOT_DRIVER(sandbox_host_blk) = {
|
||||
.ops = &sandbox_host_blk_ops,
|
||||
.priv_auto_alloc_size = sizeof(struct host_block_dev),
|
||||
};
|
||||
#else
|
||||
U_BOOT_LEGACY_BLK(sandbox_host) = {
|
||||
.if_typename = "host",
|
||||
.if_type = IF_TYPE_HOST,
|
||||
.max_devs = CONFIG_HOST_MAX_DEVICES,
|
||||
.get_dev = host_get_dev_err,
|
||||
};
|
||||
#endif
|
||||
|
||||
29
drivers/block/sandbox_scsi.c
Normal file
29
drivers/block/sandbox_scsi.c
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Google, Inc
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* This file contains dummy implementations of SCSI functions requried so
|
||||
* that CONFIG_SCSI can be enabled for sandbox.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <scsi.h>
|
||||
|
||||
void scsi_bus_reset(void)
|
||||
{
|
||||
}
|
||||
|
||||
void scsi_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
int scsi_exec(ccb *pccb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void scsi_print_error(ccb *pccb)
|
||||
{
|
||||
}
|
||||
33
drivers/block/sata_sandbox.c
Normal file
33
drivers/block/sata_sandbox.c
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Google, Inc
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
int init_sata(int dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int reset_sata(int dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scan_sata(int dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -33,7 +33,7 @@
|
||||
#define PRINTF(fmt,args...)
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_CMD_SCSI) && defined(CONFIG_SCSI_SYM53C8XX)
|
||||
#if defined(CONFIG_SCSI) && defined(CONFIG_SCSI_SYM53C8XX)
|
||||
|
||||
#undef SCSI_SINGLE_STEP
|
||||
/*
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <systemace.h>
|
||||
#include <dm.h>
|
||||
#include <part.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
@@ -69,11 +69,9 @@ static u16 ace_readw(unsigned off)
|
||||
return in16(base + off);
|
||||
}
|
||||
|
||||
static unsigned long systemace_read(struct blk_desc *block_dev,
|
||||
unsigned long start, lbaint_t blkcnt,
|
||||
void *buffer);
|
||||
|
||||
#ifndef CONFIG_BLK
|
||||
static struct blk_desc systemace_dev = { 0 };
|
||||
#endif
|
||||
|
||||
static int get_cf_lock(void)
|
||||
{
|
||||
@@ -104,42 +102,19 @@ static void release_cf_lock(void)
|
||||
ace_writew((val & 0xffff), 0x18);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PARTITIONS
|
||||
struct blk_desc *systemace_get_dev(int dev)
|
||||
{
|
||||
/* The first time through this, the systemace_dev object is
|
||||
not yet initialized. In that case, fill it in. */
|
||||
if (systemace_dev.blksz == 0) {
|
||||
systemace_dev.if_type = IF_TYPE_UNKNOWN;
|
||||
systemace_dev.devnum = 0;
|
||||
systemace_dev.part_type = PART_TYPE_UNKNOWN;
|
||||
systemace_dev.type = DEV_TYPE_HARDDISK;
|
||||
systemace_dev.blksz = 512;
|
||||
systemace_dev.log2blksz = LOG2(systemace_dev.blksz);
|
||||
systemace_dev.removable = 1;
|
||||
systemace_dev.block_read = systemace_read;
|
||||
|
||||
/*
|
||||
* Ensure the correct bus mode (8/16 bits) gets enabled
|
||||
*/
|
||||
ace_writew(width == 8 ? 0 : 0x0001, 0);
|
||||
|
||||
part_init(&systemace_dev);
|
||||
|
||||
}
|
||||
|
||||
return &systemace_dev;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This function is called (by dereferencing the block_read pointer in
|
||||
* the dev_desc) to read blocks of data. The return value is the
|
||||
* number of blocks read. A zero return indicates an error.
|
||||
*/
|
||||
#ifdef CONFIG_BLK
|
||||
static unsigned long systemace_read(struct udevice *dev, unsigned long start,
|
||||
lbaint_t blkcnt, void *buffer)
|
||||
#else
|
||||
static unsigned long systemace_read(struct blk_desc *block_dev,
|
||||
unsigned long start, lbaint_t blkcnt,
|
||||
void *buffer)
|
||||
#endif
|
||||
{
|
||||
int retry;
|
||||
unsigned blk_countdown;
|
||||
@@ -257,3 +232,72 @@ static unsigned long systemace_read(struct blk_desc *block_dev,
|
||||
|
||||
return blkcnt;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLK
|
||||
static int systemace_bind(struct udevice *dev)
|
||||
{
|
||||
struct blk_desc *bdesc;
|
||||
struct udevice *bdev;
|
||||
int ret;
|
||||
|
||||
ret = blk_create_devicef(dev, "systemace_blk", "blk", IF_TYPE_SYSTEMACE,
|
||||
-1, 512, 0, &bdev);
|
||||
if (ret) {
|
||||
debug("Cannot create block device\n");
|
||||
return ret;
|
||||
}
|
||||
bdesc = dev_get_uclass_platdata(bdev);
|
||||
bdesc->removable = 1;
|
||||
bdesc->part_type = PART_TYPE_UNKNOWN;
|
||||
bdesc->log2blksz = LOG2(bdesc->blksz);
|
||||
|
||||
/* Ensure the correct bus mode (8/16 bits) gets enabled */
|
||||
ace_writew(width == 8 ? 0 : 0x0001, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct blk_ops systemace_blk_ops = {
|
||||
.read = systemace_read,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(systemace_blk) = {
|
||||
.name = "systemace_blk",
|
||||
.id = UCLASS_BLK,
|
||||
.ops = &systemace_blk_ops,
|
||||
.bind = systemace_bind,
|
||||
};
|
||||
#else
|
||||
static int systemace_get_dev(int dev, struct blk_desc **descp)
|
||||
{
|
||||
/* The first time through this, the systemace_dev object is
|
||||
not yet initialized. In that case, fill it in. */
|
||||
if (systemace_dev.blksz == 0) {
|
||||
systemace_dev.if_type = IF_TYPE_UNKNOWN;
|
||||
systemace_dev.devnum = 0;
|
||||
systemace_dev.part_type = PART_TYPE_UNKNOWN;
|
||||
systemace_dev.type = DEV_TYPE_HARDDISK;
|
||||
systemace_dev.blksz = 512;
|
||||
systemace_dev.log2blksz = LOG2(systemace_dev.blksz);
|
||||
systemace_dev.removable = 1;
|
||||
systemace_dev.block_read = systemace_read;
|
||||
|
||||
/*
|
||||
* Ensure the correct bus mode (8/16 bits) gets enabled
|
||||
*/
|
||||
ace_writew(width == 8 ? 0 : 0x0001, 0);
|
||||
|
||||
part_init(&systemace_dev);
|
||||
}
|
||||
*descp = &systemace_dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_LEGACY_BLK(systemace) = {
|
||||
.if_typename = "ace",
|
||||
.if_type = IF_TYPE_SYSTEMACE,
|
||||
.max_devs = 1,
|
||||
.get_dev = systemace_get_dev,
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -112,6 +112,8 @@ int device_unbind(struct udevice *dev)
|
||||
|
||||
devres_release_all(dev);
|
||||
|
||||
if (dev->flags & DM_NAME_ALLOCED)
|
||||
free((char *)dev->name);
|
||||
free(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -657,8 +657,8 @@ fdt_addr_t dev_get_addr_name(struct udevice *dev, const char *name)
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
int index;
|
||||
|
||||
index = fdt_find_string(gd->fdt_blob, dev->parent->of_offset,
|
||||
"reg-names", name);
|
||||
index = fdt_find_string(gd->fdt_blob, dev->of_offset, "reg-names",
|
||||
name);
|
||||
if (index < 0)
|
||||
return index;
|
||||
|
||||
@@ -706,12 +706,18 @@ bool device_is_last_sibling(struct udevice *dev)
|
||||
return list_is_last(&dev->sibling_node, &parent->child_head);
|
||||
}
|
||||
|
||||
void device_set_name_alloced(struct udevice *dev)
|
||||
{
|
||||
dev->flags |= DM_NAME_ALLOCED;
|
||||
}
|
||||
|
||||
int device_set_name(struct udevice *dev, const char *name)
|
||||
{
|
||||
name = strdup(name);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
dev->name = name;
|
||||
device_set_name_alloced(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -171,6 +171,10 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
|
||||
|
||||
dm_dbg(" - found match at '%s'\n", entry->name);
|
||||
ret = device_bind(parent, entry, name, NULL, offset, &dev);
|
||||
if (ret == -ENODEV) {
|
||||
dm_dbg("Driver '%s' refuses to bind\n", entry->name);
|
||||
continue;
|
||||
}
|
||||
if (ret) {
|
||||
dm_warn("Error binding driver '%s': %d\n", entry->name,
|
||||
ret);
|
||||
|
||||
@@ -50,8 +50,9 @@ static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
|
||||
|
||||
if (dfu->data.mmc.hw_partition >= 0) {
|
||||
part_num_bkp = mmc->block_dev.hwpart;
|
||||
ret = mmc_select_hwpart(dfu->data.mmc.dev_num,
|
||||
dfu->data.mmc.hw_partition);
|
||||
ret = blk_select_hwpart_devnum(IF_TYPE_MMC,
|
||||
dfu->data.mmc.dev_num,
|
||||
dfu->data.mmc.hw_partition);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@@ -75,12 +76,16 @@ static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
|
||||
if (n != blk_count) {
|
||||
error("MMC operation failed");
|
||||
if (dfu->data.mmc.hw_partition >= 0)
|
||||
mmc_select_hwpart(dfu->data.mmc.dev_num, part_num_bkp);
|
||||
blk_select_hwpart_devnum(IF_TYPE_MMC,
|
||||
dfu->data.mmc.dev_num,
|
||||
part_num_bkp);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (dfu->data.mmc.hw_partition >= 0) {
|
||||
ret = mmc_select_hwpart(dfu->data.mmc.dev_num, part_num_bkp);
|
||||
ret = blk_select_hwpart_devnum(IF_TYPE_MMC,
|
||||
dfu->data.mmc.dev_num,
|
||||
part_num_bkp);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
193
drivers/gpio/74x164_gpio.c
Normal file
193
drivers/gpio/74x164_gpio.c
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Take drivers/gpio/gpio-74x164.c as reference.
|
||||
*
|
||||
* 74Hx164 - Generic serial-in/parallel-out 8-bits shift register GPIO driver
|
||||
*
|
||||
* Copyright (C) 2016 Peng Fan <van.freenix@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
#include <dm.h>
|
||||
#include <fdtdec.h>
|
||||
#include <malloc.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/io.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <spi.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/*
|
||||
* struct gen_74x164_chip - Data for 74Hx164
|
||||
*
|
||||
* @oe: OE pin
|
||||
* @nregs: number of registers
|
||||
* @buffer: buffer for chained chips
|
||||
*/
|
||||
#define GEN_74X164_NUMBER_GPIOS 8
|
||||
|
||||
struct gen_74x164_priv {
|
||||
struct gpio_desc oe;
|
||||
u32 nregs;
|
||||
/*
|
||||
* Since the nregs are chained, every byte sent will make
|
||||
* the previous byte shift to the next register in the
|
||||
* chain. Thus, the first byte sent will end up in the last
|
||||
* register at the end of the transfer. So, to have a logical
|
||||
* numbering, store the bytes in reverse order.
|
||||
*/
|
||||
u8 *buffer;
|
||||
};
|
||||
|
||||
static int gen_74x164_write_conf(struct udevice *dev)
|
||||
{
|
||||
struct gen_74x164_priv *priv = dev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
ret = dm_spi_claim_bus(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = dm_spi_xfer(dev, priv->nregs * 8, priv->buffer, NULL,
|
||||
SPI_XFER_BEGIN | SPI_XFER_END);
|
||||
|
||||
dm_spi_release_bus(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gen_74x164_get_value(struct udevice *dev, unsigned offset)
|
||||
{
|
||||
struct gen_74x164_priv *priv = dev_get_priv(dev);
|
||||
uint bank = priv->nregs - 1 - offset / 8;
|
||||
uint pin = offset % 8;
|
||||
|
||||
return (priv->buffer[bank] >> pin) & 0x1;
|
||||
}
|
||||
|
||||
static int gen_74x164_set_value(struct udevice *dev, unsigned offset,
|
||||
int value)
|
||||
{
|
||||
struct gen_74x164_priv *priv = dev_get_priv(dev);
|
||||
uint bank = priv->nregs - 1 - offset / 8;
|
||||
uint pin = offset % 8;
|
||||
int ret;
|
||||
|
||||
if (value)
|
||||
priv->buffer[bank] |= 1 << pin;
|
||||
else
|
||||
priv->buffer[bank] &= ~(1 << pin);
|
||||
|
||||
ret = gen_74x164_write_conf(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gen_74x164_direction_input(struct udevice *dev, unsigned offset)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static int gen_74x164_direction_output(struct udevice *dev, unsigned offset,
|
||||
int value)
|
||||
{
|
||||
return gen_74x164_set_value(dev, offset, value);
|
||||
}
|
||||
|
||||
static int gen_74x164_get_function(struct udevice *dev, unsigned offset)
|
||||
{
|
||||
return GPIOF_OUTPUT;
|
||||
}
|
||||
|
||||
static int gen_74x164_xlate(struct udevice *dev, struct gpio_desc *desc,
|
||||
struct fdtdec_phandle_args *args)
|
||||
{
|
||||
desc->offset = args->args[0];
|
||||
desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_gpio_ops gen_74x164_ops = {
|
||||
.direction_input = gen_74x164_direction_input,
|
||||
.direction_output = gen_74x164_direction_output,
|
||||
.get_value = gen_74x164_get_value,
|
||||
.set_value = gen_74x164_set_value,
|
||||
.get_function = gen_74x164_get_function,
|
||||
.xlate = gen_74x164_xlate,
|
||||
};
|
||||
|
||||
static int gen_74x164_probe(struct udevice *dev)
|
||||
{
|
||||
struct gen_74x164_priv *priv = dev_get_priv(dev);
|
||||
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
char *str, name[32];
|
||||
int ret;
|
||||
const void *fdt = gd->fdt_blob;
|
||||
int node = dev->of_offset;
|
||||
|
||||
snprintf(name, sizeof(name), "%s_", dev->name);
|
||||
str = strdup(name);
|
||||
if (!str)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* See Linux kernel:
|
||||
* Documentation/devicetree/bindings/gpio/gpio-74x164.txt
|
||||
*/
|
||||
priv->nregs = fdtdec_get_int(fdt, node, "registers-number", 1);
|
||||
priv->buffer = calloc(priv->nregs, sizeof(u8));
|
||||
if (!priv->buffer) {
|
||||
ret = -ENOMEM;
|
||||
goto free_str;
|
||||
}
|
||||
|
||||
ret = fdtdec_get_byte_array(fdt, node, "registers-default",
|
||||
priv->buffer, priv->nregs);
|
||||
if (ret)
|
||||
dev_dbg(dev, "No registers-default property\n");
|
||||
|
||||
ret = gpio_request_by_name(dev, "oe-gpios", 0, &priv->oe,
|
||||
GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
|
||||
if (ret) {
|
||||
dev_err(dev, "No oe-pins property\n");
|
||||
goto free_buf;
|
||||
}
|
||||
|
||||
uc_priv->bank_name = str;
|
||||
uc_priv->gpio_count = priv->nregs * 8;
|
||||
|
||||
ret = gen_74x164_write_conf(dev);
|
||||
if (ret)
|
||||
goto free_buf;
|
||||
|
||||
dev_dbg(dev, "%s is ready\n", dev->name);
|
||||
|
||||
return 0;
|
||||
|
||||
free_buf:
|
||||
free(priv->buffer);
|
||||
free_str:
|
||||
free(str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct udevice_id gen_74x164_ids[] = {
|
||||
{ .compatible = "fairchild,74hc595" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(74x164) = {
|
||||
.name = "74x164",
|
||||
.id = UCLASS_GPIO,
|
||||
.ops = &gen_74x164_ops,
|
||||
.probe = gen_74x164_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct gen_74x164_priv),
|
||||
.of_match = gen_74x164_ids,
|
||||
};
|
||||
@@ -143,4 +143,34 @@ config ZYNQ_GPIO
|
||||
help
|
||||
Supports GPIO access on Zynq SoC.
|
||||
|
||||
config DM_74X164
|
||||
bool "74x164 serial-in/parallel-out 8-bits shift register"
|
||||
depends on DM_GPIO
|
||||
help
|
||||
Driver for 74x164 compatible serial-in/parallel-out 8-outputs
|
||||
shift registers, such as 74lv165, 74hc595.
|
||||
This driver can be used to provide access to more gpio outputs.
|
||||
|
||||
config DM_PCA953X
|
||||
bool "PCA95[357]x, PCA9698, TCA64xx, and MAX7310 I/O ports"
|
||||
depends on DM_GPIO
|
||||
help
|
||||
Say yes here to provide access to several register-oriented
|
||||
SMBus I/O expanders, made mostly by NXP or TI. Compatible
|
||||
models include:
|
||||
|
||||
4 bits: pca9536, pca9537
|
||||
|
||||
8 bits: max7310, max7315, pca6107, pca9534, pca9538, pca9554,
|
||||
pca9556, pca9557, pca9574, tca6408, xra1202
|
||||
|
||||
16 bits: max7312, max7313, pca9535, pca9539, pca9555, pca9575,
|
||||
tca6416
|
||||
|
||||
24 bits: tca6424
|
||||
|
||||
40 bits: pca9505, pca9698
|
||||
|
||||
Now, max 24 bits chips and PCA953X compatible chips are
|
||||
supported
|
||||
endmenu
|
||||
|
||||
@@ -11,6 +11,9 @@ obj-$(CONFIG_AXP_GPIO) += axp_gpio.o
|
||||
endif
|
||||
obj-$(CONFIG_DM_GPIO) += gpio-uclass.o
|
||||
|
||||
obj-$(CONFIG_DM_PCA953X) += pca953x_gpio.o
|
||||
obj-$(CONFIG_DM_74X164) += 74x164_gpio.o
|
||||
|
||||
obj-$(CONFIG_AT91_GPIO) += at91_gpio.o
|
||||
obj-$(CONFIG_ATMEL_PIO4) += atmel_pio4.o
|
||||
obj-$(CONFIG_INTEL_ICH6_GPIO) += intel_ich6_gpio.o
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <malloc.h>
|
||||
@@ -113,19 +114,33 @@ int gpio_lookup_name(const char *name, struct udevice **devp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gpio_xlate_offs_flags(struct udevice *dev,
|
||||
struct gpio_desc *desc,
|
||||
struct fdtdec_phandle_args *args)
|
||||
{
|
||||
if (args->args_count < 1)
|
||||
return -EINVAL;
|
||||
|
||||
desc->offset = args->args[0];
|
||||
|
||||
if (args->args_count < 2)
|
||||
return 0;
|
||||
|
||||
if (args->args[1] & GPIO_ACTIVE_LOW)
|
||||
desc->flags = GPIOD_ACTIVE_LOW;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_find_and_xlate(struct gpio_desc *desc,
|
||||
struct fdtdec_phandle_args *args)
|
||||
{
|
||||
struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
|
||||
|
||||
/* Use the first argument as the offset by default */
|
||||
if (args->args_count > 0)
|
||||
desc->offset = args->args[0];
|
||||
if (ops->xlate)
|
||||
return ops->xlate(desc->dev, desc, args);
|
||||
else
|
||||
desc->offset = -1;
|
||||
desc->flags = 0;
|
||||
|
||||
return ops->xlate ? ops->xlate(desc->dev, desc, args) : 0;
|
||||
return gpio_xlate_offs_flags(desc->dev, desc, args);
|
||||
}
|
||||
|
||||
int dm_gpio_request(struct gpio_desc *desc, const char *label)
|
||||
@@ -605,6 +620,7 @@ static int _gpio_request_by_name_nodev(const void *blob, int node,
|
||||
|
||||
desc->dev = NULL;
|
||||
desc->offset = 0;
|
||||
desc->flags = 0;
|
||||
ret = fdtdec_parse_phandle_with_args(blob, node, list_name,
|
||||
"#gpio-cells", 0, index, &args);
|
||||
if (ret) {
|
||||
|
||||
@@ -162,15 +162,6 @@ static int broadwell_gpio_ofdata_to_platdata(struct udevice *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int broadwell_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
|
||||
struct fdtdec_phandle_args *args)
|
||||
{
|
||||
desc->offset = args->args[0];
|
||||
desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_gpio_ops gpio_broadwell_ops = {
|
||||
.request = broadwell_gpio_request,
|
||||
.direction_input = broadwell_gpio_direction_input,
|
||||
@@ -178,7 +169,6 @@ static const struct dm_gpio_ops gpio_broadwell_ops = {
|
||||
.get_value = broadwell_gpio_get_value,
|
||||
.set_value = broadwell_gpio_set_value,
|
||||
.get_function = broadwell_gpio_get_function,
|
||||
.xlate = broadwell_gpio_xlate,
|
||||
};
|
||||
|
||||
static const struct udevice_id intel_broadwell_gpio_ids[] = {
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <asm/io.h>
|
||||
#include <asm/errno.h>
|
||||
#include <malloc.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
@@ -277,22 +276,12 @@ static int omap_gpio_get_function(struct udevice *dev, unsigned offset)
|
||||
return GPIOF_INPUT;
|
||||
}
|
||||
|
||||
static int omap_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
|
||||
struct fdtdec_phandle_args *args)
|
||||
{
|
||||
desc->offset = args->args[0];
|
||||
desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_gpio_ops gpio_omap_ops = {
|
||||
.direction_input = omap_gpio_direction_input,
|
||||
.direction_output = omap_gpio_direction_output,
|
||||
.get_value = omap_gpio_get_value,
|
||||
.set_value = omap_gpio_set_value,
|
||||
.get_function = omap_gpio_get_function,
|
||||
.xlate = omap_gpio_xlate,
|
||||
};
|
||||
|
||||
static int omap_gpio_probe(struct udevice *dev)
|
||||
|
||||
351
drivers/gpio/pca953x_gpio.c
Normal file
351
drivers/gpio/pca953x_gpio.c
Normal file
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
* Take linux kernel driver drivers/gpio/gpio-pca953x.c for reference.
|
||||
*
|
||||
* Copyright (C) 2016 Peng Fan <van.freenix@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note:
|
||||
* The driver's compatible table is borrowed from Linux Kernel,
|
||||
* but now max supported gpio pins is 24 and only PCA953X_TYPE
|
||||
* is supported. PCA957X_TYPE is not supported now.
|
||||
* Also the Polarity Inversion feature is not supported now.
|
||||
*
|
||||
* TODO:
|
||||
* 1. Support PCA957X_TYPE
|
||||
* 2. Support max 40 gpio pins
|
||||
* 3. Support Plolarity Inversion
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
#include <dm.h>
|
||||
#include <fdtdec.h>
|
||||
#include <i2c.h>
|
||||
#include <malloc.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/io.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
#define PCA953X_INPUT 0
|
||||
#define PCA953X_OUTPUT 1
|
||||
#define PCA953X_INVERT 2
|
||||
#define PCA953X_DIRECTION 3
|
||||
|
||||
#define PCA_GPIO_MASK 0x00FF
|
||||
#define PCA_INT 0x0100
|
||||
#define PCA953X_TYPE 0x1000
|
||||
#define PCA957X_TYPE 0x2000
|
||||
#define PCA_TYPE_MASK 0xF000
|
||||
#define PCA_CHIP_TYPE(x) ((x) & PCA_TYPE_MASK)
|
||||
|
||||
enum {
|
||||
PCA953X_DIRECTION_IN,
|
||||
PCA953X_DIRECTION_OUT,
|
||||
};
|
||||
|
||||
#define MAX_BANK 3
|
||||
#define BANK_SZ 8
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/*
|
||||
* struct pca953x_info - Data for pca953x
|
||||
*
|
||||
* @dev: udevice structure for the device
|
||||
* @addr: i2c slave address
|
||||
* @invert: Polarity inversion or not
|
||||
* @gpio_count: the number of gpio pins that the device supports
|
||||
* @chip_type: indicate the chip type,PCA953X or PCA957X
|
||||
* @bank_count: the number of banks that the device supports
|
||||
* @reg_output: array to hold the value of output registers
|
||||
* @reg_direction: array to hold the value of direction registers
|
||||
*/
|
||||
struct pca953x_info {
|
||||
struct udevice *dev;
|
||||
int addr;
|
||||
int invert;
|
||||
int gpio_count;
|
||||
int chip_type;
|
||||
int bank_count;
|
||||
u8 reg_output[MAX_BANK];
|
||||
u8 reg_direction[MAX_BANK];
|
||||
};
|
||||
|
||||
static int pca953x_write_single(struct udevice *dev, int reg, u8 val,
|
||||
int offset)
|
||||
{
|
||||
struct pca953x_info *info = dev_get_platdata(dev);
|
||||
int bank_shift = fls((info->gpio_count - 1) / BANK_SZ);
|
||||
int off = offset / BANK_SZ;
|
||||
int ret = 0;
|
||||
|
||||
ret = dm_i2c_write(dev, (reg << bank_shift) + off, &val, 1);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s error\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pca953x_read_single(struct udevice *dev, int reg, u8 *val,
|
||||
int offset)
|
||||
{
|
||||
struct pca953x_info *info = dev_get_platdata(dev);
|
||||
int bank_shift = fls((info->gpio_count - 1) / BANK_SZ);
|
||||
int off = offset / BANK_SZ;
|
||||
int ret;
|
||||
u8 byte;
|
||||
|
||||
ret = dm_i2c_read(dev, (reg << bank_shift) + off, &byte, 1);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s error\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*val = byte;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pca953x_read_regs(struct udevice *dev, int reg, u8 *val)
|
||||
{
|
||||
struct pca953x_info *info = dev_get_platdata(dev);
|
||||
int ret = 0;
|
||||
|
||||
if (info->gpio_count <= 8) {
|
||||
ret = dm_i2c_read(dev, reg, val, 1);
|
||||
} else if (info->gpio_count <= 16) {
|
||||
ret = dm_i2c_read(dev, reg << 1, val, info->bank_count);
|
||||
} else {
|
||||
dev_err(dev, "Unsupported now\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pca953x_is_output(struct udevice *dev, int offset)
|
||||
{
|
||||
struct pca953x_info *info = dev_get_platdata(dev);
|
||||
|
||||
int bank = offset / BANK_SZ;
|
||||
int off = offset % BANK_SZ;
|
||||
|
||||
/*0: output; 1: input */
|
||||
return !(info->reg_direction[bank] & (1 << off));
|
||||
}
|
||||
|
||||
static int pca953x_get_value(struct udevice *dev, unsigned offset)
|
||||
{
|
||||
int ret;
|
||||
u8 val = 0;
|
||||
|
||||
ret = pca953x_read_single(dev, PCA953X_INPUT, &val, offset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return (val >> offset) & 0x1;
|
||||
}
|
||||
|
||||
static int pca953x_set_value(struct udevice *dev, unsigned offset,
|
||||
int value)
|
||||
{
|
||||
struct pca953x_info *info = dev_get_platdata(dev);
|
||||
int bank = offset / BANK_SZ;
|
||||
int off = offset % BANK_SZ;
|
||||
u8 val;
|
||||
int ret;
|
||||
|
||||
if (value)
|
||||
val = info->reg_output[bank] | (1 << off);
|
||||
else
|
||||
val = info->reg_output[bank] & ~(1 << off);
|
||||
|
||||
ret = pca953x_write_single(dev, PCA953X_OUTPUT, val, offset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
info->reg_output[bank] = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pca953x_set_direction(struct udevice *dev, unsigned offset, int dir)
|
||||
{
|
||||
struct pca953x_info *info = dev_get_platdata(dev);
|
||||
int bank = offset / BANK_SZ;
|
||||
int off = offset % BANK_SZ;
|
||||
u8 val;
|
||||
int ret;
|
||||
|
||||
if (dir == PCA953X_DIRECTION_IN)
|
||||
val = info->reg_direction[bank] | (1 << off);
|
||||
else
|
||||
val = info->reg_direction[bank] & ~(1 << off);
|
||||
|
||||
ret = pca953x_write_single(dev, PCA953X_DIRECTION, val, offset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
info->reg_direction[bank] = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pca953x_direction_input(struct udevice *dev, unsigned offset)
|
||||
{
|
||||
return pca953x_set_direction(dev, offset, PCA953X_DIRECTION_IN);
|
||||
}
|
||||
|
||||
static int pca953x_direction_output(struct udevice *dev, unsigned offset,
|
||||
int value)
|
||||
{
|
||||
/* Configure output value. */
|
||||
pca953x_set_value(dev, offset, value);
|
||||
|
||||
/* Configure direction as output. */
|
||||
pca953x_set_direction(dev, offset, PCA953X_DIRECTION_OUT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pca953x_get_function(struct udevice *dev, unsigned offset)
|
||||
{
|
||||
if (pca953x_is_output(dev, offset))
|
||||
return GPIOF_OUTPUT;
|
||||
else
|
||||
return GPIOF_INPUT;
|
||||
}
|
||||
|
||||
static int pca953x_xlate(struct udevice *dev, struct gpio_desc *desc,
|
||||
struct fdtdec_phandle_args *args)
|
||||
{
|
||||
desc->offset = args->args[0];
|
||||
desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_gpio_ops pca953x_ops = {
|
||||
.direction_input = pca953x_direction_input,
|
||||
.direction_output = pca953x_direction_output,
|
||||
.get_value = pca953x_get_value,
|
||||
.set_value = pca953x_set_value,
|
||||
.get_function = pca953x_get_function,
|
||||
.xlate = pca953x_xlate,
|
||||
};
|
||||
|
||||
static int pca953x_probe(struct udevice *dev)
|
||||
{
|
||||
struct pca953x_info *info = dev_get_platdata(dev);
|
||||
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
|
||||
char name[32], *str;
|
||||
int addr;
|
||||
ulong driver_data;
|
||||
int ret;
|
||||
|
||||
if (!info) {
|
||||
dev_err(dev, "platdata not ready\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (!chip) {
|
||||
dev_err(dev, "i2c not ready\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
addr = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "reg", 0);
|
||||
if (addr == 0)
|
||||
return -ENODEV;
|
||||
|
||||
info->addr = addr;
|
||||
|
||||
driver_data = dev_get_driver_data(dev);
|
||||
|
||||
info->gpio_count = driver_data & PCA_GPIO_MASK;
|
||||
if (info->gpio_count > MAX_BANK * BANK_SZ) {
|
||||
dev_err(dev, "Max support %d pins now\n", MAX_BANK * BANK_SZ);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
info->chip_type = PCA_CHIP_TYPE(driver_data);
|
||||
if (info->chip_type != PCA953X_TYPE) {
|
||||
dev_err(dev, "Only support PCA953X chip type now.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
info->bank_count = DIV_ROUND_UP(info->gpio_count, BANK_SZ);
|
||||
|
||||
ret = pca953x_read_regs(dev, PCA953X_OUTPUT, info->reg_output);
|
||||
if (ret) {
|
||||
dev_err(dev, "Error reading output register\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = pca953x_read_regs(dev, PCA953X_DIRECTION, info->reg_direction);
|
||||
if (ret) {
|
||||
dev_err(dev, "Error reading direction register\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
snprintf(name, sizeof(name), "gpio@%x_", info->addr);
|
||||
str = strdup(name);
|
||||
if (!str)
|
||||
return -ENOMEM;
|
||||
uc_priv->bank_name = str;
|
||||
uc_priv->gpio_count = info->gpio_count;
|
||||
|
||||
dev_dbg(dev, "%s is ready\n", str);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define OF_953X(__nrgpio, __int) (ulong)(__nrgpio | PCA953X_TYPE | __int)
|
||||
#define OF_957X(__nrgpio, __int) (ulong)(__nrgpio | PCA957X_TYPE | __int)
|
||||
|
||||
static const struct udevice_id pca953x_ids[] = {
|
||||
{ .compatible = "nxp,pca9505", .data = OF_953X(40, PCA_INT), },
|
||||
{ .compatible = "nxp,pca9534", .data = OF_953X(8, PCA_INT), },
|
||||
{ .compatible = "nxp,pca9535", .data = OF_953X(16, PCA_INT), },
|
||||
{ .compatible = "nxp,pca9536", .data = OF_953X(4, 0), },
|
||||
{ .compatible = "nxp,pca9537", .data = OF_953X(4, PCA_INT), },
|
||||
{ .compatible = "nxp,pca9538", .data = OF_953X(8, PCA_INT), },
|
||||
{ .compatible = "nxp,pca9539", .data = OF_953X(16, PCA_INT), },
|
||||
{ .compatible = "nxp,pca9554", .data = OF_953X(8, PCA_INT), },
|
||||
{ .compatible = "nxp,pca9555", .data = OF_953X(16, PCA_INT), },
|
||||
{ .compatible = "nxp,pca9556", .data = OF_953X(8, 0), },
|
||||
{ .compatible = "nxp,pca9557", .data = OF_953X(8, 0), },
|
||||
{ .compatible = "nxp,pca9574", .data = OF_957X(8, PCA_INT), },
|
||||
{ .compatible = "nxp,pca9575", .data = OF_957X(16, PCA_INT), },
|
||||
{ .compatible = "nxp,pca9698", .data = OF_953X(40, 0), },
|
||||
|
||||
{ .compatible = "maxim,max7310", .data = OF_953X(8, 0), },
|
||||
{ .compatible = "maxim,max7312", .data = OF_953X(16, PCA_INT), },
|
||||
{ .compatible = "maxim,max7313", .data = OF_953X(16, PCA_INT), },
|
||||
{ .compatible = "maxim,max7315", .data = OF_953X(8, PCA_INT), },
|
||||
|
||||
{ .compatible = "ti,pca6107", .data = OF_953X(8, PCA_INT), },
|
||||
{ .compatible = "ti,tca6408", .data = OF_953X(8, PCA_INT), },
|
||||
{ .compatible = "ti,tca6416", .data = OF_953X(16, PCA_INT), },
|
||||
{ .compatible = "ti,tca6424", .data = OF_953X(24, PCA_INT), },
|
||||
|
||||
{ .compatible = "onsemi,pca9654", .data = OF_953X(8, PCA_INT), },
|
||||
|
||||
{ .compatible = "exar,xra1202", .data = OF_953X(8, 0), },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(pca953x) = {
|
||||
.name = "pca953x",
|
||||
.id = UCLASS_GPIO,
|
||||
.ops = &pca953x_ops,
|
||||
.probe = pca953x_probe,
|
||||
.platdata_auto_alloc_size = sizeof(struct pca953x_info),
|
||||
.of_match = pca953x_ids,
|
||||
};
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <asm/io.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <linux/compat.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <mach/pic32.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
@@ -99,14 +98,6 @@ static int pic32_gpio_direction_output(struct udevice *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pic32_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
|
||||
struct fdtdec_phandle_args *args)
|
||||
{
|
||||
desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pic32_gpio_get_function(struct udevice *dev, unsigned offset)
|
||||
{
|
||||
int ret = GPIOF_UNUSED;
|
||||
@@ -131,7 +122,6 @@ static const struct dm_gpio_ops gpio_pic32_ops = {
|
||||
.get_value = pic32_gpio_get_value,
|
||||
.set_value = pic32_gpio_set_value,
|
||||
.get_function = pic32_gpio_get_function,
|
||||
.xlate = pic32_gpio_xlate,
|
||||
};
|
||||
|
||||
static int pic32_gpio_probe(struct udevice *dev)
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <dm/pinctrl.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/clock/rk3288-cru.h>
|
||||
|
||||
enum {
|
||||
@@ -98,15 +97,6 @@ static int rockchip_gpio_get_function(struct udevice *dev, unsigned offset)
|
||||
#endif
|
||||
}
|
||||
|
||||
static int rockchip_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
|
||||
struct fdtdec_phandle_args *args)
|
||||
{
|
||||
desc->offset = args->args[0];
|
||||
desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rockchip_gpio_probe(struct udevice *dev)
|
||||
{
|
||||
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
@@ -135,7 +125,6 @@ static const struct dm_gpio_ops gpio_rockchip_ops = {
|
||||
.get_value = rockchip_gpio_get_value,
|
||||
.set_value = rockchip_gpio_set_value,
|
||||
.get_function = rockchip_gpio_get_function,
|
||||
.xlate = rockchip_gpio_xlate,
|
||||
};
|
||||
|
||||
static const struct udevice_id rockchip_gpio_ids[] = {
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include <asm/io.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
@@ -276,22 +275,12 @@ static int exynos_gpio_get_function(struct udevice *dev, unsigned offset)
|
||||
return GPIOF_FUNC;
|
||||
}
|
||||
|
||||
static int exynos_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
|
||||
struct fdtdec_phandle_args *args)
|
||||
{
|
||||
desc->offset = args->args[0];
|
||||
desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_gpio_ops gpio_exynos_ops = {
|
||||
.direction_input = exynos_gpio_direction_input,
|
||||
.direction_output = exynos_gpio_direction_output,
|
||||
.get_value = exynos_gpio_get_value,
|
||||
.set_value = exynos_gpio_set_value,
|
||||
.get_function = exynos_gpio_get_function,
|
||||
.xlate = exynos_gpio_xlate,
|
||||
};
|
||||
|
||||
static int gpio_exynos_probe(struct udevice *dev)
|
||||
|
||||
@@ -2,7 +2,7 @@ menu "MMC Host controller Support"
|
||||
|
||||
config MMC
|
||||
bool "Enable MMC support"
|
||||
depends on ARCH_SUNXI
|
||||
depends on ARCH_SUNXI || SANDBOX
|
||||
help
|
||||
TODO: Move all architectures to use this option
|
||||
|
||||
@@ -58,4 +58,13 @@ config MMC_UNIPHIER
|
||||
help
|
||||
This selects support for the SD/MMC Host Controller on UniPhier SoCs.
|
||||
|
||||
config SANDBOX_MMC
|
||||
bool "Sandbox MMC support"
|
||||
depends on MMC && SANDBOX
|
||||
help
|
||||
This select a dummy sandbox MMC driver. At present this does nothing
|
||||
other than allow sandbox to be build with MMC support. This
|
||||
improves build coverage for sandbox and makes it easier to detect
|
||||
MMC build errors with sandbox.
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -5,7 +5,13 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-$(CONFIG_DM_MMC) += mmc-uclass.o
|
||||
ifdef CONFIG_DM_MMC
|
||||
obj-$(CONFIG_GENERIC_MMC) += mmc-uclass.o
|
||||
endif
|
||||
|
||||
ifndef CONFIG_BLK
|
||||
obj-$(CONFIG_GENERIC_MMC) += mmc_legacy.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_ARM_PL180_MMCI) += arm_pl180_mmci.o
|
||||
obj-$(CONFIG_ATMEL_SDHCI) += atmel_sdhci.o
|
||||
@@ -34,7 +40,11 @@ obj-$(CONFIG_ROCKCHIP_DWMMC) += rockchip_dw_mmc.o
|
||||
obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o
|
||||
obj-$(CONFIG_S3C_SDI) += s3c_sdi.o
|
||||
obj-$(CONFIG_S5P_SDHCI) += s5p_sdhci.o
|
||||
ifdef CONFIG_BLK
|
||||
ifdef CONFIG_GENERIC_MMC
|
||||
obj-$(CONFIG_SANDBOX) += sandbox_mmc.o
|
||||
endif
|
||||
endif
|
||||
obj-$(CONFIG_SDHCI) += sdhci.o
|
||||
obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o
|
||||
obj-$(CONFIG_SH_SDHI) += sh_sdhi.o
|
||||
|
||||
@@ -21,6 +21,112 @@ struct mmc *mmc_get_mmc_dev(struct udevice *dev)
|
||||
return upriv->mmc;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLK
|
||||
struct mmc *find_mmc_device(int dev_num)
|
||||
{
|
||||
struct udevice *dev, *mmc_dev;
|
||||
int ret;
|
||||
|
||||
ret = blk_get_device(IF_TYPE_MMC, dev_num, &dev);
|
||||
|
||||
if (ret) {
|
||||
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
|
||||
printf("MMC Device %d not found\n", dev_num);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mmc_dev = dev_get_parent(dev);
|
||||
|
||||
return mmc_get_mmc_dev(mmc_dev);
|
||||
}
|
||||
|
||||
int get_mmc_num(void)
|
||||
{
|
||||
return max(blk_find_max_devnum(IF_TYPE_MMC), 0);
|
||||
}
|
||||
|
||||
int mmc_get_next_devnum(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = get_mmc_num();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return ret + 1;
|
||||
}
|
||||
|
||||
struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
|
||||
{
|
||||
struct blk_desc *desc;
|
||||
struct udevice *dev;
|
||||
|
||||
device_find_first_child(mmc->dev, &dev);
|
||||
if (!dev)
|
||||
return NULL;
|
||||
desc = dev_get_uclass_platdata(dev);
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
void mmc_do_preinit(void)
|
||||
{
|
||||
struct udevice *dev;
|
||||
struct uclass *uc;
|
||||
int ret;
|
||||
|
||||
ret = uclass_get(UCLASS_MMC, &uc);
|
||||
if (ret)
|
||||
return;
|
||||
uclass_foreach_dev(dev, uc) {
|
||||
struct mmc *m = mmc_get_mmc_dev(dev);
|
||||
|
||||
if (!m)
|
||||
continue;
|
||||
#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
|
||||
mmc_set_preinit(m, 1);
|
||||
#endif
|
||||
if (m->preinit)
|
||||
mmc_start_init(m);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
|
||||
void print_mmc_devices(char separator)
|
||||
{
|
||||
struct udevice *dev;
|
||||
char *mmc_type;
|
||||
bool first = true;
|
||||
|
||||
for (uclass_first_device(UCLASS_MMC, &dev);
|
||||
dev;
|
||||
uclass_next_device(&dev)) {
|
||||
struct mmc *m = mmc_get_mmc_dev(dev);
|
||||
|
||||
if (!first) {
|
||||
printf("%c", separator);
|
||||
if (separator != '\n')
|
||||
puts(" ");
|
||||
}
|
||||
if (m->has_init)
|
||||
mmc_type = IS_SD(m) ? "SD" : "eMMC";
|
||||
else
|
||||
mmc_type = NULL;
|
||||
|
||||
printf("%s: %d", m->cfg->name, mmc_get_blk_desc(m)->devnum);
|
||||
if (mmc_type)
|
||||
printf(" (%s)", mmc_type);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
#else
|
||||
void print_mmc_devices(char separator) { }
|
||||
#endif
|
||||
#endif /* CONFIG_BLK */
|
||||
|
||||
U_BOOT_DRIVER(mmc) = {
|
||||
.name = "mmc",
|
||||
.id = UCLASS_MMC,
|
||||
|
||||
@@ -21,9 +21,6 @@
|
||||
#include <div64.h>
|
||||
#include "mmc_private.h"
|
||||
|
||||
static struct list_head mmc_devices;
|
||||
static int cur_dev_num = -1;
|
||||
|
||||
__weak int board_mmc_getwp(struct mmc *mmc)
|
||||
{
|
||||
return -1;
|
||||
@@ -178,25 +175,6 @@ int mmc_set_blocklen(struct mmc *mmc, int len)
|
||||
return mmc_send_cmd(mmc, &cmd, NULL);
|
||||
}
|
||||
|
||||
struct mmc *find_mmc_device(int dev_num)
|
||||
{
|
||||
struct mmc *m;
|
||||
struct list_head *entry;
|
||||
|
||||
list_for_each(entry, &mmc_devices) {
|
||||
m = list_entry(entry, struct mmc, link);
|
||||
|
||||
if (m->block_dev.devnum == dev_num)
|
||||
return m;
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
|
||||
printf("MMC Device %d not found\n", dev_num);
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
|
||||
lbaint_t blkcnt)
|
||||
{
|
||||
@@ -238,9 +216,17 @@ static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
|
||||
return blkcnt;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLK
|
||||
static ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
|
||||
void *dst)
|
||||
#else
|
||||
static ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start,
|
||||
lbaint_t blkcnt, void *dst)
|
||||
#endif
|
||||
{
|
||||
#ifdef CONFIG_BLK
|
||||
struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
|
||||
#endif
|
||||
int dev_num = block_dev->devnum;
|
||||
int err;
|
||||
lbaint_t cur, blocks_todo = blkcnt;
|
||||
@@ -252,14 +238,14 @@ static ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start,
|
||||
if (!mmc)
|
||||
return 0;
|
||||
|
||||
err = mmc_select_hwpart(dev_num, block_dev->hwpart);
|
||||
err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
|
||||
if (err < 0)
|
||||
return 0;
|
||||
|
||||
if ((start + blkcnt) > mmc->block_dev.lba) {
|
||||
if ((start + blkcnt) > block_dev->lba) {
|
||||
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
|
||||
printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
|
||||
start + blkcnt, mmc->block_dev.lba);
|
||||
start + blkcnt, block_dev->lba);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -577,43 +563,15 @@ static int mmc_set_capacity(struct mmc *mmc, int part_num)
|
||||
return -1;
|
||||
}
|
||||
|
||||
mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
|
||||
mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mmc_select_hwpart(int dev_num, int hwpart)
|
||||
static int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
|
||||
{
|
||||
struct mmc *mmc = find_mmc_device(dev_num);
|
||||
int ret;
|
||||
|
||||
if (!mmc)
|
||||
return -ENODEV;
|
||||
|
||||
if (mmc->block_dev.hwpart == hwpart)
|
||||
return 0;
|
||||
|
||||
if (mmc->part_config == MMCPART_NOAVAILABLE) {
|
||||
printf("Card doesn't support part_switch\n");
|
||||
return -EMEDIUMTYPE;
|
||||
}
|
||||
|
||||
ret = mmc_switch_part(dev_num, hwpart);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int mmc_switch_part(int dev_num, unsigned int part_num)
|
||||
{
|
||||
struct mmc *mmc = find_mmc_device(dev_num);
|
||||
int ret;
|
||||
|
||||
if (!mmc)
|
||||
return -1;
|
||||
|
||||
ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
|
||||
(mmc->part_config & ~PART_ACCESS_MASK)
|
||||
| (part_num & PART_ACCESS_MASK));
|
||||
@@ -624,12 +582,55 @@ int mmc_switch_part(int dev_num, unsigned int part_num)
|
||||
*/
|
||||
if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
|
||||
ret = mmc_set_capacity(mmc, part_num);
|
||||
mmc->block_dev.hwpart = part_num;
|
||||
mmc_get_blk_desc(mmc)->hwpart = part_num;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLK
|
||||
static int mmc_select_hwpart(struct udevice *bdev, int hwpart)
|
||||
{
|
||||
struct udevice *mmc_dev = dev_get_parent(bdev);
|
||||
struct mmc *mmc = mmc_get_mmc_dev(mmc_dev);
|
||||
struct blk_desc *desc = dev_get_uclass_platdata(bdev);
|
||||
int ret;
|
||||
|
||||
if (desc->hwpart == hwpart)
|
||||
return 0;
|
||||
|
||||
if (mmc->part_config == MMCPART_NOAVAILABLE)
|
||||
return -EMEDIUMTYPE;
|
||||
|
||||
ret = mmc_switch_part(mmc, hwpart);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int mmc_select_hwpartp(struct blk_desc *desc, int hwpart)
|
||||
{
|
||||
struct mmc *mmc = find_mmc_device(desc->devnum);
|
||||
int ret;
|
||||
|
||||
if (!mmc)
|
||||
return -ENODEV;
|
||||
|
||||
if (mmc->block_dev.hwpart == hwpart)
|
||||
return 0;
|
||||
|
||||
if (mmc->part_config == MMCPART_NOAVAILABLE)
|
||||
return -EMEDIUMTYPE;
|
||||
|
||||
ret = mmc_switch_part(mmc, hwpart);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int mmc_hwpart_config(struct mmc *mmc,
|
||||
const struct mmc_hwpart_conf *conf,
|
||||
enum mmc_hwpart_conf_mode mode)
|
||||
@@ -1039,6 +1040,7 @@ static int mmc_startup(struct mmc *mmc)
|
||||
int timeout = 1000;
|
||||
bool has_parts = false;
|
||||
bool part_completed;
|
||||
struct blk_desc *bdesc;
|
||||
|
||||
#ifdef CONFIG_MMC_SPI_CRC_ON
|
||||
if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
|
||||
@@ -1335,7 +1337,7 @@ static int mmc_startup(struct mmc *mmc)
|
||||
mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
|
||||
}
|
||||
|
||||
err = mmc_set_capacity(mmc, mmc->block_dev.hwpart);
|
||||
err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -1475,31 +1477,32 @@ static int mmc_startup(struct mmc *mmc)
|
||||
}
|
||||
|
||||
/* fill in device description */
|
||||
mmc->block_dev.lun = 0;
|
||||
mmc->block_dev.hwpart = 0;
|
||||
mmc->block_dev.type = 0;
|
||||
mmc->block_dev.blksz = mmc->read_bl_len;
|
||||
mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz);
|
||||
mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
|
||||
bdesc = mmc_get_blk_desc(mmc);
|
||||
bdesc->lun = 0;
|
||||
bdesc->hwpart = 0;
|
||||
bdesc->type = 0;
|
||||
bdesc->blksz = mmc->read_bl_len;
|
||||
bdesc->log2blksz = LOG2(bdesc->blksz);
|
||||
bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
|
||||
#if !defined(CONFIG_SPL_BUILD) || \
|
||||
(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
|
||||
!defined(CONFIG_USE_TINY_PRINTF))
|
||||
sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x",
|
||||
sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
|
||||
mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
|
||||
(mmc->cid[3] >> 16) & 0xffff);
|
||||
sprintf(mmc->block_dev.product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
|
||||
sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
|
||||
(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
|
||||
(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
|
||||
(mmc->cid[2] >> 24) & 0xff);
|
||||
sprintf(mmc->block_dev.revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
|
||||
sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
|
||||
(mmc->cid[2] >> 16) & 0xf);
|
||||
#else
|
||||
mmc->block_dev.vendor[0] = 0;
|
||||
mmc->block_dev.product[0] = 0;
|
||||
mmc->block_dev.revision[0] = 0;
|
||||
bdesc->vendor[0] = 0;
|
||||
bdesc->product[0] = 0;
|
||||
bdesc->revision[0] = 0;
|
||||
#endif
|
||||
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
|
||||
part_init(&mmc->block_dev);
|
||||
part_init(bdesc);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
@@ -1537,8 +1540,55 @@ int __deprecated mmc_register(struct mmc *mmc)
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLK
|
||||
int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg)
|
||||
{
|
||||
struct blk_desc *bdesc;
|
||||
struct udevice *bdev;
|
||||
int ret;
|
||||
|
||||
ret = blk_create_devicef(dev, "mmc_blk", "blk", IF_TYPE_MMC, -1, 512,
|
||||
0, &bdev);
|
||||
if (ret) {
|
||||
debug("Cannot create block device\n");
|
||||
return ret;
|
||||
}
|
||||
bdesc = dev_get_uclass_platdata(bdev);
|
||||
mmc->cfg = cfg;
|
||||
mmc->priv = dev;
|
||||
|
||||
/* the following chunk was from mmc_register() */
|
||||
|
||||
/* Setup dsr related values */
|
||||
mmc->dsr_imp = 0;
|
||||
mmc->dsr = 0xffffffff;
|
||||
/* Setup the universal parts of the block interface just once */
|
||||
bdesc->removable = 1;
|
||||
|
||||
/* setup initial part type */
|
||||
bdesc->part_type = mmc->cfg->part_type;
|
||||
mmc->dev = dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mmc_unbind(struct udevice *dev)
|
||||
{
|
||||
struct udevice *bdev;
|
||||
|
||||
device_find_first_child(dev, &bdev);
|
||||
if (bdev) {
|
||||
device_remove(bdev);
|
||||
device_unbind(bdev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
struct mmc *mmc_create(const struct mmc_config *cfg, void *priv)
|
||||
{
|
||||
struct blk_desc *bdesc;
|
||||
struct mmc *mmc;
|
||||
|
||||
/* quick validation */
|
||||
@@ -1559,19 +1609,17 @@ struct mmc *mmc_create(const struct mmc_config *cfg, void *priv)
|
||||
mmc->dsr_imp = 0;
|
||||
mmc->dsr = 0xffffffff;
|
||||
/* Setup the universal parts of the block interface just once */
|
||||
mmc->block_dev.if_type = IF_TYPE_MMC;
|
||||
mmc->block_dev.devnum = cur_dev_num++;
|
||||
mmc->block_dev.removable = 1;
|
||||
mmc->block_dev.block_read = mmc_bread;
|
||||
mmc->block_dev.block_write = mmc_bwrite;
|
||||
mmc->block_dev.block_erase = mmc_berase;
|
||||
bdesc = mmc_get_blk_desc(mmc);
|
||||
bdesc->if_type = IF_TYPE_MMC;
|
||||
bdesc->removable = 1;
|
||||
bdesc->devnum = mmc_get_next_devnum();
|
||||
bdesc->block_read = mmc_bread;
|
||||
bdesc->block_write = mmc_bwrite;
|
||||
bdesc->block_erase = mmc_berase;
|
||||
|
||||
/* setup initial part type */
|
||||
mmc->block_dev.part_type = mmc->cfg->part_type;
|
||||
|
||||
INIT_LIST_HEAD(&mmc->link);
|
||||
|
||||
list_add_tail(&mmc->link, &mmc_devices);
|
||||
bdesc->part_type = mmc->cfg->part_type;
|
||||
mmc_list_add(mmc);
|
||||
|
||||
return mmc;
|
||||
}
|
||||
@@ -1581,15 +1629,23 @@ void mmc_destroy(struct mmc *mmc)
|
||||
/* only freeing memory for now */
|
||||
free(mmc);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PARTITIONS
|
||||
struct blk_desc *mmc_get_dev(int dev)
|
||||
#ifndef CONFIG_BLK
|
||||
static int mmc_get_dev(int dev, struct blk_desc **descp)
|
||||
{
|
||||
struct mmc *mmc = find_mmc_device(dev);
|
||||
if (!mmc || mmc_init(mmc))
|
||||
return NULL;
|
||||
int ret;
|
||||
|
||||
return &mmc->block_dev;
|
||||
if (!mmc)
|
||||
return -ENODEV;
|
||||
ret = mmc_init(mmc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*descp = &mmc->block_dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1636,7 +1692,7 @@ int mmc_start_init(struct mmc *mmc)
|
||||
return err;
|
||||
|
||||
/* The internal partition reset to user partition(0) at every CMD0*/
|
||||
mmc->block_dev.hwpart = 0;
|
||||
mmc_get_blk_desc(mmc)->hwpart = 0;
|
||||
|
||||
/* Test for SD version 2 */
|
||||
err = mmc_send_if_cond(mmc);
|
||||
@@ -1683,7 +1739,11 @@ int mmc_init(struct mmc *mmc)
|
||||
{
|
||||
int err = 0;
|
||||
unsigned start;
|
||||
#ifdef CONFIG_DM_MMC
|
||||
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
|
||||
|
||||
upriv->mmc = mmc;
|
||||
#endif
|
||||
if (mmc->has_init)
|
||||
return 0;
|
||||
|
||||
@@ -1716,66 +1776,11 @@ __weak int board_mmc_init(bd_t *bis)
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
|
||||
|
||||
void print_mmc_devices(char separator)
|
||||
{
|
||||
struct mmc *m;
|
||||
struct list_head *entry;
|
||||
char *mmc_type;
|
||||
|
||||
list_for_each(entry, &mmc_devices) {
|
||||
m = list_entry(entry, struct mmc, link);
|
||||
|
||||
if (m->has_init)
|
||||
mmc_type = IS_SD(m) ? "SD" : "eMMC";
|
||||
else
|
||||
mmc_type = NULL;
|
||||
|
||||
printf("%s: %d", m->cfg->name, m->block_dev.devnum);
|
||||
if (mmc_type)
|
||||
printf(" (%s)", mmc_type);
|
||||
|
||||
if (entry->next != &mmc_devices) {
|
||||
printf("%c", separator);
|
||||
if (separator != '\n')
|
||||
puts (" ");
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
#else
|
||||
void print_mmc_devices(char separator) { }
|
||||
#endif
|
||||
|
||||
int get_mmc_num(void)
|
||||
{
|
||||
return cur_dev_num;
|
||||
}
|
||||
|
||||
void mmc_set_preinit(struct mmc *mmc, int preinit)
|
||||
{
|
||||
mmc->preinit = preinit;
|
||||
}
|
||||
|
||||
static void do_preinit(void)
|
||||
{
|
||||
struct mmc *m;
|
||||
struct list_head *entry;
|
||||
|
||||
list_for_each(entry, &mmc_devices) {
|
||||
m = list_entry(entry, struct mmc, link);
|
||||
|
||||
#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
|
||||
mmc_set_preinit(m, 1);
|
||||
#endif
|
||||
if (m->preinit)
|
||||
mmc_start_init(m);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DM_MMC) && defined(CONFIG_SPL_BUILD)
|
||||
static int mmc_probe(bd_t *bis)
|
||||
{
|
||||
@@ -1828,9 +1833,9 @@ int mmc_initialize(bd_t *bis)
|
||||
return 0;
|
||||
initialized = 1;
|
||||
|
||||
INIT_LIST_HEAD (&mmc_devices);
|
||||
cur_dev_num = 0;
|
||||
|
||||
#ifndef CONFIG_BLK
|
||||
mmc_list_init();
|
||||
#endif
|
||||
ret = mmc_probe(bis);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -1839,7 +1844,7 @@ int mmc_initialize(bd_t *bis)
|
||||
print_mmc_devices(',');
|
||||
#endif
|
||||
|
||||
do_preinit();
|
||||
mmc_do_preinit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1965,3 +1970,25 @@ int mmc_set_rst_n_function(struct mmc *mmc, u8 enable)
|
||||
enable);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BLK
|
||||
static const struct blk_ops mmc_blk_ops = {
|
||||
.read = mmc_bread,
|
||||
.write = mmc_bwrite,
|
||||
.select_hwpart = mmc_select_hwpart,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(mmc_blk) = {
|
||||
.name = "mmc_blk",
|
||||
.id = UCLASS_BLK,
|
||||
.ops = &mmc_blk_ops,
|
||||
};
|
||||
#else
|
||||
U_BOOT_LEGACY_BLK(mmc) = {
|
||||
.if_typename = "mmc",
|
||||
.if_type = IF_TYPE_MMC,
|
||||
.max_devs = -1,
|
||||
.get_dev = mmc_get_dev,
|
||||
.select_hwpart = mmc_select_hwpartp,
|
||||
};
|
||||
#endif
|
||||
|
||||
108
drivers/mmc/mmc_legacy.c
Normal file
108
drivers/mmc/mmc_legacy.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Google, Inc
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <mmc.h>
|
||||
|
||||
static struct list_head mmc_devices;
|
||||
static int cur_dev_num = -1;
|
||||
|
||||
struct mmc *find_mmc_device(int dev_num)
|
||||
{
|
||||
struct mmc *m;
|
||||
struct list_head *entry;
|
||||
|
||||
list_for_each(entry, &mmc_devices) {
|
||||
m = list_entry(entry, struct mmc, link);
|
||||
|
||||
if (m->block_dev.devnum == dev_num)
|
||||
return m;
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
|
||||
printf("MMC Device %d not found\n", dev_num);
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int mmc_get_next_devnum(void)
|
||||
{
|
||||
return cur_dev_num++;
|
||||
}
|
||||
|
||||
struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
|
||||
{
|
||||
return &mmc->block_dev;
|
||||
}
|
||||
|
||||
int get_mmc_num(void)
|
||||
{
|
||||
return cur_dev_num;
|
||||
}
|
||||
|
||||
void mmc_do_preinit(void)
|
||||
{
|
||||
struct mmc *m;
|
||||
struct list_head *entry;
|
||||
|
||||
list_for_each(entry, &mmc_devices) {
|
||||
m = list_entry(entry, struct mmc, link);
|
||||
|
||||
#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
|
||||
mmc_set_preinit(m, 1);
|
||||
#endif
|
||||
if (m->preinit)
|
||||
mmc_start_init(m);
|
||||
}
|
||||
}
|
||||
|
||||
void mmc_list_init(void)
|
||||
{
|
||||
INIT_LIST_HEAD(&mmc_devices);
|
||||
cur_dev_num = 0;
|
||||
}
|
||||
|
||||
void mmc_list_add(struct mmc *mmc)
|
||||
{
|
||||
INIT_LIST_HEAD(&mmc->link);
|
||||
|
||||
list_add_tail(&mmc->link, &mmc_devices);
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
|
||||
void print_mmc_devices(char separator)
|
||||
{
|
||||
struct mmc *m;
|
||||
struct list_head *entry;
|
||||
char *mmc_type;
|
||||
|
||||
list_for_each(entry, &mmc_devices) {
|
||||
m = list_entry(entry, struct mmc, link);
|
||||
|
||||
if (m->has_init)
|
||||
mmc_type = IS_SD(m) ? "SD" : "eMMC";
|
||||
else
|
||||
mmc_type = NULL;
|
||||
|
||||
printf("%s: %d", m->cfg->name, m->block_dev.devnum);
|
||||
if (mmc_type)
|
||||
printf(" (%s)", mmc_type);
|
||||
|
||||
if (entry->next != &mmc_devices) {
|
||||
printf("%c", separator);
|
||||
if (separator != '\n')
|
||||
puts(" ");
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
#else
|
||||
void print_mmc_devices(char separator) { }
|
||||
#endif
|
||||
@@ -25,8 +25,13 @@ void mmc_adapter_card_type_ident(void);
|
||||
unsigned long mmc_berase(struct blk_desc *block_dev, lbaint_t start,
|
||||
lbaint_t blkcnt);
|
||||
|
||||
unsigned long mmc_bwrite(struct blk_desc *block_dev, lbaint_t start,
|
||||
lbaint_t blkcnt, const void *src);
|
||||
#ifdef CONFIG_BLK
|
||||
ulong mmc_bwrite(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
|
||||
const void *src);
|
||||
#else
|
||||
ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
|
||||
const void *src);
|
||||
#endif
|
||||
|
||||
#else /* CONFIG_SPL_BUILD */
|
||||
|
||||
@@ -46,4 +51,28 @@ static inline ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start,
|
||||
|
||||
#endif /* CONFIG_SPL_BUILD */
|
||||
|
||||
/**
|
||||
* mmc_get_next_devnum() - Get the next available MMC device number
|
||||
*
|
||||
* @return next available device number (0 = first), or -ve on error
|
||||
*/
|
||||
int mmc_get_next_devnum(void);
|
||||
|
||||
/**
|
||||
* mmc_do_preinit() - Get an MMC device ready for use
|
||||
*/
|
||||
void mmc_do_preinit(void);
|
||||
|
||||
/**
|
||||
* mmc_list_init() - Set up the list of MMC devices
|
||||
*/
|
||||
void mmc_list_init(void);
|
||||
|
||||
/**
|
||||
* mmc_list_add() - Add a new MMC device to the list of devices
|
||||
*
|
||||
* @mmc: Device to add
|
||||
*/
|
||||
void mmc_list_add(struct mmc *mmc);
|
||||
|
||||
#endif /* _MMC_PRIVATE_H_ */
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <part.h>
|
||||
#include <div64.h>
|
||||
#include <linux/math64.h>
|
||||
@@ -78,7 +79,8 @@ unsigned long mmc_berase(struct blk_desc *block_dev, lbaint_t start,
|
||||
if (!mmc)
|
||||
return -1;
|
||||
|
||||
err = mmc_select_hwpart(dev_num, block_dev->hwpart);
|
||||
err = blk_select_hwpart_devnum(IF_TYPE_MMC, dev_num,
|
||||
block_dev->hwpart);
|
||||
if (err < 0)
|
||||
return -1;
|
||||
|
||||
@@ -121,9 +123,9 @@ static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start,
|
||||
struct mmc_data data;
|
||||
int timeout = 1000;
|
||||
|
||||
if ((start + blkcnt) > mmc->block_dev.lba) {
|
||||
if ((start + blkcnt) > mmc_get_blk_desc(mmc)->lba) {
|
||||
printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
|
||||
start + blkcnt, mmc->block_dev.lba);
|
||||
start + blkcnt, mmc_get_blk_desc(mmc)->lba);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -171,9 +173,17 @@ static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start,
|
||||
return blkcnt;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLK
|
||||
ulong mmc_bwrite(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
|
||||
const void *src)
|
||||
#else
|
||||
ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
|
||||
const void *src)
|
||||
#endif
|
||||
{
|
||||
#ifdef CONFIG_BLK
|
||||
struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
|
||||
#endif
|
||||
int dev_num = block_dev->devnum;
|
||||
lbaint_t cur, blocks_todo = blkcnt;
|
||||
int err;
|
||||
@@ -182,7 +192,7 @@ ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
|
||||
if (!mmc)
|
||||
return 0;
|
||||
|
||||
err = mmc_select_hwpart(dev_num, block_dev->hwpart);
|
||||
err = blk_select_hwpart_devnum(IF_TYPE_MMC, dev_num, block_dev->hwpart);
|
||||
if (err < 0)
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -825,6 +825,7 @@ static int omap_hsmmc_probe(struct udevice *dev)
|
||||
gpio_request_by_name(dev, "wp-gpios", 0, &priv->wp_gpio, GPIOD_IS_IN);
|
||||
#endif
|
||||
|
||||
mmc->dev = dev;
|
||||
upriv->mmc = mmc;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -41,7 +41,12 @@ static int pic32_sdhci_probe(struct udevice *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return add_sdhci(host, f_min_max[1], f_min_max[0]);
|
||||
ret = add_sdhci(host, f_min_max[1], f_min_max[0]);
|
||||
if (ret)
|
||||
return ret;
|
||||
host->mmc->dev = dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id pic32_sdhci_ids[] = {
|
||||
|
||||
@@ -104,6 +104,7 @@ static int rockchip_dwmmc_probe(struct udevice *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
host->mmc->dev = dev;
|
||||
upriv->mmc = host->mmc;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -8,18 +8,150 @@
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <mmc.h>
|
||||
#include <asm/test.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
struct sandbox_mmc_plat {
|
||||
struct mmc_config cfg;
|
||||
struct mmc mmc;
|
||||
};
|
||||
|
||||
/**
|
||||
* sandbox_mmc_send_cmd() - Emulate SD commands
|
||||
*
|
||||
* This emulate an SD card version 2. Single-block reads result in zero data.
|
||||
* Multiple-block reads return a test string.
|
||||
*/
|
||||
static int sandbox_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
|
||||
struct mmc_data *data)
|
||||
{
|
||||
switch (cmd->cmdidx) {
|
||||
case MMC_CMD_ALL_SEND_CID:
|
||||
break;
|
||||
case SD_CMD_SEND_RELATIVE_ADDR:
|
||||
cmd->response[0] = 0 << 16; /* mmc->rca */
|
||||
case MMC_CMD_GO_IDLE_STATE:
|
||||
break;
|
||||
case SD_CMD_SEND_IF_COND:
|
||||
cmd->response[0] = 0xaa;
|
||||
break;
|
||||
case MMC_CMD_SEND_STATUS:
|
||||
cmd->response[0] = MMC_STATUS_RDY_FOR_DATA;
|
||||
break;
|
||||
case MMC_CMD_SELECT_CARD:
|
||||
break;
|
||||
case MMC_CMD_SEND_CSD:
|
||||
cmd->response[0] = 0;
|
||||
cmd->response[1] = 10 << 16; /* 1 << block_len */
|
||||
break;
|
||||
case SD_CMD_SWITCH_FUNC: {
|
||||
u32 *resp = (u32 *)data->dest;
|
||||
|
||||
resp[7] = cpu_to_be32(SD_HIGHSPEED_BUSY);
|
||||
break;
|
||||
}
|
||||
case MMC_CMD_READ_SINGLE_BLOCK:
|
||||
memset(data->dest, '\0', data->blocksize);
|
||||
break;
|
||||
case MMC_CMD_READ_MULTIPLE_BLOCK:
|
||||
strcpy(data->dest, "this is a test");
|
||||
break;
|
||||
case MMC_CMD_STOP_TRANSMISSION:
|
||||
break;
|
||||
case SD_CMD_APP_SEND_OP_COND:
|
||||
cmd->response[0] = OCR_BUSY | OCR_HCS;
|
||||
cmd->response[1] = 0;
|
||||
cmd->response[2] = 0;
|
||||
break;
|
||||
case MMC_CMD_APP_CMD:
|
||||
break;
|
||||
case MMC_CMD_SET_BLOCKLEN:
|
||||
debug("block len %d\n", cmd->cmdarg);
|
||||
break;
|
||||
case SD_CMD_APP_SEND_SCR: {
|
||||
u32 *scr = (u32 *)data->dest;
|
||||
|
||||
scr[0] = cpu_to_be32(2 << 24 | 1 << 15); /* SD version 3 */
|
||||
break;
|
||||
}
|
||||
default:
|
||||
debug("%s: Unknown command %d\n", __func__, cmd->cmdidx);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sandbox_mmc_set_ios(struct mmc *mmc)
|
||||
{
|
||||
}
|
||||
|
||||
static int sandbox_mmc_init(struct mmc *mmc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sandbox_mmc_getcd(struct mmc *mmc)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct mmc_ops sandbox_mmc_ops = {
|
||||
.send_cmd = sandbox_mmc_send_cmd,
|
||||
.set_ios = sandbox_mmc_set_ios,
|
||||
.init = sandbox_mmc_init,
|
||||
.getcd = sandbox_mmc_getcd,
|
||||
};
|
||||
|
||||
int sandbox_mmc_probe(struct udevice *dev)
|
||||
{
|
||||
struct sandbox_mmc_plat *plat = dev_get_platdata(dev);
|
||||
|
||||
return mmc_init(&plat->mmc);
|
||||
}
|
||||
|
||||
int sandbox_mmc_bind(struct udevice *dev)
|
||||
{
|
||||
struct sandbox_mmc_plat *plat = dev_get_platdata(dev);
|
||||
struct mmc_config *cfg = &plat->cfg;
|
||||
int ret;
|
||||
|
||||
cfg->name = dev->name;
|
||||
cfg->ops = &sandbox_mmc_ops;
|
||||
cfg->host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS | MMC_MODE_8BIT;
|
||||
cfg->voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34;
|
||||
cfg->f_min = 1000000;
|
||||
cfg->f_max = 52000000;
|
||||
cfg->b_max = U32_MAX;
|
||||
|
||||
ret = mmc_bind(dev, &plat->mmc, cfg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sandbox_mmc_unbind(struct udevice *dev)
|
||||
{
|
||||
mmc_unbind(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id sandbox_mmc_ids[] = {
|
||||
{ .compatible = "sandbox,mmc" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(warm_mmc_sandbox) = {
|
||||
U_BOOT_DRIVER(mmc_sandbox) = {
|
||||
.name = "mmc_sandbox",
|
||||
.id = UCLASS_MMC,
|
||||
.of_match = sandbox_mmc_ids,
|
||||
.bind = sandbox_mmc_bind,
|
||||
.unbind = sandbox_mmc_unbind,
|
||||
.probe = sandbox_mmc_probe,
|
||||
.platdata_auto_alloc_size = sizeof(struct sandbox_mmc_plat),
|
||||
};
|
||||
|
||||
@@ -108,6 +108,7 @@ static int socfpga_dwmmc_probe(struct udevice *dev)
|
||||
return ret;
|
||||
|
||||
upriv->mmc = host->mmc;
|
||||
host->mmc->dev = dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -725,6 +725,7 @@ int uniphier_sd_probe(struct udevice *dev)
|
||||
return -EIO;
|
||||
|
||||
upriv->mmc = priv->mmc;
|
||||
priv->mmc->dev = dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ static int arasan_sdhci_probe(struct udevice *dev)
|
||||
CONFIG_ZYNQ_SDHCI_MIN_FREQ);
|
||||
|
||||
upriv->mmc = host->mmc;
|
||||
host->mmc->dev = dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -175,11 +175,7 @@ pci_dev_t pci_find_devices(struct pci_device_id *ids, int index)
|
||||
int bus;
|
||||
|
||||
for (hose = pci_get_hose_head(); hose; hose = hose->next) {
|
||||
#ifdef CONFIG_SYS_SCSI_SCAN_BUS_REVERSE
|
||||
for (bus = hose->last_busno; bus >= hose->first_busno; bus--) {
|
||||
#else
|
||||
for (bus = hose->first_busno; bus <= hose->last_busno; bus++) {
|
||||
#endif
|
||||
bdf = pci_hose_find_devices(hose, bus, ids, &index);
|
||||
if (bdf != -1)
|
||||
return bdf;
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
* (C) Copyright 2004-2007 Freescale Semiconductor, Inc.
|
||||
* TsiChung Liew, Tsi-Chung.Liew@freescale.com.
|
||||
*
|
||||
* Modified to add device model (DM) support
|
||||
* (C) Copyright 2015 Angelo Dureghello <angelo@sysam.it>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
@@ -11,9 +14,10 @@
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <dm/platform_data/serial_coldfire.h>
|
||||
#include <serial.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
#include <asm/immap.h>
|
||||
#include <asm/uart.h>
|
||||
|
||||
@@ -21,91 +25,110 @@ DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
extern void uart_port_conf(int port);
|
||||
|
||||
static int mcf_serial_init(void)
|
||||
static int mcf_serial_init_common(uart_t *uart, int port_idx, int baudrate)
|
||||
{
|
||||
volatile uart_t *uart;
|
||||
u32 counter;
|
||||
|
||||
uart = (volatile uart_t *)(CONFIG_SYS_UART_BASE);
|
||||
|
||||
uart_port_conf(CONFIG_SYS_UART_PORT);
|
||||
uart_port_conf(port_idx);
|
||||
|
||||
/* write to SICR: SIM2 = uart mode,dcd does not affect rx */
|
||||
uart->ucr = UART_UCR_RESET_RX;
|
||||
uart->ucr = UART_UCR_RESET_TX;
|
||||
uart->ucr = UART_UCR_RESET_ERROR;
|
||||
uart->ucr = UART_UCR_RESET_MR;
|
||||
writeb(UART_UCR_RESET_RX, &uart->ucr);
|
||||
writeb(UART_UCR_RESET_TX, &uart->ucr);
|
||||
writeb(UART_UCR_RESET_ERROR, &uart->ucr);
|
||||
writeb(UART_UCR_RESET_MR, &uart->ucr);
|
||||
__asm__("nop");
|
||||
|
||||
uart->uimr = 0;
|
||||
writeb(0, &uart->uimr);
|
||||
|
||||
/* write to CSR: RX/TX baud rate from timers */
|
||||
uart->ucsr = (UART_UCSR_RCS_SYS_CLK | UART_UCSR_TCS_SYS_CLK);
|
||||
writeb(UART_UCSR_RCS_SYS_CLK | UART_UCSR_TCS_SYS_CLK, &uart->ucsr);
|
||||
|
||||
uart->umr = (UART_UMR_BC_8 | UART_UMR_PM_NONE);
|
||||
uart->umr = UART_UMR_SB_STOP_BITS_1;
|
||||
writeb(UART_UMR_BC_8 | UART_UMR_PM_NONE, &uart->umr);
|
||||
writeb(UART_UMR_SB_STOP_BITS_1, &uart->umr);
|
||||
|
||||
/* Setting up BaudRate */
|
||||
counter = (u32) ((gd->bus_clk / 32) + (gd->baudrate / 2));
|
||||
counter = counter / gd->baudrate;
|
||||
counter = (u32) ((gd->bus_clk / 32) + (baudrate / 2));
|
||||
counter = counter / baudrate;
|
||||
|
||||
/* write to CTUR: divide counter upper byte */
|
||||
uart->ubg1 = (u8) ((counter & 0xff00) >> 8);
|
||||
writeb((u8)((counter & 0xff00) >> 8), &uart->ubg1);
|
||||
/* write to CTLR: divide counter lower byte */
|
||||
uart->ubg2 = (u8) (counter & 0x00ff);
|
||||
writeb((u8)(counter & 0x00ff), &uart->ubg2);
|
||||
|
||||
uart->ucr = (UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED);
|
||||
writeb(UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED, &uart->ucr);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void mcf_serial_setbrg_common(uart_t *uart, int baudrate)
|
||||
{
|
||||
u32 counter;
|
||||
|
||||
/* Setting up BaudRate */
|
||||
counter = (u32) ((gd->bus_clk / 32) + (baudrate / 2));
|
||||
counter = counter / baudrate;
|
||||
|
||||
/* write to CTUR: divide counter upper byte */
|
||||
writeb(((counter & 0xff00) >> 8), &uart->ubg1);
|
||||
/* write to CTLR: divide counter lower byte */
|
||||
writeb((counter & 0x00ff), &uart->ubg2);
|
||||
|
||||
writeb(UART_UCR_RESET_RX, &uart->ucr);
|
||||
writeb(UART_UCR_RESET_TX, &uart->ucr);
|
||||
|
||||
writeb(UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED, &uart->ucr);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_DM_SERIAL
|
||||
|
||||
static int mcf_serial_init(void)
|
||||
{
|
||||
uart_t *uart_base;
|
||||
int port_idx;
|
||||
|
||||
uart_base = (uart_t *)CONFIG_SYS_UART_BASE;
|
||||
port_idx = CONFIG_SYS_UART_PORT;
|
||||
|
||||
return mcf_serial_init_common(uart_base, port_idx, gd->baudrate);
|
||||
}
|
||||
|
||||
static void mcf_serial_putc(const char c)
|
||||
{
|
||||
volatile uart_t *uart = (volatile uart_t *)(CONFIG_SYS_UART_BASE);
|
||||
uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
|
||||
|
||||
if (c == '\n')
|
||||
serial_putc('\r');
|
||||
|
||||
/* Wait for last character to go. */
|
||||
while (!(uart->usr & UART_USR_TXRDY)) ;
|
||||
while (!(readb(&uart->usr) & UART_USR_TXRDY))
|
||||
;
|
||||
|
||||
uart->utb = c;
|
||||
writeb(c, &uart->utb);
|
||||
}
|
||||
|
||||
static int mcf_serial_getc(void)
|
||||
{
|
||||
volatile uart_t *uart = (volatile uart_t *)(CONFIG_SYS_UART_BASE);
|
||||
uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
|
||||
|
||||
/* Wait for a character to arrive. */
|
||||
while (!(uart->usr & UART_USR_RXRDY)) ;
|
||||
return uart->urb;
|
||||
}
|
||||
while (!(readb(&uart->usr) & UART_USR_RXRDY))
|
||||
;
|
||||
|
||||
static int mcf_serial_tstc(void)
|
||||
{
|
||||
volatile uart_t *uart = (volatile uart_t *)(CONFIG_SYS_UART_BASE);
|
||||
|
||||
return (uart->usr & UART_USR_RXRDY);
|
||||
return readb(&uart->urb);
|
||||
}
|
||||
|
||||
static void mcf_serial_setbrg(void)
|
||||
{
|
||||
volatile uart_t *uart = (volatile uart_t *)(CONFIG_SYS_UART_BASE);
|
||||
u32 counter;
|
||||
uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
|
||||
|
||||
/* Setting up BaudRate */
|
||||
counter = (u32) ((gd->bus_clk / 32) + (gd->baudrate / 2));
|
||||
counter = counter / gd->baudrate;
|
||||
mcf_serial_setbrg_common(uart, gd->baudrate);
|
||||
}
|
||||
|
||||
/* write to CTUR: divide counter upper byte */
|
||||
uart->ubg1 = ((counter & 0xff00) >> 8);
|
||||
/* write to CTLR: divide counter lower byte */
|
||||
uart->ubg2 = (counter & 0x00ff);
|
||||
static int mcf_serial_tstc(void)
|
||||
{
|
||||
uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
|
||||
|
||||
uart->ucr = UART_UCR_RESET_RX;
|
||||
uart->ucr = UART_UCR_RESET_TX;
|
||||
|
||||
uart->ucr = UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED;
|
||||
return readb(&uart->usr) & UART_USR_RXRDY;
|
||||
}
|
||||
|
||||
static struct serial_device mcf_serial_drv = {
|
||||
@@ -128,3 +151,80 @@ __weak struct serial_device *default_serial_console(void)
|
||||
{
|
||||
return &mcf_serial_drv;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DM_SERIAL
|
||||
|
||||
static int coldfire_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct coldfire_serial_platdata *plat = dev->platdata;
|
||||
|
||||
return mcf_serial_init_common((uart_t *)plat->base,
|
||||
plat->port, plat->baudrate);
|
||||
}
|
||||
|
||||
static int coldfire_serial_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct coldfire_serial_platdata *plat = dev->platdata;
|
||||
uart_t *uart = (uart_t *)plat->base;
|
||||
|
||||
/* Wait for last character to go. */
|
||||
if (!(readb(&uart->usr) & UART_USR_TXRDY))
|
||||
return -EAGAIN;
|
||||
|
||||
writeb(ch, &uart->utb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int coldfire_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct coldfire_serial_platdata *plat = dev->platdata;
|
||||
uart_t *uart = (uart_t *)(plat->base);
|
||||
|
||||
/* Wait for a character to arrive. */
|
||||
if (!(readb(&uart->usr) & UART_USR_RXRDY))
|
||||
return -EAGAIN;
|
||||
|
||||
return readb(&uart->urb);
|
||||
}
|
||||
|
||||
int coldfire_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct coldfire_serial_platdata *plat = dev->platdata;
|
||||
uart_t *uart = (uart_t *)(plat->base);
|
||||
|
||||
mcf_serial_setbrg_common(uart, baudrate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int coldfire_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct coldfire_serial_platdata *plat = dev->platdata;
|
||||
uart_t *uart = (uart_t *)(plat->base);
|
||||
|
||||
if (input)
|
||||
return readb(&uart->usr) & UART_USR_RXRDY ? 1 : 0;
|
||||
else
|
||||
return readb(&uart->usr) & UART_USR_TXRDY ? 0 : 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops coldfire_serial_ops = {
|
||||
.putc = coldfire_serial_putc,
|
||||
.pending = coldfire_serial_pending,
|
||||
.getc = coldfire_serial_getc,
|
||||
.setbrg = coldfire_serial_setbrg,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(serial_coldfire) = {
|
||||
.name = "serial_coldfire",
|
||||
.id = UCLASS_SERIAL,
|
||||
.probe = coldfire_serial_probe,
|
||||
.ops = &coldfire_serial_ops,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -26,15 +26,20 @@ struct soft_spi_platdata {
|
||||
struct gpio_desc mosi;
|
||||
struct gpio_desc miso;
|
||||
int spi_delay_us;
|
||||
int flags;
|
||||
};
|
||||
|
||||
#define SPI_MASTER_NO_RX BIT(0)
|
||||
#define SPI_MASTER_NO_TX BIT(1)
|
||||
|
||||
struct soft_spi_priv {
|
||||
unsigned int mode;
|
||||
};
|
||||
|
||||
static int soft_spi_scl(struct udevice *dev, int bit)
|
||||
{
|
||||
struct soft_spi_platdata *plat = dev->platdata;
|
||||
struct udevice *bus = dev_get_parent(dev);
|
||||
struct soft_spi_platdata *plat = dev_get_platdata(bus);
|
||||
|
||||
dm_gpio_set_value(&plat->sclk, bit);
|
||||
|
||||
@@ -43,7 +48,8 @@ static int soft_spi_scl(struct udevice *dev, int bit)
|
||||
|
||||
static int soft_spi_sda(struct udevice *dev, int bit)
|
||||
{
|
||||
struct soft_spi_platdata *plat = dev->platdata;
|
||||
struct udevice *bus = dev_get_parent(dev);
|
||||
struct soft_spi_platdata *plat = dev_get_platdata(bus);
|
||||
|
||||
dm_gpio_set_value(&plat->mosi, bit);
|
||||
|
||||
@@ -52,7 +58,8 @@ static int soft_spi_sda(struct udevice *dev, int bit)
|
||||
|
||||
static int soft_spi_cs_activate(struct udevice *dev)
|
||||
{
|
||||
struct soft_spi_platdata *plat = dev->platdata;
|
||||
struct udevice *bus = dev_get_parent(dev);
|
||||
struct soft_spi_platdata *plat = dev_get_platdata(bus);
|
||||
|
||||
dm_gpio_set_value(&plat->cs, 0);
|
||||
dm_gpio_set_value(&plat->sclk, 0);
|
||||
@@ -63,7 +70,8 @@ static int soft_spi_cs_activate(struct udevice *dev)
|
||||
|
||||
static int soft_spi_cs_deactivate(struct udevice *dev)
|
||||
{
|
||||
struct soft_spi_platdata *plat = dev->platdata;
|
||||
struct udevice *bus = dev_get_parent(dev);
|
||||
struct soft_spi_platdata *plat = dev_get_platdata(bus);
|
||||
|
||||
dm_gpio_set_value(&plat->cs, 0);
|
||||
|
||||
@@ -100,8 +108,9 @@ static int soft_spi_release_bus(struct udevice *dev)
|
||||
static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen,
|
||||
const void *dout, void *din, unsigned long flags)
|
||||
{
|
||||
struct soft_spi_priv *priv = dev_get_priv(dev);
|
||||
struct soft_spi_platdata *plat = dev->platdata;
|
||||
struct udevice *bus = dev_get_parent(dev);
|
||||
struct soft_spi_priv *priv = dev_get_priv(bus);
|
||||
struct soft_spi_platdata *plat = dev_get_platdata(bus);
|
||||
uchar tmpdin = 0;
|
||||
uchar tmpdout = 0;
|
||||
const u8 *txd = dout;
|
||||
@@ -134,14 +143,16 @@ static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen,
|
||||
|
||||
if (!cpha)
|
||||
soft_spi_scl(dev, 0);
|
||||
soft_spi_sda(dev, tmpdout & 0x80);
|
||||
if ((plat->flags & SPI_MASTER_NO_TX) == 0)
|
||||
soft_spi_sda(dev, !!(tmpdout & 0x80));
|
||||
udelay(plat->spi_delay_us);
|
||||
if (cpha)
|
||||
soft_spi_scl(dev, 0);
|
||||
else
|
||||
soft_spi_scl(dev, 1);
|
||||
tmpdin <<= 1;
|
||||
tmpdin |= dm_gpio_get_value(&plat->miso);
|
||||
if ((plat->flags & SPI_MASTER_NO_RX) == 0)
|
||||
tmpdin |= dm_gpio_get_value(&plat->miso);
|
||||
tmpdout <<= 1;
|
||||
udelay(plat->spi_delay_us);
|
||||
if (cpha)
|
||||
@@ -203,24 +214,36 @@ static int soft_spi_probe(struct udevice *dev)
|
||||
struct spi_slave *slave = dev_get_parent_priv(dev);
|
||||
struct soft_spi_platdata *plat = dev->platdata;
|
||||
int cs_flags, clk_flags;
|
||||
int ret;
|
||||
|
||||
cs_flags = (slave->mode & SPI_CS_HIGH) ? 0 : GPIOD_ACTIVE_LOW;
|
||||
clk_flags = (slave->mode & SPI_CPOL) ? GPIOD_ACTIVE_LOW : 0;
|
||||
if (gpio_request_by_name(dev, "cs-gpio", 0, &plat->cs,
|
||||
|
||||
if (gpio_request_by_name(dev, "cs-gpios", 0, &plat->cs,
|
||||
GPIOD_IS_OUT | cs_flags) ||
|
||||
gpio_request_by_name(dev, "sclk-gpio", 0, &plat->sclk,
|
||||
GPIOD_IS_OUT | clk_flags) ||
|
||||
gpio_request_by_name(dev, "mosi-gpio", 0, &plat->mosi,
|
||||
GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE) ||
|
||||
gpio_request_by_name(dev, "miso-gpio", 0, &plat->miso,
|
||||
GPIOD_IS_IN))
|
||||
gpio_request_by_name(dev, "gpio-sck", 0, &plat->sclk,
|
||||
GPIOD_IS_OUT | clk_flags))
|
||||
return -EINVAL;
|
||||
|
||||
ret = gpio_request_by_name(dev, "gpio-mosi", 0, &plat->mosi,
|
||||
GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
|
||||
if (ret)
|
||||
plat->flags |= SPI_MASTER_NO_TX;
|
||||
|
||||
ret = gpio_request_by_name(dev, "gpio-miso", 0, &plat->miso,
|
||||
GPIOD_IS_IN);
|
||||
if (ret)
|
||||
plat->flags |= SPI_MASTER_NO_RX;
|
||||
|
||||
if ((plat->flags & (SPI_MASTER_NO_RX | SPI_MASTER_NO_TX)) ==
|
||||
(SPI_MASTER_NO_RX | SPI_MASTER_NO_TX))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id soft_spi_ids[] = {
|
||||
{ .compatible = "u-boot,soft-spi" },
|
||||
{ .compatible = "spi-gpio" },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
@@ -45,12 +45,12 @@ static int spi_set_speed_mode(struct udevice *bus, int speed, int mode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_claim_bus(struct spi_slave *slave)
|
||||
int dm_spi_claim_bus(struct udevice *dev)
|
||||
{
|
||||
struct udevice *dev = slave->dev;
|
||||
struct udevice *bus = dev->parent;
|
||||
struct dm_spi_ops *ops = spi_get_ops(bus);
|
||||
struct dm_spi_bus *spi = dev_get_uclass_priv(bus);
|
||||
struct spi_slave *slave = dev_get_parent_priv(dev);
|
||||
int speed;
|
||||
int ret;
|
||||
|
||||
@@ -73,9 +73,8 @@ int spi_claim_bus(struct spi_slave *slave)
|
||||
return ops->claim_bus ? ops->claim_bus(dev) : 0;
|
||||
}
|
||||
|
||||
void spi_release_bus(struct spi_slave *slave)
|
||||
void dm_spi_release_bus(struct udevice *dev)
|
||||
{
|
||||
struct udevice *dev = slave->dev;
|
||||
struct udevice *bus = dev->parent;
|
||||
struct dm_spi_ops *ops = spi_get_ops(bus);
|
||||
|
||||
@@ -83,10 +82,9 @@ void spi_release_bus(struct spi_slave *slave)
|
||||
ops->release_bus(dev);
|
||||
}
|
||||
|
||||
int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
|
||||
const void *dout, void *din, unsigned long flags)
|
||||
int dm_spi_xfer(struct udevice *dev, unsigned int bitlen,
|
||||
const void *dout, void *din, unsigned long flags)
|
||||
{
|
||||
struct udevice *dev = slave->dev;
|
||||
struct udevice *bus = dev->parent;
|
||||
|
||||
if (bus->uclass->uc_drv->id != UCLASS_SPI)
|
||||
@@ -95,6 +93,22 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
|
||||
return spi_get_ops(bus)->xfer(dev, bitlen, dout, din, flags);
|
||||
}
|
||||
|
||||
int spi_claim_bus(struct spi_slave *slave)
|
||||
{
|
||||
return dm_spi_claim_bus(slave->dev);
|
||||
}
|
||||
|
||||
void spi_release_bus(struct spi_slave *slave)
|
||||
{
|
||||
dm_spi_release_bus(slave->dev);
|
||||
}
|
||||
|
||||
int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
|
||||
const void *dout, void *din, unsigned long flags)
|
||||
{
|
||||
return dm_spi_xfer(slave->dev, bitlen, dout, din, flags);
|
||||
}
|
||||
|
||||
static int spi_post_bind(struct udevice *dev)
|
||||
{
|
||||
/* Scan the bus for devices */
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-$(CONFIG_DM_USB) += common.o
|
||||
obj-$(CONFIG_USB_EHCI_FSL) += fsl-dt-fixup.o
|
||||
obj-$(CONFIG_USB_XHCI_FSL) += fsl-dt-fixup.o
|
||||
|
||||
40
drivers/usb/common/common.c
Normal file
40
drivers/usb/common/common.c
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Provides code common for host and device side USB.
|
||||
*
|
||||
* (C) Copyright 2016
|
||||
* Texas Instruments Incorporated, <www.ti.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <libfdt.h>
|
||||
#include <linux/usb/otg.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static const char *const usb_dr_modes[] = {
|
||||
[USB_DR_MODE_UNKNOWN] = "",
|
||||
[USB_DR_MODE_HOST] = "host",
|
||||
[USB_DR_MODE_PERIPHERAL] = "peripheral",
|
||||
[USB_DR_MODE_OTG] = "otg",
|
||||
};
|
||||
|
||||
enum usb_dr_mode usb_get_dr_mode(int node)
|
||||
{
|
||||
const void *fdt = gd->fdt_blob;
|
||||
const char *dr_mode;
|
||||
int i;
|
||||
|
||||
dr_mode = fdt_getprop(fdt, node, "dr_mode", NULL);
|
||||
if (!dr_mode) {
|
||||
error("usb dr_mode not found\n");
|
||||
return USB_DR_MODE_UNKNOWN;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(usb_dr_modes); i++)
|
||||
if (!strcmp(dr_mode, usb_dr_modes[i]))
|
||||
return i;
|
||||
|
||||
return USB_DR_MODE_UNKNOWN;
|
||||
}
|
||||
@@ -620,6 +620,13 @@ static int tegra_lcd_ofdata_to_platdata(struct udevice *dev)
|
||||
static int tegra_lcd_bind(struct udevice *dev)
|
||||
{
|
||||
struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
|
||||
const void *blob = gd->fdt_blob;
|
||||
int node = dev->of_offset;
|
||||
int rgb;
|
||||
|
||||
rgb = fdt_subnode_offset(blob, node, "rgb");
|
||||
if ((rgb < 0) || !fdtdec_get_is_enabled(blob, rgb))
|
||||
return -ENODEV;
|
||||
|
||||
plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT *
|
||||
(1 << LCD_MAX_LOG2_BPP) / 8;
|
||||
|
||||
Reference in New Issue
Block a user