83 #include <linux/kernel.h>
84 #include <linux/module.h>
85 #include <asm/uaccess.h>
86 #include <linux/types.h>
88 #include <linux/ptrace.h>
89 #include <linux/slab.h>
90 #include <linux/string.h>
96 #include <linux/pci.h>
99 #define PMC551_VERSION \
100 "Ramix PMC551 PCI Mezzanine Ram Driver. (C) 1999,2000 Nortel Networks.\n"
102 #define PCI_VENDOR_ID_V3_SEMI 0x11b0
103 #define PCI_DEVICE_ID_V3_SEMI_V370PDC 0x0200
105 #define PMC551_PCI_MEM_MAP0 0x50
106 #define PMC551_PCI_MEM_MAP1 0x54
107 #define PMC551_PCI_MEM_MAP_MAP_ADDR_MASK 0x3ff00000
108 #define PMC551_PCI_MEM_MAP_APERTURE_MASK 0x000000f0
109 #define PMC551_PCI_MEM_MAP_REG_EN 0x00000002
110 #define PMC551_PCI_MEM_MAP_ENABLE 0x00000001
112 #define PMC551_SDRAM_MA 0x60
113 #define PMC551_SDRAM_CMD 0x62
114 #define PMC551_DRAM_CFG 0x64
115 #define PMC551_SYS_CTRL_REG 0x78
117 #define PMC551_DRAM_BLK0 0x68
118 #define PMC551_DRAM_BLK1 0x6c
119 #define PMC551_DRAM_BLK2 0x70
120 #define PMC551_DRAM_BLK3 0x74
121 #define PMC551_DRAM_BLK_GET_SIZE(x) (524288 << ((x >> 4) & 0x0f))
122 #define PMC551_DRAM_BLK_SET_COL_MUX(x, v) (((x) & ~0x00007000) | (((v) & 0x7) << 12))
123 #define PMC551_DRAM_BLK_SET_ROW_MUX(x, v) (((x) & ~0x00000f00) | (((v) & 0xf) << 8))
136 static int pmc551_point(
struct mtd_info *mtd, loff_t
from,
size_t len,
142 u32 soff_hi, soff_lo;
143 u32 eoff_hi, eoff_lo;
148 #ifdef CONFIG_MTD_PMC551_DEBUG
153 end = instr->
addr + instr->
len - 1;
154 eoff_hi = end & ~(priv->
asize - 1);
155 soff_hi = instr->
addr & ~(priv->
asize - 1);
156 eoff_lo = end & (priv->
asize - 1);
157 soff_lo = instr->
addr & (priv->
asize - 1);
159 pmc551_point(mtd, instr->
addr, instr->
len, &retlen,
160 (
void **)&ptr,
NULL);
162 if (soff_hi == eoff_hi || mtd->
size == priv->
asize) {
169 while (soff_hi != eoff_hi) {
170 #ifdef CONFIG_MTD_PMC551_DEBUG
172 "eoff_hi: %ld\n", (
long)soff_hi, (
long)eoff_hi);
175 if (soff_hi + priv->
asize >= mtd->
size) {
178 soff_hi += priv->
asize;
179 pmc551_point(mtd, (priv->
base_map0 | soff_hi),
180 priv->
asize, &retlen,
181 (
void **)&ptr,
NULL);
183 memset(ptr, 0xff, eoff_lo);
188 #ifdef CONFIG_MTD_PMC551_DEBUG
196 static int pmc551_point(
struct mtd_info *mtd, loff_t
from,
size_t len,
203 #ifdef CONFIG_MTD_PMC551_DEBUG
207 soff_hi = from & ~(priv->
asize - 1);
208 soff_lo = from & (priv->
asize - 1);
217 *virt = priv->
start + soff_lo;
222 static int pmc551_unpoint(
struct mtd_info *mtd, loff_t from,
size_t len)
224 #ifdef CONFIG_MTD_PMC551_DEBUG
230 static int pmc551_read(
struct mtd_info *mtd, loff_t from,
size_t len,
234 u32 soff_hi, soff_lo;
235 u32 eoff_hi, eoff_lo;
240 #ifdef CONFIG_MTD_PMC551_DEBUG
242 (
long)from, (
long)len, (
long)priv->
asize);
245 end = from + len - 1;
246 soff_hi = from & ~(priv->
asize - 1);
247 eoff_hi = end & ~(priv->
asize - 1);
248 soff_lo = from & (priv->
asize - 1);
249 eoff_lo = end & (priv->
asize - 1);
251 pmc551_point(mtd, from, len, retlen, (
void **)&ptr,
NULL);
253 if (soff_hi == eoff_hi) {
261 while (soff_hi != eoff_hi) {
262 #ifdef CONFIG_MTD_PMC551_DEBUG
264 "eoff_hi: %ld\n", (
long)soff_hi, (
long)eoff_hi);
267 copyto += priv->
asize;
268 if (soff_hi + priv->
asize >= mtd->
size) {
271 soff_hi += priv->
asize;
272 pmc551_point(mtd, soff_hi, priv->
asize, retlen,
273 (
void **)&ptr,
NULL);
275 memcpy(copyto, ptr, eoff_lo);
280 #ifdef CONFIG_MTD_PMC551_DEBUG
283 *retlen = copyto -
buf;
287 static int pmc551_write(
struct mtd_info *mtd, loff_t to,
size_t len,
288 size_t * retlen,
const u_char * buf)
291 u32 soff_hi, soff_lo;
292 u32 eoff_hi, eoff_lo;
297 #ifdef CONFIG_MTD_PMC551_DEBUG
299 (
long)to, (
long)len, (
long)priv->
asize);
303 soff_hi = to & ~(priv->
asize - 1);
304 eoff_hi = end & ~(priv->
asize - 1);
305 soff_lo = to & (priv->
asize - 1);
306 eoff_lo = end & (priv->
asize - 1);
308 pmc551_point(mtd, to, len, retlen, (
void **)&ptr,
NULL);
310 if (soff_hi == eoff_hi) {
313 memcpy(ptr, copyfrom, len);
318 while (soff_hi != eoff_hi) {
319 #ifdef CONFIG_MTD_PMC551_DEBUG
321 "eoff_hi: %ld\n", (
long)soff_hi, (
long)eoff_hi);
324 copyfrom += priv->
asize;
325 if (soff_hi >= mtd->
size) {
328 soff_hi += priv->
asize;
329 pmc551_point(mtd, soff_hi, priv->
asize, retlen,
330 (
void **)&ptr,
NULL);
332 memcpy(ptr, copyfrom, eoff_lo);
337 #ifdef CONFIG_MTD_PMC551_DEBUG
340 *retlen = copyfrom -
buf;
358 #ifdef CONFIG_MTD_PMC551_BUGFIX
380 for (i = 0; i < 10; i++) {
383 while (counter++ < 100) {
388 while (counter++ < 100) {
392 bcmd |= (0x40 | 0x20);
419 #ifndef CONFIG_MTD_PMC551_BUGFIX
492 for (i = 1; i <= 8; i++) {
541 cmd &= ~PCI_STATUS_DEVSEL_MASK;
559 #ifdef CONFIG_MTD_PMC551_DEBUG
564 "0x%llx\n", (size < 1024) ? size : (size < 1048576) ?
565 size >> 10 : size >> 20,
566 (size < 1024) ?
"" : (size < 1048576) ?
"Ki" :
"Mi", size,
567 ((dcmd & (0x1 << 3)) == 0) ?
"non-" :
"",
575 "pmc551: DRAM_BLK0 Size: %d at %d\n"
576 "pmc551: DRAM_BLK0 Row MUX: %d, Col MUX: %d\n",
577 (((0x1 << 1) & dcmd) == 0) ?
"RW" :
"RO",
578 (((0x1 << 0) & dcmd) == 0) ?
"Off" :
"On",
580 ((dcmd >> 20) & 0x7FF), ((dcmd >> 13) & 0x7),
581 ((dcmd >> 9) & 0xF));
585 "pmc551: DRAM_BLK1 Size: %d at %d\n"
586 "pmc551: DRAM_BLK1 Row MUX: %d, Col MUX: %d\n",
587 (((0x1 << 1) & dcmd) == 0) ?
"RW" :
"RO",
588 (((0x1 << 0) & dcmd) == 0) ?
"Off" :
"On",
590 ((dcmd >> 20) & 0x7FF), ((dcmd >> 13) & 0x7),
591 ((dcmd >> 9) & 0xF));
595 "pmc551: DRAM_BLK2 Size: %d at %d\n"
596 "pmc551: DRAM_BLK2 Row MUX: %d, Col MUX: %d\n",
597 (((0x1 << 1) & dcmd) == 0) ?
"RW" :
"RO",
598 (((0x1 << 0) & dcmd) == 0) ?
"Off" :
"On",
600 ((dcmd >> 20) & 0x7FF), ((dcmd >> 13) & 0x7),
601 ((dcmd >> 9) & 0xF));
605 "pmc551: DRAM_BLK3 Size: %d at %d\n"
606 "pmc551: DRAM_BLK3 Row MUX: %d, Col MUX: %d\n",
607 (((0x1 << 1) & dcmd) == 0) ?
"RW" :
"RO",
608 (((0x1 << 0) & dcmd) == 0) ?
"Off" :
"On",
610 ((dcmd >> 20) & 0x7FF), ((dcmd >> 13) & 0x7),
611 ((dcmd >> 9) & 0xF));
615 (((0x1 << 1) & cmd) == 0) ?
"off" :
"on");
617 (((0x1 << 0) & cmd) == 0) ?
"off" :
"on");
621 ((PCI_STATUS_DEVSEL_MASK & cmd) == 0x000) ?
"Fast" :
622 ((PCI_STATUS_DEVSEL_MASK & cmd) == 0x200) ?
"Medium" :
623 ((PCI_STATUS_DEVSEL_MASK & cmd) == 0x400) ?
"Slow" :
"Invalid");
626 ((PCI_COMMAND_FAST_BACK & cmd) == 0) ?
"Not " :
"");
630 "pmc551: System Control Register is %slocked to PCI access\n"
631 "pmc551: System Control Register is %slocked to EEPROM access\n",
632 (bcmd & 0x1) ?
"software" :
"hardware",
633 (bcmd & 0x20) ?
"" :
"un", (bcmd & 0x40) ?
"" :
"un");
649 static int msize = 0;
650 static int asize = 0;
660 static int __init init_pmc551(
void)
669 msize = (1 << (
ffs(msize) - 1)) << 20;
670 if (msize > (1 << 30)) {
678 asize = (1 << (
ffs(asize) - 1)) << 20;
679 if (asize > (1 << 30)) {
695 PCI_Device)) ==
NULL) {
710 if ((length = fixup_pmc551(PCI_Device)) <= 0) {
722 "size 0x%x\n", length);
742 priv->
dev = PCI_Device;
744 if (asize > length) {
746 "fit %dM\n", length >> 20);
748 }
else if (asize == 0 || asize == length) {
750 "size %dM\n", length >> 20);
754 "size %dM\n", asize >> 20);
757 priv->
start = pci_iomap(PCI_Device, 0, priv->
asize);
765 #ifdef CONFIG_MTD_PMC551_DEBUG
772 | (
ffs(priv->
asize >> 20) - 1) << 4);
777 #ifdef CONFIG_MTD_PMC551_DEBUG
784 mtd->
_erase = pmc551_erase;
785 mtd->
_read = pmc551_read;
786 mtd->
_write = pmc551_write;
787 mtd->
_point = pmc551_point;
790 mtd->
name =
"PMC551 RAM board";
811 (length < 1024) ? length :
812 (length < 1048576) ? length >> 10 : length >> 20,
813 (length < 1024) ?
"" : (length < 1048576) ?
"Ki" :
"Mi");
835 static void __exit cleanup_pmc551(
void)
841 while ((mtd = pmc551list)) {