18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2011, Netlogic Microsystems. 38c2ecf20Sopenharmony_ci * Copyright 2004, Matt Porter <mporter@kernel.crashing.org> 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This file is licensed under the terms of the GNU General Public 68c2ecf20Sopenharmony_ci * License version 2. This program is licensed "as is" without any 78c2ecf20Sopenharmony_ci * warranty of any kind, whether express or implied. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/device.h> 118c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/io.h> 158c2ecf20Sopenharmony_ci#include <linux/delay.h> 168c2ecf20Sopenharmony_ci#include <linux/ioport.h> 178c2ecf20Sopenharmony_ci#include <linux/resource.h> 188c2ecf20Sopenharmony_ci#include <linux/spi/flash.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <linux/mtd/mtd.h> 218c2ecf20Sopenharmony_ci#include <linux/mtd/physmap.h> 228c2ecf20Sopenharmony_ci#include <linux/mtd/platnand.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <asm/netlogic/haldefs.h> 258c2ecf20Sopenharmony_ci#include <asm/netlogic/xlr/iomap.h> 268c2ecf20Sopenharmony_ci#include <asm/netlogic/xlr/flash.h> 278c2ecf20Sopenharmony_ci#include <asm/netlogic/xlr/bridge.h> 288c2ecf20Sopenharmony_ci#include <asm/netlogic/xlr/gpio.h> 298c2ecf20Sopenharmony_ci#include <asm/netlogic/xlr/xlr.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* 328c2ecf20Sopenharmony_ci * Default NOR partition layout 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_cistatic struct mtd_partition xlr_nor_parts[] = { 358c2ecf20Sopenharmony_ci { 368c2ecf20Sopenharmony_ci .name = "User FS", 378c2ecf20Sopenharmony_ci .offset = 0x800000, 388c2ecf20Sopenharmony_ci .size = MTDPART_SIZ_FULL, 398c2ecf20Sopenharmony_ci } 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* 438c2ecf20Sopenharmony_ci * Default NAND partition layout 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_cistatic struct mtd_partition xlr_nand_parts[] = { 468c2ecf20Sopenharmony_ci { 478c2ecf20Sopenharmony_ci .name = "Root Filesystem", 488c2ecf20Sopenharmony_ci .offset = 64 * 64 * 2048, 498c2ecf20Sopenharmony_ci .size = 432 * 64 * 2048, 508c2ecf20Sopenharmony_ci }, 518c2ecf20Sopenharmony_ci { 528c2ecf20Sopenharmony_ci .name = "Home Filesystem", 538c2ecf20Sopenharmony_ci .offset = MTDPART_OFS_APPEND, 548c2ecf20Sopenharmony_ci .size = MTDPART_SIZ_FULL, 558c2ecf20Sopenharmony_ci }, 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* Use PHYSMAP flash for NOR */ 598c2ecf20Sopenharmony_cistruct physmap_flash_data xlr_nor_data = { 608c2ecf20Sopenharmony_ci .width = 2, 618c2ecf20Sopenharmony_ci .parts = xlr_nor_parts, 628c2ecf20Sopenharmony_ci .nr_parts = ARRAY_SIZE(xlr_nor_parts), 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic struct resource xlr_nor_res[] = { 668c2ecf20Sopenharmony_ci { 678c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 688c2ecf20Sopenharmony_ci }, 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic struct platform_device xlr_nor_dev = { 728c2ecf20Sopenharmony_ci .name = "physmap-flash", 738c2ecf20Sopenharmony_ci .dev = { 748c2ecf20Sopenharmony_ci .platform_data = &xlr_nor_data, 758c2ecf20Sopenharmony_ci }, 768c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(xlr_nor_res), 778c2ecf20Sopenharmony_ci .resource = xlr_nor_res, 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* 818c2ecf20Sopenharmony_ci * Use "gen_nand" driver for NAND flash 828c2ecf20Sopenharmony_ci * 838c2ecf20Sopenharmony_ci * There seems to be no way to store a private pointer containing 848c2ecf20Sopenharmony_ci * platform specific info in gen_nand drivier. We will use a global 858c2ecf20Sopenharmony_ci * struct for now, since we currently have only one NAND chip per board. 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_cistruct xlr_nand_flash_priv { 888c2ecf20Sopenharmony_ci int cs; 898c2ecf20Sopenharmony_ci uint64_t flash_mmio; 908c2ecf20Sopenharmony_ci}; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic struct xlr_nand_flash_priv nand_priv; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic void xlr_nand_ctrl(struct nand_chip *chip, int cmd, 958c2ecf20Sopenharmony_ci unsigned int ctrl) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci if (ctrl & NAND_CLE) 988c2ecf20Sopenharmony_ci nlm_write_reg(nand_priv.flash_mmio, 998c2ecf20Sopenharmony_ci FLASH_NAND_CLE(nand_priv.cs), cmd); 1008c2ecf20Sopenharmony_ci else if (ctrl & NAND_ALE) 1018c2ecf20Sopenharmony_ci nlm_write_reg(nand_priv.flash_mmio, 1028c2ecf20Sopenharmony_ci FLASH_NAND_ALE(nand_priv.cs), cmd); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistruct platform_nand_data xlr_nand_data = { 1068c2ecf20Sopenharmony_ci .chip = { 1078c2ecf20Sopenharmony_ci .nr_chips = 1, 1088c2ecf20Sopenharmony_ci .nr_partitions = ARRAY_SIZE(xlr_nand_parts), 1098c2ecf20Sopenharmony_ci .chip_delay = 50, 1108c2ecf20Sopenharmony_ci .partitions = xlr_nand_parts, 1118c2ecf20Sopenharmony_ci }, 1128c2ecf20Sopenharmony_ci .ctrl = { 1138c2ecf20Sopenharmony_ci .cmd_ctrl = xlr_nand_ctrl, 1148c2ecf20Sopenharmony_ci }, 1158c2ecf20Sopenharmony_ci}; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic struct resource xlr_nand_res[] = { 1188c2ecf20Sopenharmony_ci { 1198c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 1208c2ecf20Sopenharmony_ci }, 1218c2ecf20Sopenharmony_ci}; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic struct platform_device xlr_nand_dev = { 1248c2ecf20Sopenharmony_ci .name = "gen_nand", 1258c2ecf20Sopenharmony_ci .id = -1, 1268c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(xlr_nand_res), 1278c2ecf20Sopenharmony_ci .resource = xlr_nand_res, 1288c2ecf20Sopenharmony_ci .dev = { 1298c2ecf20Sopenharmony_ci .platform_data = &xlr_nand_data, 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci}; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/* 1348c2ecf20Sopenharmony_ci * XLR/XLS supports upto 8 devices on its FLASH interface. The value in 1358c2ecf20Sopenharmony_ci * FLASH_BAR (on the MEM/IO bridge) gives the base for mapping all the 1368c2ecf20Sopenharmony_ci * flash devices. 1378c2ecf20Sopenharmony_ci * Under this, each flash device has an offset and size given by the 1388c2ecf20Sopenharmony_ci * CSBASE_ADDR and CSBASE_MASK registers for the device. 1398c2ecf20Sopenharmony_ci * 1408c2ecf20Sopenharmony_ci * The CSBASE_ registers are expected to be setup by the bootloader. 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_cistatic void setup_flash_resource(uint64_t flash_mmio, 1438c2ecf20Sopenharmony_ci uint64_t flash_map_base, int cs, struct resource *res) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci u32 base, mask; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci base = nlm_read_reg(flash_mmio, FLASH_CSBASE_ADDR(cs)); 1488c2ecf20Sopenharmony_ci mask = nlm_read_reg(flash_mmio, FLASH_CSADDR_MASK(cs)); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci res->start = flash_map_base + ((unsigned long)base << 16); 1518c2ecf20Sopenharmony_ci res->end = res->start + (mask + 1) * 64 * 1024; 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic int __init xlr_flash_init(void) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci uint64_t gpio_mmio, flash_mmio, flash_map_base; 1578c2ecf20Sopenharmony_ci u32 gpio_resetcfg, flash_bar; 1588c2ecf20Sopenharmony_ci int cs, boot_nand, boot_nor; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci /* Flash address bits 39:24 is in bridge flash BAR */ 1618c2ecf20Sopenharmony_ci flash_bar = nlm_read_reg(nlm_io_base, BRIDGE_FLASH_BAR); 1628c2ecf20Sopenharmony_ci flash_map_base = (flash_bar & 0xffff0000) << 8; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci gpio_mmio = nlm_mmio_base(NETLOGIC_IO_GPIO_OFFSET); 1658c2ecf20Sopenharmony_ci flash_mmio = nlm_mmio_base(NETLOGIC_IO_FLASH_OFFSET); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci /* Get the chip reset config */ 1688c2ecf20Sopenharmony_ci gpio_resetcfg = nlm_read_reg(gpio_mmio, GPIO_PWRON_RESET_CFG_REG); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* Check for boot flash type */ 1718c2ecf20Sopenharmony_ci boot_nor = boot_nand = 0; 1728c2ecf20Sopenharmony_ci if (nlm_chip_is_xls()) { 1738c2ecf20Sopenharmony_ci /* On XLS, check boot from NAND bit (GPIO reset reg bit 16) */ 1748c2ecf20Sopenharmony_ci if (gpio_resetcfg & (1 << 16)) 1758c2ecf20Sopenharmony_ci boot_nand = 1; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci /* check boot from PCMCIA, (GPIO reset reg bit 15 */ 1788c2ecf20Sopenharmony_ci if ((gpio_resetcfg & (1 << 15)) == 0) 1798c2ecf20Sopenharmony_ci boot_nor = 1; /* not set, booted from NOR */ 1808c2ecf20Sopenharmony_ci } else { /* XLR */ 1818c2ecf20Sopenharmony_ci /* check boot from PCMCIA (bit 16 in GPIO reset on XLR) */ 1828c2ecf20Sopenharmony_ci if ((gpio_resetcfg & (1 << 16)) == 0) 1838c2ecf20Sopenharmony_ci boot_nor = 1; /* not set, booted from NOR */ 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* boot flash at chip select 0 */ 1878c2ecf20Sopenharmony_ci cs = 0; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (boot_nand) { 1908c2ecf20Sopenharmony_ci nand_priv.cs = cs; 1918c2ecf20Sopenharmony_ci nand_priv.flash_mmio = flash_mmio; 1928c2ecf20Sopenharmony_ci setup_flash_resource(flash_mmio, flash_map_base, cs, 1938c2ecf20Sopenharmony_ci xlr_nand_res); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci /* Initialize NAND flash at CS 0 */ 1968c2ecf20Sopenharmony_ci nlm_write_reg(flash_mmio, FLASH_CSDEV_PARM(cs), 1978c2ecf20Sopenharmony_ci FLASH_NAND_CSDEV_PARAM); 1988c2ecf20Sopenharmony_ci nlm_write_reg(flash_mmio, FLASH_CSTIME_PARMA(cs), 1998c2ecf20Sopenharmony_ci FLASH_NAND_CSTIME_PARAMA); 2008c2ecf20Sopenharmony_ci nlm_write_reg(flash_mmio, FLASH_CSTIME_PARMB(cs), 2018c2ecf20Sopenharmony_ci FLASH_NAND_CSTIME_PARAMB); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci pr_info("ChipSelect %d: NAND Flash %pR\n", cs, xlr_nand_res); 2048c2ecf20Sopenharmony_ci return platform_device_register(&xlr_nand_dev); 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (boot_nor) { 2088c2ecf20Sopenharmony_ci setup_flash_resource(flash_mmio, flash_map_base, cs, 2098c2ecf20Sopenharmony_ci xlr_nor_res); 2108c2ecf20Sopenharmony_ci pr_info("ChipSelect %d: NOR Flash %pR\n", cs, xlr_nor_res); 2118c2ecf20Sopenharmony_ci return platform_device_register(&xlr_nor_dev); 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci return 0; 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ciarch_initcall(xlr_flash_init); 217