Commit | Line | Data |
---|---|---|
f1bf52e8 | 1 | // SPDX-License-Identifier: GPL-2.0 |
2a0a288e DN |
2 | /* |
3 | * NAND Flash Controller Device Driver | |
4 | * Copyright © 2009-2010, Intel Corporation and its suppliers. | |
2a0a288e | 5 | */ |
da4734be MY |
6 | |
7 | #include <linux/errno.h> | |
8 | #include <linux/io.h> | |
2a0a288e DN |
9 | #include <linux/kernel.h> |
10 | #include <linux/module.h> | |
11 | #include <linux/pci.h> | |
2a0a288e DN |
12 | |
13 | #include "denali.h" | |
14 | ||
15 | #define DENALI_NAND_NAME "denali-nand-pci" | |
16 | ||
1bb88666 MY |
17 | #define INTEL_CE4100 1 |
18 | #define INTEL_MRST 2 | |
19 | ||
2a0a288e | 20 | /* List of platforms this NAND controller has be integrated into */ |
94f7039a | 21 | static const struct pci_device_id denali_pci_ids[] = { |
2a0a288e DN |
22 | { PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 }, |
23 | { PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST }, | |
24 | { /* end: all zeroes */ } | |
25 | }; | |
26 | MODULE_DEVICE_TABLE(pci, denali_pci_ids); | |
27 | ||
7de117fd MY |
28 | NAND_ECC_CAPS_SINGLE(denali_pci_ecc_caps, denali_calc_ecc_bytes, 512, 8, 15); |
29 | ||
2a0a288e DN |
30 | static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) |
31 | { | |
2a0a288e DN |
32 | resource_size_t csr_base, mem_base; |
33 | unsigned long csr_len, mem_len; | |
d8e8fd0e MY |
34 | struct denali_controller *denali; |
35 | struct denali_chip *dchip; | |
36 | int nsels, ret, i; | |
2a0a288e | 37 | |
add243d5 | 38 | denali = devm_kzalloc(&dev->dev, sizeof(*denali), GFP_KERNEL); |
2a0a288e DN |
39 | if (!denali) |
40 | return -ENOMEM; | |
41 | ||
add243d5 | 42 | ret = pcim_enable_device(dev); |
2a0a288e | 43 | if (ret) { |
af83a67c | 44 | dev_err(&dev->dev, "Spectra: pci_enable_device failed.\n"); |
add243d5 | 45 | return ret; |
2a0a288e DN |
46 | } |
47 | ||
48 | if (id->driver_data == INTEL_CE4100) { | |
2a0a288e DN |
49 | mem_base = pci_resource_start(dev, 0); |
50 | mem_len = pci_resource_len(dev, 1); | |
51 | csr_base = pci_resource_start(dev, 1); | |
52 | csr_len = pci_resource_len(dev, 1); | |
53 | } else { | |
2a0a288e DN |
54 | csr_base = pci_resource_start(dev, 0); |
55 | csr_len = pci_resource_len(dev, 0); | |
56 | mem_base = pci_resource_start(dev, 1); | |
57 | mem_len = pci_resource_len(dev, 1); | |
58 | if (!mem_len) { | |
59 | mem_base = csr_base + csr_len; | |
60 | mem_len = csr_len; | |
61 | } | |
62 | } | |
63 | ||
64 | pci_set_master(dev); | |
65 | denali->dev = &dev->dev; | |
66 | denali->irq = dev->irq; | |
7de117fd | 67 | denali->ecc_caps = &denali_pci_ecc_caps; |
1dfac31a | 68 | denali->clk_rate = 50000000; /* 50 MHz */ |
1bb88666 | 69 | denali->clk_x_rate = 200000000; /* 200 MHz */ |
2a0a288e DN |
70 | |
71 | ret = pci_request_regions(dev, DENALI_NAND_NAME); | |
72 | if (ret) { | |
af83a67c | 73 | dev_err(&dev->dev, "Spectra: Unable to request memory regions\n"); |
add243d5 | 74 | return ret; |
2a0a288e DN |
75 | } |
76 | ||
0d3a966d MY |
77 | denali->reg = ioremap_nocache(csr_base, csr_len); |
78 | if (!denali->reg) { | |
af83a67c | 79 | dev_err(&dev->dev, "Spectra: Unable to remap memory region\n"); |
add243d5 | 80 | return -ENOMEM; |
2a0a288e DN |
81 | } |
82 | ||
0d3a966d MY |
83 | denali->host = ioremap_nocache(mem_base, mem_len); |
84 | if (!denali->host) { | |
af83a67c | 85 | dev_err(&dev->dev, "Spectra: ioremap_nocache failed!"); |
2a0a288e | 86 | ret = -ENOMEM; |
13defd47 | 87 | goto out_unmap_reg; |
2a0a288e DN |
88 | } |
89 | ||
90 | ret = denali_init(denali); | |
91 | if (ret) | |
13defd47 | 92 | goto out_unmap_host; |
2a0a288e | 93 | |
d8e8fd0e MY |
94 | nsels = denali->nbanks; |
95 | ||
96 | dchip = devm_kzalloc(denali->dev, struct_size(dchip, sels, nsels), | |
97 | GFP_KERNEL); | |
98 | if (!dchip) { | |
99 | ret = -ENOMEM; | |
100 | goto out_remove_denali; | |
101 | } | |
102 | ||
103 | dchip->chip.ecc.options |= NAND_ECC_MAXIMIZE; | |
104 | ||
105 | dchip->nsels = nsels; | |
106 | ||
107 | for (i = 0; i < nsels; i++) | |
108 | dchip->sels[i].bank = i; | |
109 | ||
110 | ret = denali_chip_init(denali, dchip); | |
111 | if (ret) | |
112 | goto out_remove_denali; | |
113 | ||
2a0a288e DN |
114 | pci_set_drvdata(dev, denali); |
115 | ||
116 | return 0; | |
117 | ||
d8e8fd0e MY |
118 | out_remove_denali: |
119 | denali_remove(denali); | |
13defd47 | 120 | out_unmap_host: |
0d3a966d | 121 | iounmap(denali->host); |
13defd47 | 122 | out_unmap_reg: |
0d3a966d | 123 | iounmap(denali->reg); |
2a0a288e DN |
124 | return ret; |
125 | } | |
126 | ||
2a0a288e DN |
127 | static void denali_pci_remove(struct pci_dev *dev) |
128 | { | |
d8e8fd0e | 129 | struct denali_controller *denali = pci_get_drvdata(dev); |
2a0a288e DN |
130 | |
131 | denali_remove(denali); | |
0d3a966d MY |
132 | iounmap(denali->reg); |
133 | iounmap(denali->host); | |
2a0a288e DN |
134 | } |
135 | ||
136 | static struct pci_driver denali_pci_driver = { | |
137 | .name = DENALI_NAND_NAME, | |
138 | .id_table = denali_pci_ids, | |
139 | .probe = denali_pci_probe, | |
140 | .remove = denali_pci_remove, | |
141 | }; | |
2445d33d | 142 | module_pci_driver(denali_pci_driver); |
d822401d JC |
143 | |
144 | MODULE_DESCRIPTION("PCI driver for Denali NAND controller"); | |
145 | MODULE_AUTHOR("Intel Corporation and its suppliers"); | |
146 | MODULE_LICENSE("GPL v2"); |