Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions components/drivers/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ rsource "hwcrypto/Kconfig"
rsource "wlan/Kconfig"
rsource "mailbox/Kconfig"
rsource "phye/Kconfig"
rsource "ata/Kconfig"
rsource "block/Kconfig"
rsource "nvme/Kconfig"
rsource "scsi/Kconfig"
Expand Down
22 changes: 22 additions & 0 deletions components/drivers/ata/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
menuconfig RT_USING_ATA
bool "Using Advanced Technology Attachment (ATA) device drivers"
depends on RT_USING_DM
depends on RT_USING_BLK
depends on RT_USING_DMA
default n

config RT_ATA_AHCI
bool "Advanced Host Controller Interface (AHCI)"
depends on RT_USING_ATA
depends on RT_USING_SCSI
default y

config RT_ATA_AHCI_PCI
bool "AHCI support on PCI bus"
depends on RT_ATA_AHCI
depends on RT_USING_PCI
default n

if RT_USING_ATA
osource "$(SOC_DM_ATA_DIR)/Kconfig"
endif
21 changes: 21 additions & 0 deletions components/drivers/ata/SConscript
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from building import *

group = []

if not GetDepend(['RT_USING_ATA']):
Return('group')

cwd = GetCurrentDir()
CPPPATH = [cwd + '/../include']

src = []

if GetDepend(['RT_ATA_AHCI']):
src += ['ahci.c']

if GetDepend(['RT_ATA_AHCI_PCI']):
src += ['ahci-pci.c']

group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)

Return('group')
206 changes: 206 additions & 0 deletions components/drivers/ata/ahci-pci.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-02-25 GuEe-GUI the first version
*/

#include <rtthread.h>
#include <rtdevice.h>

#define AHCI_REG_BAR 5

struct pci_ahci_quirk
{
int bar_idx;
rt_bool_t bar_offset;

const struct rt_ahci_ops *ops;
};

struct pci_ahci_host
{
struct rt_ahci_host parent;
const struct pci_ahci_quirk *quirk;

rt_bool_t is_msi;
};

#define raw_to_pci_ahci_host(raw) rt_container_of(raw, struct pci_ahci_host, parent)

static rt_err_t pci_ahci_init(struct rt_ahci_host *host)
{
struct rt_pci_device *pdev;

pdev = rt_container_of(host->parent.dev, struct rt_pci_device, parent);

if (pdev->vendor == PCI_VENDOR_ID_JMICRON)
{
rt_pci_write_config_u8(pdev, 0x41, 0xa1);
}

return RT_EOK;
}

static const struct rt_ahci_ops pci_ahci_ops =
{
.host_init = pci_ahci_init,
};

static rt_err_t pci_ahci_intel_init(struct rt_ahci_host *host)
{
rt_uint16_t val;
struct rt_pci_device *pdev;

pdev = rt_container_of(host->parent.dev, struct rt_pci_device, parent);

rt_pci_read_config_u16(pdev, 0x92, &val);
rt_pci_write_config_u16(pdev, 0x92, val & ~0xf);

rt_thread_mdelay(10);
rt_pci_write_config_u16(pdev, 0x92, val | 0xf);

return RT_EOK;
}

static const struct rt_ahci_ops pci_ahci_intel_ops =
{
.host_init = pci_ahci_intel_init,
};

static rt_err_t pci_ahci_probe(struct rt_pci_device *pdev)
{
rt_err_t err;
int bar_idx;
struct rt_ahci_host *ahci;
struct pci_ahci_host *pci_ahci = rt_calloc(1, sizeof(*pci_ahci));
const struct pci_ahci_quirk *quirk = pdev->id->data;

if (!pci_ahci)
{
return -RT_ENOMEM;
}

pci_ahci->quirk = quirk;
ahci = &pci_ahci->parent;
ahci->parent.dev = &pdev->parent;

bar_idx = quirk && quirk->bar_offset ? quirk->bar_idx : AHCI_REG_BAR;

ahci->regs = rt_pci_iomap(pdev, bar_idx);

if (!ahci->regs)
{
err = -RT_EIO;
goto _fail;
}

ahci->ops = quirk && quirk->ops ? quirk->ops : &pci_ahci_ops;

if (rt_pci_msi_enable(pdev) > 0)
{
pci_ahci->is_msi = RT_TRUE;
}
else
{
rt_pci_irq_unmask(pdev);
}
ahci->irq = pdev->irq;

rt_pci_set_master(pdev);

if ((err = rt_ahci_host_register(ahci)))
{
goto _disable;
}

pdev->parent.user_data = pci_ahci;

return RT_EOK;

_disable:
if (pci_ahci->is_msi)
{
rt_pci_msix_disable(pdev);
}
else
{
rt_pci_irq_mask(pdev);
}
rt_pci_clear_master(pdev);
rt_iounmap(ahci->regs);

_fail:
rt_free(pci_ahci);

return err;
}

static rt_err_t pci_ahci_remove(struct rt_pci_device *pdev)
{
struct rt_ahci_host *ahci;
struct pci_ahci_host *pci_ahci = pdev->parent.user_data;

ahci = &pci_ahci->parent;

rt_ahci_host_unregister(ahci);

if (pci_ahci->is_msi)
{
rt_pci_msi_disable(pdev);
}
else
{
/* INTx is shared, don't mask all */
rt_hw_interrupt_umask(pdev->irq);
rt_pci_irq_mask(pdev);
}

rt_pci_clear_master(pdev);

rt_iounmap(ahci->regs);
rt_free(pci_ahci);

return RT_EOK;
}

static rt_err_t pci_ahci_shutdown(struct rt_pci_device *pdev)
{
return pci_ahci_remove(pdev);
}

static struct pci_ahci_quirk intel_quirk =
{
.ops = &pci_ahci_intel_ops,
};

static struct pci_ahci_quirk cavium_sata_quirk =
{
.bar_idx = 0,
.bar_offset = RT_TRUE,
};

static const struct rt_pci_device_id pci_ahci_ids[] =
{
{ RT_PCI_DEVICE_ID(PCI_VENDOR_ID_INTEL, 0x2922), .data = &intel_quirk },
{ RT_PCI_DEVICE_ID(PCI_VENDOR_ID_ASMEDIA, 0x0611) },
{ RT_PCI_DEVICE_ID(PCI_VENDOR_ID_MARVELL, 0x6121) },
{ RT_PCI_DEVICE_ID(PCI_VENDOR_ID_MARVELL, 0x6145) },
{ RT_PCI_DEVICE_ID(PCI_VENDOR_ID_CAVIUM, 0xa01c), .data = &cavium_sata_quirk },
{ RT_PCI_DEVICE_CLASS(PCIS_STORAGE_SATA_AHCI, ~0) },
{ /* sentinel */ }
};

static struct rt_pci_driver pci_ahci_driver =
{
.name = "ahci-pci",

.ids = pci_ahci_ids,
.probe = pci_ahci_probe,
.remove = pci_ahci_remove,
.shutdown = pci_ahci_shutdown,
};
RT_PCI_DRIVER_EXPORT(pci_ahci_driver);
Loading
Loading