162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * QNAP TS-109/TS-209 Board Setup 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Maintainer: Byron Bradley <byron.bbradley@gmail.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#include <linux/gpio.h> 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/platform_device.h> 1162306a36Sopenharmony_ci#include <linux/pci.h> 1262306a36Sopenharmony_ci#include <linux/irq.h> 1362306a36Sopenharmony_ci#include <linux/mtd/physmap.h> 1462306a36Sopenharmony_ci#include <linux/mtd/rawnand.h> 1562306a36Sopenharmony_ci#include <linux/mv643xx_eth.h> 1662306a36Sopenharmony_ci#include <linux/gpio_keys.h> 1762306a36Sopenharmony_ci#include <linux/input.h> 1862306a36Sopenharmony_ci#include <linux/i2c.h> 1962306a36Sopenharmony_ci#include <linux/serial_reg.h> 2062306a36Sopenharmony_ci#include <linux/ata_platform.h> 2162306a36Sopenharmony_ci#include <asm/mach-types.h> 2262306a36Sopenharmony_ci#include <asm/mach/arch.h> 2362306a36Sopenharmony_ci#include <asm/mach/pci.h> 2462306a36Sopenharmony_ci#include "common.h" 2562306a36Sopenharmony_ci#include "mpp.h" 2662306a36Sopenharmony_ci#include "orion5x.h" 2762306a36Sopenharmony_ci#include "tsx09-common.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define QNAP_TS209_NOR_BOOT_BASE 0xf4000000 3062306a36Sopenharmony_ci#define QNAP_TS209_NOR_BOOT_SIZE SZ_8M 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/**************************************************************************** 3362306a36Sopenharmony_ci * 8MiB NOR flash. The struct mtd_partition is not in the same order as the 3462306a36Sopenharmony_ci * partitions on the device because we want to keep compatibility with 3562306a36Sopenharmony_ci * existing QNAP firmware. 3662306a36Sopenharmony_ci * 3762306a36Sopenharmony_ci * Layout as used by QNAP: 3862306a36Sopenharmony_ci * [2] 0x00000000-0x00200000 : "Kernel" 3962306a36Sopenharmony_ci * [3] 0x00200000-0x00600000 : "RootFS1" 4062306a36Sopenharmony_ci * [4] 0x00600000-0x00700000 : "RootFS2" 4162306a36Sopenharmony_ci * [6] 0x00700000-0x00760000 : "NAS Config" (read-only) 4262306a36Sopenharmony_ci * [5] 0x00760000-0x00780000 : "U-Boot Config" 4362306a36Sopenharmony_ci * [1] 0x00780000-0x00800000 : "U-Boot" (read-only) 4462306a36Sopenharmony_ci ***************************************************************************/ 4562306a36Sopenharmony_cistatic struct mtd_partition qnap_ts209_partitions[] = { 4662306a36Sopenharmony_ci { 4762306a36Sopenharmony_ci .name = "U-Boot", 4862306a36Sopenharmony_ci .size = 0x00080000, 4962306a36Sopenharmony_ci .offset = 0x00780000, 5062306a36Sopenharmony_ci .mask_flags = MTD_WRITEABLE, 5162306a36Sopenharmony_ci }, { 5262306a36Sopenharmony_ci .name = "Kernel", 5362306a36Sopenharmony_ci .size = 0x00200000, 5462306a36Sopenharmony_ci .offset = 0, 5562306a36Sopenharmony_ci }, { 5662306a36Sopenharmony_ci .name = "RootFS1", 5762306a36Sopenharmony_ci .size = 0x00400000, 5862306a36Sopenharmony_ci .offset = 0x00200000, 5962306a36Sopenharmony_ci }, { 6062306a36Sopenharmony_ci .name = "RootFS2", 6162306a36Sopenharmony_ci .size = 0x00100000, 6262306a36Sopenharmony_ci .offset = 0x00600000, 6362306a36Sopenharmony_ci }, { 6462306a36Sopenharmony_ci .name = "U-Boot Config", 6562306a36Sopenharmony_ci .size = 0x00020000, 6662306a36Sopenharmony_ci .offset = 0x00760000, 6762306a36Sopenharmony_ci }, { 6862306a36Sopenharmony_ci .name = "NAS Config", 6962306a36Sopenharmony_ci .size = 0x00060000, 7062306a36Sopenharmony_ci .offset = 0x00700000, 7162306a36Sopenharmony_ci .mask_flags = MTD_WRITEABLE, 7262306a36Sopenharmony_ci }, 7362306a36Sopenharmony_ci}; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic struct physmap_flash_data qnap_ts209_nor_flash_data = { 7662306a36Sopenharmony_ci .width = 1, 7762306a36Sopenharmony_ci .parts = qnap_ts209_partitions, 7862306a36Sopenharmony_ci .nr_parts = ARRAY_SIZE(qnap_ts209_partitions) 7962306a36Sopenharmony_ci}; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic struct resource qnap_ts209_nor_flash_resource = { 8262306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 8362306a36Sopenharmony_ci .start = QNAP_TS209_NOR_BOOT_BASE, 8462306a36Sopenharmony_ci .end = QNAP_TS209_NOR_BOOT_BASE + QNAP_TS209_NOR_BOOT_SIZE - 1, 8562306a36Sopenharmony_ci}; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic struct platform_device qnap_ts209_nor_flash = { 8862306a36Sopenharmony_ci .name = "physmap-flash", 8962306a36Sopenharmony_ci .id = 0, 9062306a36Sopenharmony_ci .dev = { 9162306a36Sopenharmony_ci .platform_data = &qnap_ts209_nor_flash_data, 9262306a36Sopenharmony_ci }, 9362306a36Sopenharmony_ci .resource = &qnap_ts209_nor_flash_resource, 9462306a36Sopenharmony_ci .num_resources = 1, 9562306a36Sopenharmony_ci}; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/***************************************************************************** 9862306a36Sopenharmony_ci * PCI 9962306a36Sopenharmony_ci ****************************************************************************/ 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci#define QNAP_TS209_PCI_SLOT0_OFFS 7 10262306a36Sopenharmony_ci#define QNAP_TS209_PCI_SLOT0_IRQ_PIN 6 10362306a36Sopenharmony_ci#define QNAP_TS209_PCI_SLOT1_IRQ_PIN 7 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic void __init qnap_ts209_pci_preinit(void) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci int pin; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* 11062306a36Sopenharmony_ci * Configure PCI GPIO IRQ pins 11162306a36Sopenharmony_ci */ 11262306a36Sopenharmony_ci pin = QNAP_TS209_PCI_SLOT0_IRQ_PIN; 11362306a36Sopenharmony_ci if (gpio_request(pin, "PCI Int1") == 0) { 11462306a36Sopenharmony_ci if (gpio_direction_input(pin) == 0) { 11562306a36Sopenharmony_ci irq_set_irq_type(gpio_to_irq(pin), IRQ_TYPE_LEVEL_LOW); 11662306a36Sopenharmony_ci } else { 11762306a36Sopenharmony_ci printk(KERN_ERR "qnap_ts209_pci_preinit failed to " 11862306a36Sopenharmony_ci "set_irq_type pin %d\n", pin); 11962306a36Sopenharmony_ci gpio_free(pin); 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci } else { 12262306a36Sopenharmony_ci printk(KERN_ERR "qnap_ts209_pci_preinit failed to gpio_request " 12362306a36Sopenharmony_ci "%d\n", pin); 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci pin = QNAP_TS209_PCI_SLOT1_IRQ_PIN; 12762306a36Sopenharmony_ci if (gpio_request(pin, "PCI Int2") == 0) { 12862306a36Sopenharmony_ci if (gpio_direction_input(pin) == 0) { 12962306a36Sopenharmony_ci irq_set_irq_type(gpio_to_irq(pin), IRQ_TYPE_LEVEL_LOW); 13062306a36Sopenharmony_ci } else { 13162306a36Sopenharmony_ci printk(KERN_ERR "qnap_ts209_pci_preinit failed " 13262306a36Sopenharmony_ci "to set_irq_type pin %d\n", pin); 13362306a36Sopenharmony_ci gpio_free(pin); 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci } else { 13662306a36Sopenharmony_ci printk(KERN_ERR "qnap_ts209_pci_preinit failed to gpio_request " 13762306a36Sopenharmony_ci "%d\n", pin); 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic int __init qnap_ts209_pci_map_irq(const struct pci_dev *dev, u8 slot, 14262306a36Sopenharmony_ci u8 pin) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci int irq; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* 14762306a36Sopenharmony_ci * Check for devices with hard-wired IRQs. 14862306a36Sopenharmony_ci */ 14962306a36Sopenharmony_ci irq = orion5x_pci_map_irq(dev, slot, pin); 15062306a36Sopenharmony_ci if (irq != -1) 15162306a36Sopenharmony_ci return irq; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* 15462306a36Sopenharmony_ci * PCI IRQs are connected via GPIOs. 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_ci switch (slot - QNAP_TS209_PCI_SLOT0_OFFS) { 15762306a36Sopenharmony_ci case 0: 15862306a36Sopenharmony_ci return gpio_to_irq(QNAP_TS209_PCI_SLOT0_IRQ_PIN); 15962306a36Sopenharmony_ci case 1: 16062306a36Sopenharmony_ci return gpio_to_irq(QNAP_TS209_PCI_SLOT1_IRQ_PIN); 16162306a36Sopenharmony_ci default: 16262306a36Sopenharmony_ci return -1; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic struct hw_pci qnap_ts209_pci __initdata = { 16762306a36Sopenharmony_ci .nr_controllers = 2, 16862306a36Sopenharmony_ci .preinit = qnap_ts209_pci_preinit, 16962306a36Sopenharmony_ci .setup = orion5x_pci_sys_setup, 17062306a36Sopenharmony_ci .scan = orion5x_pci_sys_scan_bus, 17162306a36Sopenharmony_ci .map_irq = qnap_ts209_pci_map_irq, 17262306a36Sopenharmony_ci}; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic int __init qnap_ts209_pci_init(void) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci if (machine_is_ts209()) 17762306a36Sopenharmony_ci pci_common_init(&qnap_ts209_pci); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return 0; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cisubsys_initcall(qnap_ts209_pci_init); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci/***************************************************************************** 18562306a36Sopenharmony_ci * RTC S35390A on I2C bus 18662306a36Sopenharmony_ci ****************************************************************************/ 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci#define TS209_RTC_GPIO 3 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic struct i2c_board_info __initdata qnap_ts209_i2c_rtc = { 19162306a36Sopenharmony_ci I2C_BOARD_INFO("s35390a", 0x30), 19262306a36Sopenharmony_ci .irq = 0, 19362306a36Sopenharmony_ci}; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci/**************************************************************************** 19662306a36Sopenharmony_ci * GPIO Attached Keys 19762306a36Sopenharmony_ci * Power button is attached to the PIC microcontroller 19862306a36Sopenharmony_ci ****************************************************************************/ 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci#define QNAP_TS209_GPIO_KEY_MEDIA 1 20162306a36Sopenharmony_ci#define QNAP_TS209_GPIO_KEY_RESET 2 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic struct gpio_keys_button qnap_ts209_buttons[] = { 20462306a36Sopenharmony_ci { 20562306a36Sopenharmony_ci .code = KEY_COPY, 20662306a36Sopenharmony_ci .gpio = QNAP_TS209_GPIO_KEY_MEDIA, 20762306a36Sopenharmony_ci .desc = "USB Copy Button", 20862306a36Sopenharmony_ci .active_low = 1, 20962306a36Sopenharmony_ci }, { 21062306a36Sopenharmony_ci .code = KEY_RESTART, 21162306a36Sopenharmony_ci .gpio = QNAP_TS209_GPIO_KEY_RESET, 21262306a36Sopenharmony_ci .desc = "Reset Button", 21362306a36Sopenharmony_ci .active_low = 1, 21462306a36Sopenharmony_ci }, 21562306a36Sopenharmony_ci}; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic struct gpio_keys_platform_data qnap_ts209_button_data = { 21862306a36Sopenharmony_ci .buttons = qnap_ts209_buttons, 21962306a36Sopenharmony_ci .nbuttons = ARRAY_SIZE(qnap_ts209_buttons), 22062306a36Sopenharmony_ci}; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic struct platform_device qnap_ts209_button_device = { 22362306a36Sopenharmony_ci .name = "gpio-keys", 22462306a36Sopenharmony_ci .id = -1, 22562306a36Sopenharmony_ci .num_resources = 0, 22662306a36Sopenharmony_ci .dev = { 22762306a36Sopenharmony_ci .platform_data = &qnap_ts209_button_data, 22862306a36Sopenharmony_ci }, 22962306a36Sopenharmony_ci}; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci/***************************************************************************** 23262306a36Sopenharmony_ci * SATA 23362306a36Sopenharmony_ci ****************************************************************************/ 23462306a36Sopenharmony_cistatic struct mv_sata_platform_data qnap_ts209_sata_data = { 23562306a36Sopenharmony_ci .n_ports = 2, 23662306a36Sopenharmony_ci}; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci/***************************************************************************** 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci * General Setup 24162306a36Sopenharmony_ci ****************************************************************************/ 24262306a36Sopenharmony_cistatic unsigned int ts209_mpp_modes[] __initdata = { 24362306a36Sopenharmony_ci MPP0_UNUSED, 24462306a36Sopenharmony_ci MPP1_GPIO, /* USB copy button */ 24562306a36Sopenharmony_ci MPP2_GPIO, /* Load defaults button */ 24662306a36Sopenharmony_ci MPP3_GPIO, /* GPIO RTC */ 24762306a36Sopenharmony_ci MPP4_UNUSED, 24862306a36Sopenharmony_ci MPP5_UNUSED, 24962306a36Sopenharmony_ci MPP6_GPIO, /* PCI Int A */ 25062306a36Sopenharmony_ci MPP7_GPIO, /* PCI Int B */ 25162306a36Sopenharmony_ci MPP8_UNUSED, 25262306a36Sopenharmony_ci MPP9_UNUSED, 25362306a36Sopenharmony_ci MPP10_UNUSED, 25462306a36Sopenharmony_ci MPP11_UNUSED, 25562306a36Sopenharmony_ci MPP12_SATA_LED, /* SATA 0 presence */ 25662306a36Sopenharmony_ci MPP13_SATA_LED, /* SATA 1 presence */ 25762306a36Sopenharmony_ci MPP14_SATA_LED, /* SATA 0 active */ 25862306a36Sopenharmony_ci MPP15_SATA_LED, /* SATA 1 active */ 25962306a36Sopenharmony_ci MPP16_UART, /* UART1 RXD */ 26062306a36Sopenharmony_ci MPP17_UART, /* UART1 TXD */ 26162306a36Sopenharmony_ci MPP18_GPIO, /* SW_RST */ 26262306a36Sopenharmony_ci MPP19_UNUSED, 26362306a36Sopenharmony_ci 0, 26462306a36Sopenharmony_ci}; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic void __init qnap_ts209_init(void) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci /* 26962306a36Sopenharmony_ci * Setup basic Orion functions. Need to be called early. 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_ci orion5x_init(); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci orion5x_mpp_conf(ts209_mpp_modes); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci /* 27662306a36Sopenharmony_ci * MPP[20] PCI clock 0 27762306a36Sopenharmony_ci * MPP[21] PCI clock 1 27862306a36Sopenharmony_ci * MPP[22] USB 0 over current 27962306a36Sopenharmony_ci * MPP[23-25] Reserved 28062306a36Sopenharmony_ci */ 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci /* 28362306a36Sopenharmony_ci * Configure peripherals. 28462306a36Sopenharmony_ci */ 28562306a36Sopenharmony_ci mvebu_mbus_add_window_by_id(ORION_MBUS_DEVBUS_BOOT_TARGET, 28662306a36Sopenharmony_ci ORION_MBUS_DEVBUS_BOOT_ATTR, 28762306a36Sopenharmony_ci QNAP_TS209_NOR_BOOT_BASE, 28862306a36Sopenharmony_ci QNAP_TS209_NOR_BOOT_SIZE); 28962306a36Sopenharmony_ci platform_device_register(&qnap_ts209_nor_flash); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci orion5x_ehci0_init(); 29262306a36Sopenharmony_ci orion5x_ehci1_init(); 29362306a36Sopenharmony_ci qnap_tsx09_find_mac_addr(QNAP_TS209_NOR_BOOT_BASE + 29462306a36Sopenharmony_ci qnap_ts209_partitions[5].offset, 29562306a36Sopenharmony_ci qnap_ts209_partitions[5].size); 29662306a36Sopenharmony_ci orion5x_eth_init(&qnap_tsx09_eth_data); 29762306a36Sopenharmony_ci orion5x_i2c_init(); 29862306a36Sopenharmony_ci orion5x_sata_init(&qnap_ts209_sata_data); 29962306a36Sopenharmony_ci orion5x_uart0_init(); 30062306a36Sopenharmony_ci orion5x_uart1_init(); 30162306a36Sopenharmony_ci orion5x_xor_init(); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci platform_device_register(&qnap_ts209_button_device); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci /* Get RTC IRQ and register the chip */ 30662306a36Sopenharmony_ci if (gpio_request(TS209_RTC_GPIO, "rtc") == 0) { 30762306a36Sopenharmony_ci if (gpio_direction_input(TS209_RTC_GPIO) == 0) 30862306a36Sopenharmony_ci qnap_ts209_i2c_rtc.irq = gpio_to_irq(TS209_RTC_GPIO); 30962306a36Sopenharmony_ci else 31062306a36Sopenharmony_ci gpio_free(TS209_RTC_GPIO); 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci if (qnap_ts209_i2c_rtc.irq == 0) 31362306a36Sopenharmony_ci pr_warn("qnap_ts209_init: failed to get RTC IRQ\n"); 31462306a36Sopenharmony_ci i2c_register_board_info(0, &qnap_ts209_i2c_rtc, 1); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* register tsx09 specific power-off method */ 31762306a36Sopenharmony_ci pm_power_off = qnap_tsx09_power_off; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ciMACHINE_START(TS209, "QNAP TS-109/TS-209") 32162306a36Sopenharmony_ci /* Maintainer: Byron Bradley <byron.bbradley@gmail.com> */ 32262306a36Sopenharmony_ci .atag_offset = 0x100, 32362306a36Sopenharmony_ci .nr_irqs = ORION5X_NR_IRQS, 32462306a36Sopenharmony_ci .init_machine = qnap_ts209_init, 32562306a36Sopenharmony_ci .map_io = orion5x_map_io, 32662306a36Sopenharmony_ci .init_early = orion5x_init_early, 32762306a36Sopenharmony_ci .init_irq = orion5x_init_irq, 32862306a36Sopenharmony_ci .init_time = orion5x_timer_init, 32962306a36Sopenharmony_ci .fixup = tag_fixup_mem32, 33062306a36Sopenharmony_ci .restart = orion5x_restart, 33162306a36Sopenharmony_ciMACHINE_END 332