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/platform_device.h>
18 #include <linux/pci.h>
21 static void thunder_mmc_acquire_bus(struct cvm_mmc_host
*host
)
23 down(&host
->mmc_serializer
);
26 static void thunder_mmc_release_bus(struct cvm_mmc_host
*host
)
28 up(&host
->mmc_serializer
);
31 static void thunder_mmc_int_enable(struct cvm_mmc_host
*host
, u64 val
)
33 writeq(val
, host
->base
+ MIO_EMM_INT(host
));
34 writeq(val
, host
->base
+ MIO_EMM_INT_EN_SET(host
));
37 static int thunder_mmc_register_interrupts(struct cvm_mmc_host
*host
,
42 nvec
= pci_alloc_irq_vectors(pdev
, 1, 9, PCI_IRQ_MSIX
);
46 /* register interrupts */
47 for (i
= 0; i
< nvec
; i
++) {
48 ret
= devm_request_irq(&pdev
->dev
, pci_irq_vector(pdev
, i
),
50 0, cvm_mmc_irq_names
[i
], host
);
57 static int thunder_mmc_probe(struct pci_dev
*pdev
,
58 const struct pci_device_id
*id
)
60 struct device_node
*node
= pdev
->dev
.of_node
;
61 struct device
*dev
= &pdev
->dev
;
62 struct device_node
*child_node
;
63 struct cvm_mmc_host
*host
;
66 host
= devm_kzalloc(dev
, sizeof(*host
), GFP_KERNEL
);
70 pci_set_drvdata(pdev
, host
);
71 ret
= pcim_enable_device(pdev
);
75 ret
= pci_request_regions(pdev
, KBUILD_MODNAME
);
79 host
->base
= pcim_iomap(pdev
, 0, pci_resource_len(pdev
, 0));
85 /* On ThunderX these are identical */
86 host
->dma_base
= host
->base
;
88 host
->reg_off
= 0x2000;
89 host
->reg_off_dma
= 0x160;
91 host
->clk
= devm_clk_get(dev
, NULL
);
92 if (IS_ERR(host
->clk
)) {
93 ret
= PTR_ERR(host
->clk
);
97 ret
= clk_prepare_enable(host
->clk
);
100 host
->sys_freq
= clk_get_rate(host
->clk
);
102 spin_lock_init(&host
->irq_handler_lock
);
103 sema_init(&host
->mmc_serializer
, 1);
106 host
->acquire_bus
= thunder_mmc_acquire_bus
;
107 host
->release_bus
= thunder_mmc_release_bus
;
108 host
->int_enable
= thunder_mmc_int_enable
;
111 host
->big_dma_addr
= true;
112 host
->need_irq_handler_lock
= true;
113 host
->last_slot
= -1;
115 ret
= dma_set_mask(dev
, DMA_BIT_MASK(48));
120 * Clear out any pending interrupts that may be left over from
121 * bootloader. Writing 1 to the bits clears them.
123 writeq(127, host
->base
+ MIO_EMM_INT_EN(host
));
124 writeq(3, host
->base
+ MIO_EMM_DMA_INT_ENA_W1C(host
));
126 writeq(BIT_ULL(16), host
->base
+ MIO_EMM_DMA_FIFO_CFG(host
));
128 ret
= thunder_mmc_register_interrupts(host
, pdev
);
132 for_each_child_of_node(node
, child_node
) {
134 * mmc_of_parse and devm* require one device per slot.
135 * Create a dummy device per slot and set the node pointer to
136 * the slot. The easiest way to get this is using
137 * of_platform_device_create.
139 if (of_device_is_compatible(child_node
, "mmc-slot")) {
140 host
->slot_pdev
[i
] = of_platform_device_create(child_node
, NULL
,
142 if (!host
->slot_pdev
[i
])
145 ret
= cvm_mmc_of_slot_probe(&host
->slot_pdev
[i
]->dev
, host
);
147 of_node_put(child_node
);
153 dev_info(dev
, "probed\n");
157 for (i
= 0; i
< CAVIUM_MAX_MMC
; i
++) {
159 cvm_mmc_of_slot_remove(host
->slot
[i
]);
160 if (host
->slot_pdev
[i
]) {
161 get_device(&host
->slot_pdev
[i
]->dev
);
162 of_platform_device_destroy(&host
->slot_pdev
[i
]->dev
, NULL
);
163 put_device(&host
->slot_pdev
[i
]->dev
);
166 clk_disable_unprepare(host
->clk
);
167 pci_release_regions(pdev
);
171 static void thunder_mmc_remove(struct pci_dev
*pdev
)
173 struct cvm_mmc_host
*host
= pci_get_drvdata(pdev
);
177 for (i
= 0; i
< CAVIUM_MAX_MMC
; i
++)
179 cvm_mmc_of_slot_remove(host
->slot
[i
]);
181 dma_cfg
= readq(host
->dma_base
+ MIO_EMM_DMA_CFG(host
));
182 dma_cfg
&= ~MIO_EMM_DMA_CFG_EN
;
183 writeq(dma_cfg
, host
->dma_base
+ MIO_EMM_DMA_CFG(host
));
185 clk_disable_unprepare(host
->clk
);
186 pci_release_regions(pdev
);
189 static const struct pci_device_id thunder_mmc_id_table
[] = {
190 { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM
, 0xa010) },
191 { 0, } /* end of table */
194 static struct pci_driver thunder_mmc_driver
= {
195 .name
= KBUILD_MODNAME
,
196 .id_table
= thunder_mmc_id_table
,
197 .probe
= thunder_mmc_probe
,
198 .remove
= thunder_mmc_remove
,
201 module_pci_driver(thunder_mmc_driver
);
203 MODULE_AUTHOR("Cavium Inc.");
204 MODULE_DESCRIPTION("Cavium ThunderX eMMC Driver");
205 MODULE_LICENSE("GPL");
206 MODULE_DEVICE_TABLE(pci
, thunder_mmc_id_table
);