mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 15:14:43 +00:00
dm: Add support for scsi/sata based devices
All sata based drivers are bind and corresponding block device is created. Based on this find_scsi_device() is able to get back block device based on scsi_curr_dev pointer. intr_scsi() is commented now but it can be replaced by calling find_scsi_device() and scsi_scan(). scsi_dev_desc[] is commented out but common/scsi.c heavily depends on it. That's why CONFIG_SYS_SCSI_MAX_DEVICE is hardcoded to 1 and symbol is reassigned to a block description allocated by uclass. There is only one block description by device now but it doesn't need to be correct when more devices are present. scsi_bind() ensures corresponding block device creation. uclass post_probe (scsi_post_probe()) is doing low level init. SCSI/SATA DM based drivers requires to have 64bit base address as the first entry in platform data structure to setup mmio_base. Signed-off-by: Michal Simek <michal.simek@xilinx.com> Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
720ba46e71
commit
e8a016b537
11 changed files with 165 additions and 13 deletions
|
@ -620,7 +620,7 @@ static int initr_ambapp_print(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SCSI)
|
||||
#if defined(CONFIG_SCSI) && !defined(CONFIG_DM_SCSI)
|
||||
static int initr_scsi(void)
|
||||
{
|
||||
puts("SCSI: ");
|
||||
|
@ -923,7 +923,7 @@ init_fnc_t init_sequence_r[] = {
|
|||
initr_ambapp_print,
|
||||
#endif
|
||||
#endif
|
||||
#ifdef CONFIG_SCSI
|
||||
#if defined(CONFIG_SCSI) && !defined(CONFIG_DM_SCSI)
|
||||
INIT_FUNC_WATCHDOG_RESET
|
||||
initr_scsi,
|
||||
#endif
|
||||
|
|
|
@ -10,7 +10,10 @@
|
|||
#include <inttypes.h>
|
||||
#include <pci.h>
|
||||
#include <scsi.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <dm/uclass-internal.h>
|
||||
|
||||
#if !defined(CONFIG_DM_SCSI)
|
||||
#ifdef CONFIG_SCSI_DEV_LIST
|
||||
#define SCSI_DEV_LIST CONFIG_SCSI_DEV_LIST
|
||||
#else
|
||||
|
@ -31,6 +34,7 @@
|
|||
#endif
|
||||
#define SCSI_DEV_LIST {SCSI_VEND_ID, SCSI_DEV_ID}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT)
|
||||
const struct pci_device_id scsi_device_list[] = { SCSI_DEV_LIST };
|
||||
|
@ -39,11 +43,13 @@ static ccb tempccb; /* temporary scsi command buffer */
|
|||
|
||||
static unsigned char tempbuff[512]; /* temporary data buffer */
|
||||
|
||||
#if !defined(CONFIG_DM_SCSI)
|
||||
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];
|
||||
#endif
|
||||
|
||||
/* almost the maximum amount of the scsi_ext command.. */
|
||||
#define SCSI_MAX_READ_BLK 0xFFFF
|
||||
|
@ -444,6 +450,7 @@ static void scsi_init_dev_desc_priv(struct blk_desc *dev_desc)
|
|||
#endif
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_DM_SCSI)
|
||||
/**
|
||||
* scsi_init_dev_desc - initialize all SCSI specific blk_desc properties
|
||||
*
|
||||
|
@ -460,6 +467,7 @@ static void scsi_init_dev_desc(struct blk_desc *dev_desc, int devnum)
|
|||
|
||||
scsi_init_dev_desc_priv(dev_desc);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* scsi_detect_dev - Detect scsi device
|
||||
|
@ -540,6 +548,73 @@ removable:
|
|||
* (re)-scan the scsi bus and reports scsi device info
|
||||
* to the user if mode = 1
|
||||
*/
|
||||
#if defined(CONFIG_DM_SCSI)
|
||||
int scsi_scan(int mode)
|
||||
{
|
||||
unsigned char i, lun;
|
||||
struct uclass *uc;
|
||||
struct udevice *dev; /* SCSI controller */
|
||||
int ret;
|
||||
|
||||
if (mode == 1)
|
||||
printf("scanning bus for devices...\n");
|
||||
|
||||
ret = uclass_get(UCLASS_SCSI, &uc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
uclass_foreach_dev(dev, uc) {
|
||||
struct scsi_platdata *plat; /* scsi controller platdata */
|
||||
|
||||
/* probe SCSI controller driver */
|
||||
ret = device_probe(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Get controller platdata */
|
||||
plat = dev_get_platdata(dev);
|
||||
|
||||
for (i = 0; i < plat->max_id; i++) {
|
||||
for (lun = 0; lun < plat->max_lun; lun++) {
|
||||
struct udevice *bdev; /* block device */
|
||||
/* block device description */
|
||||
struct blk_desc *bdesc;
|
||||
char str[10];
|
||||
|
||||
/*
|
||||
* Create only one block device and do detection
|
||||
* to make sure that there won't be a lot of
|
||||
* block devices created
|
||||
*/
|
||||
snprintf(str, sizeof(str), "id%dlun%d", i, lun);
|
||||
ret = blk_create_devicef(dev, "scsi_blk",
|
||||
str, IF_TYPE_SCSI,
|
||||
-1, 0, 0, &bdev);
|
||||
if (ret) {
|
||||
debug("Can't create device\n");
|
||||
return ret;
|
||||
}
|
||||
bdesc = dev_get_uclass_platdata(bdev);
|
||||
|
||||
scsi_init_dev_desc_priv(bdesc);
|
||||
bdesc->lun = lun;
|
||||
ret = scsi_detect_dev(i, bdesc);
|
||||
if (ret) {
|
||||
device_unbind(bdev);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mode == 1) {
|
||||
printf(" Device %d: ", 0);
|
||||
dev_print(bdesc);
|
||||
} /* if mode */
|
||||
} /* next LUN */
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int scsi_scan(int mode)
|
||||
{
|
||||
unsigned char i, lun;
|
||||
|
@ -576,6 +651,7 @@ int scsi_scan(int mode)
|
|||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BLK
|
||||
static const struct blk_ops scsi_blk_ops = {
|
||||
|
|
|
@ -19,6 +19,15 @@ config AHCI
|
|||
operations at present. The block device interface has not been converted
|
||||
to driver model.
|
||||
|
||||
config DM_SCSI
|
||||
bool "Support SCSI controllers with driver model"
|
||||
depends on BLK
|
||||
help
|
||||
This option enables the SCSI (Small Computer System Interface) uclass
|
||||
which supports SCSI and SATA HDDs. For every device configuration
|
||||
(IDs/LUNs) a block device is created with RAW read/write and
|
||||
filesystem support.
|
||||
|
||||
config BLOCK_CACHE
|
||||
bool "Use block device cache"
|
||||
default n
|
||||
|
@ -27,3 +36,7 @@ config BLOCK_CACHE
|
|||
This is most useful when accessing filesystems under U-Boot since
|
||||
it will prevent repeated reads from directory structures and other
|
||||
filesystem data structures.
|
||||
|
||||
menu "SATA/SCSI device support"
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -12,6 +12,7 @@ obj-y += blk_legacy.o
|
|||
endif
|
||||
|
||||
obj-$(CONFIG_AHCI) += ahci-uclass.o
|
||||
obj-$(CONFIG_DM_SCSI) += scsi-uclass.o
|
||||
obj-$(CONFIG_SCSI_AHCI) += ahci.o
|
||||
obj-$(CONFIG_DWC_AHSATA) += dwc_ahsata.o
|
||||
obj-$(CONFIG_FSL_SATA) += fsl_sata.o
|
||||
|
|
|
@ -168,7 +168,7 @@ int ahci_reset(void __iomem *base)
|
|||
|
||||
static int ahci_host_init(struct ahci_probe_ent *probe_ent)
|
||||
{
|
||||
#ifndef CONFIG_SCSI_AHCI_PLAT
|
||||
#if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI)
|
||||
# ifdef CONFIG_DM_PCI
|
||||
struct udevice *dev = probe_ent->dev;
|
||||
struct pci_child_platdata *pplat = dev_get_parent_platdata(dev);
|
||||
|
@ -198,7 +198,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
|
|||
writel(cap_save, mmio + HOST_CAP);
|
||||
writel_with_flush(0xf, mmio + HOST_PORTS_IMPL);
|
||||
|
||||
#ifndef CONFIG_SCSI_AHCI_PLAT
|
||||
#if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI)
|
||||
# ifdef CONFIG_DM_PCI
|
||||
if (pplat->vendor == PCI_VENDOR_ID_INTEL) {
|
||||
u16 tmp16;
|
||||
|
@ -327,6 +327,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
|
|||
writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
|
||||
tmp = readl(mmio + HOST_CTL);
|
||||
debug("HOST_CTL 0x%x\n", tmp);
|
||||
#if !defined(CONFIG_DM_SCSI)
|
||||
#ifndef CONFIG_SCSI_AHCI_PLAT
|
||||
# ifdef CONFIG_DM_PCI
|
||||
dm_pci_read_config16(dev, PCI_COMMAND, &tmp16);
|
||||
|
@ -337,6 +338,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
|
|||
tmp |= PCI_COMMAND_MASTER;
|
||||
pci_write_config_word(pdev, PCI_COMMAND, tmp16);
|
||||
# endif
|
||||
#endif
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -344,8 +346,8 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
|
|||
|
||||
static void ahci_print_info(struct ahci_probe_ent *probe_ent)
|
||||
{
|
||||
#ifndef CONFIG_SCSI_AHCI_PLAT
|
||||
# ifdef CONFIG_DM_PCI
|
||||
#if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI)
|
||||
# if defined(CONFIG_DM_PCI)
|
||||
struct udevice *dev = probe_ent->dev;
|
||||
# else
|
||||
pci_dev_t pdev = probe_ent->dev;
|
||||
|
@ -372,7 +374,7 @@ static void ahci_print_info(struct ahci_probe_ent *probe_ent)
|
|||
else
|
||||
speed_s = "?";
|
||||
|
||||
#ifdef CONFIG_SCSI_AHCI_PLAT
|
||||
#if defined(CONFIG_SCSI_AHCI_PLAT) || defined(CONFIG_DM_SCSI)
|
||||
scc_s = "SATA";
|
||||
#else
|
||||
# ifdef CONFIG_DM_PCI
|
||||
|
@ -424,13 +426,15 @@ static void ahci_print_info(struct ahci_probe_ent *probe_ent)
|
|||
}
|
||||
|
||||
#ifndef CONFIG_SCSI_AHCI_PLAT
|
||||
# ifdef CONFIG_DM_PCI
|
||||
# if defined(CONFIG_DM_PCI) || defined(CONFIG_DM_SCSI)
|
||||
static int ahci_init_one(struct udevice *dev)
|
||||
# else
|
||||
static int ahci_init_one(pci_dev_t dev)
|
||||
# endif
|
||||
{
|
||||
#if !defined(CONFIG_DM_SCSI)
|
||||
u16 vendor;
|
||||
#endif
|
||||
int rc;
|
||||
|
||||
probe_ent = malloc(sizeof(struct ahci_probe_ent));
|
||||
|
@ -450,6 +454,7 @@ static int ahci_init_one(pci_dev_t dev)
|
|||
probe_ent->pio_mask = 0x1f;
|
||||
probe_ent->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */
|
||||
|
||||
#if !defined(CONFIG_DM_SCSI)
|
||||
#ifdef CONFIG_DM_PCI
|
||||
probe_ent->mmio_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_5,
|
||||
PCI_REGION_MEM);
|
||||
|
@ -473,6 +478,10 @@ static int ahci_init_one(pci_dev_t dev)
|
|||
if (vendor == 0x197b)
|
||||
pci_write_config_byte(dev, 0x41, 0xa1);
|
||||
#endif
|
||||
#else
|
||||
struct scsi_platdata *plat = dev_get_platdata(dev);
|
||||
probe_ent->mmio_base = (void *)plat->base;
|
||||
#endif
|
||||
|
||||
debug("ahci mmio_base=0x%p\n", probe_ent->mmio_base);
|
||||
/* initialize adapter */
|
||||
|
@ -954,14 +963,17 @@ int scsi_exec(ccb *pccb)
|
|||
|
||||
}
|
||||
|
||||
|
||||
#if defined(CONFIG_DM_SCSI)
|
||||
void scsi_low_level_init(int busdevfunc, struct udevice *dev)
|
||||
#else
|
||||
void scsi_low_level_init(int busdevfunc)
|
||||
#endif
|
||||
{
|
||||
int i;
|
||||
u32 linkmap;
|
||||
|
||||
#ifndef CONFIG_SCSI_AHCI_PLAT
|
||||
# ifdef CONFIG_DM_PCI
|
||||
# if defined(CONFIG_DM_PCI)
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
|
@ -969,6 +981,8 @@ void scsi_low_level_init(int busdevfunc)
|
|||
if (ret)
|
||||
return;
|
||||
ahci_init_one(dev);
|
||||
# elif defined(CONFIG_DM_SCSI)
|
||||
ahci_init_one(dev);
|
||||
# else
|
||||
ahci_init_one(busdevfunc);
|
||||
# endif
|
||||
|
|
|
@ -26,7 +26,7 @@ static const char *if_typename_str[IF_TYPE_COUNT] = {
|
|||
|
||||
static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
|
||||
[IF_TYPE_IDE] = UCLASS_INVALID,
|
||||
[IF_TYPE_SCSI] = UCLASS_INVALID,
|
||||
[IF_TYPE_SCSI] = UCLASS_SCSI,
|
||||
[IF_TYPE_ATAPI] = UCLASS_INVALID,
|
||||
[IF_TYPE_USB] = UCLASS_MASS_STORAGE,
|
||||
[IF_TYPE_DOC] = UCLASS_INVALID,
|
||||
|
|
27
drivers/block/scsi-uclass.c
Normal file
27
drivers/block/scsi-uclass.c
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Google, Inc
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
* Copyright (c) 2016 Xilinx, Inc
|
||||
* Written by Michal Simek
|
||||
*
|
||||
* Based on ahci-uclass.c
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <scsi.h>
|
||||
|
||||
static int scsi_post_probe(struct udevice *dev)
|
||||
{
|
||||
debug("%s: device %p\n", __func__, dev);
|
||||
scsi_low_level_init(0, dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
UCLASS_DRIVER(scsi) = {
|
||||
.id = UCLASS_SCSI,
|
||||
.name = "scsi",
|
||||
.post_probe = scsi_post_probe,
|
||||
};
|
|
@ -145,7 +145,7 @@ struct ahci_ioports {
|
|||
};
|
||||
|
||||
struct ahci_probe_ent {
|
||||
#ifdef CONFIG_DM_PCI
|
||||
#if defined(CONFIG_DM_PCI) || defined(CONFIG_DM_SCSI)
|
||||
struct udevice *dev;
|
||||
#else
|
||||
pci_dev_t dev;
|
||||
|
|
|
@ -66,6 +66,7 @@ enum uclass_id {
|
|||
UCLASS_REMOTEPROC, /* Remote Processor device */
|
||||
UCLASS_RESET, /* Reset controller device */
|
||||
UCLASS_RTC, /* Real time clock device */
|
||||
UCLASS_SCSI, /* SCSI device */
|
||||
UCLASS_SERIAL, /* Serial UART */
|
||||
UCLASS_SPI, /* SPI bus */
|
||||
UCLASS_SPMI, /* System Power Management Interface bus */
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define __SATA_H__
|
||||
#include <part.h>
|
||||
|
||||
#if !defined(CONFIG_DM_SCSI)
|
||||
int init_sata(int dev);
|
||||
int reset_sata(int dev);
|
||||
int scan_sata(int dev);
|
||||
|
@ -15,5 +16,6 @@ int __sata_stop(void);
|
|||
int sata_port_status(int dev, int port);
|
||||
|
||||
extern struct blk_desc sata_dev_desc[];
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -166,8 +166,11 @@ typedef struct SCSI_cmd_block{
|
|||
void scsi_print_error(ccb *pccb);
|
||||
int scsi_exec(ccb *pccb);
|
||||
void scsi_bus_reset(void);
|
||||
#if !defined(CONFIG_DM_SCSI)
|
||||
void scsi_low_level_init(int busdevfunc);
|
||||
|
||||
#else
|
||||
void scsi_low_level_init(int busdevfunc, struct udevice *dev);
|
||||
#endif
|
||||
|
||||
/***************************************************************************
|
||||
* functions residing inside cmd_scsi.c
|
||||
|
@ -175,6 +178,21 @@ void scsi_low_level_init(int busdevfunc);
|
|||
void scsi_init(void);
|
||||
int scsi_scan(int mode);
|
||||
|
||||
#if defined(CONFIG_DM_SCSI)
|
||||
/**
|
||||
* struct scsi_platdata - stores information about SCSI controller
|
||||
*
|
||||
* @base: Controller base address
|
||||
* @max_lun: Maximum number of logical units
|
||||
* @max_id: Maximum number of target ids
|
||||
*/
|
||||
struct scsi_platdata {
|
||||
unsigned long base;
|
||||
unsigned long max_lun;
|
||||
unsigned long max_id;
|
||||
};
|
||||
#endif
|
||||
|
||||
#define SCSI_IDENTIFY 0xC0 /* not used */
|
||||
|
||||
/* Hardware errors */
|
||||
|
|
Loading…
Reference in a new issue