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));
82 /* On ThunderX these are identical */
83 host
->dma_base
= host
->base
;
85 host
->reg_off
= 0x2000;
86 host
->reg_off_dma
= 0x160;
88 host
->clk
= devm_clk_get(dev
, NULL
);
89 if (IS_ERR(host
->clk
))
90 return PTR_ERR(host
->clk
);
92 ret
= clk_prepare_enable(host
->clk
);
95 host
->sys_freq
= clk_get_rate(host
->clk
);
97 spin_lock_init(&host
->irq_handler_lock
);
98 sema_init(&host
->mmc_serializer
, 1);
101 host
->acquire_bus
= thunder_mmc_acquire_bus
;
102 host
->release_bus
= thunder_mmc_release_bus
;
103 host
->int_enable
= thunder_mmc_int_enable
;
106 host
->big_dma_addr
= true;
107 host
->need_irq_handler_lock
= true;
108 host
->last_slot
= -1;
110 ret
= dma_set_mask(dev
, DMA_BIT_MASK(48));
115 * Clear out any pending interrupts that may be left over from
116 * bootloader. Writing 1 to the bits clears them.
118 writeq(127, host
->base
+ MIO_EMM_INT_EN(host
));
119 writeq(3, host
->base
+ MIO_EMM_DMA_INT_ENA_W1C(host
));
121 writeq(BIT_ULL(16), host
->base
+ MIO_EMM_DMA_FIFO_CFG(host
));
123 ret
= thunder_mmc_register_interrupts(host
, pdev
);
127 for_each_child_of_node(node
, child_node
) {
129 * mmc_of_parse and devm* require one device per slot.
130 * Create a dummy device per slot and set the node pointer to
131 * the slot. The easiest way to get this is using
132 * of_platform_device_create.
134 if (of_device_is_compatible(child_node
, "mmc-slot")) {
135 host
->slot_pdev
[i
] = of_platform_device_create(child_node
, NULL
,
137 if (!host
->slot_pdev
[i
])
140 ret
= cvm_mmc_of_slot_probe(&host
->slot_pdev
[i
]->dev
, host
);
146 dev_info(dev
, "probed\n");
150 for (i
= 0; i
< CAVIUM_MAX_MMC
; i
++) {
152 cvm_mmc_of_slot_remove(host
->slot
[i
]);
153 if (host
->slot_pdev
[i
]) {
154 get_device(&host
->slot_pdev
[i
]->dev
);
155 of_platform_device_destroy(&host
->slot_pdev
[i
]->dev
, NULL
);
156 put_device(&host
->slot_pdev
[i
]->dev
);
159 clk_disable_unprepare(host
->clk
);
163 static void thunder_mmc_remove(struct pci_dev
*pdev
)
165 struct cvm_mmc_host
*host
= pci_get_drvdata(pdev
);
169 for (i
= 0; i
< CAVIUM_MAX_MMC
; i
++)
171 cvm_mmc_of_slot_remove(host
->slot
[i
]);
173 dma_cfg
= readq(host
->dma_base
+ MIO_EMM_DMA_CFG(host
));
174 dma_cfg
&= ~MIO_EMM_DMA_CFG_EN
;
175 writeq(dma_cfg
, host
->dma_base
+ MIO_EMM_DMA_CFG(host
));
177 clk_disable_unprepare(host
->clk
);
180 static const struct pci_device_id thunder_mmc_id_table
[] = {
181 { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM
, 0xa010) },
182 { 0, } /* end of table */
185 static struct pci_driver thunder_mmc_driver
= {
186 .name
= KBUILD_MODNAME
,
187 .id_table
= thunder_mmc_id_table
,
188 .probe
= thunder_mmc_probe
,
189 .remove
= thunder_mmc_remove
,
192 module_pci_driver(thunder_mmc_driver
);
194 MODULE_AUTHOR("Cavium Inc.");
195 MODULE_DESCRIPTION("Cavium ThunderX eMMC Driver");
196 MODULE_LICENSE("GPL");
197 MODULE_DEVICE_TABLE(pci
, thunder_mmc_id_table
);