Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * arch/arm/mach-orion5x/ts78xx-setup.c
0004  *
0005  * Maintainer: Alexander Clouter <alex@digriz.org.uk>
0006  */
0007 
0008 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0009 
0010 #include <linux/kernel.h>
0011 #include <linux/init.h>
0012 #include <linux/sysfs.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/mv643xx_eth.h>
0015 #include <linux/ata_platform.h>
0016 #include <linux/mtd/platnand.h>
0017 #include <linux/timeriomem-rng.h>
0018 #include <asm/mach-types.h>
0019 #include <asm/mach/arch.h>
0020 #include <asm/mach/map.h>
0021 #include "common.h"
0022 #include "mpp.h"
0023 #include "orion5x.h"
0024 #include "ts78xx-fpga.h"
0025 
0026 /*****************************************************************************
0027  * TS-78xx Info
0028  ****************************************************************************/
0029 
0030 /*
0031  * FPGA - lives where the PCI bus would be at ORION5X_PCI_MEM_PHYS_BASE
0032  */
0033 #define TS78XX_FPGA_REGS_PHYS_BASE  0xe8000000
0034 #define TS78XX_FPGA_REGS_VIRT_BASE  IOMEM(0xff900000)
0035 #define TS78XX_FPGA_REGS_SIZE       SZ_1M
0036 
0037 static struct ts78xx_fpga_data ts78xx_fpga = {
0038     .id     = 0,
0039     .state      = 1,
0040 /*  .supports   = ... - populated by ts78xx_fpga_supports() */
0041 };
0042 
0043 /*****************************************************************************
0044  * I/O Address Mapping
0045  ****************************************************************************/
0046 static struct map_desc ts78xx_io_desc[] __initdata = {
0047     {
0048         .virtual    = (unsigned long)TS78XX_FPGA_REGS_VIRT_BASE,
0049         .pfn        = __phys_to_pfn(TS78XX_FPGA_REGS_PHYS_BASE),
0050         .length     = TS78XX_FPGA_REGS_SIZE,
0051         .type       = MT_DEVICE,
0052     },
0053 };
0054 
0055 static void __init ts78xx_map_io(void)
0056 {
0057     orion5x_map_io();
0058     iotable_init(ts78xx_io_desc, ARRAY_SIZE(ts78xx_io_desc));
0059 }
0060 
0061 /*****************************************************************************
0062  * Ethernet
0063  ****************************************************************************/
0064 static struct mv643xx_eth_platform_data ts78xx_eth_data = {
0065     .phy_addr   = MV643XX_ETH_PHY_ADDR(0),
0066 };
0067 
0068 /*****************************************************************************
0069  * SATA
0070  ****************************************************************************/
0071 static struct mv_sata_platform_data ts78xx_sata_data = {
0072     .n_ports    = 2,
0073 };
0074 
0075 /*****************************************************************************
0076  * RTC M48T86 - nicked^Wborrowed from arch/arm/mach-ep93xx/ts72xx.c
0077  ****************************************************************************/
0078 #define TS_RTC_CTRL (TS78XX_FPGA_REGS_PHYS_BASE + 0x808)
0079 #define TS_RTC_DATA (TS78XX_FPGA_REGS_PHYS_BASE + 0x80c)
0080 
0081 static struct resource ts78xx_ts_rtc_resources[] = {
0082     DEFINE_RES_MEM(TS_RTC_CTRL, 0x01),
0083     DEFINE_RES_MEM(TS_RTC_DATA, 0x01),
0084 };
0085 
0086 static struct platform_device ts78xx_ts_rtc_device = {
0087     .name       = "rtc-m48t86",
0088     .id     = -1,
0089     .resource   = ts78xx_ts_rtc_resources,
0090     .num_resources  = ARRAY_SIZE(ts78xx_ts_rtc_resources),
0091 };
0092 
0093 static int ts78xx_ts_rtc_load(void)
0094 {
0095     int rc;
0096 
0097     if (ts78xx_fpga.supports.ts_rtc.init == 0) {
0098         rc = platform_device_register(&ts78xx_ts_rtc_device);
0099         if (!rc)
0100             ts78xx_fpga.supports.ts_rtc.init = 1;
0101     } else {
0102         rc = platform_device_add(&ts78xx_ts_rtc_device);
0103     }
0104 
0105     if (rc)
0106         pr_info("RTC could not be registered: %d\n", rc);
0107 
0108     return rc;
0109 }
0110 
0111 static void ts78xx_ts_rtc_unload(void)
0112 {
0113     platform_device_del(&ts78xx_ts_rtc_device);
0114 }
0115 
0116 /*****************************************************************************
0117  * NAND Flash
0118  ****************************************************************************/
0119 #define TS_NAND_CTRL    (TS78XX_FPGA_REGS_VIRT_BASE + 0x800)    /* VIRT */
0120 #define TS_NAND_DATA    (TS78XX_FPGA_REGS_PHYS_BASE + 0x804)    /* PHYS */
0121 
0122 /*
0123  * hardware specific access to control-lines
0124  *
0125  * ctrl:
0126  * NAND_NCE: bit 0 -> bit 2
0127  * NAND_CLE: bit 1 -> bit 1
0128  * NAND_ALE: bit 2 -> bit 0
0129  */
0130 static void ts78xx_ts_nand_cmd_ctrl(struct nand_chip *this, int cmd,
0131                     unsigned int ctrl)
0132 {
0133     if (ctrl & NAND_CTRL_CHANGE) {
0134         unsigned char bits;
0135 
0136         bits = (ctrl & NAND_NCE) << 2;
0137         bits |= ctrl & NAND_CLE;
0138         bits |= (ctrl & NAND_ALE) >> 2;
0139 
0140         writeb((readb(TS_NAND_CTRL) & ~0x7) | bits, TS_NAND_CTRL);
0141     }
0142 
0143     if (cmd != NAND_CMD_NONE)
0144         writeb(cmd, this->legacy.IO_ADDR_W);
0145 }
0146 
0147 static int ts78xx_ts_nand_dev_ready(struct nand_chip *chip)
0148 {
0149     return readb(TS_NAND_CTRL) & 0x20;
0150 }
0151 
0152 static void ts78xx_ts_nand_write_buf(struct nand_chip *chip,
0153                      const uint8_t *buf, int len)
0154 {
0155     void __iomem *io_base = chip->legacy.IO_ADDR_W;
0156     unsigned long off = ((unsigned long)buf & 3);
0157     int sz;
0158 
0159     if (off) {
0160         sz = min_t(int, 4 - off, len);
0161         writesb(io_base, buf, sz);
0162         buf += sz;
0163         len -= sz;
0164     }
0165 
0166     sz = len >> 2;
0167     if (sz) {
0168         u32 *buf32 = (u32 *)buf;
0169         writesl(io_base, buf32, sz);
0170         buf += sz << 2;
0171         len -= sz << 2;
0172     }
0173 
0174     if (len)
0175         writesb(io_base, buf, len);
0176 }
0177 
0178 static void ts78xx_ts_nand_read_buf(struct nand_chip *chip,
0179                     uint8_t *buf, int len)
0180 {
0181     void __iomem *io_base = chip->legacy.IO_ADDR_R;
0182     unsigned long off = ((unsigned long)buf & 3);
0183     int sz;
0184 
0185     if (off) {
0186         sz = min_t(int, 4 - off, len);
0187         readsb(io_base, buf, sz);
0188         buf += sz;
0189         len -= sz;
0190     }
0191 
0192     sz = len >> 2;
0193     if (sz) {
0194         u32 *buf32 = (u32 *)buf;
0195         readsl(io_base, buf32, sz);
0196         buf += sz << 2;
0197         len -= sz << 2;
0198     }
0199 
0200     if (len)
0201         readsb(io_base, buf, len);
0202 }
0203 
0204 static struct mtd_partition ts78xx_ts_nand_parts[] = {
0205     {
0206         .name       = "mbr",
0207         .offset     = 0,
0208         .size       = SZ_128K,
0209         .mask_flags = MTD_WRITEABLE,
0210     }, {
0211         .name       = "kernel",
0212         .offset     = MTDPART_OFS_APPEND,
0213         .size       = SZ_4M,
0214     }, {
0215         .name       = "initrd",
0216         .offset     = MTDPART_OFS_APPEND,
0217         .size       = SZ_4M,
0218     }, {
0219         .name       = "rootfs",
0220         .offset     = MTDPART_OFS_APPEND,
0221         .size       = MTDPART_SIZ_FULL,
0222     }
0223 };
0224 
0225 static struct platform_nand_data ts78xx_ts_nand_data = {
0226     .chip   = {
0227         .nr_chips       = 1,
0228         .partitions     = ts78xx_ts_nand_parts,
0229         .nr_partitions      = ARRAY_SIZE(ts78xx_ts_nand_parts),
0230         .chip_delay     = 15,
0231         .bbt_options        = NAND_BBT_USE_FLASH,
0232     },
0233     .ctrl   = {
0234         /*
0235          * The HW ECC offloading functions, used to give about a 9%
0236          * performance increase for 'dd if=/dev/mtdblockX' and 5% for
0237          * nanddump.  This all however was changed by git commit
0238          * e6cf5df1838c28bb060ac45b5585e48e71bbc740 so now there is
0239          * no performance advantage to be had so we no longer bother
0240          */
0241         .cmd_ctrl       = ts78xx_ts_nand_cmd_ctrl,
0242         .dev_ready      = ts78xx_ts_nand_dev_ready,
0243         .write_buf      = ts78xx_ts_nand_write_buf,
0244         .read_buf       = ts78xx_ts_nand_read_buf,
0245     },
0246 };
0247 
0248 static struct resource ts78xx_ts_nand_resources
0249             = DEFINE_RES_MEM(TS_NAND_DATA, 4);
0250 
0251 static struct platform_device ts78xx_ts_nand_device = {
0252     .name       = "gen_nand",
0253     .id     = -1,
0254     .dev        = {
0255         .platform_data  = &ts78xx_ts_nand_data,
0256     },
0257     .resource   = &ts78xx_ts_nand_resources,
0258     .num_resources  = 1,
0259 };
0260 
0261 static int ts78xx_ts_nand_load(void)
0262 {
0263     int rc;
0264 
0265     if (ts78xx_fpga.supports.ts_nand.init == 0) {
0266         rc = platform_device_register(&ts78xx_ts_nand_device);
0267         if (!rc)
0268             ts78xx_fpga.supports.ts_nand.init = 1;
0269     } else
0270         rc = platform_device_add(&ts78xx_ts_nand_device);
0271 
0272     if (rc)
0273         pr_info("NAND could not be registered: %d\n", rc);
0274     return rc;
0275 };
0276 
0277 static void ts78xx_ts_nand_unload(void)
0278 {
0279     platform_device_del(&ts78xx_ts_nand_device);
0280 }
0281 
0282 /*****************************************************************************
0283  * HW RNG
0284  ****************************************************************************/
0285 #define TS_RNG_DATA (TS78XX_FPGA_REGS_PHYS_BASE | 0x044)
0286 
0287 static struct resource ts78xx_ts_rng_resource
0288             = DEFINE_RES_MEM(TS_RNG_DATA, 4);
0289 
0290 static struct timeriomem_rng_data ts78xx_ts_rng_data = {
0291     .period     = 1000000, /* one second */
0292 };
0293 
0294 static struct platform_device ts78xx_ts_rng_device = {
0295     .name       = "timeriomem_rng",
0296     .id     = -1,
0297     .dev        = {
0298         .platform_data  = &ts78xx_ts_rng_data,
0299     },
0300     .resource   = &ts78xx_ts_rng_resource,
0301     .num_resources  = 1,
0302 };
0303 
0304 static int ts78xx_ts_rng_load(void)
0305 {
0306     int rc;
0307 
0308     if (ts78xx_fpga.supports.ts_rng.init == 0) {
0309         rc = platform_device_register(&ts78xx_ts_rng_device);
0310         if (!rc)
0311             ts78xx_fpga.supports.ts_rng.init = 1;
0312     } else
0313         rc = platform_device_add(&ts78xx_ts_rng_device);
0314 
0315     if (rc)
0316         pr_info("RNG could not be registered: %d\n", rc);
0317     return rc;
0318 };
0319 
0320 static void ts78xx_ts_rng_unload(void)
0321 {
0322     platform_device_del(&ts78xx_ts_rng_device);
0323 }
0324 
0325 /*****************************************************************************
0326  * FPGA 'hotplug' support code
0327  ****************************************************************************/
0328 static void ts78xx_fpga_devices_zero_init(void)
0329 {
0330     ts78xx_fpga.supports.ts_rtc.init = 0;
0331     ts78xx_fpga.supports.ts_nand.init = 0;
0332     ts78xx_fpga.supports.ts_rng.init = 0;
0333 }
0334 
0335 static void ts78xx_fpga_supports(void)
0336 {
0337     /* TODO: put this 'table' into ts78xx-fpga.h */
0338     switch (ts78xx_fpga.id) {
0339     case TS7800_REV_1:
0340     case TS7800_REV_2:
0341     case TS7800_REV_3:
0342     case TS7800_REV_4:
0343     case TS7800_REV_5:
0344     case TS7800_REV_6:
0345     case TS7800_REV_7:
0346     case TS7800_REV_8:
0347     case TS7800_REV_9:
0348         ts78xx_fpga.supports.ts_rtc.present = 1;
0349         ts78xx_fpga.supports.ts_nand.present = 1;
0350         ts78xx_fpga.supports.ts_rng.present = 1;
0351         break;
0352     default:
0353         /* enable devices if magic matches */
0354         switch ((ts78xx_fpga.id >> 8) & 0xffffff) {
0355         case TS7800_FPGA_MAGIC:
0356             pr_warn("unrecognised FPGA revision 0x%.2x\n",
0357                 ts78xx_fpga.id & 0xff);
0358             ts78xx_fpga.supports.ts_rtc.present = 1;
0359             ts78xx_fpga.supports.ts_nand.present = 1;
0360             ts78xx_fpga.supports.ts_rng.present = 1;
0361             break;
0362         default:
0363             ts78xx_fpga.supports.ts_rtc.present = 0;
0364             ts78xx_fpga.supports.ts_nand.present = 0;
0365             ts78xx_fpga.supports.ts_rng.present = 0;
0366         }
0367     }
0368 }
0369 
0370 static int ts78xx_fpga_load_devices(void)
0371 {
0372     int tmp, ret = 0;
0373 
0374     if (ts78xx_fpga.supports.ts_rtc.present == 1) {
0375         tmp = ts78xx_ts_rtc_load();
0376         if (tmp)
0377             ts78xx_fpga.supports.ts_rtc.present = 0;
0378         ret |= tmp;
0379     }
0380     if (ts78xx_fpga.supports.ts_nand.present == 1) {
0381         tmp = ts78xx_ts_nand_load();
0382         if (tmp)
0383             ts78xx_fpga.supports.ts_nand.present = 0;
0384         ret |= tmp;
0385     }
0386     if (ts78xx_fpga.supports.ts_rng.present == 1) {
0387         tmp = ts78xx_ts_rng_load();
0388         if (tmp)
0389             ts78xx_fpga.supports.ts_rng.present = 0;
0390         ret |= tmp;
0391     }
0392 
0393     return ret;
0394 }
0395 
0396 static int ts78xx_fpga_unload_devices(void)
0397 {
0398 
0399     if (ts78xx_fpga.supports.ts_rtc.present == 1)
0400         ts78xx_ts_rtc_unload();
0401     if (ts78xx_fpga.supports.ts_nand.present == 1)
0402         ts78xx_ts_nand_unload();
0403     if (ts78xx_fpga.supports.ts_rng.present == 1)
0404         ts78xx_ts_rng_unload();
0405 
0406     return 0;
0407 }
0408 
0409 static int ts78xx_fpga_load(void)
0410 {
0411     ts78xx_fpga.id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
0412 
0413     pr_info("FPGA magic=0x%.6x, rev=0x%.2x\n",
0414             (ts78xx_fpga.id >> 8) & 0xffffff,
0415             ts78xx_fpga.id & 0xff);
0416 
0417     ts78xx_fpga_supports();
0418 
0419     if (ts78xx_fpga_load_devices()) {
0420         ts78xx_fpga.state = -1;
0421         return -EBUSY;
0422     }
0423 
0424     return 0;
0425 };
0426 
0427 static int ts78xx_fpga_unload(void)
0428 {
0429     unsigned int fpga_id;
0430 
0431     fpga_id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
0432 
0433     /*
0434      * There does not seem to be a feasible way to block access to the GPIO
0435      * pins from userspace (/dev/mem).  This if clause should hopefully warn
0436      * those foolish enough not to follow 'policy' :)
0437      *
0438      * UrJTAG SVN since r1381 can be used to reprogram the FPGA
0439      */
0440     if (ts78xx_fpga.id != fpga_id) {
0441         pr_err("FPGA magic/rev mismatch\n"
0442             "TS-78xx FPGA: was 0x%.6x/%.2x but now 0x%.6x/%.2x\n",
0443             (ts78xx_fpga.id >> 8) & 0xffffff, ts78xx_fpga.id & 0xff,
0444             (fpga_id >> 8) & 0xffffff, fpga_id & 0xff);
0445         ts78xx_fpga.state = -1;
0446         return -EBUSY;
0447     }
0448 
0449     if (ts78xx_fpga_unload_devices()) {
0450         ts78xx_fpga.state = -1;
0451         return -EBUSY;
0452     }
0453 
0454     return 0;
0455 };
0456 
0457 static ssize_t ts78xx_fpga_show(struct kobject *kobj,
0458             struct kobj_attribute *attr, char *buf)
0459 {
0460     if (ts78xx_fpga.state < 0)
0461         return sprintf(buf, "borked\n");
0462 
0463     return sprintf(buf, "%s\n", (ts78xx_fpga.state) ? "online" : "offline");
0464 }
0465 
0466 static ssize_t ts78xx_fpga_store(struct kobject *kobj,
0467             struct kobj_attribute *attr, const char *buf, size_t n)
0468 {
0469     int value, ret;
0470 
0471     if (ts78xx_fpga.state < 0) {
0472         pr_err("FPGA borked, you must powercycle ASAP\n");
0473         return -EBUSY;
0474     }
0475 
0476     if (strncmp(buf, "online", sizeof("online") - 1) == 0)
0477         value = 1;
0478     else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
0479         value = 0;
0480     else
0481         return -EINVAL;
0482 
0483     if (ts78xx_fpga.state == value)
0484         return n;
0485 
0486     ret = (ts78xx_fpga.state == 0)
0487         ? ts78xx_fpga_load()
0488         : ts78xx_fpga_unload();
0489 
0490     if (!(ret < 0))
0491         ts78xx_fpga.state = value;
0492 
0493     return n;
0494 }
0495 
0496 static struct kobj_attribute ts78xx_fpga_attr =
0497     __ATTR(ts78xx_fpga, 0644, ts78xx_fpga_show, ts78xx_fpga_store);
0498 
0499 /*****************************************************************************
0500  * General Setup
0501  ****************************************************************************/
0502 static unsigned int ts78xx_mpp_modes[] __initdata = {
0503     MPP0_UNUSED,
0504     MPP1_GPIO,      /* JTAG Clock */
0505     MPP2_GPIO,      /* JTAG Data In */
0506     MPP3_GPIO,      /* Lat ECP2 256 FPGA - PB2B */
0507     MPP4_GPIO,      /* JTAG Data Out */
0508     MPP5_GPIO,      /* JTAG TMS */
0509     MPP6_GPIO,      /* Lat ECP2 256 FPGA - PB31A_CLK4+ */
0510     MPP7_GPIO,      /* Lat ECP2 256 FPGA - PB22B */
0511     MPP8_UNUSED,
0512     MPP9_UNUSED,
0513     MPP10_UNUSED,
0514     MPP11_UNUSED,
0515     MPP12_UNUSED,
0516     MPP13_UNUSED,
0517     MPP14_UNUSED,
0518     MPP15_UNUSED,
0519     MPP16_UART,
0520     MPP17_UART,
0521     MPP18_UART,
0522     MPP19_UART,
0523     /*
0524      * MPP[20] PCI Clock Out 1
0525      * MPP[21] PCI Clock Out 0
0526      * MPP[22] Unused
0527      * MPP[23] Unused
0528      * MPP[24] Unused
0529      * MPP[25] Unused
0530      */
0531     0,
0532 };
0533 
0534 static void __init ts78xx_init(void)
0535 {
0536     int ret;
0537 
0538     /*
0539      * Setup basic Orion functions. Need to be called early.
0540      */
0541     orion5x_init();
0542 
0543     orion5x_mpp_conf(ts78xx_mpp_modes);
0544 
0545     /*
0546      * Configure peripherals.
0547      */
0548     orion5x_ehci0_init();
0549     orion5x_ehci1_init();
0550     orion5x_eth_init(&ts78xx_eth_data);
0551     orion5x_sata_init(&ts78xx_sata_data);
0552     orion5x_uart0_init();
0553     orion5x_uart1_init();
0554     orion5x_xor_init();
0555 
0556     /* FPGA init */
0557     ts78xx_fpga_devices_zero_init();
0558     ret = ts78xx_fpga_load();
0559     ret = sysfs_create_file(firmware_kobj, &ts78xx_fpga_attr.attr);
0560     if (ret)
0561         pr_err("sysfs_create_file failed: %d\n", ret);
0562 }
0563 
0564 MACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC")
0565     /* Maintainer: Alexander Clouter <alex@digriz.org.uk> */
0566     .atag_offset    = 0x100,
0567     .nr_irqs    = ORION5X_NR_IRQS,
0568     .init_machine   = ts78xx_init,
0569     .map_io     = ts78xx_map_io,
0570     .init_early = orion5x_init_early,
0571     .init_irq   = orion5x_init_irq,
0572     .init_time  = orion5x_timer_init,
0573     .restart    = orion5x_restart,
0574 MACHINE_END