diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-u300/clock.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-u300/core.c | 47 | ||||
-rw-r--r-- | arch/arm/mach-u300/include/mach/u300-regs.h | 2 | ||||
-rw-r--r-- | arch/arm/plat-pxa/include/plat/pxa3xx_nand.h | 18 | ||||
-rw-r--r-- | arch/mips/include/asm/mach-bcm63xx/bcm963xx_tag.h | 97 | ||||
-rw-r--r-- | arch/powerpc/Kconfig | 7 | ||||
-rw-r--r-- | arch/powerpc/include/asm/fsl_lbc.h | 34 | ||||
-rw-r--r-- | arch/powerpc/sysdev/fsl_lbc.c | 244 |
8 files changed, 397 insertions, 58 deletions
diff --git a/arch/arm/mach-u300/clock.c b/arch/arm/mach-u300/clock.c index 60acf9e708ae..7458fc6df5c6 100644 --- a/arch/arm/mach-u300/clock.c +++ b/arch/arm/mach-u300/clock.c | |||
@@ -66,7 +66,7 @@ static DEFINE_SPINLOCK(syscon_resetreg_lock); | |||
66 | * AMBA bus | 66 | * AMBA bus |
67 | * | | 67 | * | |
68 | * +- CPU | 68 | * +- CPU |
69 | * +- NANDIF NAND Flash interface | 69 | * +- FSMC NANDIF NAND Flash interface |
70 | * +- SEMI Shared Memory interface | 70 | * +- SEMI Shared Memory interface |
71 | * +- ISP Image Signal Processor (U335 only) | 71 | * +- ISP Image Signal Processor (U335 only) |
72 | * +- CDS (U335 only) | 72 | * +- CDS (U335 only) |
@@ -726,7 +726,7 @@ static struct clk cpu_clk = { | |||
726 | }; | 726 | }; |
727 | 727 | ||
728 | static struct clk nandif_clk = { | 728 | static struct clk nandif_clk = { |
729 | .name = "NANDIF", | 729 | .name = "FSMC", |
730 | .parent = &amba_clk, | 730 | .parent = &amba_clk, |
731 | .hw_ctrld = false, | 731 | .hw_ctrld = false, |
732 | .reset = true, | 732 | .reset = true, |
@@ -1259,7 +1259,7 @@ static struct clk_lookup lookups[] = { | |||
1259 | /* Connected directly to the AMBA bus */ | 1259 | /* Connected directly to the AMBA bus */ |
1260 | DEF_LOOKUP("amba", &amba_clk), | 1260 | DEF_LOOKUP("amba", &amba_clk), |
1261 | DEF_LOOKUP("cpu", &cpu_clk), | 1261 | DEF_LOOKUP("cpu", &cpu_clk), |
1262 | DEF_LOOKUP("fsmc", &nandif_clk), | 1262 | DEF_LOOKUP("fsmc-nand", &nandif_clk), |
1263 | DEF_LOOKUP("semi", &semi_clk), | 1263 | DEF_LOOKUP("semi", &semi_clk), |
1264 | #ifdef CONFIG_MACH_U300_BS335 | 1264 | #ifdef CONFIG_MACH_U300_BS335 |
1265 | DEF_LOOKUP("isp", &isp_clk), | 1265 | DEF_LOOKUP("isp", &isp_clk), |
diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c index ea41c236be0f..aa53ee22438f 100644 --- a/arch/arm/mach-u300/core.c +++ b/arch/arm/mach-u300/core.c | |||
@@ -21,7 +21,8 @@ | |||
21 | #include <linux/gpio.h> | 21 | #include <linux/gpio.h> |
22 | #include <linux/clk.h> | 22 | #include <linux/clk.h> |
23 | #include <linux/err.h> | 23 | #include <linux/err.h> |
24 | #include <mach/coh901318.h> | 24 | #include <linux/mtd/nand.h> |
25 | #include <linux/mtd/fsmc.h> | ||
25 | 26 | ||
26 | #include <asm/types.h> | 27 | #include <asm/types.h> |
27 | #include <asm/setup.h> | 28 | #include <asm/setup.h> |
@@ -30,6 +31,7 @@ | |||
30 | #include <asm/mach/map.h> | 31 | #include <asm/mach/map.h> |
31 | #include <asm/mach/irq.h> | 32 | #include <asm/mach/irq.h> |
32 | 33 | ||
34 | #include <mach/coh901318.h> | ||
33 | #include <mach/hardware.h> | 35 | #include <mach/hardware.h> |
34 | #include <mach/syscon.h> | 36 | #include <mach/syscon.h> |
35 | #include <mach/dma_channels.h> | 37 | #include <mach/dma_channels.h> |
@@ -285,6 +287,13 @@ static struct resource rtc_resources[] = { | |||
285 | */ | 287 | */ |
286 | static struct resource fsmc_resources[] = { | 288 | static struct resource fsmc_resources[] = { |
287 | { | 289 | { |
290 | .name = "nand_data", | ||
291 | .start = U300_NAND_CS0_PHYS_BASE, | ||
292 | .end = U300_NAND_CS0_PHYS_BASE + SZ_16K - 1, | ||
293 | .flags = IORESOURCE_MEM, | ||
294 | }, | ||
295 | { | ||
296 | .name = "fsmc_regs", | ||
288 | .start = U300_NAND_IF_PHYS_BASE, | 297 | .start = U300_NAND_IF_PHYS_BASE, |
289 | .end = U300_NAND_IF_PHYS_BASE + SZ_4K - 1, | 298 | .end = U300_NAND_IF_PHYS_BASE + SZ_4K - 1, |
290 | .flags = IORESOURCE_MEM, | 299 | .flags = IORESOURCE_MEM, |
@@ -1429,11 +1438,39 @@ static struct platform_device rtc_device = { | |||
1429 | .resource = rtc_resources, | 1438 | .resource = rtc_resources, |
1430 | }; | 1439 | }; |
1431 | 1440 | ||
1432 | static struct platform_device fsmc_device = { | 1441 | static struct mtd_partition u300_partitions[] = { |
1433 | .name = "nandif", | 1442 | { |
1443 | .name = "bootrecords", | ||
1444 | .offset = 0, | ||
1445 | .size = SZ_128K, | ||
1446 | }, | ||
1447 | { | ||
1448 | .name = "free", | ||
1449 | .offset = SZ_128K, | ||
1450 | .size = 8064 * SZ_1K, | ||
1451 | }, | ||
1452 | { | ||
1453 | .name = "platform", | ||
1454 | .offset = 8192 * SZ_1K, | ||
1455 | .size = 253952 * SZ_1K, | ||
1456 | }, | ||
1457 | }; | ||
1458 | |||
1459 | static struct fsmc_nand_platform_data nand_platform_data = { | ||
1460 | .partitions = u300_partitions, | ||
1461 | .nr_partitions = ARRAY_SIZE(u300_partitions), | ||
1462 | .options = NAND_SKIP_BBTSCAN, | ||
1463 | .width = FSMC_NAND_BW8, | ||
1464 | }; | ||
1465 | |||
1466 | static struct platform_device nand_device = { | ||
1467 | .name = "fsmc-nand", | ||
1434 | .id = -1, | 1468 | .id = -1, |
1435 | .num_resources = ARRAY_SIZE(fsmc_resources), | ||
1436 | .resource = fsmc_resources, | 1469 | .resource = fsmc_resources, |
1470 | .num_resources = ARRAY_SIZE(fsmc_resources), | ||
1471 | .dev = { | ||
1472 | .platform_data = &nand_platform_data, | ||
1473 | }, | ||
1437 | }; | 1474 | }; |
1438 | 1475 | ||
1439 | static struct platform_device ave_device = { | 1476 | static struct platform_device ave_device = { |
@@ -1465,7 +1502,7 @@ static struct platform_device *platform_devs[] __initdata = { | |||
1465 | &keypad_device, | 1502 | &keypad_device, |
1466 | &rtc_device, | 1503 | &rtc_device, |
1467 | &gpio_device, | 1504 | &gpio_device, |
1468 | &fsmc_device, | 1505 | &nand_device, |
1469 | &wdog_device, | 1506 | &wdog_device, |
1470 | &ave_device | 1507 | &ave_device |
1471 | }; | 1508 | }; |
diff --git a/arch/arm/mach-u300/include/mach/u300-regs.h b/arch/arm/mach-u300/include/mach/u300-regs.h index 56721a0cd2af..8b85df4c8d8f 100644 --- a/arch/arm/mach-u300/include/mach/u300-regs.h +++ b/arch/arm/mach-u300/include/mach/u300-regs.h | |||
@@ -20,11 +20,9 @@ | |||
20 | 20 | ||
21 | /* NAND Flash CS0 */ | 21 | /* NAND Flash CS0 */ |
22 | #define U300_NAND_CS0_PHYS_BASE 0x80000000 | 22 | #define U300_NAND_CS0_PHYS_BASE 0x80000000 |
23 | #define U300_NAND_CS0_VIRT_BASE 0xff040000 | ||
24 | 23 | ||
25 | /* NFIF */ | 24 | /* NFIF */ |
26 | #define U300_NAND_IF_PHYS_BASE 0x9f800000 | 25 | #define U300_NAND_IF_PHYS_BASE 0x9f800000 |
27 | #define U300_NAND_IF_VIRT_BASE 0xff030000 | ||
28 | 26 | ||
29 | /* AHB Peripherals */ | 27 | /* AHB Peripherals */ |
30 | #define U300_AHB_PER_PHYS_BASE 0xa0000000 | 28 | #define U300_AHB_PER_PHYS_BASE 0xa0000000 |
diff --git a/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h b/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h index 3478eae32d8a..01a8448e471c 100644 --- a/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +++ b/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h | |||
@@ -30,15 +30,15 @@ struct pxa3xx_nand_cmdset { | |||
30 | }; | 30 | }; |
31 | 31 | ||
32 | struct pxa3xx_nand_flash { | 32 | struct pxa3xx_nand_flash { |
33 | const struct pxa3xx_nand_timing *timing; /* NAND Flash timing */ | 33 | uint32_t chip_id; |
34 | const struct pxa3xx_nand_cmdset *cmdset; | 34 | unsigned int page_per_block; /* Pages per block (PG_PER_BLK) */ |
35 | 35 | unsigned int page_size; /* Page size in bytes (PAGE_SZ) */ | |
36 | uint32_t page_per_block;/* Pages per block (PG_PER_BLK) */ | 36 | unsigned int flash_width; /* Width of Flash memory (DWIDTH_M) */ |
37 | uint32_t page_size; /* Page size in bytes (PAGE_SZ) */ | 37 | unsigned int dfc_width; /* Width of flash controller(DWIDTH_C) */ |
38 | uint32_t flash_width; /* Width of Flash memory (DWIDTH_M) */ | 38 | unsigned int num_blocks; /* Number of physical blocks in Flash */ |
39 | uint32_t dfc_width; /* Width of flash controller(DWIDTH_C) */ | 39 | |
40 | uint32_t num_blocks; /* Number of physical blocks in Flash */ | 40 | struct pxa3xx_nand_cmdset *cmdset; /* NAND command set */ |
41 | uint32_t chip_id; | 41 | struct pxa3xx_nand_timing *timing; /* NAND Flash timing */ |
42 | }; | 42 | }; |
43 | 43 | ||
44 | struct pxa3xx_nand_platform_data { | 44 | struct pxa3xx_nand_platform_data { |
diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm963xx_tag.h b/arch/mips/include/asm/mach-bcm63xx/bcm963xx_tag.h new file mode 100644 index 000000000000..5325084d5c48 --- /dev/null +++ b/arch/mips/include/asm/mach-bcm63xx/bcm963xx_tag.h | |||
@@ -0,0 +1,97 @@ | |||
1 | #ifndef __BCM963XX_TAG_H | ||
2 | #define __BCM963XX_TAG_H | ||
3 | |||
4 | #define TAGVER_LEN 4 /* Length of Tag Version */ | ||
5 | #define TAGLAYOUT_LEN 4 /* Length of FlashLayoutVer */ | ||
6 | #define SIG1_LEN 20 /* Company Signature 1 Length */ | ||
7 | #define SIG2_LEN 14 /* Company Signature 2 Lenght */ | ||
8 | #define BOARDID_LEN 16 /* Length of BoardId */ | ||
9 | #define ENDIANFLAG_LEN 2 /* Endian Flag Length */ | ||
10 | #define CHIPID_LEN 6 /* Chip Id Length */ | ||
11 | #define IMAGE_LEN 10 /* Length of Length Field */ | ||
12 | #define ADDRESS_LEN 12 /* Length of Address field */ | ||
13 | #define DUALFLAG_LEN 2 /* Dual Image flag Length */ | ||
14 | #define INACTIVEFLAG_LEN 2 /* Inactie Flag Length */ | ||
15 | #define RSASIG_LEN 20 /* Length of RSA Signature in tag */ | ||
16 | #define TAGINFO1_LEN 30 /* Length of vendor information field1 in tag */ | ||
17 | #define FLASHLAYOUTVER_LEN 4 /* Length of Flash Layout Version String tag */ | ||
18 | #define TAGINFO2_LEN 16 /* Length of vendor information field2 in tag */ | ||
19 | #define CRC_LEN 4 /* Length of CRC in bytes */ | ||
20 | #define ALTTAGINFO_LEN 54 /* Alternate length for vendor information; Pirelli */ | ||
21 | |||
22 | #define NUM_PIRELLI 2 | ||
23 | #define IMAGETAG_CRC_START 0xFFFFFFFF | ||
24 | |||
25 | #define PIRELLI_BOARDS { \ | ||
26 | "AGPF-S0", \ | ||
27 | "DWV-S0", \ | ||
28 | } | ||
29 | |||
30 | /* | ||
31 | * The broadcom firmware assumes the rootfs starts the image, | ||
32 | * therefore uses the rootfs start (flash_image_address) | ||
33 | * to determine where to flash the image. Since we have the kernel first | ||
34 | * we have to give it the kernel address, but the crc uses the length | ||
35 | * associated with this address (root_length), which is added to the kernel | ||
36 | * length (kernel_length) to determine the length of image to flash and thus | ||
37 | * needs to be rootfs + deadcode (jffs2 EOF marker) | ||
38 | */ | ||
39 | |||
40 | struct bcm_tag { | ||
41 | /* 0-3: Version of the image tag */ | ||
42 | char tag_version[TAGVER_LEN]; | ||
43 | /* 4-23: Company Line 1 */ | ||
44 | char sig_1[SIG1_LEN]; | ||
45 | /* 24-37: Company Line 2 */ | ||
46 | char sig_2[SIG2_LEN]; | ||
47 | /* 38-43: Chip this image is for */ | ||
48 | char chip_id[CHIPID_LEN]; | ||
49 | /* 44-59: Board name */ | ||
50 | char board_id[BOARDID_LEN]; | ||
51 | /* 60-61: Map endianness -- 1 BE 0 LE */ | ||
52 | char big_endian[ENDIANFLAG_LEN]; | ||
53 | /* 62-71: Total length of image */ | ||
54 | char total_length[IMAGE_LEN]; | ||
55 | /* 72-83: Address in memory of CFE */ | ||
56 | char cfe__address[ADDRESS_LEN]; | ||
57 | /* 84-93: Size of CFE */ | ||
58 | char cfe_length[IMAGE_LEN]; | ||
59 | /* 94-105: Address in memory of image start | ||
60 | * (kernel for OpenWRT, rootfs for stock firmware) | ||
61 | */ | ||
62 | char flash_image_start[ADDRESS_LEN]; | ||
63 | /* 106-115: Size of rootfs */ | ||
64 | char root_length[IMAGE_LEN]; | ||
65 | /* 116-127: Address in memory of kernel */ | ||
66 | char kernel_address[ADDRESS_LEN]; | ||
67 | /* 128-137: Size of kernel */ | ||
68 | char kernel_length[IMAGE_LEN]; | ||
69 | /* 138-139: Unused at the moment */ | ||
70 | char dual_image[DUALFLAG_LEN]; | ||
71 | /* 140-141: Unused at the moment */ | ||
72 | char inactive_flag[INACTIVEFLAG_LEN]; | ||
73 | /* 142-161: RSA Signature (not used; some vendors may use this) */ | ||
74 | char rsa_signature[RSASIG_LEN]; | ||
75 | /* 162-191: Compilation and related information (not used in OpenWrt) */ | ||
76 | char information1[TAGINFO1_LEN]; | ||
77 | /* 192-195: Version flash layout */ | ||
78 | char flash_layout_ver[FLASHLAYOUTVER_LEN]; | ||
79 | /* 196-199: kernel+rootfs CRC32 */ | ||
80 | char fskernel_crc[CRC_LEN]; | ||
81 | /* 200-215: Unused except on Alice Gate where is is information */ | ||
82 | char information2[TAGINFO2_LEN]; | ||
83 | /* 216-219: CRC32 of image less imagetag (kernel for Alice Gate) */ | ||
84 | char image_crc[CRC_LEN]; | ||
85 | /* 220-223: CRC32 of rootfs partition */ | ||
86 | char rootfs_crc[CRC_LEN]; | ||
87 | /* 224-227: CRC32 of kernel partition */ | ||
88 | char kernel_crc[CRC_LEN]; | ||
89 | /* 228-235: Unused at present */ | ||
90 | char reserved1[8]; | ||
91 | /* 236-239: CRC32 of header excluding tagVersion */ | ||
92 | char header_crc[CRC_LEN]; | ||
93 | /* 240-255: Unused at present */ | ||
94 | char reserved2[16]; | ||
95 | }; | ||
96 | |||
97 | #endif /* __BCM63XX_TAG_H */ | ||
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 4b1e521d966f..29158913a66b 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
@@ -688,9 +688,12 @@ config 4xx_SOC | |||
688 | bool | 688 | bool |
689 | 689 | ||
690 | config FSL_LBC | 690 | config FSL_LBC |
691 | bool | 691 | bool "Freescale Local Bus support" |
692 | depends on FSL_SOC | ||
692 | help | 693 | help |
693 | Freescale Localbus support | 694 | Enables reporting of errors from the Freescale local bus |
695 | controller. Also contains some common code used by | ||
696 | drivers for specific local bus peripherals. | ||
694 | 697 | ||
695 | config FSL_GTM | 698 | config FSL_GTM |
696 | bool | 699 | bool |
diff --git a/arch/powerpc/include/asm/fsl_lbc.h b/arch/powerpc/include/asm/fsl_lbc.h index 1b5a21041f9b..5c1bf3466749 100644 --- a/arch/powerpc/include/asm/fsl_lbc.h +++ b/arch/powerpc/include/asm/fsl_lbc.h | |||
@@ -1,9 +1,10 @@ | |||
1 | /* Freescale Local Bus Controller | 1 | /* Freescale Local Bus Controller |
2 | * | 2 | * |
3 | * Copyright (c) 2006-2007 Freescale Semiconductor | 3 | * Copyright © 2006-2007, 2010 Freescale Semiconductor |
4 | * | 4 | * |
5 | * Authors: Nick Spence <nick.spence@freescale.com>, | 5 | * Authors: Nick Spence <nick.spence@freescale.com>, |
6 | * Scott Wood <scottwood@freescale.com> | 6 | * Scott Wood <scottwood@freescale.com> |
7 | * Jack Lan <jack.lan@freescale.com> | ||
7 | * | 8 | * |
8 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 10 | * it under the terms of the GNU General Public License as published by |
@@ -26,6 +27,8 @@ | |||
26 | #include <linux/compiler.h> | 27 | #include <linux/compiler.h> |
27 | #include <linux/types.h> | 28 | #include <linux/types.h> |
28 | #include <linux/io.h> | 29 | #include <linux/io.h> |
30 | #include <linux/device.h> | ||
31 | #include <linux/spinlock.h> | ||
29 | 32 | ||
30 | struct fsl_lbc_bank { | 33 | struct fsl_lbc_bank { |
31 | __be32 br; /**< Base Register */ | 34 | __be32 br; /**< Base Register */ |
@@ -125,13 +128,23 @@ struct fsl_lbc_regs { | |||
125 | #define LTESR_ATMW 0x00800000 | 128 | #define LTESR_ATMW 0x00800000 |
126 | #define LTESR_ATMR 0x00400000 | 129 | #define LTESR_ATMR 0x00400000 |
127 | #define LTESR_CS 0x00080000 | 130 | #define LTESR_CS 0x00080000 |
131 | #define LTESR_UPM 0x00000002 | ||
128 | #define LTESR_CC 0x00000001 | 132 | #define LTESR_CC 0x00000001 |
129 | #define LTESR_NAND_MASK (LTESR_FCT | LTESR_PAR | LTESR_CC) | 133 | #define LTESR_NAND_MASK (LTESR_FCT | LTESR_PAR | LTESR_CC) |
134 | #define LTESR_MASK (LTESR_BM | LTESR_FCT | LTESR_PAR | LTESR_WP \ | ||
135 | | LTESR_ATMW | LTESR_ATMR | LTESR_CS | LTESR_UPM \ | ||
136 | | LTESR_CC) | ||
137 | #define LTESR_CLEAR 0xFFFFFFFF | ||
138 | #define LTECCR_CLEAR 0xFFFFFFFF | ||
139 | #define LTESR_STATUS LTESR_MASK | ||
140 | #define LTEIR_ENABLE LTESR_MASK | ||
141 | #define LTEDR_ENABLE 0x00000000 | ||
130 | __be32 ltedr; /**< Transfer Error Disable Register */ | 142 | __be32 ltedr; /**< Transfer Error Disable Register */ |
131 | __be32 lteir; /**< Transfer Error Interrupt Register */ | 143 | __be32 lteir; /**< Transfer Error Interrupt Register */ |
132 | __be32 lteatr; /**< Transfer Error Attributes Register */ | 144 | __be32 lteatr; /**< Transfer Error Attributes Register */ |
133 | __be32 ltear; /**< Transfer Error Address Register */ | 145 | __be32 ltear; /**< Transfer Error Address Register */ |
134 | u8 res6[0xC]; | 146 | __be32 lteccr; /**< Transfer Error ECC Register */ |
147 | u8 res6[0x8]; | ||
135 | __be32 lbcr; /**< Configuration Register */ | 148 | __be32 lbcr; /**< Configuration Register */ |
136 | #define LBCR_LDIS 0x80000000 | 149 | #define LBCR_LDIS 0x80000000 |
137 | #define LBCR_LDIS_SHIFT 31 | 150 | #define LBCR_LDIS_SHIFT 31 |
@@ -235,6 +248,7 @@ struct fsl_upm { | |||
235 | int width; | 248 | int width; |
236 | }; | 249 | }; |
237 | 250 | ||
251 | extern u32 fsl_lbc_addr(phys_addr_t addr_base); | ||
238 | extern int fsl_lbc_find(phys_addr_t addr_base); | 252 | extern int fsl_lbc_find(phys_addr_t addr_base); |
239 | extern int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm); | 253 | extern int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm); |
240 | 254 | ||
@@ -265,7 +279,23 @@ static inline void fsl_upm_end_pattern(struct fsl_upm *upm) | |||
265 | cpu_relax(); | 279 | cpu_relax(); |
266 | } | 280 | } |
267 | 281 | ||
282 | /* overview of the fsl lbc controller */ | ||
283 | |||
284 | struct fsl_lbc_ctrl { | ||
285 | /* device info */ | ||
286 | struct device *dev; | ||
287 | struct fsl_lbc_regs __iomem *regs; | ||
288 | int irq; | ||
289 | wait_queue_head_t irq_wait; | ||
290 | spinlock_t lock; | ||
291 | void *nand; | ||
292 | |||
293 | /* status read from LTESR by irq handler */ | ||
294 | unsigned int irq_status; | ||
295 | }; | ||
296 | |||
268 | extern int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, | 297 | extern int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, |
269 | u32 mar); | 298 | u32 mar); |
299 | extern struct fsl_lbc_ctrl *fsl_lbc_ctrl_dev; | ||
270 | 300 | ||
271 | #endif /* __ASM_FSL_LBC_H */ | 301 | #endif /* __ASM_FSL_LBC_H */ |
diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/fsl_lbc.c index dceb8d1a843d..4fcb5a4e60dd 100644 --- a/arch/powerpc/sysdev/fsl_lbc.c +++ b/arch/powerpc/sysdev/fsl_lbc.c | |||
@@ -1,9 +1,12 @@ | |||
1 | /* | 1 | /* |
2 | * Freescale LBC and UPM routines. | 2 | * Freescale LBC and UPM routines. |
3 | * | 3 | * |
4 | * Copyright (c) 2007-2008 MontaVista Software, Inc. | 4 | * Copyright © 2007-2008 MontaVista Software, Inc. |
5 | * Copyright © 2010 Freescale Semiconductor | ||
5 | * | 6 | * |
6 | * Author: Anton Vorontsov <avorontsov@ru.mvista.com> | 7 | * Author: Anton Vorontsov <avorontsov@ru.mvista.com> |
8 | * Author: Jack Lan <Jack.Lan@freescale.com> | ||
9 | * Author: Roy Zang <tie-fei.zang@freescale.com> | ||
7 | * | 10 | * |
8 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
@@ -19,39 +22,37 @@ | |||
19 | #include <linux/types.h> | 22 | #include <linux/types.h> |
20 | #include <linux/io.h> | 23 | #include <linux/io.h> |
21 | #include <linux/of.h> | 24 | #include <linux/of.h> |
25 | #include <linux/slab.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | #include <linux/mod_devicetable.h> | ||
22 | #include <asm/prom.h> | 29 | #include <asm/prom.h> |
23 | #include <asm/fsl_lbc.h> | 30 | #include <asm/fsl_lbc.h> |
24 | 31 | ||
25 | static spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock); | 32 | static spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock); |
26 | static struct fsl_lbc_regs __iomem *fsl_lbc_regs; | 33 | struct fsl_lbc_ctrl *fsl_lbc_ctrl_dev; |
34 | EXPORT_SYMBOL(fsl_lbc_ctrl_dev); | ||
27 | 35 | ||
28 | static char __initdata *compat_lbc[] = { | 36 | /** |
29 | "fsl,pq2-localbus", | 37 | * fsl_lbc_addr - convert the base address |
30 | "fsl,pq2pro-localbus", | 38 | * @addr_base: base address of the memory bank |
31 | "fsl,pq3-localbus", | 39 | * |
32 | "fsl,elbc", | 40 | * This function converts a base address of lbc into the right format for the |
33 | }; | 41 | * BR register. If the SOC has eLBC then it returns 32bit physical address |
34 | 42 | * else it convers a 34bit local bus physical address to correct format of | |
35 | static int __init fsl_lbc_init(void) | 43 | * 32bit address for BR register (Example: MPC8641). |
44 | */ | ||
45 | u32 fsl_lbc_addr(phys_addr_t addr_base) | ||
36 | { | 46 | { |
37 | struct device_node *lbus; | 47 | struct device_node *np = fsl_lbc_ctrl_dev->dev->of_node; |
38 | int i; | 48 | u32 addr = addr_base & 0xffff8000; |
39 | 49 | ||
40 | for (i = 0; i < ARRAY_SIZE(compat_lbc); i++) { | 50 | if (of_device_is_compatible(np, "fsl,elbc")) |
41 | lbus = of_find_compatible_node(NULL, NULL, compat_lbc[i]); | 51 | return addr; |
42 | if (lbus) | ||
43 | goto found; | ||
44 | } | ||
45 | return -ENODEV; | ||
46 | 52 | ||
47 | found: | 53 | return addr | ((addr_base & 0x300000000ull) >> 19); |
48 | fsl_lbc_regs = of_iomap(lbus, 0); | ||
49 | of_node_put(lbus); | ||
50 | if (!fsl_lbc_regs) | ||
51 | return -ENOMEM; | ||
52 | return 0; | ||
53 | } | 54 | } |
54 | arch_initcall(fsl_lbc_init); | 55 | EXPORT_SYMBOL(fsl_lbc_addr); |
55 | 56 | ||
56 | /** | 57 | /** |
57 | * fsl_lbc_find - find Localbus bank | 58 | * fsl_lbc_find - find Localbus bank |
@@ -65,15 +66,17 @@ arch_initcall(fsl_lbc_init); | |||
65 | int fsl_lbc_find(phys_addr_t addr_base) | 66 | int fsl_lbc_find(phys_addr_t addr_base) |
66 | { | 67 | { |
67 | int i; | 68 | int i; |
69 | struct fsl_lbc_regs __iomem *lbc; | ||
68 | 70 | ||
69 | if (!fsl_lbc_regs) | 71 | if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) |
70 | return -ENODEV; | 72 | return -ENODEV; |
71 | 73 | ||
72 | for (i = 0; i < ARRAY_SIZE(fsl_lbc_regs->bank); i++) { | 74 | lbc = fsl_lbc_ctrl_dev->regs; |
73 | __be32 br = in_be32(&fsl_lbc_regs->bank[i].br); | 75 | for (i = 0; i < ARRAY_SIZE(lbc->bank); i++) { |
74 | __be32 or = in_be32(&fsl_lbc_regs->bank[i].or); | 76 | __be32 br = in_be32(&lbc->bank[i].br); |
77 | __be32 or = in_be32(&lbc->bank[i].or); | ||
75 | 78 | ||
76 | if (br & BR_V && (br & or & BR_BA) == addr_base) | 79 | if (br & BR_V && (br & or & BR_BA) == fsl_lbc_addr(addr_base)) |
77 | return i; | 80 | return i; |
78 | } | 81 | } |
79 | 82 | ||
@@ -94,22 +97,27 @@ int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm) | |||
94 | { | 97 | { |
95 | int bank; | 98 | int bank; |
96 | __be32 br; | 99 | __be32 br; |
100 | struct fsl_lbc_regs __iomem *lbc; | ||
97 | 101 | ||
98 | bank = fsl_lbc_find(addr_base); | 102 | bank = fsl_lbc_find(addr_base); |
99 | if (bank < 0) | 103 | if (bank < 0) |
100 | return bank; | 104 | return bank; |
101 | 105 | ||
102 | br = in_be32(&fsl_lbc_regs->bank[bank].br); | 106 | if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) |
107 | return -ENODEV; | ||
108 | |||
109 | lbc = fsl_lbc_ctrl_dev->regs; | ||
110 | br = in_be32(&lbc->bank[bank].br); | ||
103 | 111 | ||
104 | switch (br & BR_MSEL) { | 112 | switch (br & BR_MSEL) { |
105 | case BR_MS_UPMA: | 113 | case BR_MS_UPMA: |
106 | upm->mxmr = &fsl_lbc_regs->mamr; | 114 | upm->mxmr = &lbc->mamr; |
107 | break; | 115 | break; |
108 | case BR_MS_UPMB: | 116 | case BR_MS_UPMB: |
109 | upm->mxmr = &fsl_lbc_regs->mbmr; | 117 | upm->mxmr = &lbc->mbmr; |
110 | break; | 118 | break; |
111 | case BR_MS_UPMC: | 119 | case BR_MS_UPMC: |
112 | upm->mxmr = &fsl_lbc_regs->mcmr; | 120 | upm->mxmr = &lbc->mcmr; |
113 | break; | 121 | break; |
114 | default: | 122 | default: |
115 | return -EINVAL; | 123 | return -EINVAL; |
@@ -148,9 +156,12 @@ int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar) | |||
148 | int ret = 0; | 156 | int ret = 0; |
149 | unsigned long flags; | 157 | unsigned long flags; |
150 | 158 | ||
159 | if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) | ||
160 | return -ENODEV; | ||
161 | |||
151 | spin_lock_irqsave(&fsl_lbc_lock, flags); | 162 | spin_lock_irqsave(&fsl_lbc_lock, flags); |
152 | 163 | ||
153 | out_be32(&fsl_lbc_regs->mar, mar); | 164 | out_be32(&fsl_lbc_ctrl_dev->regs->mar, mar); |
154 | 165 | ||
155 | switch (upm->width) { | 166 | switch (upm->width) { |
156 | case 8: | 167 | case 8: |
@@ -172,3 +183,166 @@ int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar) | |||
172 | return ret; | 183 | return ret; |
173 | } | 184 | } |
174 | EXPORT_SYMBOL(fsl_upm_run_pattern); | 185 | EXPORT_SYMBOL(fsl_upm_run_pattern); |
186 | |||
187 | static int __devinit fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl) | ||
188 | { | ||
189 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; | ||
190 | |||
191 | /* clear event registers */ | ||
192 | setbits32(&lbc->ltesr, LTESR_CLEAR); | ||
193 | out_be32(&lbc->lteatr, 0); | ||
194 | out_be32(&lbc->ltear, 0); | ||
195 | out_be32(&lbc->lteccr, LTECCR_CLEAR); | ||
196 | out_be32(&lbc->ltedr, LTEDR_ENABLE); | ||
197 | |||
198 | /* Enable interrupts for any detected events */ | ||
199 | out_be32(&lbc->lteir, LTEIR_ENABLE); | ||
200 | |||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | /* | ||
205 | * NOTE: This interrupt is used to report localbus events of various kinds, | ||
206 | * such as transaction errors on the chipselects. | ||
207 | */ | ||
208 | |||
209 | static irqreturn_t fsl_lbc_ctrl_irq(int irqno, void *data) | ||
210 | { | ||
211 | struct fsl_lbc_ctrl *ctrl = data; | ||
212 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; | ||
213 | u32 status; | ||
214 | |||
215 | status = in_be32(&lbc->ltesr); | ||
216 | if (!status) | ||
217 | return IRQ_NONE; | ||
218 | |||
219 | out_be32(&lbc->ltesr, LTESR_CLEAR); | ||
220 | out_be32(&lbc->lteatr, 0); | ||
221 | out_be32(&lbc->ltear, 0); | ||
222 | ctrl->irq_status = status; | ||
223 | |||
224 | if (status & LTESR_BM) | ||
225 | dev_err(ctrl->dev, "Local bus monitor time-out: " | ||
226 | "LTESR 0x%08X\n", status); | ||
227 | if (status & LTESR_WP) | ||
228 | dev_err(ctrl->dev, "Write protect error: " | ||
229 | "LTESR 0x%08X\n", status); | ||
230 | if (status & LTESR_ATMW) | ||
231 | dev_err(ctrl->dev, "Atomic write error: " | ||
232 | "LTESR 0x%08X\n", status); | ||
233 | if (status & LTESR_ATMR) | ||
234 | dev_err(ctrl->dev, "Atomic read error: " | ||
235 | "LTESR 0x%08X\n", status); | ||
236 | if (status & LTESR_CS) | ||
237 | dev_err(ctrl->dev, "Chip select error: " | ||
238 | "LTESR 0x%08X\n", status); | ||
239 | if (status & LTESR_UPM) | ||
240 | ; | ||
241 | if (status & LTESR_FCT) { | ||
242 | dev_err(ctrl->dev, "FCM command time-out: " | ||
243 | "LTESR 0x%08X\n", status); | ||
244 | smp_wmb(); | ||
245 | wake_up(&ctrl->irq_wait); | ||
246 | } | ||
247 | if (status & LTESR_PAR) { | ||
248 | dev_err(ctrl->dev, "Parity or Uncorrectable ECC error: " | ||
249 | "LTESR 0x%08X\n", status); | ||
250 | smp_wmb(); | ||
251 | wake_up(&ctrl->irq_wait); | ||
252 | } | ||
253 | if (status & LTESR_CC) { | ||
254 | smp_wmb(); | ||
255 | wake_up(&ctrl->irq_wait); | ||
256 | } | ||
257 | if (status & ~LTESR_MASK) | ||
258 | dev_err(ctrl->dev, "Unknown error: " | ||
259 | "LTESR 0x%08X\n", status); | ||
260 | return IRQ_HANDLED; | ||
261 | } | ||
262 | |||
263 | /* | ||
264 | * fsl_lbc_ctrl_probe | ||
265 | * | ||
266 | * called by device layer when it finds a device matching | ||
267 | * one our driver can handled. This code allocates all of | ||
268 | * the resources needed for the controller only. The | ||
269 | * resources for the NAND banks themselves are allocated | ||
270 | * in the chip probe function. | ||
271 | */ | ||
272 | |||
273 | static int __devinit fsl_lbc_ctrl_probe(struct platform_device *dev) | ||
274 | { | ||
275 | int ret; | ||
276 | |||
277 | if (!dev->dev.of_node) { | ||
278 | dev_err(&dev->dev, "Device OF-Node is NULL"); | ||
279 | return -EFAULT; | ||
280 | } | ||
281 | |||
282 | fsl_lbc_ctrl_dev = kzalloc(sizeof(*fsl_lbc_ctrl_dev), GFP_KERNEL); | ||
283 | if (!fsl_lbc_ctrl_dev) | ||
284 | return -ENOMEM; | ||
285 | |||
286 | dev_set_drvdata(&dev->dev, fsl_lbc_ctrl_dev); | ||
287 | |||
288 | spin_lock_init(&fsl_lbc_ctrl_dev->lock); | ||
289 | init_waitqueue_head(&fsl_lbc_ctrl_dev->irq_wait); | ||
290 | |||
291 | fsl_lbc_ctrl_dev->regs = of_iomap(dev->dev.of_node, 0); | ||
292 | if (!fsl_lbc_ctrl_dev->regs) { | ||
293 | dev_err(&dev->dev, "failed to get memory region\n"); | ||
294 | ret = -ENODEV; | ||
295 | goto err; | ||
296 | } | ||
297 | |||
298 | fsl_lbc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0); | ||
299 | if (fsl_lbc_ctrl_dev->irq == NO_IRQ) { | ||
300 | dev_err(&dev->dev, "failed to get irq resource\n"); | ||
301 | ret = -ENODEV; | ||
302 | goto err; | ||
303 | } | ||
304 | |||
305 | fsl_lbc_ctrl_dev->dev = &dev->dev; | ||
306 | |||
307 | ret = fsl_lbc_ctrl_init(fsl_lbc_ctrl_dev); | ||
308 | if (ret < 0) | ||
309 | goto err; | ||
310 | |||
311 | ret = request_irq(fsl_lbc_ctrl_dev->irq, fsl_lbc_ctrl_irq, 0, | ||
312 | "fsl-lbc", fsl_lbc_ctrl_dev); | ||
313 | if (ret != 0) { | ||
314 | dev_err(&dev->dev, "failed to install irq (%d)\n", | ||
315 | fsl_lbc_ctrl_dev->irq); | ||
316 | ret = fsl_lbc_ctrl_dev->irq; | ||
317 | goto err; | ||
318 | } | ||
319 | |||
320 | return 0; | ||
321 | |||
322 | err: | ||
323 | iounmap(fsl_lbc_ctrl_dev->regs); | ||
324 | kfree(fsl_lbc_ctrl_dev); | ||
325 | return ret; | ||
326 | } | ||
327 | |||
328 | static const struct of_device_id fsl_lbc_match[] = { | ||
329 | { .compatible = "fsl,elbc", }, | ||
330 | { .compatible = "fsl,pq3-localbus", }, | ||
331 | { .compatible = "fsl,pq2-localbus", }, | ||
332 | { .compatible = "fsl,pq2pro-localbus", }, | ||
333 | {}, | ||
334 | }; | ||
335 | |||
336 | static struct platform_driver fsl_lbc_ctrl_driver = { | ||
337 | .driver = { | ||
338 | .name = "fsl-lbc", | ||
339 | .of_match_table = fsl_lbc_match, | ||
340 | }, | ||
341 | .probe = fsl_lbc_ctrl_probe, | ||
342 | }; | ||
343 | |||
344 | static int __init fsl_lbc_init(void) | ||
345 | { | ||
346 | return platform_driver_register(&fsl_lbc_ctrl_driver); | ||
347 | } | ||
348 | module_init(fsl_lbc_init); | ||