source: trunk/target/linux/mpc83xx/patches-2.6.32/001-rb600.patch @ 19587

Last change on this file since 19587 was 19587, checked in by juhosg, 7 years ago

mpc83xx: add 2.6.32 support

File size: 51.0 KB
  • new file arch/powerpc/boot/dts/rb600.dts

    - +  
     1/* 
     2 * RouterBOARD 600 series Device Tree Source 
     3 * 
     4 * Copyright 2009 Michael Guntsche <mike@it-loops.com> 
     5 * 
     6 * This program is free software; you can redistribute  it and/or modify it 
     7 * under  the terms of  the GNU General  Public License as published by the 
     8 * Free Software Foundation;  either version 2 of the  License, or (at your 
     9 * option) any later version. 
     10 */ 
     11 
     12/dts-v1/; 
     13 
     14/ { 
     15        model = "RB600"; 
     16        compatible = "MPC83xx"; 
     17        #address-cells = <1>; 
     18        #size-cells = <1>; 
     19 
     20        aliases { 
     21                ethernet0 = &enet0; 
     22                ethernet1 = &enet1; 
     23        }; 
     24 
     25        chosen { 
     26                linux,stdout-path = "/soc8343@e0000000/serial@4500"; 
     27        }; 
     28 
     29        cpus { 
     30                #address-cells = <1>; 
     31                #size-cells = <0>; 
     32 
     33                PowerPC,8343E@0 { 
     34                        device_type = "cpu"; 
     35                        reg = <0x0>; 
     36                        d-cache-line-size = <0x20>; 
     37                        i-cache-line-size = <0x20>; 
     38                        d-cache-size = <0x8000>; 
     39                        i-cache-size = <0x8000>; 
     40                        timebase-frequency = <0x0000000>; // filled by the bootwrapper from the firmware blob 
     41                        clock-frequency = <0x00000000>; // filled by the bootwrapper from the firmware blob 
     42                }; 
     43        }; 
     44 
     45        memory { 
     46                device_type = "memory"; 
     47                reg = <0x0 0x0000000>; // filled by the bootwrapper from the firmware blob 
     48        }; 
     49 
     50        cf@f9200000 { 
     51                lb-timings = <0x5dc 0x3e8 0x1194 0x5dc 0x2af8>; 
     52                interrupt-at-level = <0x0>; 
     53                interrupt-parent = <&ipic>; 
     54                interrupts = <0x16 0x8>; 
     55                lbc_extra_divider = <0x1>; 
     56                reg = <0xf9200000 0x200000>; 
     57                device_type = "rb,cf"; 
     58        }; 
     59 
     60        cf@f9000000 { 
     61                lb-timings = <0x5dc 0x3e8 0x1194 0x5dc 0x2af8>; 
     62                interrupt-at-level = <0x0>; 
     63                interrupt-parent = <&ipic>; 
     64                interrupts = <0x14 0x8>; 
     65                lbc_extra_divider = <0x1>; 
     66                reg = <0xf9000000 0x200000>; 
     67                device_type = "rb,cf"; 
     68        }; 
     69 
     70        flash { 
     71                reg = <0xff800000 0x20000>; 
     72        }; 
     73 
     74        nnand { 
     75                reg = <0xf0000000 0x1000>; 
     76        }; 
     77 
     78        nand { 
     79                ale = <&gpio 0x6>; 
     80                cle = <&gpio 0x5>; 
     81                nce = <&gpio 0x4>; 
     82                rdy = <&gpio 0x3>; 
     83                reg = <0xf8000000 0x1000>; 
     84                device_type = "rb,nand"; 
     85        }; 
     86 
     87        fancon { 
     88                interrupt-parent = <&ipic>; 
     89                interrupts = <0x17 0x8>; 
     90                sense = <&gpio 0x7>; 
     91                fan_on = <&gpio 0x9>; 
     92        }; 
     93 
     94        pci0: pci@e0008500 { 
     95                device_type = "pci"; 
     96                compatible = "fsl,mpc8349-pci"; 
     97                reg = <0xe0008500 0x100 0xe0008300 0x8>; 
     98                #address-cells = <3>; 
     99                #size-cells = <2>; 
     100                #interrupt-cells = <1>; 
     101                ranges = <0x2000000 0x0 0x80000000 0x80000000 0x0 0x20000000 0x1000000 0x0 0x0 0xd0000000 0x0 0x4000000>; 
     102                bus-range = <0x0 0x0>; 
     103                interrupt-map = < 
     104                        0x5800 0x0 0x0 0x1 &ipic 0x15 0x8 
     105                        0x6000 0x0 0x0 0x1 &ipic 0x30 0x8 
     106                        0x6000 0x0 0x0 0x2 &ipic 0x11 0x8 
     107                        0x6800 0x0 0x0 0x1 &ipic 0x11 0x8 
     108                        0x6800 0x0 0x0 0x2 &ipic 0x12 0x8 
     109                        0x7000 0x0 0x0 0x1 &ipic 0x12 0x8 
     110                        0x7000 0x0 0x0 0x2 &ipic 0x13 0x8 
     111                        0x7800 0x0 0x0 0x1 &ipic 0x13 0x8 
     112                        0x7800 0x0 0x0 0x2 &ipic 0x30 0x8 
     113                        0x8000 0x0 0x0 0x1 &ipic 0x30 0x8 
     114                        0x8000 0x0 0x0 0x2 &ipic 0x12 0x8 
     115                        0x8000 0x0 0x0 0x3 &ipic 0x11 0x8 
     116                        0x8000 0x0 0x0 0x4 &ipic 0x13 0x8 
     117                        0xa000 0x0 0x0 0x1 &ipic 0x30 0x8 
     118                        0xa000 0x0 0x0 0x2 &ipic 0x11 0x8 
     119                        0xa000 0x0 0x0 0x3 &ipic 0x12 0x8 
     120                        0xa000 0x0 0x0 0x4 &ipic 0x13 0x8 
     121                        0xa800 0x0 0x0 0x1 &ipic 0x11 0x8 
     122                        0xa800 0x0 0x0 0x2 &ipic 0x12 0x8 
     123                        0xa800 0x0 0x0 0x3 &ipic 0x13 0x8 
     124                        0xa800 0x0 0x0 0x4 &ipic 0x30 0x8>; 
     125                interrupt-map-mask = <0xf800 0x0 0x0 0x7>; 
     126                interrupt-parent = <&ipic>; 
     127        }; 
     128 
     129        soc8343@e0000000 { 
     130                #address-cells = <1>; 
     131                #size-cells = <1>; 
     132                device_type = "soc"; 
     133                compatible = "simple-bus"; 
     134                ranges = <0x0 0xe0000000 0x100000>; 
     135                reg = <0xe0000000 0x200>; 
     136                bus-frequency = <0x1>; 
     137 
     138                led { 
     139                        user_led = <0x400 0x8>; 
     140                }; 
     141 
     142                beeper { 
     143                        reg = <0x500 0x100>; 
     144                }; 
     145 
     146                gpio: gpio@0 { 
     147                        reg = <0xc08 0x4>; 
     148                        device-id = <0x0>; 
     149                        compatible = "gpio"; 
     150                        device_type = "gpio"; 
     151                }; 
     152 
     153                enet0: ethernet@25000 { 
     154                        #address-cells = <1>; 
     155                        #size-cells = <1>; 
     156                        cell-index = <0>; 
     157                        phy-handle = <&phy0>; 
     158                        tbi-handle = <&tbi0>; 
     159                        interrupt-parent = <&ipic>; 
     160                        interrupts = <0x23 0x8 0x24 0x8 0x25 0x8>; 
     161                        local-mac-address = [00 00 00 00 00 00]; 
     162                        reg = <0x25000 0x1000>; 
     163                        ranges = <0x0 0x25000 0x1000>; 
     164                        compatible = "gianfar"; 
     165                        model = "TSEC"; 
     166                        device_type = "network"; 
     167 
     168                        mdio@520 { 
     169                                #address-cells = <1>; 
     170                                #size-cells = <0>; 
     171                                compatible = "fsl,gianfar-tbi"; 
     172                                reg = <0x520 0x20>; 
     173 
     174                                tbi0: tbi-phy@11 { 
     175                                        reg = <0x11>; 
     176                                        device_type = "tbi-phy"; 
     177                                }; 
     178                        }; 
     179                }; 
     180 
     181                enet1: ethernet@24000 { 
     182                        #address-cells = <1>; 
     183                        #size-cells = <1>; 
     184                        cell-index = <1>; 
     185                        phy-handle = <&phy1>; 
     186                        tbi-handle = <&tbi1>; 
     187                        interrupt-parent = <&ipic>; 
     188                        interrupts = <0x20 0x8 0x21 0x8 0x22 0x8>; 
     189                        local-mac-address = [00 00 00 00 00 00]; 
     190                        reg = <0x24000 0x1000>; 
     191                        ranges = <0x0 0x24000 0x1000>; 
     192                        compatible = "gianfar"; 
     193                        model = "TSEC"; 
     194                        device_type = "network"; 
     195 
     196                        mdio@520 { 
     197                                #size-cells = <0x0>; 
     198                                #address-cells = <0x1>; 
     199                                reg = <0x520 0x20>; 
     200                                compatible = "fsl,gianfar-mdio"; 
     201 
     202                                phy0: ethernet-phy@0 { 
     203                                        device_type = "ethernet-phy"; 
     204                                        reg = <0x0>; 
     205                                }; 
     206 
     207                                phy1: ethernet-phy@1 { 
     208                                        device_type = "ethernet-phy"; 
     209                                        reg = <0x1>; 
     210                                }; 
     211 
     212                                tbi1: tbi-phy@11 { 
     213                                        reg = <0x11>; 
     214                                        device_type = "tbi-phy"; 
     215                                }; 
     216                        }; 
     217                }; 
     218 
     219                ipic: pic@700 { 
     220                        interrupt-controller; 
     221                        #address-cells = <0>; 
     222                        #interrupt-cells = <2>; 
     223                        reg = <0x700 0x100>; 
     224                        device_type = "ipic"; 
     225                }; 
     226 
     227                serial@4500 { 
     228                        interrupt-parent = <&ipic>; 
     229                        interrupts = <0x9 0x8>; 
     230                        clock-frequency = <0xfe4f840>; 
     231                        reg = <0x4500 0x100>; 
     232                        compatible = "ns16550"; 
     233                        device_type = "serial"; 
     234                }; 
     235 
     236                wdt@200 { 
     237                        reg = <0x200 0x100>; 
     238                        compatible = "mpc83xx_wdt"; 
     239                        device_type = "watchdog"; 
     240                }; 
     241        }; 
     242}; 
  • arch/powerpc/boot/Makefile

    a b src-plat := of.c cuboot-52xx.c cuboot-82 
    7373                cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c \ 
    7474                cuboot-bamboo.c cuboot-mpc7448hpc2.c cuboot-taishan.c \ 
    7575                fixed-head.S ep88xc.c ep405.c cuboot-c2k.c \ 
    76                 cuboot-katmai.c cuboot-rainier.c redboot-8xx.c ep8248e.c \ 
     76                cuboot-katmai.c cuboot-rainier.c redboot-8xx.c ep8248e.c rb600.c \ 
    7777                cuboot-warp.c cuboot-85xx-cpm2.c cuboot-yosemite.c simpleboot.c \ 
    7878                virtex405-head.S virtex.c redboot-83xx.c cuboot-sam440ep.c \ 
    7979                cuboot-acadia.c cuboot-amigaone.c cuboot-kilauea.c 
    image-$(CONFIG_MPC834x_ITX) += cuImage. 
    231231image-$(CONFIG_MPC834x_MDS)             += cuImage.mpc834x_mds 
    232232image-$(CONFIG_MPC836x_MDS)             += cuImage.mpc836x_mds 
    233233image-$(CONFIG_ASP834x)                 += dtbImage.asp834x-redboot 
     234image-$(CONFIG_RB_PPC)                  += dtbImage.rb600 
    234235 
    235236# Board ports in arch/powerpc/platform/85xx/Kconfig 
    236237image-$(CONFIG_MPC8540_ADS)             += cuImage.mpc8540ads 
  • new file arch/powerpc/boot/rb600.c

    - +  
     1/* 
     2 * The RouterBOARD platform -- for booting RB600(A) RouterBOARDs. 
     3 * 
     4 * Author: Michael Guntsche <mike@it-loops.com> 
     5 * 
     6 * Copyright (c) 2009 Michael Guntsche 
     7 * 
     8 * This program is free software; you can redistribute it and/or modify it 
     9 * under the terms of the GNU General Public License version 2 as published 
     10 * by the Free Software Foundation. 
     11 */ 
     12 
     13#include "ops.h" 
     14#include "types.h" 
     15#include "io.h" 
     16#include "stdio.h" 
     17#include <libfdt.h> 
     18 
     19BSS_STACK(4*1024); 
     20 
     21u64 memsize64; 
     22const void *fw_dtb; 
     23 
     24static void rb600_fixups(void) 
     25{ 
     26        const u32 *reg, *timebase, *clock; 
     27        int node, size; 
     28        void *chosen; 
     29        const char* bootargs; 
     30 
     31        dt_fixup_memory(0, memsize64); 
     32 
     33        /* Set the MAC addresses. */ 
     34        node = fdt_path_offset(fw_dtb, "/soc8343@e0000000/ethernet@24000"); 
     35        reg = fdt_getprop(fw_dtb, node, "mac-address", &size); 
     36        dt_fixup_mac_address_by_alias("ethernet1", (const u8 *)reg); 
     37 
     38        node = fdt_path_offset(fw_dtb, "/soc8343@e0000000/ethernet@25000"); 
     39        reg = fdt_getprop(fw_dtb, node, "mac-address", &size); 
     40        dt_fixup_mac_address_by_alias("ethernet0", (const u8 *)reg); 
     41 
     42        /* Find the CPU timebase and clock frequencies. */ 
     43        node = fdt_node_offset_by_prop_value(fw_dtb, -1, "device_type", "cpu", sizeof("cpu")); 
     44        timebase = fdt_getprop(fw_dtb, node, "timebase-frequency", &size); 
     45        clock = fdt_getprop(fw_dtb, node, "clock-frequency", &size); 
     46        dt_fixup_cpu_clocks(*clock, *timebase, 0); 
     47 
     48        /* Fixup chosen 
     49         * The bootloader reads the kernelparm segment and adds the content to 
     50         * bootargs. This is needed to specify root and other boot flags. 
     51         */ 
     52        chosen = finddevice("/chosen"); 
     53        node = fdt_path_offset(fw_dtb, "/chosen"); 
     54        bootargs = fdt_getprop(fw_dtb, node, "bootargs", &size); 
     55        setprop_str(chosen, "bootargs", bootargs); 
     56} 
     57 
     58void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, 
     59                   unsigned long r6, unsigned long r7) 
     60{ 
     61        const u32 *reg; 
     62        int node, size; 
     63 
     64        fw_dtb = (const void *)r3; 
     65 
     66        /* Find the memory range. */ 
     67        node = fdt_node_offset_by_prop_value(fw_dtb, -1, "device_type", "memory", sizeof("memory")); 
     68        reg = fdt_getprop(fw_dtb, node, "reg", &size); 
     69        memsize64 = reg[1]; 
     70 
     71        /* Now we have the memory size; initialize the heap. */ 
     72        simple_alloc_init(_end, memsize64 - (unsigned long)_end, 32, 64); 
     73 
     74        /* Prepare the device tree and find the console. */ 
     75        fdt_init(_dtb_start); 
     76        serial_console_init(); 
     77 
     78        /* Remaining fixups... */ 
     79        platform_ops.fixups = rb600_fixups; 
     80} 
  • arch/powerpc/boot/wrapper

    a b ps3) 
    202202    isection=.kernel:initrd 
    203203    link_address='' 
    204204    ;; 
    205 ep88xc|ep405|ep8248e) 
     205ep88xc|ep405|ep8248e|rb600) 
    206206    platformo="$object/fixed-head.o $object/$platform.o" 
    207207    binary=y 
    208208    ;; 
  • arch/powerpc/kernel/Makefile

    a b obj32-$(CONFIG_PPC_PERF_CTRS) += mpc7450 
    104104 
    105105obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o 
    106106 
     107ifneq ($(CONFIG_RB_IOMAP),y) 
    107108ifneq ($(CONFIG_PPC_INDIRECT_IO),y) 
    108109obj-y                           += iomap.o 
    109110endif 
     111endif 
    110112 
    111113obj-$(CONFIG_PPC64)             += $(obj64-y) 
    112114obj-$(CONFIG_PPC32)             += $(obj32-y) 
  • arch/powerpc/platforms/83xx/Kconfig

    a b config MPC832x_RDB 
    3030        help 
    3131          This option enables support for the MPC8323 RDB board. 
    3232 
     33config RB_PPC 
     34        bool "MikroTik RouterBOARD 600 series" 
     35        select DEFAULT_UIMAGE 
     36        select QUICC_ENGINE 
     37        select PPC_MPC834x 
     38        select RB_IOMAP 
     39        help 
     40          This option enables support for MikroTik RouterBOARD 600 series boards. 
     41 
    3342config MPC834x_MDS 
    3443        bool "Freescale MPC834x MDS" 
    3544        select DEFAULT_UIMAGE 
  • arch/powerpc/platforms/83xx/Makefile

    a b obj-$(CONFIG_SUSPEND) += suspend.o susp 
    66obj-$(CONFIG_MCU_MPC8349EMITX)  += mcu_mpc8349emitx.o 
    77obj-$(CONFIG_MPC831x_RDB)       += mpc831x_rdb.o 
    88obj-$(CONFIG_MPC832x_RDB)       += mpc832x_rdb.o 
     9obj-$(CONFIG_RB_PPC)            += rbppc.o 
    910obj-$(CONFIG_MPC834x_MDS)       += mpc834x_mds.o 
    1011obj-$(CONFIG_MPC834x_ITX)       += mpc834x_itx.o 
    1112obj-$(CONFIG_MPC836x_MDS)       += mpc836x_mds.o 
  • new file arch/powerpc/platforms/83xx/rbppc.c

    - +  
     1/* 
     2 * Copyright (C) 2008-2009 Noah Fontes <nfontes@transtruct.org> 
     3 * Copyright (C) 2009 Michael Guntsche <mike@it-loops.com> 
     4 * Copyright (C) Mikrotik 2007 
     5 * 
     6 * This program is free software; you can redistribute it and/or modify it 
     7 * under the terms of the GNU General Public License as published by the 
     8 * Free Software Foundation; either version 2 of the License, or (at your 
     9 * option) any later version. 
     10 */ 
     11 
     12#include <linux/delay.h> 
     13#include <linux/root_dev.h> 
     14#include <linux/initrd.h> 
     15#include <linux/interrupt.h> 
     16#include <linux/of_platform.h> 
     17#include <linux/of_device.h> 
     18#include <linux/of_platform.h> 
     19#include <asm/time.h> 
     20#include <asm/ipic.h> 
     21#include <asm/udbg.h> 
     22#include <asm/qe.h> 
     23#include <asm/qe_ic.h> 
     24#include <sysdev/fsl_soc.h> 
     25#include <sysdev/fsl_pci.h> 
     26#include "mpc83xx.h" 
     27 
     28#define SYSCTL          0x100 
     29#define SICRL           0x014 
     30 
     31#define GTCFR2          0x04 
     32#define GTMDR4          0x22 
     33#define GTRFR4          0x26 
     34#define GTCNR4          0x2e 
     35#define GTVER4          0x36 
     36#define GTPSR4          0x3e 
     37 
     38#define GTCFR_BCM       0x40 
     39#define GTCFR_STP4      0x20 
     40#define GTCFR_RST4      0x10 
     41#define GTCFR_STP3      0x02 
     42#define GTCFR_RST3      0x01 
     43 
     44#define GTMDR_ORI       0x10 
     45#define GTMDR_FRR       0x08 
     46#define GTMDR_ICLK16    0x04 
     47 
     48extern int par_io_data_set(u8 port, u8 pin, u8 val); 
     49extern int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain, 
     50                             int assignment, int has_irq); 
     51 
     52static unsigned timer_freq; 
     53static void *gtm; 
     54 
     55static int beeper_irq; 
     56static unsigned beeper_gpio_pin[2]; 
     57 
     58irqreturn_t rbppc_timer_irq(int irq, void *ptr) 
     59{ 
     60        static int toggle = 0; 
     61 
     62        par_io_data_set(beeper_gpio_pin[0], beeper_gpio_pin[1], toggle); 
     63        toggle = !toggle; 
     64 
     65        /* ack interrupt */ 
     66        out_be16(gtm + GTVER4, 3); 
     67 
     68        return IRQ_HANDLED; 
     69} 
     70 
     71void rbppc_beep(unsigned freq) 
     72{ 
     73        unsigned gtmdr; 
     74 
     75        if (freq > 5000) freq = 5000; 
     76 
     77        if (!gtm) 
     78                return; 
     79        if (!freq) { 
     80                out_8(gtm + GTCFR2, GTCFR_STP4 | GTCFR_STP3); 
     81                return; 
     82        } 
     83 
     84        out_8(gtm + GTCFR2, GTCFR_RST4 | GTCFR_STP3); 
     85        out_be16(gtm + GTPSR4, 255); 
     86        gtmdr = GTMDR_FRR | GTMDR_ICLK16; 
     87        if (beeper_irq != NO_IRQ) gtmdr |= GTMDR_ORI; 
     88        out_be16(gtm + GTMDR4, gtmdr); 
     89        out_be16(gtm + GTVER4, 3); 
     90 
     91        out_be16(gtm + GTRFR4, timer_freq / 16 / 256 / freq / 2); 
     92        out_be16(gtm + GTCNR4, 0); 
     93} 
     94EXPORT_SYMBOL(rbppc_beep); 
     95 
     96static void __init rbppc_setup_arch(void) 
     97{ 
     98        struct device_node *np; 
     99 
     100        np = of_find_node_by_type(NULL, "cpu"); 
     101        if (np) { 
     102                const unsigned *fp = of_get_property(np, "clock-frequency", NULL); 
     103                loops_per_jiffy = fp ? *fp / HZ : 0; 
     104 
     105                of_node_put(np); 
     106        } 
     107 
     108        np = of_find_node_by_name(NULL, "serial"); 
     109        if (np) { 
     110                timer_freq = 
     111                    *(unsigned *) of_get_property(np, "clock-frequency", NULL); 
     112                of_node_put(np); 
     113        } 
     114 
     115#ifdef CONFIG_PCI 
     116        np = of_find_node_by_type(NULL, "pci"); 
     117        if (np) { 
     118                mpc83xx_add_bridge(np); 
     119        } 
     120#endif 
     121 
     122#ifdef CONFIG_QUICC_ENGINE 
     123        np = of_find_node_by_name(np, "par_io"); 
     124        if (np) { 
     125                qe_reset(); 
     126                par_io_init(np); 
     127                of_node_put(np); 
     128 
     129                np = NULL; 
     130                while (1) { 
     131                        np = of_find_node_by_name(np, "ucc"); 
     132                        if (!np) break; 
     133 
     134                        par_io_of_config(np); 
     135                } 
     136        } 
     137#endif 
     138 
     139} 
     140 
     141void __init rbppc_init_IRQ(void) 
     142{ 
     143        struct device_node *np; 
     144 
     145        np = of_find_node_by_type(NULL, "ipic"); 
     146        if (np) { 
     147                ipic_init(np, 0); 
     148                ipic_set_default_priority(); 
     149                of_node_put(np); 
     150        } 
     151 
     152#ifdef CONFIG_QUICC_ENGINE 
     153        np = of_find_node_by_type(NULL, "qeic"); 
     154        if (np) { 
     155                qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic); 
     156                of_node_put(np); 
     157        } 
     158#endif 
     159} 
     160 
     161static int __init rbppc_probe(void) 
     162{ 
     163        char *model; 
     164 
     165        model = of_get_flat_dt_prop(of_get_flat_dt_root(), "model", NULL); 
     166 
     167        if (!model) 
     168                return 0; 
     169 
     170        if (strcmp(model, "RB600") == 0) 
     171                return 1; 
     172 
     173        return 0; 
     174} 
     175 
     176static void __init rbppc_beeper_init(struct device_node *beeper) 
     177{ 
     178        struct resource res; 
     179        struct device_node *gpio; 
     180        const unsigned *pin; 
     181        const unsigned *gpio_id; 
     182 
     183        if (of_address_to_resource(beeper, 0, &res)) { 
     184                printk(KERN_ERR "rbppc_beeper_init(%s): Beeper error: No region specified\n", beeper->full_name); 
     185                return; 
     186        } 
     187 
     188        pin = of_get_property(beeper, "gpio", NULL); 
     189        if (pin) { 
     190                gpio = of_find_node_by_phandle(pin[0]); 
     191 
     192                if (!gpio) { 
     193                        printk(KERN_ERR "rbppc_beeper_init(%s): Beeper error: GPIO handle %x not found\n", beeper->full_name, pin[0]); 
     194                        return; 
     195                } 
     196 
     197                gpio_id = of_get_property(gpio, "device-id", NULL); 
     198                if (!gpio_id) { 
     199                        printk(KERN_ERR "rbppc_beeper_init(%s): Beeper error: No device-id specified in GPIO\n", beeper->full_name); 
     200                        return; 
     201                } 
     202 
     203                beeper_gpio_pin[0] = *gpio_id; 
     204                beeper_gpio_pin[1] = pin[1]; 
     205 
     206                par_io_config_pin(*gpio_id, pin[1], 1, 0, 0, 0); 
     207        } else { 
     208                void *sysctl; 
     209 
     210                sysctl = ioremap_nocache(get_immrbase() + SYSCTL, 0x100); 
     211                out_be32(sysctl + SICRL, 
     212                         in_be32(sysctl + SICRL) | (1 << (31 - 19))); 
     213                iounmap(sysctl); 
     214        } 
     215 
     216        gtm = ioremap_nocache(res.start, res.end - res.start + 1); 
     217 
     218        beeper_irq = irq_of_parse_and_map(beeper, 0); 
     219        if (beeper_irq != NO_IRQ) { 
     220                int e = request_irq(beeper_irq, rbppc_timer_irq, 0, "beeper", NULL); 
     221                if (e) { 
     222                        printk(KERN_ERR "rbppc_beeper_init(%s): Request of beeper irq failed!\n", beeper->full_name); 
     223                } 
     224        } 
     225} 
     226 
     227#define SBIT(x) (0x80000000 >> (x)) 
     228#define DBIT(x, y) ((y) << (32 - (((x % 16) + 1) * 2))) 
     229 
     230#define SICRL_RB600(x) ((x) + (0x114 >> 2)) 
     231#define GPIO_DIR_RB600(x) ((x) + (0xc00 >> 2)) 
     232#define GPIO_DATA_RB600(x) ((x) + (0xc08 >> 2)) 
     233 
     234static void rbppc_restart(char *cmd) 
     235{ 
     236        __be32 __iomem *reg; 
     237 
     238        reg = ioremap(get_immrbase(), 0x1000); 
     239        local_irq_disable(); 
     240        out_be32(SICRL_RB600(reg), in_be32(SICRL_RB600(reg)) & ~0x00800000); 
     241        out_be32(GPIO_DIR_RB600(reg), in_be32(GPIO_DIR_RB600(reg)) | SBIT(2)); 
     242        out_be32(GPIO_DATA_RB600(reg), in_be32(GPIO_DATA_RB600(reg)) & ~SBIT(2)); 
     243 
     244        while (1); 
     245} 
     246 
     247static void rbppc_halt(void) 
     248{ 
     249        while (1); 
     250} 
     251 
     252static struct of_device_id rbppc_ids[] = { 
     253        { .type = "soc", }, 
     254        { .compatible = "soc", }, 
     255        { .compatible = "simple-bus", }, 
     256        { .compatible = "gianfar", }, 
     257        { }, 
     258}; 
     259 
     260static int __init rbppc_declare_of_platform_devices(void) 
     261{ 
     262        struct device_node *np; 
     263        unsigned idx; 
     264 
     265        of_platform_bus_probe(NULL, rbppc_ids, NULL); 
     266 
     267        np = of_find_node_by_type(NULL, "mdio"); 
     268        if (np) { 
     269                unsigned len; 
     270                unsigned *res; 
     271                const unsigned *eres; 
     272                struct device_node *ep; 
     273 
     274                ep = of_find_compatible_node(NULL, "network", "ucc_geth"); 
     275                if (ep) { 
     276                        eres = of_get_property(ep, "reg", &len); 
     277                        res = (unsigned *) of_get_property(np, "reg", &len); 
     278                        if (res && eres) { 
     279                                res[0] = eres[0] + 0x120; 
     280                        } 
     281                } 
     282        } 
     283 
     284        np = of_find_node_by_name(NULL, "nand"); 
     285        if (np) { 
     286                of_platform_device_create(np, "nand", NULL); 
     287        } 
     288 
     289        idx = 0; 
     290        for_each_node_by_type(np, "rb,cf") { 
     291                char dev_name[12]; 
     292                snprintf(dev_name, sizeof(dev_name), "cf.%u", idx); 
     293                of_platform_device_create(np, dev_name, NULL); 
     294                ++idx; 
     295        } 
     296 
     297        np = of_find_node_by_name(NULL, "beeper"); 
     298        if (np) { 
     299                rbppc_beeper_init(np); 
     300        } 
     301 
     302        return 0; 
     303} 
     304machine_device_initcall(rb600, rbppc_declare_of_platform_devices); 
     305 
     306define_machine(rb600) { 
     307        .name                           = "MikroTik RouterBOARD 600 series", 
     308        .probe                          = rbppc_probe, 
     309        .setup_arch                     = rbppc_setup_arch, 
     310        .init_IRQ                       = rbppc_init_IRQ, 
     311        .get_irq                        = ipic_get_irq, 
     312        .restart                        = rbppc_restart, 
     313        .halt                           = rbppc_halt, 
     314        .time_init                      = mpc83xx_time_init, 
     315        .calibrate_decr                 = generic_calibrate_decr, 
     316}; 
  • arch/powerpc/platforms/Kconfig

    a b config GENERIC_IOMAP 
    142142        bool 
    143143        default n 
    144144 
     145config RB_IOMAP 
     146        bool 
     147        default y if RB_PPC 
     148 
    145149source "drivers/cpufreq/Kconfig" 
    146150 
    147151menu "CPU Frequency drivers" 
  • arch/powerpc/sysdev/Makefile

    a b obj-$(CONFIG_PPC_MPC52xx) += mpc5xxx_clo 
    5656ifeq ($(CONFIG_SUSPEND),y) 
    5757obj-$(CONFIG_6xx)               += 6xx-suspend.o 
    5858endif 
     59 
     60obj-$(CONFIG_RB_IOMAP)          += rb_iomap.o 
  • new file arch/powerpc/sysdev/rb_iomap.c

    - +  
     1#include <linux/init.h> 
     2#include <linux/pci.h> 
     3#include <linux/mm.h> 
     4#include <asm/io.h> 
     5 
     6#define LOCALBUS_START          0x40000000 
     7#define LOCALBUS_MASK           0x007fffff 
     8#define LOCALBUS_REGMASK        0x001fffff 
     9 
     10static void __iomem *localbus_base; 
     11 
     12static inline int is_localbus(void __iomem *addr) 
     13{ 
     14        return ((unsigned) addr & ~LOCALBUS_MASK) == LOCALBUS_START; 
     15} 
     16 
     17static inline unsigned localbus_regoff(unsigned reg) { 
     18        return (reg << 16) | (((reg ^ 8) & 8) << 17); 
     19} 
     20 
     21static inline void __iomem *localbus_addr(void __iomem *addr) 
     22{ 
     23        return localbus_base 
     24            + ((unsigned) addr & LOCALBUS_MASK & ~LOCALBUS_REGMASK) 
     25            + localbus_regoff((unsigned) addr & LOCALBUS_REGMASK); 
     26} 
     27 
     28unsigned int ioread8(void __iomem *addr) 
     29{ 
     30        if (is_localbus(addr)) 
     31                return in_be16(localbus_addr(addr)) >> 8; 
     32        return readb(addr); 
     33} 
     34EXPORT_SYMBOL(ioread8); 
     35 
     36unsigned int ioread16(void __iomem *addr) 
     37{ 
     38        if (is_localbus(addr)) 
     39                return le16_to_cpu(in_be16(localbus_addr(addr))); 
     40        return readw(addr); 
     41} 
     42EXPORT_SYMBOL(ioread16); 
     43 
     44unsigned int ioread16be(void __iomem *addr) 
     45{ 
     46        return in_be16(addr); 
     47} 
     48EXPORT_SYMBOL(ioread16be); 
     49 
     50unsigned int ioread32(void __iomem *addr) 
     51{ 
     52        return readl(addr); 
     53} 
     54EXPORT_SYMBOL(ioread32); 
     55 
     56unsigned int ioread32be(void __iomem *addr) 
     57{ 
     58        return in_be32(addr); 
     59} 
     60EXPORT_SYMBOL(ioread32be); 
     61 
     62void iowrite8(u8 val, void __iomem *addr) 
     63{ 
     64        if (is_localbus(addr)) 
     65                out_be16(localbus_addr(addr), ((u16) val) << 8); 
     66        else 
     67                writeb(val, addr); 
     68} 
     69EXPORT_SYMBOL(iowrite8); 
     70 
     71void iowrite16(u16 val, void __iomem *addr) 
     72{ 
     73        if (is_localbus(addr)) 
     74                out_be16(localbus_addr(addr), cpu_to_le16(val)); 
     75        else 
     76                writew(val, addr); 
     77} 
     78EXPORT_SYMBOL(iowrite16); 
     79 
     80void iowrite16be(u16 val, void __iomem *addr) 
     81{ 
     82        out_be16(addr, val); 
     83} 
     84EXPORT_SYMBOL(iowrite16be); 
     85 
     86void iowrite32(u32 val, void __iomem *addr) 
     87{ 
     88        writel(val, addr); 
     89} 
     90EXPORT_SYMBOL(iowrite32); 
     91 
     92void iowrite32be(u32 val, void __iomem *addr) 
     93{ 
     94        out_be32(addr, val); 
     95} 
     96EXPORT_SYMBOL(iowrite32be); 
     97 
     98void ioread8_rep(void __iomem *addr, void *dst, unsigned long count) 
     99{ 
     100        if (is_localbus(addr)) { 
     101                unsigned i; 
     102                void *laddr = localbus_addr(addr); 
     103                u8 *buf = dst; 
     104 
     105                for (i = 0; i < count; ++i) { 
     106                        *buf++ = in_be16(laddr) >> 8; 
     107                } 
     108        } else { 
     109                _insb((u8 __iomem *) addr, dst, count); 
     110        } 
     111} 
     112EXPORT_SYMBOL(ioread8_rep); 
     113 
     114void ioread16_rep(void __iomem *addr, void *dst, unsigned long count) 
     115{ 
     116        if (is_localbus(addr)) { 
     117                unsigned i; 
     118                void *laddr = localbus_addr(addr); 
     119                u16 *buf = dst; 
     120 
     121                for (i = 0; i < count; ++i) { 
     122                        *buf++ = in_be16(laddr); 
     123                } 
     124        } else { 
     125                _insw_ns((u16 __iomem *) addr, dst, count); 
     126        } 
     127} 
     128EXPORT_SYMBOL(ioread16_rep); 
     129 
     130void ioread32_rep(void __iomem *addr, void *dst, unsigned long count) 
     131{ 
     132        _insl_ns((u32 __iomem *) addr, dst, count); 
     133} 
     134EXPORT_SYMBOL(ioread32_rep); 
     135 
     136void iowrite8_rep(void __iomem *addr, const void *src, unsigned long count) 
     137{ 
     138        if (is_localbus(addr)) { 
     139                unsigned i; 
     140                void *laddr = localbus_addr(addr); 
     141                const u8 *buf = src; 
     142 
     143                for (i = 0; i < count; ++i) { 
     144                        out_be16(laddr, ((u16) *buf++) << 8); 
     145                } 
     146        } else { 
     147                _outsb((u8 __iomem *) addr, src, count); 
     148        } 
     149} 
     150EXPORT_SYMBOL(iowrite8_rep); 
     151 
     152void iowrite16_rep(void __iomem *addr, const void *src, unsigned long count) 
     153{ 
     154        if (is_localbus(addr)) { 
     155                unsigned i; 
     156                void *laddr = localbus_addr(addr); 
     157                const u16 *buf = src; 
     158 
     159                for (i = 0; i < count; ++i) { 
     160                        out_be16(laddr, *buf++); 
     161                } 
     162        } else { 
     163                _outsw_ns((u16 __iomem *) addr, src, count); 
     164        } 
     165} 
     166EXPORT_SYMBOL(iowrite16_rep); 
     167 
     168void iowrite32_rep(void __iomem *addr, const void *src, unsigned long count) 
     169{ 
     170        _outsl_ns((u32 __iomem *) addr, src, count); 
     171} 
     172EXPORT_SYMBOL(iowrite32_rep); 
     173 
     174void __iomem *ioport_map(unsigned long port, unsigned int len) 
     175{ 
     176        return (void __iomem *) (port + _IO_BASE); 
     177} 
     178EXPORT_SYMBOL(ioport_unmap); 
     179 
     180void ioport_unmap(void __iomem *addr) 
     181{ 
     182        /* Nothing to do */ 
     183} 
     184EXPORT_SYMBOL(ioport_map); 
     185 
     186void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max) 
     187{ 
     188        unsigned long start = pci_resource_start(dev, bar); 
     189        unsigned long len = pci_resource_len(dev, bar); 
     190        unsigned long flags = pci_resource_flags(dev, bar); 
     191 
     192        if (!len) 
     193                return NULL; 
     194        if (max && len > max) 
     195                len = max; 
     196        if (flags & IORESOURCE_IO) 
     197                return ioport_map(start, len); 
     198        if (flags & IORESOURCE_MEM) 
     199                return ioremap(start, len); 
     200        /* What? */ 
     201        return NULL; 
     202} 
     203EXPORT_SYMBOL(pci_iomap); 
     204 
     205void pci_iounmap(struct pci_dev *dev, void __iomem *addr) 
     206{ 
     207        /* Nothing to do */ 
     208} 
     209EXPORT_SYMBOL(pci_iounmap); 
     210 
     211void __iomem *localbus_map(unsigned long addr, unsigned int len) 
     212{ 
     213        if (!localbus_base) 
     214                localbus_base = ioremap(addr & ~LOCALBUS_MASK, 
     215                                        LOCALBUS_MASK + 1); 
     216        return (void *) (LOCALBUS_START + (addr & LOCALBUS_MASK)); 
     217} 
     218EXPORT_SYMBOL(localbus_map); 
     219 
     220void localbus_unmap(void __iomem *addr) 
     221{ 
     222} 
     223EXPORT_SYMBOL(localbus_unmap); 
  • drivers/ata/Kconfig

    a b config PATA_BF54X 
    781781 
    782782          If unsure, say N. 
    783783 
     784config PATA_RB_PPC 
     785        tristate "MikroTik RB600 PATA support" 
     786        depends on RB_PPC 
     787        help 
     788          This option enables support for PATA devices on MikroTik RouterBOARD 
     789          600 series boards. 
     790 
    784791endif # ATA_SFF 
    785792endif # ATA 
  • drivers/ata/Makefile

    a b obj-$(CONFIG_PATA_PLATFORM) += pata_plat 
    7777obj-$(CONFIG_PATA_AT91) += pata_at91.o 
    7878obj-$(CONFIG_PATA_OF_PLATFORM)  += pata_of_platform.o 
    7979obj-$(CONFIG_PATA_ICSIDE)       += pata_icside.o 
     80obj-$(CONFIG_PATA_RB_PPC)       += pata_rbppc_cf.o 
    8081# Should be last but two libata driver 
    8182obj-$(CONFIG_PATA_ACPI)         += pata_acpi.o 
    8283# Should be last but one libata driver 
  • new file drivers/ata/pata_rbppc_cf.c

    - +  
     1/* 
     2 * Copyright (C) 2008-2009 Noah Fontes <nfontes@transtruct.org> 
     3 * Copyright (C) Mikrotik 2007 
     4 * 
     5 * This program is free software; you can redistribute it and/or modify it 
     6 * under the terms of the GNU General Public License as published by the 
     7 * Free Software Foundation; either version 2 of the License, or (at your 
     8 * option) any later version. 
     9 */ 
     10 
     11#include <linux/kernel.h> 
     12#include <linux/module.h> 
     13#include <linux/init.h> 
     14#include <scsi/scsi_host.h> 
     15#include <linux/libata.h> 
     16#include <linux/of_platform.h> 
     17#include <linux/ata_platform.h> 
     18 
     19#define DEBUG_UPM       0 
     20 
     21#define DRV_NAME        "pata_rbppc_cf" 
     22#define DRV_VERSION     "0.0.2" 
     23 
     24#define DEV2SEL_OFFSET  0x00100000 
     25 
     26#define IMMR_LBCFG_OFFSET       0x00005000 
     27#define IMMR_LBCFG_SIZE         0x00001000 
     28 
     29#define LOCAL_BUS_MCMR          0x00000078 
     30#define   MxMR_OP_MASK                  0x30000000 
     31#define   MxMR_OP_NORMAL                0x00000000 
     32#define   MxMR_OP_WRITE                 0x10000000 
     33#define   MxMR_OP_READ                  0x20000000 
     34#define   MxMR_OP_RUN                   0x30000000 
     35#define   MxMR_LUPWAIT_LOW              0x08000000 
     36#define   MxMR_LUPWAIT_HIGH             0x00000000 
     37#define   MxMR_LUPWAIT_ENABLE           0x00040000 
     38#define   MxMR_RLF_MASK                 0x0003c000 
     39#define   MxMR_RLF_SHIFT                        14 
     40#define   MxMR_WLF_MASK                 0x00003c00 
     41#define   MxMR_WLF_SHIFT                        10 
     42#define   MxMR_MAD_MASK                 0x0000003f 
     43#define LOCAL_BUS_MDR           0x00000088 
     44#define LOCAL_BUS_LCRR          0x000000D4 
     45#define   LCRR_CLKDIV_MASK              0x0000000f 
     46 
     47#define LOOP_SIZE       4 
     48 
     49#define UPM_READ_SINGLE_OFFSET  0x00 
     50#define UPM_WRITE_SINGLE_OFFSET 0x18 
     51#define UPM_DATA_SIZE   0x40 
     52 
     53#define LBT_CPUIN_MIN           0 
     54#define LBT_CPUOUT_MIN          1 
     55#define LBT_CPUOUT_MAX          2 
     56#define LBT_EXTDEL_MIN          3 
     57#define LBT_EXTDEL_MAX          4 
     58#define LBT_SIZE                5 
     59 
     60/* UPM machine configuration bits */ 
     61#define N_BASE  0x00f00000 
     62#define N_CS    0xf0000000 
     63#define N_CS_H1 0xc0000000 
     64#define N_CS_H2 0x30000000 
     65#define N_WE    0x0f000000 
     66#define N_WE_H1 0x0c000000 
     67#define N_WE_H2 0x03000000 
     68#define N_OE    0x00030000 
     69#define N_OE_H1 0x00020000 
     70#define N_OE_H2 0x00010000 
     71#define WAEN    0x00001000 
     72#define REDO_2  0x00000100 
     73#define REDO_3  0x00000200 
     74#define REDO_4  0x00000300 
     75#define LOOP    0x00000080 
     76#define NA      0x00000008 
     77#define UTA     0x00000004 
     78#define LAST    0x00000001 
     79 
     80#define REDO_VAL(mult)  (REDO_2 * ((mult) - 1)) 
     81#define REDO_MAX_MULT   4 
     82 
     83#define READ_BASE       (N_BASE | N_WE) 
     84#define WRITE_BASE      (N_BASE | N_OE) 
     85#define EMPTY           (N_BASE | N_CS | N_OE | N_WE | LAST) 
     86 
     87#define EOF_UPM_SETTINGS        0 
     88#define ANOTHER_TIMING          1 
     89 
     90#define OA_CPUIN_MIN            0x01 
     91#define OA_CPUOUT_MAX           0x02 
     92#define OD_CPUOUT_MIN           0x04 
     93#define OA_CPUOUT_DELTA         0x06 
     94#define OA_EXTDEL_MAX           0x08 
     95#define OD_EXTDEL_MIN           0x10 
     96#define OA_EXTDEL_DELTA         0x18 
     97#define O_MIN_CYCLE_TIME        0x20 
     98#define O_MINUS_PREV            0x40 
     99#define O_HALF_CYCLE            0x80 
     100 
     101extern void __iomem *localbus_map(unsigned long addr, unsigned int len); 
     102extern void localbus_unmap(void __iomem *addr); 
     103 
     104struct rbppc_cf_info { 
     105        unsigned lbcfg_addr; 
     106        unsigned clk_time_ps; 
     107        int cur_mode; 
     108        u32 lb_timings[LBT_SIZE]; 
     109}; 
     110static struct rbppc_cf_info *rbinfo = NULL; 
     111 
     112struct upm_setting { 
     113        unsigned value; 
     114        unsigned ns[7]; 
     115        unsigned clk_minus; 
     116        unsigned group_size; 
     117        unsigned options; 
     118}; 
     119 
     120static const struct upm_setting cfUpmReadSingle[] = { 
     121        { READ_BASE | N_OE, 
     122          /* t1 - ADDR setup time */ 
     123                {  70,  50,  30,  30,  25,  15,  10 }, 0, 0, (OA_CPUOUT_DELTA | 
     124                                                              OA_EXTDEL_MAX) }, 
     125        { READ_BASE | N_OE_H1, 
     126                {   0,   0,   0,   0,   0,   0,   0 }, 0, 0, O_HALF_CYCLE }, 
     127        { READ_BASE, 
     128          /* t2 - OE0 time */ 
     129                { 290, 290, 290,  80,  70,  65,  55 }, 0, 2, (OA_CPUOUT_MAX | 
     130                                                              OA_CPUIN_MIN) }, 
     131        { READ_BASE | WAEN, 
     132                {   1,   1,   1,   1,   1,   0,   0 }, 0, 0, 0 }, 
     133        { READ_BASE | UTA, 
     134                {   1,   1,   1,   1,   1,   1,   1 }, 0, 0, 0 }, 
     135        { READ_BASE | N_OE, 
     136          /* t9 - ADDR hold time */ 
     137                {  20,  15,  10,  10,  10,  10,  10 }, 0, 0, (OA_CPUOUT_DELTA | 
     138                                                              OD_EXTDEL_MIN) }, 
     139        { READ_BASE | N_OE | N_CS_H2, 
     140                {   0,   0,   0,   0,   0,   0,   0 }, 0, 0, O_HALF_CYCLE }, 
     141        { READ_BASE | N_OE | N_CS, 
     142          /* t6Z -IORD data tristate */ 
     143                {  30,  30,  30,  30,  30,  20,  20 }, 1, 1, O_MINUS_PREV }, 
     144        { ANOTHER_TIMING, 
     145          /* t2i -IORD recovery time */ 
     146                {   0,   0,   0,  70,  25,  25,  20 }, 2, 0, 0 }, 
     147        { ANOTHER_TIMING, 
     148          /* CS 0 -> 1 MAX */ 
     149                {   0,   0,   0,   0,   0,   0,   0 }, 1, 0, (OA_CPUOUT_DELTA | 
     150                                                              OA_EXTDEL_MAX) }, 
     151        { READ_BASE | N_OE | N_CS | LAST, 
     152                {   1,   1,   1,   1,   1,   1,   1 }, 0, 0, 0 }, 
     153        { EOF_UPM_SETTINGS, 
     154          /* min total cycle time - includes turnaround and ALE cycle */ 
     155                { 600, 383, 240, 180, 120, 100,  80 }, 2, 0, O_MIN_CYCLE_TIME }, 
     156}; 
     157 
     158static const struct upm_setting cfUpmWriteSingle[] = { 
     159        { WRITE_BASE | N_WE, 
     160          /* t1 - ADDR setup time */ 
     161                {  70,  50,  30,  30,  25,  15,  10 }, 0, 0, (OA_CPUOUT_DELTA | 
     162                                                              OA_EXTDEL_MAX) }, 
     163        { WRITE_BASE | N_WE_H1, 
     164                {   0,   0,   0,   0,   0,   0,   0 }, 0, 0, O_HALF_CYCLE }, 
     165        { WRITE_BASE, 
     166          /* t2 - WE0 time */ 
     167                { 290, 290, 290,  80,  70,  65,  55 }, 0, 1, OA_CPUOUT_DELTA }, 
     168        { WRITE_BASE | WAEN, 
     169                {   1,   1,   1,   1,   1,   0,   0 }, 0, 0, 0 }, 
     170        { WRITE_BASE | N_WE, 
     171          /* t9 - ADDR hold time */ 
     172                {  20,  15,  10,  10,  10,  10,  10 }, 0, 0, (OA_CPUOUT_DELTA | 
     173                                                              OD_EXTDEL_MIN) }, 
     174        { WRITE_BASE | N_WE | N_CS_H2, 
     175                {   0,   0,   0,   0,   0,   0,   0 }, 0, 0, O_HALF_CYCLE }, 
     176        { WRITE_BASE | N_WE | N_CS, 
     177          /* t4 - DATA hold time */ 
     178                {  30,  20,  15,  10,  10,  10,  10 }, 0, 1, O_MINUS_PREV }, 
     179        { ANOTHER_TIMING, 
     180          /* t2i -IOWR recovery time */ 
     181                {   0,   0,   0,  70,  25,  25,  20 }, 1, 0, 0 }, 
     182        { ANOTHER_TIMING, 
     183          /* CS 0 -> 1 MAX */ 
     184                {   0,   0,   0,   0,   0,   0,   0 }, 0, 0, (OA_CPUOUT_DELTA | 
     185                                                              OA_EXTDEL_MAX) }, 
     186        { WRITE_BASE | N_WE | N_CS | UTA | LAST, 
     187                {   1,   1,   1,   1,   1,   1,   1 }, 0, 0, 0 }, 
     188        /* min total cycle time - includes ALE cycle */ 
     189        { EOF_UPM_SETTINGS, 
     190                { 600, 383, 240, 180, 120, 100,  80 }, 1, 0, O_MIN_CYCLE_TIME }, 
     191}; 
     192 
     193static u8 rbppc_cf_check_status(struct ata_port *ap) { 
     194        u8 val = ioread8(ap->ioaddr.status_addr); 
     195        if (val == 0xF9) 
     196                val = 0x7F; 
     197        return val; 
     198} 
     199 
     200static u8 rbppc_cf_check_altstatus(struct ata_port *ap) { 
     201        u8 val = ioread8(ap->ioaddr.altstatus_addr); 
     202        if (val == 0xF9) 
     203                val = 0x7F; 
     204        return val; 
     205} 
     206 
     207static void rbppc_cf_dummy_noret(struct ata_port *ap) { } 
     208static int rbppc_cf_dummy_ret0(struct ata_port *ap) { return 0; } 
     209 
     210static int ps2clk(int ps, unsigned clk_time_ps) { 
     211        int psMaxOver; 
     212        if (ps <= 0) return 0; 
     213 
     214        /* round down if <= 2% over clk border, but no more than 1/4 clk cycle */ 
     215        psMaxOver = ps * 2 / 100; 
     216        if (4 * psMaxOver > clk_time_ps) { 
     217                psMaxOver = clk_time_ps / 4; 
     218        } 
     219        return (ps + clk_time_ps - 1 - psMaxOver) / clk_time_ps; 
     220} 
     221 
     222static int upm_gen_ps_table(const struct upm_setting *upm, 
     223                            int mode, struct rbppc_cf_info *info, 
     224                            int *psFinal) { 
     225        int uidx; 
     226        int lastUpmValIdx = 0; 
     227        int group_start_idx = -1; 
     228        int group_left_num = -1; 
     229        int clk_time_ps = info->clk_time_ps; 
     230 
     231        for (uidx = 0; upm[uidx].value != EOF_UPM_SETTINGS; ++uidx) { 
     232                const struct upm_setting *us = upm + uidx; 
     233                unsigned opt = us->options; 
     234                int ps = us->ns[mode] * 1000 - us->clk_minus * clk_time_ps; 
     235 
     236                if (opt & OA_CPUIN_MIN) ps += info->lb_timings[LBT_CPUIN_MIN]; 
     237                if (opt & OD_CPUOUT_MIN) ps -= info->lb_timings[LBT_CPUOUT_MIN]; 
     238                if (opt & OA_CPUOUT_MAX) ps += info->lb_timings[LBT_CPUOUT_MAX]; 
     239                if (opt & OD_EXTDEL_MIN) ps -= info->lb_timings[LBT_EXTDEL_MIN]; 
     240                if (opt & OA_EXTDEL_MAX) ps += info->lb_timings[LBT_EXTDEL_MAX]; 
     241 
     242                if (us->value == ANOTHER_TIMING) { 
     243                        /* use longest timing from alternatives */ 
     244                        if (psFinal[lastUpmValIdx] < ps) { 
     245                                psFinal[lastUpmValIdx] = ps; 
     246                        } 
     247                        ps = 0; 
     248                } 
     249                else { 
     250                        if (us->group_size) { 
     251                                group_start_idx = uidx; 
     252                                group_left_num = us->group_size; 
     253                        } 
     254                        else if (group_left_num > 0) { 
     255                                /* group time is divided on all group members */ 
     256                                int clk = ps2clk(ps, clk_time_ps); 
     257                                psFinal[group_start_idx] -= clk * clk_time_ps; 
     258                                --group_left_num; 
     259                        } 
     260                        if ((opt & O_MINUS_PREV) && lastUpmValIdx > 0) { 
     261                                int clk = ps2clk(psFinal[lastUpmValIdx], 
     262                                                 clk_time_ps); 
     263                                ps -= clk * clk_time_ps; 
     264                        } 
     265                        lastUpmValIdx = uidx; 
     266                } 
     267                psFinal[uidx] = ps; 
     268        } 
     269        return uidx; 
     270} 
     271 
     272static int free_half(int ps, int clk, int clk_time_ps) { 
     273    if (clk < 2) return 0; 
     274    return (clk * clk_time_ps - ps) * 2 >= clk_time_ps; 
     275} 
     276 
     277static void upm_gen_clk_table(const struct upm_setting *upm, 
     278                              int mode, int clk_time_ps, 
     279                              int max_uidx, const int *psFinal, int *clkFinal) { 
     280        int clk_cycle_time; 
     281        int clk_total; 
     282        int uidx; 
     283 
     284        /* convert picoseconds to clocks */ 
     285        clk_total = 0; 
     286        for (uidx = 0; uidx < max_uidx; ++uidx) { 
     287                int clk = ps2clk(psFinal[uidx], clk_time_ps); 
     288                clkFinal[uidx] = clk; 
     289                clk_total += clk; 
     290        } 
     291 
     292        /* check possibility of half cycle usage */ 
     293        for (uidx = 1; uidx < max_uidx - 1; ++uidx) { 
     294                if ((upm[uidx].options & O_HALF_CYCLE) && 
     295                    free_half(psFinal[uidx - 1], clkFinal[uidx - 1], 
     296                              clk_time_ps) && 
     297                    free_half(psFinal[uidx + 1], clkFinal[uidx + 1], 
     298                              clk_time_ps)) { 
     299                        ++clkFinal[uidx]; 
     300                        --clkFinal[uidx - 1]; 
     301                        --clkFinal[uidx + 1]; 
     302                } 
     303        } 
     304 
     305        if ((upm[max_uidx].options & O_MIN_CYCLE_TIME) == 0) return; 
     306 
     307        /* check cycle time, adjust timings if needed */ 
     308        clk_cycle_time = (ps2clk(upm[max_uidx].ns[mode] * 1000, clk_time_ps) - 
     309                          upm[max_uidx].clk_minus); 
     310        uidx = 0; 
     311        while (clk_total < clk_cycle_time) { 
     312                /* extend all timings in round-robin to match cycle time */ 
     313                if (clkFinal[uidx]) { 
     314#if DEBUG_UPM 
     315                        printk(KERN_INFO "extending %u by 1 clk\n", uidx); 
     316#endif 
     317                        ++clkFinal[uidx]; 
     318                        ++clk_total; 
     319                } 
     320                ++uidx; 
     321                if (uidx == max_uidx) uidx = 0; 
     322        } 
     323} 
     324 
     325static void add_data_val(unsigned val, int *clkLeft, int maxClk, 
     326                        unsigned *data, int *dataIdx) { 
     327        if (*clkLeft == 0) return; 
     328 
     329        if (maxClk == 0 && *clkLeft >= LOOP_SIZE * 2) { 
     330                int times; 
     331                int times1; 
     332                int times2; 
     333 
     334                times = *clkLeft / LOOP_SIZE; 
     335                if (times > REDO_MAX_MULT * 2) times = REDO_MAX_MULT * 2; 
     336                times1 = times / 2; 
     337                times2 = times - times1; 
     338 
     339                val |= LOOP; 
     340                data[*dataIdx] = val | REDO_VAL(times1); 
     341                ++(*dataIdx); 
     342                data[*dataIdx] = val | REDO_VAL(times2); 
     343                ++(*dataIdx); 
     344 
     345                *clkLeft -= times * LOOP_SIZE; 
     346                return; 
     347        } 
     348 
     349        if (maxClk < 1 || maxClk > REDO_MAX_MULT) maxClk = REDO_MAX_MULT; 
     350        if (*clkLeft < maxClk) maxClk = *clkLeft; 
     351 
     352        *clkLeft -= maxClk; 
     353        val |= REDO_VAL(maxClk); 
     354 
     355        data[*dataIdx] = val; 
     356        ++(*dataIdx); 
     357} 
     358 
     359static int upm_gen_final_data(const struct upm_setting *upm, 
     360                               int max_uidx, int *clkFinal, unsigned *data) { 
     361        int dataIdx; 
     362        int uidx; 
     363 
     364        dataIdx = 0; 
     365        for (uidx = 0; uidx < max_uidx; ++uidx) { 
     366                int clk = clkFinal[uidx]; 
     367                while (clk > 0) { 
     368                        add_data_val(upm[uidx].value, &clk, 0, 
     369                                     data, &dataIdx); 
     370                } 
     371        } 
     372        return dataIdx; 
     373} 
     374 
     375static int conv_upm_table(const struct upm_setting *upm, 
     376                          int mode, struct rbppc_cf_info *info, 
     377                          unsigned *data) { 
     378#if DEBUG_UPM 
     379        int uidx; 
     380#endif 
     381        int psFinal[32]; 
     382        int clkFinal[32]; 
     383        int max_uidx; 
     384        int data_len; 
     385 
     386        max_uidx = upm_gen_ps_table(upm, mode, info, psFinal); 
     387 
     388        upm_gen_clk_table(upm, mode, info->clk_time_ps, max_uidx, 
     389                          psFinal, clkFinal); 
     390 
     391#if DEBUG_UPM 
     392        /* dump out debug info */ 
     393        for (uidx = 0; uidx < max_uidx; ++uidx) { 
     394                if (clkFinal[uidx]) { 
     395                        printk(KERN_INFO "idx %d val %08x clk %d ps %d\n", 
     396                                uidx, upm[uidx].value, 
     397                                clkFinal[uidx], psFinal[uidx]); 
     398                } 
     399        } 
     400#endif 
     401 
     402        data_len = upm_gen_final_data(upm, max_uidx, clkFinal, data); 
     403 
     404#if DEBUG_UPM 
     405        for (uidx = 0; uidx < data_len; ++uidx) { 
     406                printk(KERN_INFO "cf UPM x result: idx %d val %08x\n", 
     407                       uidx, data[uidx]); 
     408        } 
     409#endif 
     410        return 0; 
     411} 
     412 
     413static int gen_upm_data(int mode, struct rbppc_cf_info *info, unsigned *data) { 
     414        int i; 
     415 
     416        for (i = 0; i < UPM_DATA_SIZE; ++i) { 
     417                data[i] = EMPTY; 
     418        } 
     419 
     420        if (conv_upm_table(cfUpmReadSingle, mode, info, data + UPM_READ_SINGLE_OFFSET)) { 
     421                return -1; 
     422        } 
     423        if (conv_upm_table(cfUpmWriteSingle, mode, info, data + UPM_WRITE_SINGLE_OFFSET)) { 
     424                return -1; 
     425        } 
     426        return 0; 
     427} 
     428 
     429static void rbppc_cf_program_upm(void *upmMemAddr, volatile void *lbcfg_mxmr, volatile void *lbcfg_mdr, const unsigned *upmData, unsigned offset, unsigned len) { 
     430        unsigned i; 
     431        unsigned mxmr; 
     432 
     433        mxmr = in_be32(lbcfg_mxmr); 
     434        mxmr &= ~(MxMR_OP_MASK | MxMR_MAD_MASK); 
     435        mxmr |= (MxMR_OP_WRITE | offset); 
     436        out_be32(lbcfg_mxmr, mxmr); 
     437        in_be32(lbcfg_mxmr); /* flush MxMR write */ 
     438 
     439        for (i = 0; i < len; ++i) { 
     440                int to; 
     441                unsigned data = upmData[i + offset]; 
     442                out_be32(lbcfg_mdr, data); 
     443                in_be32(lbcfg_mdr); /* flush MDR write */ 
     444 
     445                iowrite8(1, upmMemAddr); /* dummy write to any CF addr */ 
     446 
     447                /* wait for dummy write to complete */ 
     448                for (to = 10000; to >= 0; --to) { 
     449                        mxmr = in_be32(lbcfg_mxmr); 
     450                        if (((mxmr ^ (i + 1)) & MxMR_MAD_MASK) == 0) { 
     451                                break; 
     452                        } 
     453                        if (to == 0) { 
     454                                printk(KERN_ERR "rbppc_cf_program_upm: UPMx program error at 0x%x: Timeout\n", i); 
     455                        } 
     456                } 
     457        } 
     458        mxmr &= ~(MxMR_OP_MASK | MxMR_RLF_MASK | MxMR_WLF_MASK); 
     459        mxmr |= (MxMR_OP_NORMAL | (LOOP_SIZE << MxMR_RLF_SHIFT) | (LOOP_SIZE << MxMR_WLF_SHIFT)); 
     460        out_be32(lbcfg_mxmr, mxmr); 
     461} 
     462 
     463static int rbppc_cf_update_piomode(struct ata_port *ap, int mode) { 
     464        struct rbppc_cf_info *info = (struct rbppc_cf_info *)ap->host->private_data; 
     465        void *lbcfgBase; 
     466        unsigned upmData[UPM_DATA_SIZE]; 
     467 
     468        if (gen_upm_data(mode, info, upmData)) { 
     469                return -1; 
     470        } 
     471 
     472        lbcfgBase = ioremap_nocache(info->lbcfg_addr, IMMR_LBCFG_SIZE); 
     473 
     474        rbppc_cf_program_upm(ap->ioaddr.cmd_addr, ((char *)lbcfgBase) + LOCAL_BUS_MCMR, ((char *)lbcfgBase) + LOCAL_BUS_MDR, upmData, 0, UPM_DATA_SIZE); 
     475        iounmap(lbcfgBase); 
     476        return 0; 
     477} 
     478 
     479static void rbppc_cf_set_piomode(struct ata_port *ap, struct ata_device *adev) 
     480{ 
     481        struct rbppc_cf_info *info = (struct rbppc_cf_info *)ap->host->private_data; 
     482        int mode = adev->pio_mode - XFER_PIO_0; 
     483 
     484        DPRINTK("rbppc_cf_set_piomode: PIO %d\n", mode); 
     485        if (mode < 0) mode = 0; 
     486        if (mode > 6) mode = 6; 
     487 
     488        if (info->cur_mode < 0 || info->cur_mode > mode) { 
     489                if (rbppc_cf_update_piomode(ap, mode) == 0) { 
     490                        printk(KERN_INFO "rbppc_cf_set_piomode: PIO mode changed to %d\n", mode); 
     491                        info->cur_mode = mode; 
     492                } 
     493        } 
     494} 
     495 
     496static struct scsi_host_template rbppc_cf_sht = { 
     497        ATA_BASE_SHT(DRV_NAME), 
     498}; 
     499 
     500static struct ata_port_operations rbppc_cf_port_ops = { 
     501        .inherits               = &ata_bmdma_port_ops, 
     502 
     503        .sff_check_status       = rbppc_cf_check_status, 
     504        .sff_check_altstatus    = rbppc_cf_check_altstatus, 
     505 
     506        .set_piomode            = rbppc_cf_set_piomode, 
     507 
     508        .port_start             = rbppc_cf_dummy_ret0, 
     509 
     510        .sff_irq_clear          = rbppc_cf_dummy_noret, 
     511}; 
     512 
     513static int rbppc_cf_init_info(struct of_device *pdev, struct rbppc_cf_info *info) { 
     514        struct device_node *np; 
     515        struct resource res; 
     516        const u32 *u32ptr; 
     517        void *lbcfgBase; 
     518        void *lbcfg_lcrr; 
     519        unsigned lbc_clk_khz; 
     520        unsigned lbc_extra_divider = 1; 
     521        unsigned ccb_freq_hz; 
     522        unsigned lb_div; 
     523 
     524        u32ptr = of_get_property(pdev->node, "lbc_extra_divider", NULL); 
     525        if (u32ptr && *u32ptr) { 
     526                lbc_extra_divider = *u32ptr; 
     527#if DEBUG_UPM 
     528                printk(KERN_INFO "rbppc_cf_init_info: LBC extra divider %u\n", 
     529                       lbc_extra_divider); 
     530#endif 
     531        } 
     532 
     533        np = of_find_node_by_type(NULL, "serial"); 
     534        if (!np) { 
     535                printk(KERN_ERR "rbppc_cf_init_info: No serial node found\n"); 
     536                return -1; 
     537        } 
     538        u32ptr = of_get_property(np, "clock-frequency", NULL); 
     539        if (u32ptr == 0 || *u32ptr == 0) { 
     540                printk(KERN_ERR "rbppc_cf_init_info: Serial does not have clock-frequency\n"); 
     541                of_node_put(np); 
     542                return -1; 
     543        } 
     544        ccb_freq_hz = *u32ptr; 
     545        of_node_put(np); 
     546 
     547        np = of_find_node_by_type(NULL, "soc"); 
     548        if (!np) { 
     549                printk(KERN_ERR "rbppc_cf_init_info: No soc node found\n"); 
     550                return -1; 
     551        } 
     552        if (of_address_to_resource(np, 0, &res)) { 
     553                printk(KERN_ERR "rbppc_cf_init_info: soc does not have resource\n"); 
     554                of_node_put(np); 
     555                return -1; 
     556        } 
     557        info->lbcfg_addr = res.start + IMMR_LBCFG_OFFSET; 
     558        of_node_put(np); 
     559 
     560        lbcfgBase = ioremap_nocache(info->lbcfg_addr, IMMR_LBCFG_SIZE); 
     561        lbcfg_lcrr = ((char*)lbcfgBase) + LOCAL_BUS_LCRR; 
     562        lb_div = (in_be32(lbcfg_lcrr) & LCRR_CLKDIV_MASK) * lbc_extra_divider; 
     563        iounmap(lbcfgBase); 
     564 
     565        lbc_clk_khz = ccb_freq_hz / (1000 * lb_div); 
     566        info->clk_time_ps = 1000000000 / lbc_clk_khz; 
     567        printk(KERN_INFO "rbppc_cf_init_info: Using Local-Bus clock %u kHz %u ps\n", 
     568               lbc_clk_khz, info->clk_time_ps); 
     569 
     570        u32ptr = of_get_property(pdev->node, "lb-timings", NULL); 
     571        if (u32ptr) { 
     572                memcpy(info->lb_timings, u32ptr, LBT_SIZE * sizeof(*u32ptr)); 
     573#if DEBUG_UPM 
     574                printk(KERN_INFO "rbppc_cf_init_info: Got LB timings <%u %u %u %u %u>\n", 
     575                       u32ptr[0], u32ptr[1], u32ptr[2], u32ptr[3], u32ptr[4]); 
     576#endif 
     577        } 
     578        info->cur_mode = -1; 
     579        return 0; 
     580} 
     581 
     582static int rbppc_cf_probe(struct of_device *pdev, 
     583                          const struct of_device_id *match) 
     584{ 
     585        struct ata_host *host; 
     586        struct ata_port *ap; 
     587        struct rbppc_cf_info *info = NULL; 
     588        struct resource res; 
     589        void *baddr; 
     590        const u32 *u32ptr; 
     591        int irq_level = 0; 
     592        int err = -ENOMEM; 
     593 
     594        printk(KERN_INFO "rbppc_cf_probe: MikroTik RouterBOARD 600 series Compact Flash PATA driver, version " DRV_VERSION "\n"); 
     595 
     596        if (rbinfo == NULL) { 
     597                info = kmalloc(sizeof(*info), GFP_KERNEL); 
     598                if (info == NULL) { 
     599                        printk(KERN_ERR "rbppc_cf_probe: Out of memory\n"); 
     600                        goto err_info; 
     601                } 
     602                memset(info, 0, sizeof(*info)); 
     603 
     604                if (rbppc_cf_init_info(pdev, info)) { 
     605                        goto err_info; 
     606                } 
     607                rbinfo = info; 
     608        } 
     609 
     610        u32ptr = of_get_property(pdev->node, "interrupt-at-level", NULL); 
     611        if (u32ptr) { 
     612                irq_level = *u32ptr; 
     613                printk(KERN_INFO "rbppc_cf_probe: IRQ level %u\n", irq_level); 
     614        } 
     615 
     616        if (of_address_to_resource(pdev->node, 0, &res)) { 
     617            printk(KERN_ERR "rbppc_cf_probe: No reg property found\n"); 
     618            goto err_info; 
     619        } 
     620 
     621        host = ata_host_alloc(&pdev->dev, 1); 
     622        if (!host) 
     623            goto err_info; 
     624 
     625        baddr = localbus_map(res.start, res.end - res.start + 1); 
     626        host->iomap = baddr; 
     627        host->private_data = rbinfo; 
     628 
     629        ap = host->ports[0]; 
     630        ap->ops = &rbppc_cf_port_ops; 
     631        ap->pio_mask = 0x7F;    /* PIO modes 0-6 */ 
     632        ap->flags = ATA_FLAG_NO_LEGACY; 
     633        ap->mwdma_mask = 0; 
     634 
     635        ap->ioaddr.cmd_addr = baddr; 
     636        ata_sff_std_ports(&ap->ioaddr); 
     637        ap->ioaddr.ctl_addr = ap->ioaddr.cmd_addr + 14; 
     638        ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr; 
     639        ap->ioaddr.bmdma_addr = 0; 
     640 
     641        err = ata_host_activate( 
     642                host, 
     643                irq_of_parse_and_map(pdev->node, 0), ata_sff_interrupt, 
     644                irq_level ? IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW, 
     645                &rbppc_cf_sht); 
     646        if (!err) return 0; 
     647 
     648        localbus_unmap(baddr); 
     649err_info: 
     650        if (info) { 
     651                kfree(info); 
     652                rbinfo = NULL; 
     653        } 
     654        return err; 
     655} 
     656 
     657static int rbppc_cf_remove(struct of_device *pdev) 
     658{ 
     659        struct device *dev = &pdev->dev; 
     660        struct ata_host *host = dev_get_drvdata(dev); 
     661 
     662        if (host == NULL) return -1; 
     663 
     664        ata_host_detach(host); 
     665        return 0; 
     666} 
     667 
     668static struct of_device_id rbppc_cf_ids[] = { 
     669        { .name = "cf", }, 
     670        { }, 
     671}; 
     672 
     673static struct of_platform_driver rbppc_cf_driver = { 
     674        .name = "cf", 
     675        .probe = rbppc_cf_probe, 
     676        .remove = rbppc_cf_remove, 
     677        .match_table = rbppc_cf_ids, 
     678        .driver = { 
     679                .name = "rbppc-cf", 
     680                .owner = THIS_MODULE, 
     681        }, 
     682}; 
     683 
     684static int __init rbppc_init(void) 
     685{ 
     686        return of_register_platform_driver(&rbppc_cf_driver); 
     687} 
     688 
     689static void __exit rbppc_exit(void) 
     690{ 
     691        of_unregister_platform_driver(&rbppc_cf_driver); 
     692} 
     693 
     694MODULE_AUTHOR("Mikrotikls SIA"); 
     695MODULE_AUTHOR("Noah Fontes"); 
     696MODULE_DESCRIPTION("MikroTik RouterBOARD 600 series Compact Flash PATA driver"); 
     697MODULE_LICENSE("GPL"); 
     698MODULE_VERSION(DRV_VERSION); 
     699 
     700module_init(rbppc_init); 
     701module_exit(rbppc_exit); 
  • drivers/mtd/nand/Kconfig

    a b config MTD_NAND_PLATFORM 
    403403          devices. You will need to provide platform-specific functions 
    404404          via platform_data. 
    405405 
     406config MTD_NAND_RB_PPC 
     407        tristate "MikroTik RB600 NAND support" 
     408        depends on MTD_NAND && MTD_PARTITIONS && RB_PPC 
     409        help 
     410          This option enables support for the NAND device on MikroTik 
     411          RouterBOARD 600 series boards. 
     412 
    406413config MTD_ALAUDA 
    407414        tristate "MTD driver for Olympus MAUSB-10 and Fujifilm DPC-R1" 
    408415        depends on MTD_NAND && USB 
  • drivers/mtd/nand/Makefile

    a b obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) +=  
    3131obj-$(CONFIG_MTD_NAND_PXA3xx)           += pxa3xx_nand.o 
    3232obj-$(CONFIG_MTD_NAND_TMIO)             += tmio_nand.o 
    3333obj-$(CONFIG_MTD_NAND_PLATFORM)         += plat_nand.o 
     34obj-$(CONFIG_MTD_NAND_RB_PPC)           += rbppc_nand.o 
    3435obj-$(CONFIG_MTD_ALAUDA)                += alauda.o 
    3536obj-$(CONFIG_MTD_NAND_PASEMI)           += pasemi_nand.o 
    3637obj-$(CONFIG_MTD_NAND_ORION)            += orion_nand.o 
  • new file drivers/mtd/nand/rbppc_nand.c

    - +  
     1/* 
     2 * Copyright (C) 2008-2009 Noah Fontes <nfontes@transtruct.org> 
     3 * Copyright (C) 2009 Michael Guntsche <mike@it-loops.com> 
     4 * Copyright (C) Mikrotik 2007 
     5 * 
     6 * This program is free software; you can redistribute it and/or modify it 
     7 * under the terms of the GNU General Public License as published by the 
     8 * Free Software Foundation; either version 2 of the License, or (at your 
     9 * option) any later version. 
     10 */ 
     11 
     12#include <linux/init.h> 
     13#include <linux/mtd/nand.h> 
     14#include <linux/mtd/mtd.h> 
     15#include <linux/mtd/partitions.h> 
     16#include <linux/of_platform.h> 
     17#include <asm/of_platform.h> 
     18#include <asm/of_device.h> 
     19#include <linux/delay.h> 
     20#include <asm/io.h> 
     21 
     22#define DRV_NAME        "rbppc_nand" 
     23#define DRV_VERSION     "0.0.2" 
     24 
     25static struct mtd_info rmtd; 
     26static struct nand_chip rnand; 
     27 
     28struct rbppc_nand_info { 
     29        void *gpi; 
     30        void *gpo; 
     31        void *localbus; 
     32 
     33        unsigned gpio_rdy; 
     34        unsigned gpio_nce; 
     35        unsigned gpio_cle; 
     36        unsigned gpio_ale; 
     37        unsigned gpio_ctrls; 
     38}; 
     39 
     40/* We must use the OOB layout from yaffs 1 if we want this to be recognized 
     41 * properly. Borrowed from the OpenWRT patches for the RB532. 
     42 * 
     43 * See <https://dev.openwrt.org/browser/trunk/target/linux/rb532/ 
     44 * patches-2.6.28/025-rb532_nand_fixup.patch> for more details. 
     45 */ 
     46static struct nand_ecclayout rbppc_nand_oob_16 = { 
     47        .eccbytes = 6, 
     48        .eccpos = { 8, 9, 10, 13, 14, 15 }, 
     49        .oobavail = 9, 
     50        .oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } } 
     51}; 
     52 
     53static struct mtd_partition rbppc_nand_partition_info[] = { 
     54        { 
     55                name: "RouterBOARD NAND Boot", 
     56                offset: 0, 
     57                size: 4 * 1024 * 1024, 
     58        }, 
     59        { 
     60                name: "RouterBOARD NAND Main", 
     61                offset: MTDPART_OFS_NXTBLK, 
     62                size: MTDPART_SIZ_FULL, 
     63        }, 
     64}; 
     65 
     66static int rbppc_nand_dev_ready(struct mtd_info *mtd) { 
     67        struct nand_chip *chip = mtd->priv; 
     68        struct rbppc_nand_info *priv = chip->priv; 
     69 
     70        return in_be32(priv->gpi) & priv->gpio_rdy; 
     71} 
     72 
     73static void rbppc_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) { 
     74        struct nand_chip *chip = mtd->priv; 
     75        struct rbppc_nand_info *priv = chip->priv; 
     76 
     77        if (ctrl & NAND_CTRL_CHANGE) { 
     78                unsigned val = in_be32(priv->gpo); 
     79                if (!(val & priv->gpio_nce)) { 
     80                        /* make sure Local Bus has done NAND operations */ 
     81                        readb(priv->localbus); 
     82                } 
     83 
     84                if (ctrl & NAND_CLE) { 
     85                        val |= priv->gpio_cle; 
     86                } else { 
     87                        val &= ~priv->gpio_cle; 
     88                } 
     89                if (ctrl & NAND_ALE) { 
     90                        val |= priv->gpio_ale; 
     91                } else { 
     92                        val &= ~priv->gpio_ale; 
     93                } 
     94                if (!(ctrl & NAND_NCE)) { 
     95                        val |= priv->gpio_nce; 
     96                } else { 
     97                        val &= ~priv->gpio_nce; 
     98                } 
     99                out_be32(priv->gpo, val); 
     100 
     101                /* make sure GPIO output has changed */ 
     102                val ^= in_be32(priv->gpo); 
     103                if (val & priv->gpio_ctrls) { 
     104                        printk(KERN_ERR "rbppc_nand_hwcontrol: NAND GPO change failed 0x%08x\n", val); 
     105                } 
     106        } 
     107 
     108        if (cmd != NAND_CMD_NONE) writeb(cmd, chip->IO_ADDR_W); 
     109} 
     110 
     111static void rbppc_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) 
     112{ 
     113        struct nand_chip *chip = mtd->priv; 
     114        memcpy(buf, chip->IO_ADDR_R, len); 
     115} 
     116 
     117static unsigned init_ok = 0; 
     118 
     119static int rbppc_nand_probe(struct of_device *pdev, 
     120                            const struct of_device_id *match) 
     121{ 
     122        struct device_node *gpio; 
     123        struct device_node *nnand; 
     124        struct resource res; 
     125        struct rbppc_nand_info *info; 
     126        void *baddr; 
     127        const unsigned *rdy, *nce, *cle, *ale; 
     128 
     129        printk(KERN_INFO "rbppc_nand_probe: MikroTik RouterBOARD 600 series NAND driver, version " DRV_VERSION "\n"); 
     130 
     131        info = kmalloc(sizeof(*info), GFP_KERNEL); 
     132 
     133        rdy = of_get_property(pdev->node, "rdy", NULL); 
     134        nce = of_get_property(pdev->node, "nce", NULL); 
     135        cle = of_get_property(pdev->node, "cle", NULL); 
     136        ale = of_get_property(pdev->node, "ale", NULL); 
     137 
     138        if (!rdy || !nce || !cle || !ale) { 
     139                printk(KERN_ERR "rbppc_nand_probe: GPIO properties are missing\n"); 
     140                goto err; 
     141        } 
     142        if (rdy[0] != nce[0] || rdy[0] != cle[0] || rdy[0] != ale[0]) { 
     143                printk(KERN_ERR "rbppc_nand_probe: Different GPIOs are not supported\n"); 
     144                goto err; 
     145        } 
     146 
     147        gpio = of_find_node_by_phandle(rdy[0]); 
     148        if (!gpio) { 
     149                printk(KERN_ERR "rbppc_nand_probe: No GPIO<%x> node found\n", *rdy); 
     150                goto err; 
     151        } 
     152        if (of_address_to_resource(gpio, 0, &res)) { 
     153                printk(KERN_ERR "rbppc_nand_probe: No reg property in GPIO found\n"); 
     154                goto err; 
     155        } 
     156        info->gpo = ioremap_nocache(res.start, res.end - res.start + 1); 
     157 
     158        if (!of_address_to_resource(gpio, 1, &res)) { 
     159                info->gpi = ioremap_nocache(res.start, res.end - res.start + 1); 
     160        } else { 
     161                info->gpi = info->gpo; 
     162        } 
     163        of_node_put(gpio); 
     164 
     165        info->gpio_rdy = 1 << (31 - rdy[1]); 
     166        info->gpio_nce = 1 << (31 - nce[1]); 
     167        info->gpio_cle = 1 << (31 - cle[1]); 
     168        info->gpio_ale = 1 << (31 - ale[1]); 
     169        info->gpio_ctrls = info->gpio_nce | info->gpio_cle | info->gpio_ale; 
     170 
     171        nnand = of_find_node_by_name(NULL, "nnand"); 
     172        if (!nnand) { 
     173                printk("rbppc_nand_probe: No nNAND found\n"); 
     174                goto err; 
     175        } 
     176        if (of_address_to_resource(nnand, 0, &res)) { 
     177                printk("rbppc_nand_probe: No reg property in nNAND found\n"); 
     178                goto err; 
     179        } 
     180        of_node_put(nnand); 
     181        info->localbus = ioremap_nocache(res.start, res.end - res.start + 1); 
     182 
     183        if (of_address_to_resource(pdev->node, 0, &res)) { 
     184            printk("rbppc_nand_probe: No reg property found\n"); 
     185            goto err; 
     186        } 
     187        baddr = ioremap_nocache(res.start, res.end - res.start + 1); 
     188 
     189        memset(&rnand, 0, sizeof(rnand)); 
     190        rnand.cmd_ctrl = rbppc_nand_cmd_ctrl; 
     191        rnand.dev_ready = rbppc_nand_dev_ready; 
     192        rnand.read_buf = rbppc_nand_read_buf; 
     193        rnand.IO_ADDR_W = baddr; 
     194        rnand.IO_ADDR_R = baddr; 
     195        rnand.priv = info; 
     196 
     197        memset(&rmtd, 0, sizeof(rmtd)); 
     198        rnand.ecc.mode = NAND_ECC_SOFT; 
     199        rnand.ecc.layout = &rbppc_nand_oob_16; 
     200        rnand.chip_delay = 25; 
     201        rnand.options |= NAND_NO_AUTOINCR; 
     202        rmtd.priv = &rnand; 
     203        rmtd.owner = THIS_MODULE; 
     204 
     205        if (nand_scan(&rmtd, 1) && nand_scan(&rmtd, 1) && nand_scan(&rmtd, 1) && nand_scan(&rmtd, 1)) { 
     206                printk(KERN_ERR "rbppc_nand_probe: RouterBOARD NAND device not found\n"); 
     207                return -ENXIO; 
     208        } 
     209 
     210        add_mtd_partitions(&rmtd, rbppc_nand_partition_info, 2); 
     211        init_ok = 1; 
     212        return 0; 
     213 
     214err: 
     215        kfree(info); 
     216        return -1; 
     217} 
     218 
     219static struct of_device_id rbppc_nand_ids[] = { 
     220        { .name = "nand", }, 
     221        { }, 
     222}; 
     223 
     224static struct of_platform_driver rbppc_nand_driver = { 
     225        .name   = "nand", 
     226        .probe  = rbppc_nand_probe, 
     227        .match_table = rbppc_nand_ids, 
     228        .driver = { 
     229                .name = "rbppc-nand", 
     230                .owner = THIS_MODULE, 
     231        }, 
     232}; 
     233 
     234static int __init rbppc_nand_init(void) 
     235{ 
     236        return of_register_platform_driver(&rbppc_nand_driver); 
     237} 
     238 
     239static void __exit rbppc_nand_exit(void) 
     240{ 
     241        of_unregister_platform_driver(&rbppc_nand_driver); 
     242} 
     243 
     244MODULE_AUTHOR("Mikrotikls SIA"); 
     245MODULE_AUTHOR("Noah Fontes"); 
     246MODULE_AUTHOR("Michael Guntsche"); 
     247MODULE_DESCRIPTION("MikroTik RouterBOARD 600 series NAND driver"); 
     248MODULE_LICENSE("GPL"); 
     249MODULE_VERSION(DRV_VERSION); 
     250 
     251module_init(rbppc_nand_init); 
     252module_exit(rbppc_nand_exit); 
Note: See TracBrowser for help on using the repository browser.