sdhci: accomodate 64-bit PCI BARs
* init works better with this. it doesn't work yet, but at least the boot isn't completely borked. * also fix the infinite loop in SoftwareReset() to timeout after 100ms. Change-Id: I76dac8360eaf3575adf7d0b3bf3e2b72daeedb21 Reviewed-on: https://review.haiku-os.org/c/haiku/+/4923 Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
parent
50ea01e93d
commit
f9e868fc8f
@ -104,7 +104,9 @@ SdhciBus::SdhciBus(struct registers* registers, uint8_t irq)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fSemaphore = create_sem(0, "SDHCI interrupts");
|
fSemaphore = create_sem(0, "SDHCI interrupts");
|
||||||
|
|
||||||
|
DisableInterrupts();
|
||||||
|
|
||||||
fStatus = install_io_interrupt_handler(fIrq,
|
fStatus = install_io_interrupt_handler(fIrq,
|
||||||
sdhci_generic_interrupt, this, 0);
|
sdhci_generic_interrupt, this, 0);
|
||||||
|
|
||||||
@ -200,7 +202,7 @@ SdhciBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response)
|
|||||||
|
|
||||||
uint32_t replyType;
|
uint32_t replyType;
|
||||||
|
|
||||||
switch(command) {
|
switch (command) {
|
||||||
case SD_GO_IDLE_STATE:
|
case SD_GO_IDLE_STATE:
|
||||||
replyType = Command::kNoReplyType;
|
replyType = Command::kNoReplyType;
|
||||||
break;
|
break;
|
||||||
@ -338,7 +340,8 @@ SdhciBus::InitCheck()
|
|||||||
void
|
void
|
||||||
SdhciBus::Reset()
|
SdhciBus::Reset()
|
||||||
{
|
{
|
||||||
fRegisters->software_reset.ResetAll();
|
if (!fRegisters->software_reset.ResetAll())
|
||||||
|
ERROR("SdhciBus::Reset: SoftwareReset timeout\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -392,7 +395,7 @@ SdhciBus::DoIO(uint8_t command, IOOperation* operation, bool offsetAsSectors)
|
|||||||
off_t offset = operation->Offset();
|
off_t offset = operation->Offset();
|
||||||
generic_size_t length = operation->Length();
|
generic_size_t length = operation->Length();
|
||||||
|
|
||||||
TRACE("%s %"B_PRIu64 " bytes at %" B_PRIdOFF "\n",
|
TRACE("%s %" B_PRIu64 " bytes at %" B_PRIdOFF "\n",
|
||||||
isWrite ? "Write" : "Read", length, offset);
|
isWrite ? "Write" : "Read", length, offset);
|
||||||
|
|
||||||
// Check that the IO scheduler did its job in following our DMA restrictions
|
// Check that the IO scheduler did its job in following our DMA restrictions
|
||||||
@ -675,14 +678,29 @@ init_bus(device_node* node, void** bus_cookie)
|
|||||||
pci_info pciInfo;
|
pci_info pciInfo;
|
||||||
pci->get_pci_info(device, &pciInfo);
|
pci->get_pci_info(device, &pciInfo);
|
||||||
|
|
||||||
if (pciInfo.u.h0.base_register_sizes[bar] == 0) {
|
for (; bar < 6 && slot > 0; bar++, slot--) {
|
||||||
|
if ((pciInfo.u.h0.base_register_flags[bar] & PCI_address_type)
|
||||||
|
== PCI_address_type_64) {
|
||||||
|
bar++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
phys_addr_t physicalAddress = pciInfo.u.h0.base_registers[bar];
|
||||||
|
uint64 barSize = pciInfo.u.h0.base_register_sizes[bar];
|
||||||
|
if ((pciInfo.u.h0.base_register_flags[bar] & PCI_address_type)
|
||||||
|
== PCI_address_type_64) {
|
||||||
|
physicalAddress |= (uint64)pciInfo.u.h0.base_registers[bar + 1] << 32;
|
||||||
|
barSize |= (uint64)pciInfo.u.h0.base_register_sizes[bar + 1] << 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (physicalAddress == 0 || barSize == 0) {
|
||||||
ERROR("No registers to map\n");
|
ERROR("No registers to map\n");
|
||||||
return B_IO_ERROR;
|
return B_IO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
int msiCount = sPCIx86Module->get_msi_count(pciInfo.bus,
|
int msiCount = sPCIx86Module->get_msi_count(pciInfo.bus,
|
||||||
pciInfo.device, pciInfo.function);
|
pciInfo.device, pciInfo.function);
|
||||||
TRACE("interrupts count: %d\n",msiCount);
|
TRACE("interrupts count: %d\n", msiCount);
|
||||||
// FIXME if available, use MSI rather than good old IRQ...
|
// FIXME if available, use MSI rather than good old IRQ...
|
||||||
|
|
||||||
// enable bus master and io
|
// enable bus master and io
|
||||||
@ -695,8 +713,7 @@ init_bus(device_node* node, void** bus_cookie)
|
|||||||
area_id regs_area;
|
area_id regs_area;
|
||||||
struct registers* _regs;
|
struct registers* _regs;
|
||||||
regs_area = map_physical_memory("sdhc_regs_map",
|
regs_area = map_physical_memory("sdhc_regs_map",
|
||||||
pciInfo.u.h0.base_registers[bar],
|
physicalAddress, barSize, B_ANY_KERNEL_BLOCK_ADDRESS,
|
||||||
pciInfo.u.h0.base_register_sizes[bar], B_ANY_KERNEL_BLOCK_ADDRESS,
|
|
||||||
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&_regs);
|
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&_regs);
|
||||||
|
|
||||||
if (regs_area < B_OK) {
|
if (regs_area < B_OK) {
|
||||||
@ -763,22 +780,23 @@ register_child_devices(void* cookie)
|
|||||||
device_node* parent = gDeviceManager->get_parent_node(context->fNode);
|
device_node* parent = gDeviceManager->get_parent_node(context->fNode);
|
||||||
pci_device_module_info* pci;
|
pci_device_module_info* pci;
|
||||||
pci_device* device;
|
pci_device* device;
|
||||||
uint8 slots_count, bar, slotsInfo;
|
|
||||||
|
|
||||||
gDeviceManager->get_driver(parent, (driver_module_info**)&pci,
|
gDeviceManager->get_driver(parent, (driver_module_info**)&pci,
|
||||||
(void**)&device);
|
(void**)&device);
|
||||||
slotsInfo = pci->read_pci_config(device, SDHCI_PCI_SLOT_INFO, 1);
|
uint8 slotsInfo = pci->read_pci_config(device, SDHCI_PCI_SLOT_INFO, 1);
|
||||||
bar = SDHCI_PCI_SLOT_INFO_FIRST_BASE_INDEX(slotsInfo);
|
uint8 bar = SDHCI_PCI_SLOT_INFO_FIRST_BASE_INDEX(slotsInfo);
|
||||||
slots_count = SDHCI_PCI_SLOTS(slotsInfo);
|
uint8 slotsCount = SDHCI_PCI_SLOTS(slotsInfo);
|
||||||
|
|
||||||
|
TRACE("register_child_devices: %u, %u\n", bar, slotsCount);
|
||||||
|
|
||||||
char prettyName[25];
|
char prettyName[25];
|
||||||
|
|
||||||
if (slots_count > 6 || bar > 5) {
|
if (slotsCount > 6 || bar > 5) {
|
||||||
ERROR("Invalid slots count: %d or BAR count: %d \n", slots_count, bar);
|
ERROR("Invalid slots count: %d or BAR count: %d \n", slotsCount, bar);
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint8_t slot = 0; slot <= slots_count; slot++) {
|
for (uint8_t slot = 0; slot < slotsCount; slot++) {
|
||||||
sprintf(prettyName, "SDHC bus %" B_PRIu8, slot);
|
sprintf(prettyName, "SDHC bus %" B_PRIu8, slot);
|
||||||
device_attr attrs[] = {
|
device_attr attrs[] = {
|
||||||
// properties of this controller for mmc bus manager
|
// properties of this controller for mmc bus manager
|
||||||
@ -799,7 +817,7 @@ register_child_devices(void* cookie)
|
|||||||
|
|
||||||
// private data to identify device
|
// private data to identify device
|
||||||
{ SLOT_NUMBER, B_UINT8_TYPE, { ui8: slot} },
|
{ SLOT_NUMBER, B_UINT8_TYPE, { ui8: slot} },
|
||||||
{ BAR_INDEX, B_UINT8_TYPE, { ui8: bar + slot} },
|
{ BAR_INDEX, B_UINT8_TYPE, { ui8: bar} },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
device_node* node;
|
device_node* node;
|
||||||
|
@ -14,8 +14,8 @@
|
|||||||
|
|
||||||
|
|
||||||
#define SDHCI_PCI_SLOT_INFO 0x40
|
#define SDHCI_PCI_SLOT_INFO 0x40
|
||||||
#define SDHCI_PCI_SLOTS(x) ((( x >> 4) & 7))
|
#define SDHCI_PCI_SLOTS(x) ((((x) >> 4) & 0x7) + 1)
|
||||||
#define SDHCI_PCI_SLOT_INFO_FIRST_BASE_INDEX(x) (( x ) & 7)
|
#define SDHCI_PCI_SLOT_INFO_FIRST_BASE_INDEX(x) ((x) & 0x7)
|
||||||
|
|
||||||
// Ricoh specific PCI registers
|
// Ricoh specific PCI registers
|
||||||
// Ricoh devices start in a vendor-specific mode but can be switched
|
// Ricoh devices start in a vendor-specific mode but can be switched
|
||||||
@ -159,9 +159,13 @@ class SoftwareReset {
|
|||||||
public:
|
public:
|
||||||
uint8_t Bits() { return fBits; }
|
uint8_t Bits() { return fBits; }
|
||||||
|
|
||||||
void ResetAll() {
|
bool ResetAll() {
|
||||||
fBits |= 1;
|
fBits = 1;
|
||||||
while(fBits & 1);
|
int i = 0;
|
||||||
|
// wait up to 100ms
|
||||||
|
while ((fBits & 1) != 0 && i++ < 10)
|
||||||
|
snooze(10000);
|
||||||
|
return i < 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResetCommandLine() {
|
void ResetCommandLine() {
|
||||||
|
Loading…
Reference in New Issue
Block a user