Hi , Actually these are not really dummy Id's.The vendor Id ad Device Id were given by Synopsys for the PCI platform.
On Mon, Oct 3, 2011 at 2:01 PM, James Hogan <james.ho...@imgtec.com> wrote: > Hi > > On 10/03/2011 07:50 AM, Shashidhar Hiremath wrote: >> Hi James, >> Can I add separate files for PCI/Platform and from there call >> common probe/remove api's similar to SDHCI driver in kernel ? > > yes, that sounds like a good idea. > > In what way are the PCI device and vendor ids dummy? > > Cheers > James > >> >> On Fri, Sep 30, 2011 at 2:12 PM, James Hogan <james.ho...@imgtec.com> wrote: >>> Hi >>> >>> On 09/29/2011 06:40 PM, Shashidhar Hiremath wrote: >>>> Support of PCI mode for the dw_mmc driver This Patch adds the support for >>>> the scenario where the Synopsys Designware IP is present on the PCI >>>> bus.The patch adds the minimal modifications necessary for the driver to >>>> work on PCI platform. The Driver has also been tested for on the PCI >>>> platform with single Card Slot. >>>> >>>> Signed-off-by: Shashidhar Hiremath <shashidh...@vayavyalabs.com> >>>> --- >>>> v2: >>>> *As per Suggestions by Will Newton and James Hogan >>>> -Reduced the number of ifdefs >>>> >>>> drivers/mmc/host/Kconfig | 11 ++ >>>> drivers/mmc/host/dw_mmc.c | 352 >>>> ++++++++++++++++++++++++++++++++++++++++++++ >>>> drivers/mmc/host/dw_mmc.h | 13 ++ >>>> include/linux/mmc/dw_mmc.h | 4 + >>>> 4 files changed, 380 insertions(+), 0 deletions(-) >>>> >>>> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig >>>> index 8c87096..84d8908 100644 >>>> --- a/drivers/mmc/host/Kconfig >>>> +++ b/drivers/mmc/host/Kconfig >>>> @@ -526,6 +526,17 @@ config MMC_DW >>>> block, this provides host support for SD and MMC interfaces, in >>>> both >>>> PIO and external DMA modes. >>>> >>>> +config MMC_DW_PCI >>>> + bool "MMC_DW Support On PCI bus" >>>> + depends on MMC_DW && PCI >>>> + help >>>> + This selects the PCI for the Synopsys Designware Mobile Storage IP. >>>> + >>>> + If you have a controller with this interface, say Y or M here. >>>> + >>>> + If unsure, say N. >>>> + >>>> + >>>> config MMC_DW_IDMAC >>>> bool "Internal DMAC interface" >>>> depends on MMC_DW >>>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >>>> index ff0f714..0bd9e16 100644 >>>> --- a/drivers/mmc/host/dw_mmc.c >>>> +++ b/drivers/mmc/host/dw_mmc.c >>>> @@ -21,6 +21,7 @@ >>>> #include <linux/interrupt.h> >>>> #include <linux/ioport.h> >>>> #include <linux/module.h> >>>> +#include <linux/pci.h> >>>> #include <linux/platform_device.h> >>>> #include <linux/scatterlist.h> >>>> #include <linux/seq_file.h> >>>> @@ -101,6 +102,7 @@ struct dw_mci_slot { >>>> int last_detect_state; >>>> }; >>>> >>>> + >>>> static struct workqueue_struct *dw_mci_card_workqueue; >>>> >>>> #if defined(CONFIG_DEBUG_FS) >>>> @@ -682,6 +684,7 @@ static void dw_mci_set_ios(struct mmc_host *mmc, >>>> struct mmc_ios *ios) >>>> { >>>> struct dw_mci_slot *slot = mmc_priv(mmc); >>>> u32 regs; >>>> + u32 card_detect; >>>> >>>> /* set default 1 bit mode */ >>>> slot->ctype = SDMMC_CTYPE_1BIT; >>>> @@ -716,6 +719,13 @@ static void dw_mci_set_ios(struct mmc_host *mmc, >>>> struct mmc_ios *ios) >>>> switch (ios->power_mode) { >>>> case MMC_POWER_UP: >>>> set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); >>>> + /* Enable Power to the card that has been detected */ >>>> + card_detect = mci_readl(slot->host, CDETECT); >>>> + /* Enabling power for card 0 when PCI is the interface */ >>>> + mci_writel(slot->host, PWREN, ((~card_detect) & 0x1)); >>>> + break; >>>> + case MMC_POWER_OFF: >>>> + mci_writel(slot->host, PWREN, 0); >>>> break; >>>> default: >>>> break; >>>> @@ -1775,6 +1785,345 @@ static bool mci_wait_reset(struct device *dev, >>>> struct dw_mci *host) >>>> return false; >>>> } >>>> >>>> +#ifdef CONFIG_MMC_DW_PCI >>>> + >>>> +static struct pci_device_id dw_mci_id = { PCI_DEVICE(DEVICE_ID, >>>> VENDOR_ID) }; >>>> + >>>> +struct dw_mci_board pci_board_data = { >>>> + .num_slots = 1, >>>> + .caps = DW_MCI_CAPABILITIES, >>>> + .bus_hz = 33 * 1000 * 1000, >>>> + .detect_delay_ms = 200, >>>> + .fifo_depth = 32, >>>> +}; >>>> + >>>> +static int __devinit dw_mci_probe(struct pci_dev *pdev, >>>> + const struct pci_device_id *entries) >>>> +{ >>>> + struct dw_mci *host; >>>> + struct resource *regs; >>>> + struct dw_mci_board *pdata; >>>> + int irq, ret, i, width; >>>> + u32 fifo_size; >>>> + >>>> + ret = pci_enable_device(pdev); >>>> + if (ret) >>>> + return ret; >>>> + if (pci_request_regions(pdev, "dw_mmc")) { >>>> + ret = -ENODEV; >>>> + goto err_freehost; >>>> + } >>>> + irq = pdev->irq; >>>> + >>>> + host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL); >>>> + if (!host) >>>> + return -ENOMEM; >>>> + >>>> + host->pdev = pdev; >>>> + host->pdata = pdata = &pci_board_data; >>>> + >>>> + if (!pdata->select_slot && pdata->num_slots > 1) { >>>> + dev_err(&pdev->dev, >>>> + "Platform data must supply select_slot function\n"); >>>> + ret = -ENODEV; >>>> + goto err_freehost; >>>> + } >>>> + >>>> + if (!pdata->bus_hz) { >>>> + dev_err(&pdev->dev, >>>> + "Platform data must supply bus speed\n"); >>>> + ret = -ENODEV; >>>> + goto err_freehost; >>>> + } >>>> + >>>> + host->bus_hz = pdata->bus_hz; >>>> + host->quirks = pdata->quirks; >>>> + >>>> + spin_lock_init(&host->lock); >>>> + INIT_LIST_HEAD(&host->queue); >>>> + >>>> + ret = -ENOMEM; >>>> + host->regs = pci_iomap(pdev, PCI_BAR_NO, COMPLETE_BAR); >>>> + if (!host->regs) { >>>> + ret = -EIO; >>>> + goto err_free_res; >>>> + } >>>> + >>>> + host->dma_ops = pdata->dma_ops; >>>> + dw_mci_init_dma(host); >>>> + >>>> + /* >>>> + * Get the host data width - this assumes that HCON has been set with >>>> + * the correct values. >>>> + */ >>>> + i = (mci_readl(host, HCON) >> 7) & 0x7; >>>> + if (!i) { >>>> + host->push_data = dw_mci_push_data16; >>>> + host->pull_data = dw_mci_pull_data16; >>>> + width = 16; >>>> + host->data_shift = 1; >>>> + } else if (i == 2) { >>>> + host->push_data = dw_mci_push_data64; >>>> + host->pull_data = dw_mci_pull_data64; >>>> + width = 64; >>>> + host->data_shift = 3; >>>> + } else { >>>> + /* Check for a reserved value, and warn if it is */ >>>> + WARN((i != 1), >>>> + "HCON reports a reserved host data width!\n" >>>> + "Defaulting to 32-bit access.\n"); >>>> + host->push_data = dw_mci_push_data32; >>>> + host->pull_data = dw_mci_pull_data32; >>>> + width = 32; >>>> + host->data_shift = 2; >>>> + } >>>> + >>>> + /* Reset all blocks */ >>>> + if (!mci_wait_reset(&pdev->dev, host)) { >>>> + ret = -ENODEV; >>>> + goto err_dmaunmap; >>>> + } >>>> + >>>> + /* Clear the interrupts for the host controller */ >>>> + mci_writel(host, RINTSTS, 0xFFFFFFFF); >>>> + mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ >>>> + >>>> + /* Put in max timeout */ >>>> + mci_writel(host, TMOUT, 0xFFFFFFFF); >>>> + >>>> + /* >>>> + * FIFO threshold settings RxMark = fifo_size / 2 - 1, >>>> + * Tx Mark = fifo_size / 2 DMA Size = 8 >>>> + */ >>>> + if (!host->pdata->fifo_depth) { >>>> + /* >>>> + * Power-on value of RX_WMark is FIFO_DEPTH-1, but this may >>>> + * have been overwritten by the bootloader, just like we're >>>> + * about to do, so if you know the value for your hardware, >>>> you >>>> + * should put it in the platform data. >>>> + */ >>>> + fifo_size = mci_readl(host, FIFOTH); >>>> + fifo_size = 1 + ((fifo_size >> 16) & 0x7ff); >>>> + } else { >>>> + fifo_size = host->pdata->fifo_depth; >>>> + } >>>> + host->fifo_depth = fifo_size; >>>> + host->fifoth_val = ((0x2 << 28) | ((fifo_size/2 - 1) << 16) | >>>> + ((fifo_size/2) << 0)); >>>> + mci_writel(host, FIFOTH, host->fifoth_val); >>>> + >>>> + /* disable clock to CIU */ >>>> + mci_writel(host, CLKENA, 0); >>>> + mci_writel(host, CLKSRC, 0); >>>> + >>>> + tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned >>>> long)host); >>>> + dw_mci_card_workqueue = alloc_workqueue("dw-mci-card", >>>> + WQ_MEM_RECLAIM | WQ_NON_REENTRANT, 1); >>>> + if (!dw_mci_card_workqueue) >>>> + goto err_dmaunmap; >>>> + INIT_WORK(&host->card_work, dw_mci_work_routine_card); >>>> + >>>> + ret = request_irq(irq, dw_mci_interrupt, IRQF_SHARED, "dw-mci", >>>> host); >>>> + if (ret) >>>> + goto err_workqueue; >>>> + >>>> + pci_set_drvdata(pdev, host); >>>> + >>>> + if (host->pdata->num_slots) >>>> + host->num_slots = host->pdata->num_slots; >>>> + else >>>> + host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1; >>>> + >>>> + /* We need at least one slot to succeed */ >>>> + for (i = 0; i < host->num_slots; i++) { >>>> + ret = dw_mci_init_slot(host, i); >>>> + if (ret) { >>>> + ret = -ENODEV; >>>> + goto err_init_slot; >>>> + } >>>> + } >>>> + >>>> + /* >>>> + * Enable interrupts for command done, data over, data empty, card >>>> det, >>>> + * receive ready and error such as transmit, receive timeout, crc >>>> error >>>> + */ >>>> + mci_writel(host, RINTSTS, 0xFFFFFFFF); >>>> + mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | >>>> + SDMMC_INT_TXDR | SDMMC_INT_RXDR | >>>> + DW_MCI_ERROR_FLAGS | SDMMC_INT_CD); >>>> + mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci >>>> interrupt */ >>>> + >>>> + dev_info(&pdev->dev, "DW MMC controller at irq %d, " >>>> + "%d bit host data width, " >>>> + "%u deep fifo\n", >>>> + irq, width, fifo_size); >>>> + if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) >>>> + dev_info(&pdev->dev, "Internal DMAC interrupt fix >>>> enabled.\n"); >>>> + >>>> + return 0; >>>> + >>>> +err_init_slot: >>>> + /* De-init any initialized slots */ >>>> + while (i > 0) { >>>> + if (host->slot[i]) >>>> + dw_mci_cleanup_slot(host->slot[i], i); >>>> + i--; >>>> + } >>>> + free_irq(irq, host); >>>> + >>>> +err_workqueue: >>>> + destroy_workqueue(dw_mci_card_workqueue); >>>> + >>>> +err_dmaunmap: >>>> + if (host->use_dma && host->dma_ops->exit) >>>> + host->dma_ops->exit(host); >>>> + dma_free_coherent(&host->pdev->dev, PAGE_SIZE, >>>> + host->sg_cpu, host->sg_dma); >>>> + iounmap(host->regs); >>>> + >>>> + if (host->vmmc) { >>>> + regulator_disable(host->vmmc); >>>> + regulator_put(host->vmmc); >>>> + } >>>> + >>>> +err_free_res: >>>> + pci_release_regions(pdev); >>>> + >>>> +err_freehost: >>>> + kfree(host); >>>> + return ret; >>>> +} >>>> + >>>> +static void __devexit dw_mci_remove(struct pci_dev *pdev) >>>> +{ >>>> + >>>> + struct dw_mci *host = pci_get_drvdata(pdev); >>>> + int i; >>>> + >>>> + mci_writel(host, RINTSTS, 0xFFFFFFFF); >>>> + mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ >>>> + >>>> + pci_set_drvdata(pdev, NULL); >>>> + >>>> + for (i = 0; i < host->num_slots; i++) { >>>> + dev_dbg(&pdev->dev, "remove slot %d\n", i); >>>> + if (host->slot[i]) >>>> + dw_mci_cleanup_slot(host->slot[i], i); >>>> + } >>>> + >>>> + /* disable clock to CIU */ >>>> + mci_writel(host, CLKENA, 0); >>>> + mci_writel(host, CLKSRC, 0); >>>> + >>>> + free_irq(pdev->irq, host); >>>> + destroy_workqueue(dw_mci_card_workqueue); >>>> + dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); >>>> + >>>> + if (host->use_dma && host->dma_ops->exit) >>>> + host->dma_ops->exit(host); >>>> + >>>> + if (host->vmmc) { >>>> + regulator_disable(host->vmmc); >>>> + regulator_put(host->vmmc); >>>> + } >>>> + >>>> + iounmap(host->regs); >>>> + >>>> + pci_release_regions(pdev); >>>> + kfree(host); >>>> +} >>>> + >>>> +#ifdef CONFIG_PM >>>> +/* >>>> + * TODO: we should probably disable the clock to the card in the suspend >>>> path. >>>> + */ >>>> +static int dw_mci_suspend(struct pci_dev *pdev, pm_message_t mesg) >>>> +{ >>>> + int i, ret; >>>> + struct dw_mci *host = pci_get_drvdata(pdev); >>>> + >>>> + for (i = 0; i < host->num_slots; i++) { >>>> + struct dw_mci_slot *slot = host->slot[i]; >>>> + if (!slot) >>>> + continue; >>>> + ret = mmc_suspend_host(slot->mmc); >>>> + if (ret < 0) { >>>> + while (--i >= 0) { >>>> + slot = host->slot[i]; >>>> + if (slot) >>>> + mmc_resume_host(host->slot[i]->mmc); >>>> + } >>>> + return ret; >>>> + } >>>> + } >>>> + >>>> + if (host->vmmc) >>>> + regulator_disable(host->vmmc); >>>> + >>>> + return 0; >>>> +} >>>> + >>>> +static int dw_mci_resume(struct pci_dev *pdev) >>>> +{ >>>> + int i, ret; >>>> + struct dw_mci *host = pci_get_drvdata(pdev); >>>> + >>>> + if (host->vmmc) >>>> + regulator_enable(host->vmmc); >>>> + >>>> + if (host->dma_ops->init) >>>> + host->dma_ops->init(host); >>>> + >>>> + if (!mci_wait_reset(&pdev->dev, host)) { >>>> + ret = -ENODEV; >>>> + return ret; >>>> + } >>>> + >>>> + /* Restore the old value at FIFOTH register */ >>>> + mci_writel(host, FIFOTH, host->fifoth_val); >>>> + >>>> + mci_writel(host, RINTSTS, 0xFFFFFFFF); >>>> + mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | >>>> + SDMMC_INT_TXDR | SDMMC_INT_RXDR | >>>> + DW_MCI_ERROR_FLAGS | SDMMC_INT_CD); >>>> + mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); >>>> + >>>> + for (i = 0; i < host->num_slots; i++) { >>>> + struct dw_mci_slot *slot = host->slot[i]; >>>> + if (!slot) >>>> + continue; >>>> + ret = mmc_resume_host(host->slot[i]->mmc); >>>> + if (ret < 0) >>>> + return ret; >>>> + } >>>> + >>>> + return 0; >>>> +} >>>> +#else >>>> +#define dw_mci_suspend NULL >>>> +#define dw_mci_resume NULL >>>> +#endif /* CONFIG_PM */ >>>> + >>>> +static struct pci_driver dw_mci_driver = { >>>> + .name = "dw_mmc", >>>> + .id_table = &dw_mci_id, >>>> + .probe = dw_mci_probe, >>>> + .remove = dw_mci_remove, >>>> + .suspend = dw_mci_suspend, >>>> + .resume = dw_mci_resume, >>>> +}; >>>> + >>>> +static int __init dw_mci_init(void) >>>> +{ >>>> + return pci_register_driver(&dw_mci_driver); >>>> +} >>>> + >>>> +static void __exit dw_mci_exit(void) >>>> +{ >>>> + pci_unregister_driver(&dw_mci_driver); >>>> +} >>>> +#else >>>> + >>> >>> Duplication isn't the same as abstraction, and it's much worse to >>> maintain than lots of #ifdefs. What we meant was to abstract the common >>> code into separate static functions which are used by both pci/platform >>> probe/remove/suspend/resume functions (as Will has already described). >>> >>> These functions should also have pci/platform in their names to >>> distinguish them more easily. Also I see no reason why pci and platform >>> registration should be mutually exclusive, i.e. the platform driver can >>> still be registered even if PCI is enabled. >>> >>>> static int dw_mci_probe(struct platform_device *pdev) >>>> { >>>> struct dw_mci *host; >>>> @@ -1974,6 +2323,7 @@ err_freehost: >>>> >>>> static int __exit dw_mci_remove(struct platform_device *pdev) >>>> { >>>> + >>>> struct dw_mci *host = platform_get_drvdata(pdev); >>>> int i; >>>> >>>> @@ -2100,6 +2450,8 @@ static void __exit dw_mci_exit(void) >>>> platform_driver_unregister(&dw_mci_driver); >>>> } >>>> >>>> +#endif/* CONFIG_MMC_DW_PCI */ >>>> + >>>> module_init(dw_mci_init); >>>> module_exit(dw_mci_exit); >>>> >>>> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >>>> index 027d377..54bc604 100644 >>>> --- a/drivers/mmc/host/dw_mmc.h >>>> +++ b/drivers/mmc/host/dw_mmc.h >>>> @@ -164,4 +164,17 @@ >>>> (*(volatile u64 __force *)((dev)->regs + SDMMC_##reg) = (value)) >>>> #endif >>>> >>>> +/* PCI Specific macros */ >>>> +#ifdef CONFIG_MMC_DW_PCI >>>> +#define PCI_BAR_NO 2 >>>> +#define COMPLETE_BAR 0 >>>> +/* Dummy Device Id and Vendor Id */ >>>> +#define VENDOR_ID 0x700 >>>> +#define DEVICE_ID 0x1107 >>> >>> Again, in what way are these values dummy? if somebody were to want to >>> use this, would they have to change them for their specific hardware? Is >>> that a common thing to have to do for other drivers like this? >>> >>>> +/* Defining the Capabilities */ >>>> +#define DW_MCI_CAPABILITIES (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED |\ >>>> + MMC_CAP_SD_HIGHSPEED | MMC_CAP_8_BIT_DATA |\ >>>> + MMC_CAP_SDIO_IRQ) >>>> +#endif /* CONFIG_MMC_DW_PCI */ >>>> + >>>> #endif /* _DW_MMC_H_ */ >>>> diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h >>>> index 6b46819..87af5a6 100644 >>>> --- a/include/linux/mmc/dw_mmc.h >>>> +++ b/include/linux/mmc/dw_mmc.h >>>> @@ -147,7 +147,11 @@ struct dw_mci { >>>> u32 current_speed; >>>> u32 num_slots; >>>> u32 fifoth_val; >>>> +#ifdef CONFIG_MMC_DW_PCI >>>> + struct pci_dev *pdev; >>>> +#else >>>> struct platform_device *pdev; >>>> +#endif >>> >>> The only time this is used is to find &host->pdev->dev for logging >>> calls. It'd be better to replace these with a single struct device *, >>> then it'll work with both platform and pci enabled. >>> >>>> struct dw_mci_board *pdata; >>>> struct dw_mci_slot *slot[MAX_MCI_SLOTS]; >>>> >>> >>> >> >> >> > > -- regards, Shashidhar Hiremath -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html