commit
4b6e1fda10
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,115 @@ |
||||
/*
|
||||
* Copyright (C) 2000-2005, DENX Software Engineering |
||||
* Wolfgang Denk <wd@denx.de> |
||||
* Copyright (C) Procsys. All rights reserved. |
||||
* Mushtaq Khan <mushtaq_k@procsys.com> |
||||
* <mushtaqk_921@yahoo.co.in> |
||||
* Copyright (C) 2008 Freescale Semiconductor, Inc. |
||||
* Dave Liu <daveliu@freescale.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <dm.h> |
||||
#include <sata.h> |
||||
|
||||
struct blk_desc sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE]; |
||||
|
||||
#ifdef CONFIG_PARTITIONS |
||||
struct blk_desc *sata_get_dev(int dev) |
||||
{ |
||||
return (dev < CONFIG_SYS_SATA_MAX_DEVICE) ? &sata_dev_desc[dev] : NULL; |
||||
} |
||||
#endif |
||||
|
||||
#ifdef CONFIG_BLK |
||||
static unsigned long sata_bread(struct udevice *dev, lbaint_t start, |
||||
lbaint_t blkcnt, void *dst) |
||||
{ |
||||
return -ENOSYS; |
||||
} |
||||
|
||||
static unsigned long sata_bwrite(struct udevice *dev, lbaint_t start, |
||||
lbaint_t blkcnt, const void *buffer) |
||||
{ |
||||
return -ENOSYS; |
||||
} |
||||
#else |
||||
static unsigned long sata_bread(struct blk_desc *block_dev, lbaint_t start, |
||||
lbaint_t blkcnt, void *dst) |
||||
{ |
||||
return sata_read(block_dev->devnum, start, blkcnt, dst); |
||||
} |
||||
|
||||
static unsigned long sata_bwrite(struct blk_desc *block_dev, lbaint_t start, |
||||
lbaint_t blkcnt, const void *buffer) |
||||
{ |
||||
return sata_write(block_dev->devnum, start, blkcnt, buffer); |
||||
} |
||||
#endif |
||||
|
||||
int __sata_initialize(void) |
||||
{ |
||||
int rc; |
||||
int i; |
||||
|
||||
for (i = 0; i < CONFIG_SYS_SATA_MAX_DEVICE; i++) { |
||||
memset(&sata_dev_desc[i], 0, sizeof(struct blk_desc)); |
||||
sata_dev_desc[i].if_type = IF_TYPE_SATA; |
||||
sata_dev_desc[i].devnum = i; |
||||
sata_dev_desc[i].part_type = PART_TYPE_UNKNOWN; |
||||
sata_dev_desc[i].type = DEV_TYPE_HARDDISK; |
||||
sata_dev_desc[i].lba = 0; |
||||
sata_dev_desc[i].blksz = 512; |
||||
sata_dev_desc[i].log2blksz = LOG2(sata_dev_desc[i].blksz); |
||||
#ifndef CONFIG_BLK |
||||
sata_dev_desc[i].block_read = sata_bread; |
||||
sata_dev_desc[i].block_write = sata_bwrite; |
||||
#endif |
||||
rc = init_sata(i); |
||||
if (!rc) { |
||||
rc = scan_sata(i); |
||||
if (!rc && sata_dev_desc[i].lba > 0 && |
||||
sata_dev_desc[i].blksz > 0) |
||||
part_init(&sata_dev_desc[i]); |
||||
} |
||||
} |
||||
|
||||
return rc; |
||||
} |
||||
int sata_initialize(void) __attribute__((weak, alias("__sata_initialize"))); |
||||
|
||||
__weak int __sata_stop(void) |
||||
{ |
||||
int i, err = 0; |
||||
|
||||
for (i = 0; i < CONFIG_SYS_SATA_MAX_DEVICE; i++) |
||||
err |= reset_sata(i); |
||||
|
||||
if (err) |
||||
printf("Could not reset some SATA devices\n"); |
||||
|
||||
return err; |
||||
} |
||||
int sata_stop(void) __attribute__((weak, alias("__sata_stop"))); |
||||
|
||||
#ifdef CONFIG_BLK |
||||
static const struct blk_ops sata_blk_ops = { |
||||
.read = sata_bread, |
||||
.write = sata_bwrite, |
||||
}; |
||||
|
||||
U_BOOT_DRIVER(sata_blk) = { |
||||
.name = "sata_blk", |
||||
.id = UCLASS_BLK, |
||||
.ops = &sata_blk_ops, |
||||
}; |
||||
#else |
||||
U_BOOT_LEGACY_BLK(sata) = { |
||||
.if_typename = "sata", |
||||
.if_type = IF_TYPE_SATA, |
||||
.max_devs = CONFIG_SYS_SATA_MAX_DEVICE, |
||||
.desc = sata_dev_desc, |
||||
}; |
||||
#endif |
@ -0,0 +1,592 @@ |
||||
/*
|
||||
* (C) Copyright 2001 |
||||
* Denis Peter, MPL AG Switzerland |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <dm.h> |
||||
#include <inttypes.h> |
||||
#include <pci.h> |
||||
#include <scsi.h> |
||||
|
||||
#ifdef CONFIG_SCSI_DEV_LIST |
||||
#define SCSI_DEV_LIST CONFIG_SCSI_DEV_LIST |
||||
#else |
||||
#ifdef CONFIG_SCSI_SYM53C8XX |
||||
#define SCSI_VEND_ID 0x1000 |
||||
#ifndef CONFIG_SCSI_DEV_ID |
||||
#define SCSI_DEV_ID 0x0001 |
||||
#else |
||||
#define SCSI_DEV_ID CONFIG_SCSI_DEV_ID |
||||
#endif |
||||
#elif defined CONFIG_SATA_ULI5288 |
||||
|
||||
#define SCSI_VEND_ID 0x10b9 |
||||
#define SCSI_DEV_ID 0x5288 |
||||
|
||||
#elif !defined(CONFIG_SCSI_AHCI_PLAT) |
||||
#error no scsi device defined |
||||
#endif |
||||
#define SCSI_DEV_LIST {SCSI_VEND_ID, SCSI_DEV_ID} |
||||
#endif |
||||
|
||||
#if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) |
||||
const struct pci_device_id scsi_device_list[] = { SCSI_DEV_LIST }; |
||||
#endif |
||||
static ccb tempccb; /* temporary scsi command buffer */ |
||||
|
||||
static unsigned char tempbuff[512]; /* temporary data buffer */ |
||||
|
||||
static int scsi_max_devs; /* number of highest available scsi device */ |
||||
|
||||
static int scsi_curr_dev; /* current device */ |
||||
|
||||
static struct blk_desc scsi_dev_desc[CONFIG_SYS_SCSI_MAX_DEVICE]; |
||||
|
||||
/* almost the maximum amount of the scsi_ext command.. */ |
||||
#define SCSI_MAX_READ_BLK 0xFFFF |
||||
#define SCSI_LBA48_READ 0xFFFFFFF |
||||
|
||||
#ifdef CONFIG_SYS_64BIT_LBA |
||||
void scsi_setup_read16(ccb *pccb, lbaint_t start, unsigned long blocks) |
||||
{ |
||||
pccb->cmd[0] = SCSI_READ16; |
||||
pccb->cmd[1] = pccb->lun << 5; |
||||
pccb->cmd[2] = (unsigned char)(start >> 56) & 0xff; |
||||
pccb->cmd[3] = (unsigned char)(start >> 48) & 0xff; |
||||
pccb->cmd[4] = (unsigned char)(start >> 40) & 0xff; |
||||
pccb->cmd[5] = (unsigned char)(start >> 32) & 0xff; |
||||
pccb->cmd[6] = (unsigned char)(start >> 24) & 0xff; |
||||
pccb->cmd[7] = (unsigned char)(start >> 16) & 0xff; |
||||
pccb->cmd[8] = (unsigned char)(start >> 8) & 0xff; |
||||
pccb->cmd[9] = (unsigned char)start & 0xff; |
||||
pccb->cmd[10] = 0; |
||||
pccb->cmd[11] = (unsigned char)(blocks >> 24) & 0xff; |
||||
pccb->cmd[12] = (unsigned char)(blocks >> 16) & 0xff; |
||||
pccb->cmd[13] = (unsigned char)(blocks >> 8) & 0xff; |
||||
pccb->cmd[14] = (unsigned char)blocks & 0xff; |
||||
pccb->cmd[15] = 0; |
||||
pccb->cmdlen = 16; |
||||
pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ |
||||
debug("scsi_setup_read16: cmd: %02X %02X startblk %02X%02X%02X%02X%02X%02X%02X%02X blccnt %02X%02X%02X%02X\n", |
||||
pccb->cmd[0], pccb->cmd[1], |
||||
pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5], |
||||
pccb->cmd[6], pccb->cmd[7], pccb->cmd[8], pccb->cmd[9], |
||||
pccb->cmd[11], pccb->cmd[12], pccb->cmd[13], pccb->cmd[14]); |
||||
} |
||||
#endif |
||||
|
||||
void scsi_setup_read_ext(ccb *pccb, lbaint_t start, unsigned short blocks) |
||||
{ |
||||
pccb->cmd[0] = SCSI_READ10; |
||||
pccb->cmd[1] = pccb->lun << 5; |
||||
pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff; |
||||
pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff; |
||||
pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff; |
||||
pccb->cmd[5] = (unsigned char)start & 0xff; |
||||
pccb->cmd[6] = 0; |
||||
pccb->cmd[7] = (unsigned char)(blocks >> 8) & 0xff; |
||||
pccb->cmd[8] = (unsigned char)blocks & 0xff; |
||||
pccb->cmd[6] = 0; |
||||
pccb->cmdlen = 10; |
||||
pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ |
||||
debug("scsi_setup_read_ext: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n", |
||||
pccb->cmd[0], pccb->cmd[1], |
||||
pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5], |
||||
pccb->cmd[7], pccb->cmd[8]); |
||||
} |
||||
|
||||
void scsi_setup_write_ext(ccb *pccb, lbaint_t start, unsigned short blocks) |
||||
{ |
||||
pccb->cmd[0] = SCSI_WRITE10; |
||||
pccb->cmd[1] = pccb->lun << 5; |
||||
pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff; |
||||
pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff; |
||||
pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff; |
||||
pccb->cmd[5] = (unsigned char)start & 0xff; |
||||
pccb->cmd[6] = 0; |
||||
pccb->cmd[7] = ((unsigned char)(blocks >> 8)) & 0xff; |
||||
pccb->cmd[8] = (unsigned char)blocks & 0xff; |
||||
pccb->cmd[9] = 0; |
||||
pccb->cmdlen = 10; |
||||
pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ |
||||
debug("%s: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n", |
||||
__func__, |
||||
pccb->cmd[0], pccb->cmd[1], |
||||
pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5], |
||||
pccb->cmd[7], pccb->cmd[8]); |
||||
} |
||||
|
||||
void scsi_setup_read6(ccb *pccb, lbaint_t start, unsigned short blocks) |
||||
{ |
||||
pccb->cmd[0] = SCSI_READ6; |
||||
pccb->cmd[1] = pccb->lun << 5 | ((unsigned char)(start >> 16) & 0x1f); |
||||
pccb->cmd[2] = (unsigned char)(start >> 8) & 0xff; |
||||
pccb->cmd[3] = (unsigned char)start & 0xff; |
||||
pccb->cmd[4] = (unsigned char)blocks & 0xff; |
||||
pccb->cmd[5] = 0; |
||||
pccb->cmdlen = 6; |
||||
pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ |
||||
debug("scsi_setup_read6: cmd: %02X %02X startblk %02X%02X blccnt %02X\n", |
||||
pccb->cmd[0], pccb->cmd[1], |
||||
pccb->cmd[2], pccb->cmd[3], pccb->cmd[4]); |
||||
} |
||||
|
||||
|
||||
void scsi_setup_inquiry(ccb *pccb) |
||||
{ |
||||
pccb->cmd[0] = SCSI_INQUIRY; |
||||
pccb->cmd[1] = pccb->lun << 5; |
||||
pccb->cmd[2] = 0; |
||||
pccb->cmd[3] = 0; |
||||
if (pccb->datalen > 255) |
||||
pccb->cmd[4] = 255; |
||||
else |
||||
pccb->cmd[4] = (unsigned char)pccb->datalen; |
||||
pccb->cmd[5] = 0; |
||||
pccb->cmdlen = 6; |
||||
pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ |
||||
} |
||||
|
||||
#ifdef CONFIG_BLK |
||||
static ulong scsi_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, |
||||
void *buffer) |
||||
#else |
||||
static ulong scsi_read(struct blk_desc *block_dev, lbaint_t blknr, |
||||
lbaint_t blkcnt, void *buffer) |
||||
#endif |
||||
{ |
||||
#ifdef CONFIG_BLK |
||||
struct blk_desc *block_dev = dev_get_uclass_platdata(dev); |
||||
#endif |
||||
int device = block_dev->devnum; |
||||
lbaint_t start, blks; |
||||
uintptr_t buf_addr; |
||||
unsigned short smallblks = 0; |
||||
ccb *pccb = (ccb *)&tempccb; |
||||
device &= 0xff; |
||||
|
||||
/* Setup device */ |
||||
pccb->target = scsi_dev_desc[device].target; |
||||
pccb->lun = scsi_dev_desc[device].lun; |
||||
buf_addr = (unsigned long)buffer; |
||||
start = blknr; |
||||
blks = blkcnt; |
||||
debug("\nscsi_read: dev %d startblk " LBAF |
||||
", blccnt " LBAF " buffer %lx\n", |
||||
device, start, blks, (unsigned long)buffer); |
||||
do { |
||||
pccb->pdata = (unsigned char *)buf_addr; |
||||
#ifdef CONFIG_SYS_64BIT_LBA |
||||
if (start > SCSI_LBA48_READ) { |
||||
unsigned long blocks; |
||||
blocks = min_t(lbaint_t, blks, SCSI_MAX_READ_BLK); |
||||
pccb->datalen = scsi_dev_desc[device].blksz * blocks; |
||||
scsi_setup_read16(pccb, start, blocks); |
||||
start += blocks; |
||||
blks -= blocks; |
||||
} else |
||||
#endif |
||||
if (blks > SCSI_MAX_READ_BLK) { |
||||
pccb->datalen = scsi_dev_desc[device].blksz * |
||||
SCSI_MAX_READ_BLK; |
||||
smallblks = SCSI_MAX_READ_BLK; |
||||
scsi_setup_read_ext(pccb, start, smallblks); |
||||
start += SCSI_MAX_READ_BLK; |
||||
blks -= SCSI_MAX_READ_BLK; |
||||
} else { |
||||
pccb->datalen = scsi_dev_desc[device].blksz * blks; |
||||
smallblks = (unsigned short)blks; |
||||
scsi_setup_read_ext(pccb, start, smallblks); |
||||
start += blks; |
||||
blks = 0; |
||||
} |
||||
debug("scsi_read_ext: startblk " LBAF |
||||
", blccnt %x buffer %" PRIXPTR "\n", |
||||
start, smallblks, buf_addr); |
||||
if (scsi_exec(pccb) != true) { |
||||
scsi_print_error(pccb); |
||||
blkcnt -= blks; |
||||
break; |
||||
} |
||||
buf_addr += pccb->datalen; |
||||
} while (blks != 0); |
||||
debug("scsi_read_ext: end startblk " LBAF |
||||
", blccnt %x buffer %" PRIXPTR "\n", start, smallblks, buf_addr); |
||||
return blkcnt; |
||||
} |
||||
|
||||
/*******************************************************************************
|
||||
* scsi_write |
||||
*/ |
||||
|
||||
/* Almost the maximum amount of the scsi_ext command.. */ |
||||
#define SCSI_MAX_WRITE_BLK 0xFFFF |
||||
|
||||
#ifdef CONFIG_BLK |
||||
static ulong scsi_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, |
||||
const void *buffer) |
||||
#else |
||||
static ulong scsi_write(struct blk_desc *block_dev, lbaint_t blknr, |
||||
lbaint_t blkcnt, const void *buffer) |
||||
#endif |
||||
{ |
||||
#ifdef CONFIG_BLK |
||||
struct blk_desc *block_dev = dev_get_uclass_platdata(dev); |
||||
#endif |
||||
int device = block_dev->devnum; |
||||
lbaint_t start, blks; |
||||
uintptr_t buf_addr; |
||||
unsigned short smallblks; |
||||
ccb *pccb = (ccb *)&tempccb; |
||||
|
||||
device &= 0xff; |
||||
|
||||
/* Setup device */ |
||||
pccb->target = scsi_dev_desc[device].target; |
||||
pccb->lun = scsi_dev_desc[device].lun; |
||||
buf_addr = (unsigned long)buffer; |
||||
start = blknr; |
||||
blks = blkcnt; |
||||
debug("\n%s: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n", |
||||
__func__, device, start, blks, (unsigned long)buffer); |
||||
do { |
||||
pccb->pdata = (unsigned char *)buf_addr; |
||||
if (blks > SCSI_MAX_WRITE_BLK) { |
||||
pccb->datalen = (scsi_dev_desc[device].blksz * |
||||
SCSI_MAX_WRITE_BLK); |
||||
smallblks = SCSI_MAX_WRITE_BLK; |
||||
scsi_setup_write_ext(pccb, start, smallblks); |
||||
start += SCSI_MAX_WRITE_BLK; |
||||
blks -= SCSI_MAX_WRITE_BLK; |
||||
} else { |
||||
pccb->datalen = scsi_dev_desc[device].blksz * blks; |
||||
smallblks = (unsigned short)blks; |
||||
scsi_setup_write_ext(pccb, start, smallblks); |
||||
start += blks; |
||||
blks = 0; |
||||
} |
||||
debug("%s: startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n", |
||||
__func__, start, smallblks, buf_addr); |
||||
if (scsi_exec(pccb) != true) { |
||||
scsi_print_error(pccb); |
||||
blkcnt -= blks; |
||||
break; |
||||
} |
||||
buf_addr += pccb->datalen; |
||||
} while (blks != 0); |
||||
debug("%s: end startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n", |
||||
__func__, start, smallblks, buf_addr); |
||||
return blkcnt; |
||||
} |
||||
|
||||
int scsi_get_disk_count(void) |
||||
{ |
||||
return scsi_max_devs; |
||||
} |
||||
|
||||
#if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) |
||||
void scsi_init(void) |
||||
{ |
||||
int busdevfunc = -1; |
||||
int i; |
||||
/*
|
||||
* Find a device from the list, this driver will support a single |
||||
* controller. |
||||
*/ |
||||
for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) { |
||||
/* get PCI Device ID */ |
||||
#ifdef CONFIG_DM_PCI |
||||
struct udevice *dev; |
||||
int ret; |
||||
|
||||
ret = dm_pci_find_device(scsi_device_list[i].vendor, |
||||
scsi_device_list[i].device, 0, &dev); |
||||
if (!ret) { |
||||
busdevfunc = dm_pci_get_bdf(dev); |
||||
break; |
||||
} |
||||
#else |
||||
busdevfunc = pci_find_device(scsi_device_list[i].vendor, |
||||
scsi_device_list[i].device, |
||||
0); |
||||
#endif |
||||
if (busdevfunc != -1) |
||||
break; |
||||
} |
||||
|
||||
if (busdevfunc == -1) { |
||||
printf("Error: SCSI Controller(s) "); |
||||
for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) { |
||||
printf("%04X:%04X ", |
||||
scsi_device_list[i].vendor, |
||||
scsi_device_list[i].device); |
||||
} |
||||
printf("not found\n"); |
||||
return; |
||||
} |
||||
#ifdef DEBUG |
||||
else { |
||||
printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n", |
||||
scsi_device_list[i].vendor, |
||||
scsi_device_list[i].device, |
||||
(busdevfunc >> 16) & 0xFF, |
||||
(busdevfunc >> 11) & 0x1F, |
||||
(busdevfunc >> 8) & 0x7); |
||||
} |
||||
#endif |
||||
bootstage_start(BOOTSTAGE_ID_ACCUM_SCSI, "ahci"); |
||||
scsi_low_level_init(busdevfunc); |
||||
scsi_scan(1); |
||||
bootstage_accum(BOOTSTAGE_ID_ACCUM_SCSI); |
||||
} |
||||
#endif |
||||
|
||||
/* copy src to dest, skipping leading and trailing blanks
|
||||
* and null terminate the string |
||||
*/ |
||||
void scsi_ident_cpy(unsigned char *dest, unsigned char *src, unsigned int len) |
||||
{ |
||||
int start, end; |
||||
|
||||
start = 0; |
||||
while (start < len) { |
||||
if (src[start] != ' ') |
||||
break; |
||||
start++; |
||||
} |
||||
end = len-1; |
||||
while (end > start) { |
||||
if (src[end] != ' ') |
||||
break; |
||||
end--; |
||||
} |
||||
for (; start <= end; start++) |
||||
*dest ++= src[start]; |
||||
*dest = '\0'; |
||||
} |
||||
|
||||
|
||||
/* Trim trailing blanks, and NUL-terminate string
|
||||
*/ |
||||
void scsi_trim_trail(unsigned char *str, unsigned int len) |
||||
{ |
||||
unsigned char *p = str + len - 1; |
||||
|
||||
while (len-- > 0) { |
||||
*p-- = '\0'; |
||||
if (*p != ' ') |
||||
return; |
||||
} |
||||
} |
||||
|
||||
int scsi_read_capacity(ccb *pccb, lbaint_t *capacity, unsigned long *blksz) |
||||
{ |
||||
*capacity = 0; |
||||
|
||||
memset(pccb->cmd, '\0', sizeof(pccb->cmd)); |
||||
pccb->cmd[0] = SCSI_RD_CAPAC10; |
||||
pccb->cmd[1] = pccb->lun << 5; |
||||
pccb->cmdlen = 10; |
||||
pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ |
||||
|
||||
pccb->datalen = 8; |
||||
if (scsi_exec(pccb) != true) |
||||
return 1; |
||||
|
||||
*capacity = ((lbaint_t)pccb->pdata[0] << 24) | |
||||
((lbaint_t)pccb->pdata[1] << 16) | |
||||
((lbaint_t)pccb->pdata[2] << 8) | |
||||
((lbaint_t)pccb->pdata[3]); |
||||
|
||||
if (*capacity != 0xffffffff) { |
||||
/* Read capacity (10) was sufficient for this drive. */ |
||||
*blksz = ((unsigned long)pccb->pdata[4] << 24) | |
||||
((unsigned long)pccb->pdata[5] << 16) | |
||||
((unsigned long)pccb->pdata[6] << 8) | |
||||
((unsigned long)pccb->pdata[7]); |
||||
return 0; |
||||
} |
||||
|
||||
/* Read capacity (10) was insufficient. Use read capacity (16). */ |
||||
memset(pccb->cmd, '\0', sizeof(pccb->cmd)); |
||||
pccb->cmd[0] = SCSI_RD_CAPAC16; |
||||
pccb->cmd[1] = 0x10; |
||||
pccb->cmdlen = 16; |
||||
pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ |
||||
|
||||
pccb->datalen = 16; |
||||
if (scsi_exec(pccb) != true) |
||||
return 1; |
||||
|
||||
*capacity = ((uint64_t)pccb->pdata[0] << 56) | |
||||
((uint64_t)pccb->pdata[1] << 48) | |
||||
((uint64_t)pccb->pdata[2] << 40) | |
||||
((uint64_t)pccb->pdata[3] << 32) | |
||||
((uint64_t)pccb->pdata[4] << 24) | |
||||
((uint64_t)pccb->pdata[5] << 16) | |
||||
((uint64_t)pccb->pdata[6] << 8) | |
||||
((uint64_t)pccb->pdata[7]); |
||||
|
||||
*blksz = ((uint64_t)pccb->pdata[8] << 56) | |
||||
((uint64_t)pccb->pdata[9] << 48) | |
||||
((uint64_t)pccb->pdata[10] << 40) | |
||||
((uint64_t)pccb->pdata[11] << 32) | |
||||
((uint64_t)pccb->pdata[12] << 24) | |
||||
((uint64_t)pccb->pdata[13] << 16) | |
||||
((uint64_t)pccb->pdata[14] << 8) | |
||||
((uint64_t)pccb->pdata[15]); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* Some setup (fill-in) routines |
||||
*/ |
||||
void scsi_setup_test_unit_ready(ccb *pccb) |
||||
{ |
||||
pccb->cmd[0] = SCSI_TST_U_RDY; |
||||
pccb->cmd[1] = pccb->lun << 5; |
||||
pccb->cmd[2] = 0; |
||||
pccb->cmd[3] = 0; |
||||
pccb->cmd[4] = 0; |
||||
pccb->cmd[5] = 0; |
||||
pccb->cmdlen = 6; |
||||
pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ |
||||
} |
||||
|
||||
/*
|
||||
* (re)-scan the scsi bus and reports scsi device info |
||||
* to the user if mode = 1 |
||||
*/ |
||||
void scsi_scan(int mode) |
||||
{ |
||||
unsigned char i, perq, modi, lun; |
||||
lbaint_t capacity; |
||||
unsigned long blksz; |
||||
ccb *pccb = (ccb *)&tempccb; |
||||
|
||||
if (mode == 1) |
||||
printf("scanning bus for devices...\n"); |
||||
for (i = 0; i < CONFIG_SYS_SCSI_MAX_DEVICE; i++) { |
||||
scsi_dev_desc[i].target = 0xff; |
||||
scsi_dev_desc[i].lun = 0xff; |
||||
scsi_dev_desc[i].lba = 0; |
||||
scsi_dev_desc[i].blksz = 0; |
||||
scsi_dev_desc[i].log2blksz = |
||||
LOG2_INVALID(typeof(scsi_dev_desc[i].log2blksz)); |
||||
scsi_dev_desc[i].type = DEV_TYPE_UNKNOWN; |
||||
scsi_dev_desc[i].vendor[0] = 0; |
||||
scsi_dev_desc[i].product[0] = 0; |
||||
scsi_dev_desc[i].revision[0] = 0; |
||||
scsi_dev_desc[i].removable = false; |
||||
scsi_dev_desc[i].if_type = IF_TYPE_SCSI; |
||||
scsi_dev_desc[i].devnum = i; |
||||
scsi_dev_desc[i].part_type = PART_TYPE_UNKNOWN; |
||||
#ifndef CONFIG_BLK |
||||
scsi_dev_desc[i].block_read = scsi_read; |
||||
scsi_dev_desc[i].block_write = scsi_write; |
||||
#endif |
||||
} |
||||
scsi_max_devs = 0; |
||||
for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { |
||||
pccb->target = i; |
||||
for (lun = 0; lun < CONFIG_SYS_SCSI_MAX_LUN; lun++) { |
||||
pccb->lun = lun; |
||||
pccb->pdata = (unsigned char *)&tempbuff; |
||||
pccb->datalen = 512; |
||||
scsi_setup_inquiry(pccb); |
||||
if (scsi_exec(pccb) != true) { |
||||
if (pccb->contr_stat == SCSI_SEL_TIME_OUT) { |
||||
/*
|
||||
* selection timeout => assuming no |
||||
* device present |
||||
*/ |
||||
debug("Selection timeout ID %d\n", |
||||
pccb->target); |
||||
continue; |
||||
} |
||||
scsi_print_error(pccb); |
||||
continue; |
||||
} |
||||
perq = tempbuff[0]; |
||||
modi = tempbuff[1]; |
||||
if ((perq & 0x1f) == 0x1f) |
||||
continue; /* skip unknown devices */ |
||||
if ((modi & 0x80) == 0x80) /* drive is removable */ |
||||
scsi_dev_desc[scsi_max_devs].removable = true; |
||||
/* get info for this device */ |
||||
scsi_ident_cpy((unsigned char *)&scsi_dev_desc |
||||
[scsi_max_devs].vendor[0], |
||||
&tempbuff[8], 8); |
||||
scsi_ident_cpy((unsigned char *)&scsi_dev_desc |
||||
[scsi_max_devs].product[0], |
||||
&tempbuff[16], 16); |
||||
scsi_ident_cpy((unsigned char *)&scsi_dev_desc |
||||
[scsi_max_devs].revision[0], |
||||
&tempbuff[32], 4); |
||||
scsi_dev_desc[scsi_max_devs].target = pccb->target; |
||||
scsi_dev_desc[scsi_max_devs].lun = pccb->lun; |
||||
|
||||
pccb->datalen = 0; |
||||
scsi_setup_test_unit_ready(pccb); |
||||
if (scsi_exec(pccb) != true) { |
||||
if (scsi_dev_desc[scsi_max_devs].removable) { |
||||
scsi_dev_desc[scsi_max_devs].type = |
||||
perq; |
||||
goto removable; |
||||
} |
||||
scsi_print_error(pccb); |
||||
continue; |
||||
} |
||||
if (scsi_read_capacity(pccb, &capacity, &blksz)) { |
||||
scsi_print_error(pccb); |
||||
continue; |
||||
} |
||||
scsi_dev_desc[scsi_max_devs].lba = capacity; |
||||
scsi_dev_desc[scsi_max_devs].blksz = blksz; |
||||
scsi_dev_desc[scsi_max_devs].log2blksz = |
||||
LOG2(scsi_dev_desc[scsi_max_devs].blksz); |
||||
scsi_dev_desc[scsi_max_devs].type = perq; |
||||
part_init(&scsi_dev_desc[scsi_max_devs]); |
||||
removable: |
||||
if (mode == 1) { |
||||
printf(" Device %d: ", scsi_max_devs); |
||||
dev_print(&scsi_dev_desc[scsi_max_devs]); |
||||
} /* if mode */ |
||||
scsi_max_devs++; |
||||
} /* next LUN */ |
||||
} |
||||
if (scsi_max_devs > 0) |
||||
scsi_curr_dev = 0; |
||||
else |
||||
scsi_curr_dev = -1; |
||||
|
||||
printf("Found %d device(s).\n", scsi_max_devs); |
||||
#ifndef CONFIG_SPL_BUILD |
||||
setenv_ulong("scsidevs", scsi_max_devs); |
||||
#endif |
||||
} |
||||
|
||||
#ifdef CONFIG_BLK |
||||
static const struct blk_ops scsi_blk_ops = { |
||||
.read = scsi_read, |
||||
.write = scsi_write, |
||||
}; |
||||
|
||||
U_BOOT_DRIVER(scsi_blk) = { |
||||
.name = "scsi_blk", |
||||
.id = UCLASS_BLK, |
||||
.ops = &scsi_blk_ops, |
||||
}; |
||||
#else |
||||
U_BOOT_LEGACY_BLK(scsi) = { |
||||
.if_typename = "sata", |
||||
.if_type = IF_TYPE_SCSI, |
||||
.max_devs = CONFIG_SYS_SCSI_MAX_DEVICE, |
||||
.desc = scsi_dev_desc, |
||||
}; |
||||
#endif |
@ -0,0 +1,168 @@ |
||||
CONFIG_SYS_MALLOC_F_LEN=0x2000 |
||||
CONFIG_PCI=y |
||||
CONFIG_DEFAULT_DEVICE_TREE="sandbox" |
||||
CONFIG_I8042_KEYB=y |
||||
CONFIG_FIT=y |
||||
CONFIG_FIT_VERBOSE=y |
||||
CONFIG_FIT_SIGNATURE=y |
||||
CONFIG_SPL_LOAD_FIT=y |
||||
CONFIG_BOOTSTAGE=y |
||||
CONFIG_BOOTSTAGE_REPORT=y |
||||
CONFIG_BOOTSTAGE_USER_COUNT=0x20 |
||||
CONFIG_BOOTSTAGE_FDT=y |
||||
CONFIG_BOOTSTAGE_STASH=y |
||||
CONFIG_BOOTSTAGE_STASH_ADDR=0x0 |
||||
CONFIG_BOOTSTAGE_STASH_SIZE=0x4096 |
||||
CONFIG_CONSOLE_RECORD=y |
||||
CONFIG_CONSOLE_RECORD_OUT_SIZE=0x1000 |
||||
CONFIG_HUSH_PARSER=y |
||||
CONFIG_CMD_CPU=y |
||||
CONFIG_CMD_LICENSE=y |
||||
CONFIG_CMD_BOOTZ=y |
||||
# CONFIG_CMD_ELF is not set |
||||
# CONFIG_CMD_IMLS is not set |
||||
CONFIG_CMD_ASKENV=y |
||||
CONFIG_CMD_GREPENV=y |
||||
CONFIG_LOOPW=y |
||||
CONFIG_CMD_MEMTEST=y |
||||
CONFIG_CMD_MX_CYCLIC=y |
||||
CONFIG_CMD_MEMINFO=y |
||||
CONFIG_CMD_DEMO=y |
||||
CONFIG_CMD_SF=y |
||||
CONFIG_CMD_SPI=y |
||||
CONFIG_CMD_I2C=y |
||||
CONFIG_CMD_USB=y |
||||
CONFIG_CMD_REMOTEPROC=y |
||||
CONFIG_CMD_GPIO=y |
||||
CONFIG_CMD_TFTPPUT=y |
||||
CONFIG_CMD_TFTPSRV=y |
||||
CONFIG_CMD_RARP=y |
||||
CONFIG_CMD_DHCP=y |
||||
CONFIG_CMD_MII=y |
||||
CONFIG_CMD_PING=y |
||||
CONFIG_CMD_CDP=y |
||||
CONFIG_CMD_SNTP=y |
||||
CONFIG_CMD_DNS=y |
||||
CONFIG_CMD_LINK_LOCAL=y |
||||
CONFIG_CMD_TIME=y |
||||
CONFIG_CMD_TIMER=y |
||||
CONFIG_CMD_SOUND=y |
||||
CONFIG_CMD_BOOTSTAGE=y |
||||
CONFIG_CMD_PMIC=y |
||||
CONFIG_CMD_REGULATOR=y |
||||
CONFIG_CMD_TPM=y |
||||
CONFIG_CMD_TPM_TEST=y |
||||
CONFIG_CMD_EXT2=y |
||||
CONFIG_CMD_EXT4=y |
||||
CONFIG_CMD_EXT4_WRITE=y |
||||
CONFIG_CMD_FAT=y |
||||
CONFIG_CMD_FS_GENERIC=y |
||||
CONFIG_OF_CONTROL=y |
||||
CONFIG_OF_HOSTFILE=y |
||||
CONFIG_NETCONSOLE=y |
||||
CONFIG_REGMAP=y |
||||
CONFIG_SPL_REGMAP=y |
||||
CONFIG_SYSCON=y |
||||
CONFIG_SPL_SYSCON=y |
||||
CONFIG_DEVRES=y |
||||
CONFIG_DEBUG_DEVRES=y |
||||
CONFIG_ADC=y |
||||
CONFIG_ADC_SANDBOX=y |
||||
CONFIG_CLK=y |
||||
CONFIG_CPU=y |
||||
CONFIG_DM_DEMO=y |
||||
CONFIG_DM_DEMO_SIMPLE=y |
||||
CONFIG_DM_DEMO_SHAPE=y |
||||
CONFIG_PM8916_GPIO=y |
||||
CONFIG_SANDBOX_GPIO=y |
||||
CONFIG_DM_I2C_COMPAT=y |
||||
CONFIG_I2C_CROS_EC_TUNNEL=y |
||||
CONFIG_I2C_CROS_EC_LDO=y |
||||
CONFIG_DM_I2C_GPIO=y |
||||
CONFIG_SYS_I2C_SANDBOX=y |
||||
CONFIG_I2C_MUX=y |
||||
CONFIG_SPL_I2C_MUX=y |
||||
CONFIG_I2C_ARB_GPIO_CHALLENGE=y |
||||
CONFIG_CROS_EC_KEYB=y |
||||
CONFIG_LED=y |
||||
CONFIG_LED_GPIO=y |
||||
CONFIG_CMD_CROS_EC=y |
||||
CONFIG_CROS_EC=y |
||||
CONFIG_CROS_EC_I2C=y |
||||
CONFIG_CROS_EC_LPC=y |
||||
CONFIG_CROS_EC_SANDBOX=y |
||||
CONFIG_CROS_EC_SPI=y |
||||
CONFIG_PWRSEQ=y |
||||
CONFIG_SPL_PWRSEQ=y |
||||
CONFIG_RESET=y |
||||
CONFIG_DM_MMC=y |
||||
CONFIG_SPI_FLASH_SANDBOX=y |
||||
CONFIG_SPI_FLASH=y |
||||
CONFIG_SPI_FLASH_ATMEL=y |
||||
CONFIG_SPI_FLASH_EON=y |
||||
CONFIG_SPI_FLASH_GIGADEVICE=y |
||||
CONFIG_SPI_FLASH_MACRONIX=y |
||||
CONFIG_SPI_FLASH_SPANSION=y |
||||
CONFIG_SPI_FLASH_STMICRO=y |
||||
CONFIG_SPI_FLASH_SST=y |
||||
CONFIG_SPI_FLASH_WINBOND=y |
||||
CONFIG_DM_ETH=y |
||||
CONFIG_DM_PCI=y |
||||
CONFIG_DM_PCI_COMPAT=y |
||||
CONFIG_PCI_SANDBOX=y |
||||
CONFIG_PINCTRL=y |
||||
CONFIG_PINCONF=y |
||||
CONFIG_ROCKCHIP_PINCTRL=y |
||||
CONFIG_ROCKCHIP_3036_PINCTRL=y |
||||
CONFIG_PINCTRL_SANDBOX=y |
||||
CONFIG_DM_PMIC=y |
||||
CONFIG_PMIC_ACT8846=y |
||||
CONFIG_DM_PMIC_PFUZE100=y |
||||
CONFIG_DM_PMIC_MAX77686=y |
||||
CONFIG_PMIC_PM8916=y |
||||
CONFIG_PMIC_RK808=y |
||||
CONFIG_PMIC_S2MPS11=y |
||||
CONFIG_DM_PMIC_SANDBOX=y |
||||
CONFIG_PMIC_S5M8767=y |
||||
CONFIG_PMIC_TPS65090=y |
||||
CONFIG_DM_REGULATOR=y |
||||
CONFIG_REGULATOR_ACT8846=y |
||||
CONFIG_DM_REGULATOR_PFUZE100=y |
||||
CONFIG_DM_REGULATOR_MAX77686=y |
||||
CONFIG_DM_REGULATOR_FIXED=y |
||||
CONFIG_REGULATOR_RK808=y |
||||
CONFIG_REGULATOR_S5M8767=y |
||||
CONFIG_DM_REGULATOR_SANDBOX=y |
||||
CONFIG_REGULATOR_TPS65090=y |
||||
CONFIG_RAM=y |
||||
CONFIG_REMOTEPROC_SANDBOX=y |
||||
CONFIG_DM_RTC=y |
||||
CONFIG_SANDBOX_SERIAL=y |
||||
CONFIG_SOUND=y |
||||
CONFIG_SOUND_SANDBOX=y |
||||
CONFIG_SANDBOX_SPI=y |
||||
CONFIG_SPMI=y |
||||
CONFIG_SPMI_SANDBOX=y |
||||
CONFIG_TIMER=y |
||||
CONFIG_TIMER_EARLY=y |
||||
CONFIG_SANDBOX_TIMER=y |
||||
CONFIG_TPM_TIS_SANDBOX=y |
||||
CONFIG_USB=y |
||||
CONFIG_DM_USB=y |
||||
CONFIG_USB_EMUL=y |
||||
CONFIG_USB_STORAGE=y |
||||
CONFIG_USB_KEYBOARD=y |
||||
CONFIG_SYS_USB_EVENT_POLL=y |
||||
CONFIG_DM_VIDEO=y |
||||
CONFIG_CONSOLE_ROTATION=y |
||||
CONFIG_CONSOLE_TRUETYPE=y |
||||
CONFIG_CONSOLE_TRUETYPE_CANTORAONE=y |
||||
CONFIG_VIDEO_SANDBOX_SDL=y |
||||
CONFIG_CMD_DHRYSTONE=y |
||||
CONFIG_TPM=y |
||||
CONFIG_LZ4=y |
||||
CONFIG_ERRNO_STR=y |
||||
CONFIG_UNIT_TEST=y |
||||
CONFIG_UT_TIME=y |
||||
CONFIG_UT_DM=y |
||||
CONFIG_UT_ENV=y |
@ -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); |
||||
} |
@ -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) |
||||
{ |
||||
} |
@ -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; |
||||
} |
@ -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, |
||||
}; |
@ -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, |
||||
}; |
@ -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 |
@ -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; |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue