2 * Driver for MMC and SSD cards for Cavium ThunderX SOCs.
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License. See the file "COPYING" in the main directory of this archive
8 * Copyright (C) 2016 Cavium Inc.
10 #include <linux/device.h>
11 #include <linux/dma-mapping.h>
12 #include <linux/interrupt.h>
13 #include <linux/mmc/mmc.h>
14 #include <linux/module.h>
16 #include <linux/of_platform.h>
17 #include <linux/pci.h>
20 static void thunder_mmc_acquire_bus(struct cvm_mmc_host
*host
)
22 down(&host
->mmc_serializer
);
25 static void thunder_mmc_release_bus(struct cvm_mmc_host
*host
)
27 up(&host
->mmc_serializer
);
30 static void thunder_mmc_int_enable(struct cvm_mmc_host
*host
, u64 val
)
32 writeq(val
, host
->base
+ MIO_EMM_INT(host
));
33 writeq(val
, host
->base
+ MIO_EMM_INT_EN_SET(host
));
36 static int thunder_mmc_register_interrupts(struct cvm_mmc_host
*host
,
41 nvec
= pci_alloc_irq_vectors(pdev
, 1, 9, PCI_IRQ_MSIX
);
45 /* register interrupts */
46 for (i
= 0; i
< nvec
; i
++) {
47 ret
= devm_request_irq(&pdev
->dev
, pci_irq_vector(pdev
, i
),
49 0, cvm_mmc_irq_names
[i
], host
);
56 static int thunder_mmc_probe(struct pci_dev
*pdev
,
57 const struct pci_device_id
*id
)
59 struct device_node
*node
= pdev
->dev
.of_node
;
60 struct device
*dev
= &pdev
->dev
;
61 struct device_node
*child_node
;
62 struct cvm_mmc_host
*host
;
65 host
= devm_kzalloc(dev
, sizeof(*host
), GFP_KERNEL
);
69 pci_set_drvdata(pdev
, host
);
70 ret
= pcim_enable_device(pdev
);
74 ret
= pci_request_regions(pdev
, KBUILD_MODNAME
);
78 host
->base
= pcim_iomap(pdev
, 0, pci_resource_len(pdev
, 0));
84 /* On ThunderX these are identical */
85 host
->dma_base
= host
->base
;
87 host
->reg_off
= 0x2000;
88 host
->reg_off_dma
= 0x160;
90 host
->clk
= devm_clk_get(dev
, NULL
);
91 if (IS_ERR(host
->clk
)) {
92 ret
= PTR_ERR(host
->clk
);
96 ret
= clk_prepare_enable(host
->clk
);
99 host
->sys_freq
= clk_get_rate(host
->clk
);
101 spin_lock_init(&host
->irq_handler_lock
);
102 sema_init(&host
->mmc_serializer
, 1);
105 host
->acquire_bus
= thunder_mmc_acquire_bus
;
106 host
->release_bus
= thunder_mmc_release_bus
;
107 host
->int_enable
= thunder_mmc_int_enable
;
110 host
->big_dma_addr
= true;
111 host
->need_irq_handler_lock
= true;
112 host
->last_slot
= -1;
114 ret
= dma_set_mask(dev
, DMA_BIT_MASK(48));
119 * Clear out any pending interrupts that may be left over from
120 * bootloader. Writing 1 to the bits clears them.
122 writeq(127, host
->base
+ MIO_EMM_INT_EN(host
));
123 writeq(3, host
->base
+ MIO_EMM_DMA_INT_ENA_W1C(host
));
125 writeq(BIT_ULL(16), host
->base
+ MIO_EMM_DMA_FIFO_CFG(host
));
127 ret
= thunder_mmc_register_interrupts(host
, pdev
);
131 for_each_child_of_node(node
, child_node
) {
133 * mmc_of_parse and devm* require one device per slot.
134 * Create a dummy device per slot and set the node pointer to
135 * the slot. The easiest way to get this is using
136 * of_platform_device_create.
138 if (of_device_is_compatible(child_node
, "mmc-slot")) {
139 host
->slot_pdev
[i
] = of_platform_device_create(child_node
, NULL
,
141 if (!host
->slot_pdev
[i
])
144 ret
= cvm_mmc_of_slot_probe(&host
->slot_pdev
[i
]->dev
, host
);
150 dev_info(dev
, "probed\n");
154 for (i
= 0; i
< CAVIUM_MAX_MMC
; i
++) {
156 cvm_mmc_of_slot_remove(host
->slot
[i
]);
157 if (host
->slot_pdev
[i
]) {
158 get_device(&host
->slot_pdev
[i
]->dev
);
159 of_platform_device_destroy(&host
->slot_pdev
[i
]->dev
, NULL
);
160 put_device(&host
->slot_pdev
[i
]->dev
);
163 clk_disable_unprepare(host
->clk
);
164 pci_release_regions(pdev
);
168 static void thunder_mmc_remove(struct pci_dev
*pdev
)
170 struct cvm_mmc_host
*host
= pci_get_drvdata(pdev
);
174 for (i
= 0; i
< CAVIUM_MAX_MMC
; i
++)
176 cvm_mmc_of_slot_remove(host
->slot
[i
]);
178 dma_cfg
= readq(host
->dma_base
+ MIO_EMM_DMA_CFG(host
));
179 dma_cfg
&= ~MIO_EMM_DMA_CFG_EN
;
180 writeq(dma_cfg
, host
->dma_base
+ MIO_EMM_DMA_CFG(host
));
182 clk_disable_unprepare(host
->clk
);
183 pci_release_regions(pdev
);
186 static const struct pci_device_id thunder_mmc_id_table
[] = {
187 { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM
, 0xa010) },
188 { 0, } /* end of table */
191 static struct pci_driver thunder_mmc_driver
= {
192 .name
= KBUILD_MODNAME
,
193 .id_table
= thunder_mmc_id_table
,
194 .probe
= thunder_mmc_probe
,
195 .remove
= thunder_mmc_remove
,
198 module_pci_driver(thunder_mmc_driver
);
200 MODULE_AUTHOR("Cavium Inc.");
201 MODULE_DESCRIPTION("Cavium ThunderX eMMC Driver");
202 MODULE_LICENSE("GPL");
203 MODULE_DEVICE_TABLE(pci
, thunder_mmc_id_table
);