From 8bb6ce1a81b89bc8d881d02ffbe01d6c393588ac Mon Sep 17 00:00:00 2001 From: Marcus Overhagen Date: Sun, 10 Sep 2006 15:02:10 +0000 Subject: [PATCH] added controller probing and channel publishing git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18787 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../silicon_image_3112/silicon_image_3112.c | 176 ++++++++++++++++++ 1 file changed, 176 insertions(+) diff --git a/src/add-ons/kernel/busses/ide/silicon_image_3112/silicon_image_3112.c b/src/add-ons/kernel/busses/ide/silicon_image_3112/silicon_image_3112.c index 1a796b2ef4..38b0b45e80 100644 --- a/src/add-ons/kernel/busses/ide/silicon_image_3112/silicon_image_3112.c +++ b/src/add-ons/kernel/busses/ide/silicon_image_3112/silicon_image_3112.c @@ -6,13 +6,57 @@ #include #include #include +#include #include #include +#define TRACE(a...) dprintf("si-3112 " a) + +#define DRIVER_PRETTY_NAME "Silicon Image SATA" +#define CONTROLLER_DRIVER "silicon_image_3112" +#define CONTROLLER_NAME DRIVER_PRETTY_NAME #define CONTROLLER_MODULE_NAME "busses/ide/silicon_image_3112/device_v1" #define CHANNEL_MODULE_NAME "busses/ide/silicon_image_3112/channel/v1" +enum asic_type { + ASIC_SI3112 = 0, + ASIC_SI3114 = 1, +}; + +static const char *adapter_asic_names[] = { + "si3112", + "si3114", + NULL +}; + +static const struct { + uint16 channel_count; + uint32 mmio_bar_size; +} asic_data[2] = { + { 2, 0x200 }, + { 4, 0x400 }, +}; + +static const struct { + uint16 cmd; + uint16 ctl; + uint16 bmdma; + uint16 sien; + const char *name; +} controller_channel_data[] = { + { 0x80, 0x8A, 0x00, 0x148, "Primary Channel" }, + { 0xC0, 0xCA, 0x08, 0x1C8, "Secondary Channel" }, + { 0x280, 0x28A, 0x200, 0x348, "Tertiary Channel" }, + { 0x2C0, 0x2CA, 0x208, 0x3C8, "Quaternary Channel" }, +}; + +#define SI_SYSCFG 0x48 +#define SI_BMDMA2 0x200 +#define SI_INT_STEERING 0x02 +#define SI_MASK_2PORT ((1 << 22) | (1 << 23)) +#define SI_MASK_4PORT ((1 << 22) | (1 << 23) | (1 << 24) | (1 << 25)) + static ide_for_controller_interface * ide; static ide_adapter_interface * ide_adapter; @@ -22,10 +66,142 @@ static device_manager_info * dm; static status_t controller_probe(device_node_handle parent) { + pci_device device; + pci_device_module_info *pci; + device_node_handle controller_node; + uint32 mmio_base; + uint16 device_id; + uint8 int_num; + int asic_index; + int chan_index; + status_t res; + + TRACE("controller_probe\n"); + + if (dm->init_driver(parent, NULL, (driver_module_info **)&pci, (void **)&device) != B_OK) + return B_ERROR; + + device_id = pci->read_pci_config(device, PCI_device_id, 2); + int_num = pci->read_pci_config(device, PCI_interrupt_line, 1); + mmio_base = pci->read_pci_config(device, PCI_base_registers + 20, 4); + mmio_base &= PCI_address_io_mask; + + switch (device_id) { + case 0x3112: + asic_index = ASIC_SI3112; + break; + case 0x3114: + asic_index = ASIC_SI3114; + break; + default: + TRACE("unsupported asic\n"); + goto err; + } + + if (!mmio_base) { + TRACE("mmio not configured\n"); + goto err; + } + + if (int_num == 0 || int_num == 0xff) { + TRACE("irq not configured\n"); + goto err; + } + + { + io_resource_handle resource_handles[2]; + io_resource resources[2] = { + { IO_MEM, mmio_base, asic_data[asic_index].mmio_bar_size }, + {} + }; + + if (dm->acquire_io_resources(resources, resource_handles) != B_OK) { + TRACE("acquire_io_resources failed\n"); + goto err; + } + + { + + device_attr controller_attrs[] = { + // info about ourself and our consumer + { B_DRIVER_MODULE, B_STRING_TYPE, { string: CONTROLLER_DRIVER }}, + + // properties of this controller for ide bus manager + // there are always max. 2 devices + // (unless this is a Compact Flash Card with a built-in IDE controller, + // which has exactly 1 device) + { IDE_CONTROLLER_MAX_DEVICES_ITEM, B_UINT8_TYPE, { ui8: asic_data[asic_index].channel_count }}, + // of course we can DMA + { IDE_CONTROLLER_CAN_DMA_ITEM, B_UINT8_TYPE, { ui8: true }}, + // command queuing always works + { IDE_CONTROLLER_CAN_CQ_ITEM, B_UINT8_TYPE, { ui8: true }}, + // choose any name here + { IDE_CONTROLLER_CONTROLLER_NAME_ITEM, B_STRING_TYPE, { string: CONTROLLER_NAME }}, + + // DMA properties + // data must be word-aligned; + // warning: some controllers are more picky! + { B_BLOCK_DEVICE_DMA_ALIGNMENT, B_UINT32_TYPE, { ui32: 1}}, + // one S/G block must not cross 64K boundary + { B_BLOCK_DEVICE_DMA_BOUNDARY, B_UINT32_TYPE, { ui32: 0xffff }}, + // max size of S/G block is 16 bits with zero being 64K + { B_BLOCK_DEVICE_MAX_SG_BLOCK_SIZE, B_UINT32_TYPE, { ui32: 0x10000 }}, + // see definition of MAX_SG_COUNT + { B_BLOCK_DEVICE_MAX_SG_BLOCKS, B_UINT32_TYPE, { ui32: IDE_ADAPTER_MAX_SG_COUNT }}, + + // private data to find controller + { "silicon_image_3112/asic_index", B_UINT32_TYPE, { ui32: asic_index }}, + { "silicon_image_3112/int_num", B_UINT32_TYPE, { ui32: int_num }}, + { NULL } + }; + + TRACE("publishing controller"); + + res = dm->register_device(parent, controller_attrs, resource_handles, &controller_node); + if (res != B_OK || controller_node == NULL) { + TRACE("register controller failed\n"); + goto err; + } + + } + + // publish channel nodes + for (chan_index = 0; chan_index < asic_data[asic_index].channel_count; chan_index++) { + device_attr channel_attrs[] = { + // info about ourself and our consumer + { B_DRIVER_MODULE, B_STRING_TYPE, { string: CHANNEL_MODULE_NAME }}, + { B_DRIVER_PRETTY_NAME, B_STRING_TYPE, { string: DRIVER_PRETTY_NAME }}, + { PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: controller_channel_data[chan_index].name }}, + { B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: IDE_FOR_CONTROLLER_MODULE_NAME }}, + + // private data to identify channel + { IDE_CONTROLLER_CAN_DMA_ITEM, B_UINT8_TYPE, { ui8: true }}, + { "silicon_image_3112/chan_index", B_UINT32_TYPE, { ui32: chan_index }}, + { NULL } + }; + + device_node_handle channel_node; + + TRACE("publishing %s\n", controller_channel_data[chan_index].name ); + + dm->register_device(controller_node, channel_attrs, resource_handles, &channel_node); + } + + } + + dm->uninit_driver(parent); + + TRACE("controller_probe success\n"); + return B_OK; + +err: + dm->uninit_driver(parent); + TRACE("controller_probe failed\n"); return B_ERROR; } + static status_t controller_init(device_node_handle node, void *user_cookie, void **_cookie) {