18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * arch/arm/mach-iop32x/iq31244.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Board support code for the Intel EP80219 and IQ31244 platforms. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Rory Bolt <rorybolt@pacbell.net> 88c2ecf20Sopenharmony_ci * Copyright (C) 2002 Rory Bolt 98c2ecf20Sopenharmony_ci * Copyright 2003 (c) MontaVista, Software, Inc. 108c2ecf20Sopenharmony_ci * Copyright (C) 2004 Intel Corp. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/mm.h> 148c2ecf20Sopenharmony_ci#include <linux/init.h> 158c2ecf20Sopenharmony_ci#include <linux/delay.h> 168c2ecf20Sopenharmony_ci#include <linux/kernel.h> 178c2ecf20Sopenharmony_ci#include <linux/pci.h> 188c2ecf20Sopenharmony_ci#include <linux/pm.h> 198c2ecf20Sopenharmony_ci#include <linux/string.h> 208c2ecf20Sopenharmony_ci#include <linux/serial_core.h> 218c2ecf20Sopenharmony_ci#include <linux/serial_8250.h> 228c2ecf20Sopenharmony_ci#include <linux/mtd/physmap.h> 238c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 248c2ecf20Sopenharmony_ci#include <linux/io.h> 258c2ecf20Sopenharmony_ci#include <linux/gpio/machine.h> 268c2ecf20Sopenharmony_ci#include <asm/cputype.h> 278c2ecf20Sopenharmony_ci#include <asm/irq.h> 288c2ecf20Sopenharmony_ci#include <asm/mach/arch.h> 298c2ecf20Sopenharmony_ci#include <asm/mach/map.h> 308c2ecf20Sopenharmony_ci#include <asm/mach/pci.h> 318c2ecf20Sopenharmony_ci#include <asm/mach/time.h> 328c2ecf20Sopenharmony_ci#include <asm/mach-types.h> 338c2ecf20Sopenharmony_ci#include <asm/page.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include "hardware.h" 368c2ecf20Sopenharmony_ci#include "irqs.h" 378c2ecf20Sopenharmony_ci#include "gpio-iop32x.h" 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* 408c2ecf20Sopenharmony_ci * Until March of 2007 iq31244 platforms and ep80219 platforms shared the 418c2ecf20Sopenharmony_ci * same machine id, and the processor type was used to select board type. 428c2ecf20Sopenharmony_ci * However this assumption breaks for an iq80219 board which is an iop219 438c2ecf20Sopenharmony_ci * processor on an iq31244 board. The force_ep80219 flag has been added 448c2ecf20Sopenharmony_ci * for old boot loaders using the iq31244 machine id for an ep80219 platform. 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_cistatic int force_ep80219; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic int is_80219(void) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci return !!((read_cpuid_id() & 0xffffffe0) == 0x69052e20); 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic int is_ep80219(void) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci if (machine_is_ep80219() || force_ep80219) 568c2ecf20Sopenharmony_ci return 1; 578c2ecf20Sopenharmony_ci else 588c2ecf20Sopenharmony_ci return 0; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* 638c2ecf20Sopenharmony_ci * EP80219/IQ31244 timer tick configuration. 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_cistatic void __init iq31244_timer_init(void) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci if (is_ep80219()) { 688c2ecf20Sopenharmony_ci /* 33.333 MHz crystal. */ 698c2ecf20Sopenharmony_ci iop_init_time(200000000); 708c2ecf20Sopenharmony_ci } else { 718c2ecf20Sopenharmony_ci /* 33.000 MHz crystal. */ 728c2ecf20Sopenharmony_ci iop_init_time(198000000); 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* 788c2ecf20Sopenharmony_ci * IQ31244 I/O. 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_cistatic struct map_desc iq31244_io_desc[] __initdata = { 818c2ecf20Sopenharmony_ci { /* on-board devices */ 828c2ecf20Sopenharmony_ci .virtual = IQ31244_UART, 838c2ecf20Sopenharmony_ci .pfn = __phys_to_pfn(IQ31244_UART), 848c2ecf20Sopenharmony_ci .length = 0x00100000, 858c2ecf20Sopenharmony_ci .type = MT_DEVICE, 868c2ecf20Sopenharmony_ci }, 878c2ecf20Sopenharmony_ci}; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_civoid __init iq31244_map_io(void) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci iop3xx_map_io(); 928c2ecf20Sopenharmony_ci iotable_init(iq31244_io_desc, ARRAY_SIZE(iq31244_io_desc)); 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* 978c2ecf20Sopenharmony_ci * EP80219/IQ31244 PCI. 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_cistatic int __init 1008c2ecf20Sopenharmony_ciep80219_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci int irq; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (slot == 0) { 1058c2ecf20Sopenharmony_ci /* CFlash */ 1068c2ecf20Sopenharmony_ci irq = IRQ_IOP32X_XINT1; 1078c2ecf20Sopenharmony_ci } else if (slot == 1) { 1088c2ecf20Sopenharmony_ci /* 82551 Pro 100 */ 1098c2ecf20Sopenharmony_ci irq = IRQ_IOP32X_XINT0; 1108c2ecf20Sopenharmony_ci } else if (slot == 2) { 1118c2ecf20Sopenharmony_ci /* PCI-X Slot */ 1128c2ecf20Sopenharmony_ci irq = IRQ_IOP32X_XINT3; 1138c2ecf20Sopenharmony_ci } else if (slot == 3) { 1148c2ecf20Sopenharmony_ci /* SATA */ 1158c2ecf20Sopenharmony_ci irq = IRQ_IOP32X_XINT2; 1168c2ecf20Sopenharmony_ci } else { 1178c2ecf20Sopenharmony_ci printk(KERN_ERR "ep80219_pci_map_irq() called for unknown " 1188c2ecf20Sopenharmony_ci "device PCI:%d:%d:%d\n", dev->bus->number, 1198c2ecf20Sopenharmony_ci PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); 1208c2ecf20Sopenharmony_ci irq = -1; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci return irq; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic struct hw_pci ep80219_pci __initdata = { 1278c2ecf20Sopenharmony_ci .nr_controllers = 1, 1288c2ecf20Sopenharmony_ci .ops = &iop3xx_ops, 1298c2ecf20Sopenharmony_ci .setup = iop3xx_pci_setup, 1308c2ecf20Sopenharmony_ci .preinit = iop3xx_pci_preinit, 1318c2ecf20Sopenharmony_ci .map_irq = ep80219_pci_map_irq, 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic int __init 1358c2ecf20Sopenharmony_ciiq31244_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci int irq; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (slot == 0) { 1408c2ecf20Sopenharmony_ci /* CFlash */ 1418c2ecf20Sopenharmony_ci irq = IRQ_IOP32X_XINT1; 1428c2ecf20Sopenharmony_ci } else if (slot == 1) { 1438c2ecf20Sopenharmony_ci /* SATA */ 1448c2ecf20Sopenharmony_ci irq = IRQ_IOP32X_XINT2; 1458c2ecf20Sopenharmony_ci } else if (slot == 2) { 1468c2ecf20Sopenharmony_ci /* PCI-X Slot */ 1478c2ecf20Sopenharmony_ci irq = IRQ_IOP32X_XINT3; 1488c2ecf20Sopenharmony_ci } else if (slot == 3) { 1498c2ecf20Sopenharmony_ci /* 82546 GigE */ 1508c2ecf20Sopenharmony_ci irq = IRQ_IOP32X_XINT0; 1518c2ecf20Sopenharmony_ci } else { 1528c2ecf20Sopenharmony_ci printk(KERN_ERR "iq31244_pci_map_irq called for unknown " 1538c2ecf20Sopenharmony_ci "device PCI:%d:%d:%d\n", dev->bus->number, 1548c2ecf20Sopenharmony_ci PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); 1558c2ecf20Sopenharmony_ci irq = -1; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci return irq; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic struct hw_pci iq31244_pci __initdata = { 1628c2ecf20Sopenharmony_ci .nr_controllers = 1, 1638c2ecf20Sopenharmony_ci .ops = &iop3xx_ops, 1648c2ecf20Sopenharmony_ci .setup = iop3xx_pci_setup, 1658c2ecf20Sopenharmony_ci .preinit = iop3xx_pci_preinit, 1668c2ecf20Sopenharmony_ci .map_irq = iq31244_pci_map_irq, 1678c2ecf20Sopenharmony_ci}; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic int __init iq31244_pci_init(void) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci if (is_ep80219()) 1728c2ecf20Sopenharmony_ci pci_common_init(&ep80219_pci); 1738c2ecf20Sopenharmony_ci else if (machine_is_iq31244()) { 1748c2ecf20Sopenharmony_ci if (is_80219()) { 1758c2ecf20Sopenharmony_ci printk("note: iq31244 board type has been selected\n"); 1768c2ecf20Sopenharmony_ci printk("note: to select ep80219 operation:\n"); 1778c2ecf20Sopenharmony_ci printk("\t1/ specify \"force_ep80219\" on the kernel" 1788c2ecf20Sopenharmony_ci " command line\n"); 1798c2ecf20Sopenharmony_ci printk("\t2/ update boot loader to pass" 1808c2ecf20Sopenharmony_ci " the ep80219 id: %d\n", MACH_TYPE_EP80219); 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci pci_common_init(&iq31244_pci); 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci return 0; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cisubsys_initcall(iq31244_pci_init); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci/* 1928c2ecf20Sopenharmony_ci * IQ31244 machine initialisation. 1938c2ecf20Sopenharmony_ci */ 1948c2ecf20Sopenharmony_cistatic struct physmap_flash_data iq31244_flash_data = { 1958c2ecf20Sopenharmony_ci .width = 2, 1968c2ecf20Sopenharmony_ci}; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic struct resource iq31244_flash_resource = { 1998c2ecf20Sopenharmony_ci .start = 0xf0000000, 2008c2ecf20Sopenharmony_ci .end = 0xf07fffff, 2018c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 2028c2ecf20Sopenharmony_ci}; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic struct platform_device iq31244_flash_device = { 2058c2ecf20Sopenharmony_ci .name = "physmap-flash", 2068c2ecf20Sopenharmony_ci .id = 0, 2078c2ecf20Sopenharmony_ci .dev = { 2088c2ecf20Sopenharmony_ci .platform_data = &iq31244_flash_data, 2098c2ecf20Sopenharmony_ci }, 2108c2ecf20Sopenharmony_ci .num_resources = 1, 2118c2ecf20Sopenharmony_ci .resource = &iq31244_flash_resource, 2128c2ecf20Sopenharmony_ci}; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic struct plat_serial8250_port iq31244_serial_port[] = { 2158c2ecf20Sopenharmony_ci { 2168c2ecf20Sopenharmony_ci .mapbase = IQ31244_UART, 2178c2ecf20Sopenharmony_ci .membase = (char *)IQ31244_UART, 2188c2ecf20Sopenharmony_ci .irq = IRQ_IOP32X_XINT1, 2198c2ecf20Sopenharmony_ci .flags = UPF_SKIP_TEST, 2208c2ecf20Sopenharmony_ci .iotype = UPIO_MEM, 2218c2ecf20Sopenharmony_ci .regshift = 0, 2228c2ecf20Sopenharmony_ci .uartclk = 1843200, 2238c2ecf20Sopenharmony_ci }, 2248c2ecf20Sopenharmony_ci { }, 2258c2ecf20Sopenharmony_ci}; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic struct resource iq31244_uart_resource = { 2288c2ecf20Sopenharmony_ci .start = IQ31244_UART, 2298c2ecf20Sopenharmony_ci .end = IQ31244_UART + 7, 2308c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 2318c2ecf20Sopenharmony_ci}; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic struct platform_device iq31244_serial_device = { 2348c2ecf20Sopenharmony_ci .name = "serial8250", 2358c2ecf20Sopenharmony_ci .id = PLAT8250_DEV_PLATFORM, 2368c2ecf20Sopenharmony_ci .dev = { 2378c2ecf20Sopenharmony_ci .platform_data = iq31244_serial_port, 2388c2ecf20Sopenharmony_ci }, 2398c2ecf20Sopenharmony_ci .num_resources = 1, 2408c2ecf20Sopenharmony_ci .resource = &iq31244_uart_resource, 2418c2ecf20Sopenharmony_ci}; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci/* 2448c2ecf20Sopenharmony_ci * This function will send a SHUTDOWN_COMPLETE message to the PIC 2458c2ecf20Sopenharmony_ci * controller over I2C. We are not using the i2c subsystem since 2468c2ecf20Sopenharmony_ci * we are going to power off and it may be removed 2478c2ecf20Sopenharmony_ci */ 2488c2ecf20Sopenharmony_civoid ep80219_power_off(void) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci /* 2518c2ecf20Sopenharmony_ci * Send the Address byte w/ the start condition 2528c2ecf20Sopenharmony_ci */ 2538c2ecf20Sopenharmony_ci *IOP3XX_IDBR1 = 0x60; 2548c2ecf20Sopenharmony_ci *IOP3XX_ICR1 = 0xE9; 2558c2ecf20Sopenharmony_ci mdelay(1); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* 2588c2ecf20Sopenharmony_ci * Send the START_MSG byte w/ no start or stop condition 2598c2ecf20Sopenharmony_ci */ 2608c2ecf20Sopenharmony_ci *IOP3XX_IDBR1 = 0x0F; 2618c2ecf20Sopenharmony_ci *IOP3XX_ICR1 = 0xE8; 2628c2ecf20Sopenharmony_ci mdelay(1); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* 2658c2ecf20Sopenharmony_ci * Send the SHUTDOWN_COMPLETE Message ID byte w/ no start or 2668c2ecf20Sopenharmony_ci * stop condition 2678c2ecf20Sopenharmony_ci */ 2688c2ecf20Sopenharmony_ci *IOP3XX_IDBR1 = 0x03; 2698c2ecf20Sopenharmony_ci *IOP3XX_ICR1 = 0xE8; 2708c2ecf20Sopenharmony_ci mdelay(1); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* 2738c2ecf20Sopenharmony_ci * Send an ignored byte w/ stop condition 2748c2ecf20Sopenharmony_ci */ 2758c2ecf20Sopenharmony_ci *IOP3XX_IDBR1 = 0x00; 2768c2ecf20Sopenharmony_ci *IOP3XX_ICR1 = 0xEA; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci while (1) 2798c2ecf20Sopenharmony_ci ; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic void __init iq31244_init_machine(void) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci register_iop32x_gpio(); 2858c2ecf20Sopenharmony_ci gpiod_add_lookup_table(&iop3xx_i2c0_gpio_lookup); 2868c2ecf20Sopenharmony_ci gpiod_add_lookup_table(&iop3xx_i2c1_gpio_lookup); 2878c2ecf20Sopenharmony_ci platform_device_register(&iop3xx_i2c0_device); 2888c2ecf20Sopenharmony_ci platform_device_register(&iop3xx_i2c1_device); 2898c2ecf20Sopenharmony_ci platform_device_register(&iq31244_flash_device); 2908c2ecf20Sopenharmony_ci platform_device_register(&iq31244_serial_device); 2918c2ecf20Sopenharmony_ci platform_device_register(&iop3xx_dma_0_channel); 2928c2ecf20Sopenharmony_ci platform_device_register(&iop3xx_dma_1_channel); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (is_ep80219()) 2958c2ecf20Sopenharmony_ci pm_power_off = ep80219_power_off; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (!is_80219()) 2988c2ecf20Sopenharmony_ci platform_device_register(&iop3xx_aau_channel); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic int __init force_ep80219_setup(char *str) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci force_ep80219 = 1; 3048c2ecf20Sopenharmony_ci return 1; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci__setup("force_ep80219", force_ep80219_setup); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ciMACHINE_START(IQ31244, "Intel IQ31244") 3108c2ecf20Sopenharmony_ci /* Maintainer: Intel Corp. */ 3118c2ecf20Sopenharmony_ci .atag_offset = 0x100, 3128c2ecf20Sopenharmony_ci .map_io = iq31244_map_io, 3138c2ecf20Sopenharmony_ci .init_irq = iop32x_init_irq, 3148c2ecf20Sopenharmony_ci .init_time = iq31244_timer_init, 3158c2ecf20Sopenharmony_ci .init_machine = iq31244_init_machine, 3168c2ecf20Sopenharmony_ci .restart = iop3xx_restart, 3178c2ecf20Sopenharmony_ciMACHINE_END 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci/* There should have been an ep80219 machine identifier from the beginning. 3208c2ecf20Sopenharmony_ci * Boot roms older than March 2007 do not know the ep80219 machine id. Pass 3218c2ecf20Sopenharmony_ci * "force_ep80219" on the kernel command line, otherwise iq31244 operation 3228c2ecf20Sopenharmony_ci * will be selected. 3238c2ecf20Sopenharmony_ci */ 3248c2ecf20Sopenharmony_ciMACHINE_START(EP80219, "Intel EP80219") 3258c2ecf20Sopenharmony_ci /* Maintainer: Intel Corp. */ 3268c2ecf20Sopenharmony_ci .atag_offset = 0x100, 3278c2ecf20Sopenharmony_ci .map_io = iq31244_map_io, 3288c2ecf20Sopenharmony_ci .init_irq = iop32x_init_irq, 3298c2ecf20Sopenharmony_ci .init_time = iq31244_timer_init, 3308c2ecf20Sopenharmony_ci .init_machine = iq31244_init_machine, 3318c2ecf20Sopenharmony_ci .restart = iop3xx_restart, 3328c2ecf20Sopenharmony_ciMACHINE_END 333