18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * General Purpose functions for the global management of the 48c2ecf20Sopenharmony_ci * Communication Processor Module. 58c2ecf20Sopenharmony_ci * Copyright (c) 1997 Dan error_act (dmalek@jlc.net) 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * In addition to the individual control of the communication 88c2ecf20Sopenharmony_ci * channels, there are a few functions that globally affect the 98c2ecf20Sopenharmony_ci * communication processor. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Buffer descriptors must be allocated from the dual ported memory 128c2ecf20Sopenharmony_ci * space. The allocator for that is here. When the communication 138c2ecf20Sopenharmony_ci * process is reset, we reclaim the memory available. There is 148c2ecf20Sopenharmony_ci * currently no deallocator for this memory. 158c2ecf20Sopenharmony_ci * The amount of space available is platform dependent. On the 168c2ecf20Sopenharmony_ci * MBX, the EPPC software loads additional microcode into the 178c2ecf20Sopenharmony_ci * communication processor, and uses some of the DP ram for this 188c2ecf20Sopenharmony_ci * purpose. Current, the first 512 bytes and the last 256 bytes of 198c2ecf20Sopenharmony_ci * memory are used. Right now I am conservative and only use the 208c2ecf20Sopenharmony_ci * memory that can never be used for microcode. If there are 218c2ecf20Sopenharmony_ci * applications that require more DP ram, we can expand the boundaries 228c2ecf20Sopenharmony_ci * but then we have to be careful of any downloaded microcode. 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci#include <linux/errno.h> 258c2ecf20Sopenharmony_ci#include <linux/sched.h> 268c2ecf20Sopenharmony_ci#include <linux/kernel.h> 278c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 288c2ecf20Sopenharmony_ci#include <linux/param.h> 298c2ecf20Sopenharmony_ci#include <linux/string.h> 308c2ecf20Sopenharmony_ci#include <linux/mm.h> 318c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 328c2ecf20Sopenharmony_ci#include <linux/irq.h> 338c2ecf20Sopenharmony_ci#include <linux/module.h> 348c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 358c2ecf20Sopenharmony_ci#include <linux/slab.h> 368c2ecf20Sopenharmony_ci#include <asm/page.h> 378c2ecf20Sopenharmony_ci#include <asm/8xx_immap.h> 388c2ecf20Sopenharmony_ci#include <asm/cpm1.h> 398c2ecf20Sopenharmony_ci#include <asm/io.h> 408c2ecf20Sopenharmony_ci#include <asm/rheap.h> 418c2ecf20Sopenharmony_ci#include <asm/prom.h> 428c2ecf20Sopenharmony_ci#include <asm/cpm.h> 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#include <asm/fs_pd.h> 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#ifdef CONFIG_8xx_GPIO 478c2ecf20Sopenharmony_ci#include <linux/of_gpio.h> 488c2ecf20Sopenharmony_ci#endif 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define CPM_MAP_SIZE (0x4000) 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cicpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */ 538c2ecf20Sopenharmony_ciimmap_t __iomem *mpc8xx_immr = (void __iomem *)VIRT_IMMR_BASE; 548c2ecf20Sopenharmony_cistatic cpic8xx_t __iomem *cpic_reg; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic struct irq_domain *cpm_pic_host; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic void cpm_mask_irq(struct irq_data *d) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci clrbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec)); 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic void cpm_unmask_irq(struct irq_data *d) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci setbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec)); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic void cpm_end_irq(struct irq_data *d) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci out_be32(&cpic_reg->cpic_cisr, (1 << cpm_vec)); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic struct irq_chip cpm_pic = { 808c2ecf20Sopenharmony_ci .name = "CPM PIC", 818c2ecf20Sopenharmony_ci .irq_mask = cpm_mask_irq, 828c2ecf20Sopenharmony_ci .irq_unmask = cpm_unmask_irq, 838c2ecf20Sopenharmony_ci .irq_eoi = cpm_end_irq, 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ciint cpm_get_irq(void) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci int cpm_vec; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci /* 918c2ecf20Sopenharmony_ci * Get the vector by setting the ACK bit and then reading 928c2ecf20Sopenharmony_ci * the register. 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_ci out_be16(&cpic_reg->cpic_civr, 1); 958c2ecf20Sopenharmony_ci cpm_vec = in_be16(&cpic_reg->cpic_civr); 968c2ecf20Sopenharmony_ci cpm_vec >>= 11; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci return irq_linear_revmap(cpm_pic_host, cpm_vec); 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic int cpm_pic_host_map(struct irq_domain *h, unsigned int virq, 1028c2ecf20Sopenharmony_ci irq_hw_number_t hw) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci pr_debug("cpm_pic_host_map(%d, 0x%lx)\n", virq, hw); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci irq_set_status_flags(virq, IRQ_LEVEL); 1078c2ecf20Sopenharmony_ci irq_set_chip_and_handler(virq, &cpm_pic, handle_fasteoi_irq); 1088c2ecf20Sopenharmony_ci return 0; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci/* 1128c2ecf20Sopenharmony_ci * The CPM can generate the error interrupt when there is a race condition 1138c2ecf20Sopenharmony_ci * between generating and masking interrupts. All we have to do is ACK it 1148c2ecf20Sopenharmony_ci * and return. This is a no-op function so we don't need any special 1158c2ecf20Sopenharmony_ci * tests in the interrupt handler. 1168c2ecf20Sopenharmony_ci */ 1178c2ecf20Sopenharmony_cistatic irqreturn_t cpm_error_interrupt(int irq, void *dev) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic const struct irq_domain_ops cpm_pic_host_ops = { 1238c2ecf20Sopenharmony_ci .map = cpm_pic_host_map, 1248c2ecf20Sopenharmony_ci}; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ciunsigned int __init cpm_pic_init(void) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct device_node *np = NULL; 1298c2ecf20Sopenharmony_ci struct resource res; 1308c2ecf20Sopenharmony_ci unsigned int sirq = 0, hwirq, eirq; 1318c2ecf20Sopenharmony_ci int ret; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci pr_debug("cpm_pic_init\n"); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "fsl,cpm1-pic"); 1368c2ecf20Sopenharmony_ci if (np == NULL) 1378c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, "cpm-pic", "CPM"); 1388c2ecf20Sopenharmony_ci if (np == NULL) { 1398c2ecf20Sopenharmony_ci printk(KERN_ERR "CPM PIC init: can not find cpm-pic node\n"); 1408c2ecf20Sopenharmony_ci return sirq; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci ret = of_address_to_resource(np, 0, &res); 1448c2ecf20Sopenharmony_ci if (ret) 1458c2ecf20Sopenharmony_ci goto end; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci cpic_reg = ioremap(res.start, resource_size(&res)); 1488c2ecf20Sopenharmony_ci if (cpic_reg == NULL) 1498c2ecf20Sopenharmony_ci goto end; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci sirq = irq_of_parse_and_map(np, 0); 1528c2ecf20Sopenharmony_ci if (!sirq) 1538c2ecf20Sopenharmony_ci goto end; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* Initialize the CPM interrupt controller. */ 1568c2ecf20Sopenharmony_ci hwirq = (unsigned int)virq_to_hw(sirq); 1578c2ecf20Sopenharmony_ci out_be32(&cpic_reg->cpic_cicr, 1588c2ecf20Sopenharmony_ci (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) | 1598c2ecf20Sopenharmony_ci ((hwirq/2) << 13) | CICR_HP_MASK); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci out_be32(&cpic_reg->cpic_cimr, 0); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci cpm_pic_host = irq_domain_add_linear(np, 64, &cpm_pic_host_ops, NULL); 1648c2ecf20Sopenharmony_ci if (cpm_pic_host == NULL) { 1658c2ecf20Sopenharmony_ci printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n"); 1668c2ecf20Sopenharmony_ci sirq = 0; 1678c2ecf20Sopenharmony_ci goto end; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* Install our own error handler. */ 1718c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "fsl,cpm1"); 1728c2ecf20Sopenharmony_ci if (np == NULL) 1738c2ecf20Sopenharmony_ci np = of_find_node_by_type(NULL, "cpm"); 1748c2ecf20Sopenharmony_ci if (np == NULL) { 1758c2ecf20Sopenharmony_ci printk(KERN_ERR "CPM PIC init: can not find cpm node\n"); 1768c2ecf20Sopenharmony_ci goto end; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci eirq = irq_of_parse_and_map(np, 0); 1808c2ecf20Sopenharmony_ci if (!eirq) 1818c2ecf20Sopenharmony_ci goto end; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (request_irq(eirq, cpm_error_interrupt, IRQF_NO_THREAD, "error", 1848c2ecf20Sopenharmony_ci NULL)) 1858c2ecf20Sopenharmony_ci printk(KERN_ERR "Could not allocate CPM error IRQ!"); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci setbits32(&cpic_reg->cpic_cicr, CICR_IEN); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ciend: 1908c2ecf20Sopenharmony_ci of_node_put(np); 1918c2ecf20Sopenharmony_ci return sirq; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_civoid __init cpm_reset(void) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci sysconf8xx_t __iomem *siu_conf; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci cpmp = &mpc8xx_immr->im_cpm; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci#ifndef CONFIG_PPC_EARLY_DEBUG_CPM 2018c2ecf20Sopenharmony_ci /* Perform a reset. */ 2028c2ecf20Sopenharmony_ci out_be16(&cpmp->cp_cpcr, CPM_CR_RST | CPM_CR_FLG); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci /* Wait for it. */ 2058c2ecf20Sopenharmony_ci while (in_be16(&cpmp->cp_cpcr) & CPM_CR_FLG); 2068c2ecf20Sopenharmony_ci#endif 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci#ifdef CONFIG_UCODE_PATCH 2098c2ecf20Sopenharmony_ci cpm_load_patch(cpmp); 2108c2ecf20Sopenharmony_ci#endif 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci /* 2138c2ecf20Sopenharmony_ci * Set SDMA Bus Request priority 5. 2148c2ecf20Sopenharmony_ci * On 860T, this also enables FEC priority 6. I am not sure 2158c2ecf20Sopenharmony_ci * this is what we really want for some applications, but the 2168c2ecf20Sopenharmony_ci * manual recommends it. 2178c2ecf20Sopenharmony_ci * Bit 25, FAM can also be set to use FEC aggressive mode (860T). 2188c2ecf20Sopenharmony_ci */ 2198c2ecf20Sopenharmony_ci siu_conf = immr_map(im_siu_conf); 2208c2ecf20Sopenharmony_ci if ((mfspr(SPRN_IMMR) & 0xffff) == 0x0900) /* MPC885 */ 2218c2ecf20Sopenharmony_ci out_be32(&siu_conf->sc_sdcr, 0x40); 2228c2ecf20Sopenharmony_ci else 2238c2ecf20Sopenharmony_ci out_be32(&siu_conf->sc_sdcr, 1); 2248c2ecf20Sopenharmony_ci immr_unmap(siu_conf); 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(cmd_lock); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci#define MAX_CR_CMD_LOOPS 10000 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ciint cpm_command(u32 command, u8 opcode) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci int i, ret; 2348c2ecf20Sopenharmony_ci unsigned long flags; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (command & 0xffffff0f) 2378c2ecf20Sopenharmony_ci return -EINVAL; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci spin_lock_irqsave(&cmd_lock, flags); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci ret = 0; 2428c2ecf20Sopenharmony_ci out_be16(&cpmp->cp_cpcr, command | CPM_CR_FLG | (opcode << 8)); 2438c2ecf20Sopenharmony_ci for (i = 0; i < MAX_CR_CMD_LOOPS; i++) 2448c2ecf20Sopenharmony_ci if ((in_be16(&cpmp->cp_cpcr) & CPM_CR_FLG) == 0) 2458c2ecf20Sopenharmony_ci goto out; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci printk(KERN_ERR "%s(): Not able to issue CPM command\n", __func__); 2488c2ecf20Sopenharmony_ci ret = -EIO; 2498c2ecf20Sopenharmony_ciout: 2508c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cmd_lock, flags); 2518c2ecf20Sopenharmony_ci return ret; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cpm_command); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci/* 2568c2ecf20Sopenharmony_ci * Set a baud rate generator. This needs lots of work. There are 2578c2ecf20Sopenharmony_ci * four BRGs, any of which can be wired to any channel. 2588c2ecf20Sopenharmony_ci * The internal baud rate clock is the system clock divided by 16. 2598c2ecf20Sopenharmony_ci * This assumes the baudrate is 16x oversampled by the uart. 2608c2ecf20Sopenharmony_ci */ 2618c2ecf20Sopenharmony_ci#define BRG_INT_CLK (get_brgfreq()) 2628c2ecf20Sopenharmony_ci#define BRG_UART_CLK (BRG_INT_CLK/16) 2638c2ecf20Sopenharmony_ci#define BRG_UART_CLK_DIV16 (BRG_UART_CLK/16) 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_civoid 2668c2ecf20Sopenharmony_cicpm_setbrg(uint brg, uint rate) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci u32 __iomem *bp; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci /* This is good enough to get SMCs running..... */ 2718c2ecf20Sopenharmony_ci bp = &cpmp->cp_brgc1; 2728c2ecf20Sopenharmony_ci bp += brg; 2738c2ecf20Sopenharmony_ci /* 2748c2ecf20Sopenharmony_ci * The BRG has a 12-bit counter. For really slow baud rates (or 2758c2ecf20Sopenharmony_ci * really fast processors), we may have to further divide by 16. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ci if (((BRG_UART_CLK / rate) - 1) < 4096) 2788c2ecf20Sopenharmony_ci out_be32(bp, (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN); 2798c2ecf20Sopenharmony_ci else 2808c2ecf20Sopenharmony_ci out_be32(bp, (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) | 2818c2ecf20Sopenharmony_ci CPM_BRG_EN | CPM_BRG_DIV16); 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cpm_setbrg); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistruct cpm_ioport16 { 2868c2ecf20Sopenharmony_ci __be16 dir, par, odr_sor, dat, intr; 2878c2ecf20Sopenharmony_ci __be16 res[3]; 2888c2ecf20Sopenharmony_ci}; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistruct cpm_ioport32b { 2918c2ecf20Sopenharmony_ci __be32 dir, par, odr, dat; 2928c2ecf20Sopenharmony_ci}; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistruct cpm_ioport32e { 2958c2ecf20Sopenharmony_ci __be32 dir, par, sor, odr, dat; 2968c2ecf20Sopenharmony_ci}; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic void __init cpm1_set_pin32(int port, int pin, int flags) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci struct cpm_ioport32e __iomem *iop; 3018c2ecf20Sopenharmony_ci pin = 1 << (31 - pin); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (port == CPM_PORTB) 3048c2ecf20Sopenharmony_ci iop = (struct cpm_ioport32e __iomem *) 3058c2ecf20Sopenharmony_ci &mpc8xx_immr->im_cpm.cp_pbdir; 3068c2ecf20Sopenharmony_ci else 3078c2ecf20Sopenharmony_ci iop = (struct cpm_ioport32e __iomem *) 3088c2ecf20Sopenharmony_ci &mpc8xx_immr->im_cpm.cp_pedir; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if (flags & CPM_PIN_OUTPUT) 3118c2ecf20Sopenharmony_ci setbits32(&iop->dir, pin); 3128c2ecf20Sopenharmony_ci else 3138c2ecf20Sopenharmony_ci clrbits32(&iop->dir, pin); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (!(flags & CPM_PIN_GPIO)) 3168c2ecf20Sopenharmony_ci setbits32(&iop->par, pin); 3178c2ecf20Sopenharmony_ci else 3188c2ecf20Sopenharmony_ci clrbits32(&iop->par, pin); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (port == CPM_PORTB) { 3218c2ecf20Sopenharmony_ci if (flags & CPM_PIN_OPENDRAIN) 3228c2ecf20Sopenharmony_ci setbits16(&mpc8xx_immr->im_cpm.cp_pbodr, pin); 3238c2ecf20Sopenharmony_ci else 3248c2ecf20Sopenharmony_ci clrbits16(&mpc8xx_immr->im_cpm.cp_pbodr, pin); 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (port == CPM_PORTE) { 3288c2ecf20Sopenharmony_ci if (flags & CPM_PIN_SECONDARY) 3298c2ecf20Sopenharmony_ci setbits32(&iop->sor, pin); 3308c2ecf20Sopenharmony_ci else 3318c2ecf20Sopenharmony_ci clrbits32(&iop->sor, pin); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (flags & CPM_PIN_OPENDRAIN) 3348c2ecf20Sopenharmony_ci setbits32(&mpc8xx_immr->im_cpm.cp_peodr, pin); 3358c2ecf20Sopenharmony_ci else 3368c2ecf20Sopenharmony_ci clrbits32(&mpc8xx_immr->im_cpm.cp_peodr, pin); 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic void __init cpm1_set_pin16(int port, int pin, int flags) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci struct cpm_ioport16 __iomem *iop = 3438c2ecf20Sopenharmony_ci (struct cpm_ioport16 __iomem *)&mpc8xx_immr->im_ioport; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci pin = 1 << (15 - pin); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (port != 0) 3488c2ecf20Sopenharmony_ci iop += port - 1; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (flags & CPM_PIN_OUTPUT) 3518c2ecf20Sopenharmony_ci setbits16(&iop->dir, pin); 3528c2ecf20Sopenharmony_ci else 3538c2ecf20Sopenharmony_ci clrbits16(&iop->dir, pin); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (!(flags & CPM_PIN_GPIO)) 3568c2ecf20Sopenharmony_ci setbits16(&iop->par, pin); 3578c2ecf20Sopenharmony_ci else 3588c2ecf20Sopenharmony_ci clrbits16(&iop->par, pin); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci if (port == CPM_PORTA) { 3618c2ecf20Sopenharmony_ci if (flags & CPM_PIN_OPENDRAIN) 3628c2ecf20Sopenharmony_ci setbits16(&iop->odr_sor, pin); 3638c2ecf20Sopenharmony_ci else 3648c2ecf20Sopenharmony_ci clrbits16(&iop->odr_sor, pin); 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci if (port == CPM_PORTC) { 3678c2ecf20Sopenharmony_ci if (flags & CPM_PIN_SECONDARY) 3688c2ecf20Sopenharmony_ci setbits16(&iop->odr_sor, pin); 3698c2ecf20Sopenharmony_ci else 3708c2ecf20Sopenharmony_ci clrbits16(&iop->odr_sor, pin); 3718c2ecf20Sopenharmony_ci if (flags & CPM_PIN_FALLEDGE) 3728c2ecf20Sopenharmony_ci setbits16(&iop->intr, pin); 3738c2ecf20Sopenharmony_ci else 3748c2ecf20Sopenharmony_ci clrbits16(&iop->intr, pin); 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_civoid __init cpm1_set_pin(enum cpm_port port, int pin, int flags) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci if (port == CPM_PORTB || port == CPM_PORTE) 3818c2ecf20Sopenharmony_ci cpm1_set_pin32(port, pin, flags); 3828c2ecf20Sopenharmony_ci else 3838c2ecf20Sopenharmony_ci cpm1_set_pin16(port, pin, flags); 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ciint __init cpm1_clk_setup(enum cpm_clk_target target, int clock, int mode) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci int shift; 3898c2ecf20Sopenharmony_ci int i, bits = 0; 3908c2ecf20Sopenharmony_ci u32 __iomem *reg; 3918c2ecf20Sopenharmony_ci u32 mask = 7; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci u8 clk_map[][3] = { 3948c2ecf20Sopenharmony_ci {CPM_CLK_SCC1, CPM_BRG1, 0}, 3958c2ecf20Sopenharmony_ci {CPM_CLK_SCC1, CPM_BRG2, 1}, 3968c2ecf20Sopenharmony_ci {CPM_CLK_SCC1, CPM_BRG3, 2}, 3978c2ecf20Sopenharmony_ci {CPM_CLK_SCC1, CPM_BRG4, 3}, 3988c2ecf20Sopenharmony_ci {CPM_CLK_SCC1, CPM_CLK1, 4}, 3998c2ecf20Sopenharmony_ci {CPM_CLK_SCC1, CPM_CLK2, 5}, 4008c2ecf20Sopenharmony_ci {CPM_CLK_SCC1, CPM_CLK3, 6}, 4018c2ecf20Sopenharmony_ci {CPM_CLK_SCC1, CPM_CLK4, 7}, 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci {CPM_CLK_SCC2, CPM_BRG1, 0}, 4048c2ecf20Sopenharmony_ci {CPM_CLK_SCC2, CPM_BRG2, 1}, 4058c2ecf20Sopenharmony_ci {CPM_CLK_SCC2, CPM_BRG3, 2}, 4068c2ecf20Sopenharmony_ci {CPM_CLK_SCC2, CPM_BRG4, 3}, 4078c2ecf20Sopenharmony_ci {CPM_CLK_SCC2, CPM_CLK1, 4}, 4088c2ecf20Sopenharmony_ci {CPM_CLK_SCC2, CPM_CLK2, 5}, 4098c2ecf20Sopenharmony_ci {CPM_CLK_SCC2, CPM_CLK3, 6}, 4108c2ecf20Sopenharmony_ci {CPM_CLK_SCC2, CPM_CLK4, 7}, 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci {CPM_CLK_SCC3, CPM_BRG1, 0}, 4138c2ecf20Sopenharmony_ci {CPM_CLK_SCC3, CPM_BRG2, 1}, 4148c2ecf20Sopenharmony_ci {CPM_CLK_SCC3, CPM_BRG3, 2}, 4158c2ecf20Sopenharmony_ci {CPM_CLK_SCC3, CPM_BRG4, 3}, 4168c2ecf20Sopenharmony_ci {CPM_CLK_SCC3, CPM_CLK5, 4}, 4178c2ecf20Sopenharmony_ci {CPM_CLK_SCC3, CPM_CLK6, 5}, 4188c2ecf20Sopenharmony_ci {CPM_CLK_SCC3, CPM_CLK7, 6}, 4198c2ecf20Sopenharmony_ci {CPM_CLK_SCC3, CPM_CLK8, 7}, 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci {CPM_CLK_SCC4, CPM_BRG1, 0}, 4228c2ecf20Sopenharmony_ci {CPM_CLK_SCC4, CPM_BRG2, 1}, 4238c2ecf20Sopenharmony_ci {CPM_CLK_SCC4, CPM_BRG3, 2}, 4248c2ecf20Sopenharmony_ci {CPM_CLK_SCC4, CPM_BRG4, 3}, 4258c2ecf20Sopenharmony_ci {CPM_CLK_SCC4, CPM_CLK5, 4}, 4268c2ecf20Sopenharmony_ci {CPM_CLK_SCC4, CPM_CLK6, 5}, 4278c2ecf20Sopenharmony_ci {CPM_CLK_SCC4, CPM_CLK7, 6}, 4288c2ecf20Sopenharmony_ci {CPM_CLK_SCC4, CPM_CLK8, 7}, 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci {CPM_CLK_SMC1, CPM_BRG1, 0}, 4318c2ecf20Sopenharmony_ci {CPM_CLK_SMC1, CPM_BRG2, 1}, 4328c2ecf20Sopenharmony_ci {CPM_CLK_SMC1, CPM_BRG3, 2}, 4338c2ecf20Sopenharmony_ci {CPM_CLK_SMC1, CPM_BRG4, 3}, 4348c2ecf20Sopenharmony_ci {CPM_CLK_SMC1, CPM_CLK1, 4}, 4358c2ecf20Sopenharmony_ci {CPM_CLK_SMC1, CPM_CLK2, 5}, 4368c2ecf20Sopenharmony_ci {CPM_CLK_SMC1, CPM_CLK3, 6}, 4378c2ecf20Sopenharmony_ci {CPM_CLK_SMC1, CPM_CLK4, 7}, 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci {CPM_CLK_SMC2, CPM_BRG1, 0}, 4408c2ecf20Sopenharmony_ci {CPM_CLK_SMC2, CPM_BRG2, 1}, 4418c2ecf20Sopenharmony_ci {CPM_CLK_SMC2, CPM_BRG3, 2}, 4428c2ecf20Sopenharmony_ci {CPM_CLK_SMC2, CPM_BRG4, 3}, 4438c2ecf20Sopenharmony_ci {CPM_CLK_SMC2, CPM_CLK5, 4}, 4448c2ecf20Sopenharmony_ci {CPM_CLK_SMC2, CPM_CLK6, 5}, 4458c2ecf20Sopenharmony_ci {CPM_CLK_SMC2, CPM_CLK7, 6}, 4468c2ecf20Sopenharmony_ci {CPM_CLK_SMC2, CPM_CLK8, 7}, 4478c2ecf20Sopenharmony_ci }; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci switch (target) { 4508c2ecf20Sopenharmony_ci case CPM_CLK_SCC1: 4518c2ecf20Sopenharmony_ci reg = &mpc8xx_immr->im_cpm.cp_sicr; 4528c2ecf20Sopenharmony_ci shift = 0; 4538c2ecf20Sopenharmony_ci break; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci case CPM_CLK_SCC2: 4568c2ecf20Sopenharmony_ci reg = &mpc8xx_immr->im_cpm.cp_sicr; 4578c2ecf20Sopenharmony_ci shift = 8; 4588c2ecf20Sopenharmony_ci break; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci case CPM_CLK_SCC3: 4618c2ecf20Sopenharmony_ci reg = &mpc8xx_immr->im_cpm.cp_sicr; 4628c2ecf20Sopenharmony_ci shift = 16; 4638c2ecf20Sopenharmony_ci break; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci case CPM_CLK_SCC4: 4668c2ecf20Sopenharmony_ci reg = &mpc8xx_immr->im_cpm.cp_sicr; 4678c2ecf20Sopenharmony_ci shift = 24; 4688c2ecf20Sopenharmony_ci break; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci case CPM_CLK_SMC1: 4718c2ecf20Sopenharmony_ci reg = &mpc8xx_immr->im_cpm.cp_simode; 4728c2ecf20Sopenharmony_ci shift = 12; 4738c2ecf20Sopenharmony_ci break; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci case CPM_CLK_SMC2: 4768c2ecf20Sopenharmony_ci reg = &mpc8xx_immr->im_cpm.cp_simode; 4778c2ecf20Sopenharmony_ci shift = 28; 4788c2ecf20Sopenharmony_ci break; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci default: 4818c2ecf20Sopenharmony_ci printk(KERN_ERR "cpm1_clock_setup: invalid clock target\n"); 4828c2ecf20Sopenharmony_ci return -EINVAL; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(clk_map); i++) { 4868c2ecf20Sopenharmony_ci if (clk_map[i][0] == target && clk_map[i][1] == clock) { 4878c2ecf20Sopenharmony_ci bits = clk_map[i][2]; 4888c2ecf20Sopenharmony_ci break; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci if (i == ARRAY_SIZE(clk_map)) { 4938c2ecf20Sopenharmony_ci printk(KERN_ERR "cpm1_clock_setup: invalid clock combination\n"); 4948c2ecf20Sopenharmony_ci return -EINVAL; 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci bits <<= shift; 4988c2ecf20Sopenharmony_ci mask <<= shift; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (reg == &mpc8xx_immr->im_cpm.cp_sicr) { 5018c2ecf20Sopenharmony_ci if (mode == CPM_CLK_RTX) { 5028c2ecf20Sopenharmony_ci bits |= bits << 3; 5038c2ecf20Sopenharmony_ci mask |= mask << 3; 5048c2ecf20Sopenharmony_ci } else if (mode == CPM_CLK_RX) { 5058c2ecf20Sopenharmony_ci bits <<= 3; 5068c2ecf20Sopenharmony_ci mask <<= 3; 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci out_be32(reg, (in_be32(reg) & ~mask) | bits); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci return 0; 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci/* 5168c2ecf20Sopenharmony_ci * GPIO LIB API implementation 5178c2ecf20Sopenharmony_ci */ 5188c2ecf20Sopenharmony_ci#ifdef CONFIG_8xx_GPIO 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistruct cpm1_gpio16_chip { 5218c2ecf20Sopenharmony_ci struct of_mm_gpio_chip mm_gc; 5228c2ecf20Sopenharmony_ci spinlock_t lock; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci /* shadowed data register to clear/set bits safely */ 5258c2ecf20Sopenharmony_ci u16 cpdata; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci /* IRQ associated with Pins when relevant */ 5288c2ecf20Sopenharmony_ci int irq[16]; 5298c2ecf20Sopenharmony_ci}; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cistatic void cpm1_gpio16_save_regs(struct of_mm_gpio_chip *mm_gc) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci struct cpm1_gpio16_chip *cpm1_gc = 5348c2ecf20Sopenharmony_ci container_of(mm_gc, struct cpm1_gpio16_chip, mm_gc); 5358c2ecf20Sopenharmony_ci struct cpm_ioport16 __iomem *iop = mm_gc->regs; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci cpm1_gc->cpdata = in_be16(&iop->dat); 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic int cpm1_gpio16_get(struct gpio_chip *gc, unsigned int gpio) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 5438c2ecf20Sopenharmony_ci struct cpm_ioport16 __iomem *iop = mm_gc->regs; 5448c2ecf20Sopenharmony_ci u16 pin_mask; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci pin_mask = 1 << (15 - gpio); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci return !!(in_be16(&iop->dat) & pin_mask); 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cistatic void __cpm1_gpio16_set(struct of_mm_gpio_chip *mm_gc, u16 pin_mask, 5528c2ecf20Sopenharmony_ci int value) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); 5558c2ecf20Sopenharmony_ci struct cpm_ioport16 __iomem *iop = mm_gc->regs; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci if (value) 5588c2ecf20Sopenharmony_ci cpm1_gc->cpdata |= pin_mask; 5598c2ecf20Sopenharmony_ci else 5608c2ecf20Sopenharmony_ci cpm1_gc->cpdata &= ~pin_mask; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci out_be16(&iop->dat, cpm1_gc->cpdata); 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 5688c2ecf20Sopenharmony_ci struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); 5698c2ecf20Sopenharmony_ci unsigned long flags; 5708c2ecf20Sopenharmony_ci u16 pin_mask = 1 << (15 - gpio); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci spin_lock_irqsave(&cpm1_gc->lock, flags); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci __cpm1_gpio16_set(mm_gc, pin_mask, value); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cpm1_gc->lock, flags); 5778c2ecf20Sopenharmony_ci} 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_cistatic int cpm1_gpio16_to_irq(struct gpio_chip *gc, unsigned int gpio) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 5828c2ecf20Sopenharmony_ci struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci return cpm1_gc->irq[gpio] ? : -ENXIO; 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_cistatic int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) 5888c2ecf20Sopenharmony_ci{ 5898c2ecf20Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 5908c2ecf20Sopenharmony_ci struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); 5918c2ecf20Sopenharmony_ci struct cpm_ioport16 __iomem *iop = mm_gc->regs; 5928c2ecf20Sopenharmony_ci unsigned long flags; 5938c2ecf20Sopenharmony_ci u16 pin_mask = 1 << (15 - gpio); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci spin_lock_irqsave(&cpm1_gc->lock, flags); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci setbits16(&iop->dir, pin_mask); 5988c2ecf20Sopenharmony_ci __cpm1_gpio16_set(mm_gc, pin_mask, val); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cpm1_gc->lock, flags); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci return 0; 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_cistatic int cpm1_gpio16_dir_in(struct gpio_chip *gc, unsigned int gpio) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 6088c2ecf20Sopenharmony_ci struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); 6098c2ecf20Sopenharmony_ci struct cpm_ioport16 __iomem *iop = mm_gc->regs; 6108c2ecf20Sopenharmony_ci unsigned long flags; 6118c2ecf20Sopenharmony_ci u16 pin_mask = 1 << (15 - gpio); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci spin_lock_irqsave(&cpm1_gc->lock, flags); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci clrbits16(&iop->dir, pin_mask); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cpm1_gc->lock, flags); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci return 0; 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ciint cpm1_gpiochip_add16(struct device *dev) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 6258c2ecf20Sopenharmony_ci struct cpm1_gpio16_chip *cpm1_gc; 6268c2ecf20Sopenharmony_ci struct of_mm_gpio_chip *mm_gc; 6278c2ecf20Sopenharmony_ci struct gpio_chip *gc; 6288c2ecf20Sopenharmony_ci u16 mask; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL); 6318c2ecf20Sopenharmony_ci if (!cpm1_gc) 6328c2ecf20Sopenharmony_ci return -ENOMEM; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci spin_lock_init(&cpm1_gc->lock); 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci if (!of_property_read_u16(np, "fsl,cpm1-gpio-irq-mask", &mask)) { 6378c2ecf20Sopenharmony_ci int i, j; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci for (i = 0, j = 0; i < 16; i++) 6408c2ecf20Sopenharmony_ci if (mask & (1 << (15 - i))) 6418c2ecf20Sopenharmony_ci cpm1_gc->irq[i] = irq_of_parse_and_map(np, j++); 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci mm_gc = &cpm1_gc->mm_gc; 6458c2ecf20Sopenharmony_ci gc = &mm_gc->gc; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci mm_gc->save_regs = cpm1_gpio16_save_regs; 6488c2ecf20Sopenharmony_ci gc->ngpio = 16; 6498c2ecf20Sopenharmony_ci gc->direction_input = cpm1_gpio16_dir_in; 6508c2ecf20Sopenharmony_ci gc->direction_output = cpm1_gpio16_dir_out; 6518c2ecf20Sopenharmony_ci gc->get = cpm1_gpio16_get; 6528c2ecf20Sopenharmony_ci gc->set = cpm1_gpio16_set; 6538c2ecf20Sopenharmony_ci gc->to_irq = cpm1_gpio16_to_irq; 6548c2ecf20Sopenharmony_ci gc->parent = dev; 6558c2ecf20Sopenharmony_ci gc->owner = THIS_MODULE; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci return of_mm_gpiochip_add_data(np, mm_gc, cpm1_gc); 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistruct cpm1_gpio32_chip { 6618c2ecf20Sopenharmony_ci struct of_mm_gpio_chip mm_gc; 6628c2ecf20Sopenharmony_ci spinlock_t lock; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci /* shadowed data register to clear/set bits safely */ 6658c2ecf20Sopenharmony_ci u32 cpdata; 6668c2ecf20Sopenharmony_ci}; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_cistatic void cpm1_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci struct cpm1_gpio32_chip *cpm1_gc = 6718c2ecf20Sopenharmony_ci container_of(mm_gc, struct cpm1_gpio32_chip, mm_gc); 6728c2ecf20Sopenharmony_ci struct cpm_ioport32b __iomem *iop = mm_gc->regs; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci cpm1_gc->cpdata = in_be32(&iop->dat); 6758c2ecf20Sopenharmony_ci} 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_cistatic int cpm1_gpio32_get(struct gpio_chip *gc, unsigned int gpio) 6788c2ecf20Sopenharmony_ci{ 6798c2ecf20Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 6808c2ecf20Sopenharmony_ci struct cpm_ioport32b __iomem *iop = mm_gc->regs; 6818c2ecf20Sopenharmony_ci u32 pin_mask; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci pin_mask = 1 << (31 - gpio); 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci return !!(in_be32(&iop->dat) & pin_mask); 6868c2ecf20Sopenharmony_ci} 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_cistatic void __cpm1_gpio32_set(struct of_mm_gpio_chip *mm_gc, u32 pin_mask, 6898c2ecf20Sopenharmony_ci int value) 6908c2ecf20Sopenharmony_ci{ 6918c2ecf20Sopenharmony_ci struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); 6928c2ecf20Sopenharmony_ci struct cpm_ioport32b __iomem *iop = mm_gc->regs; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci if (value) 6958c2ecf20Sopenharmony_ci cpm1_gc->cpdata |= pin_mask; 6968c2ecf20Sopenharmony_ci else 6978c2ecf20Sopenharmony_ci cpm1_gc->cpdata &= ~pin_mask; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci out_be32(&iop->dat, cpm1_gc->cpdata); 7008c2ecf20Sopenharmony_ci} 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_cistatic void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 7058c2ecf20Sopenharmony_ci struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); 7068c2ecf20Sopenharmony_ci unsigned long flags; 7078c2ecf20Sopenharmony_ci u32 pin_mask = 1 << (31 - gpio); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci spin_lock_irqsave(&cpm1_gc->lock, flags); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci __cpm1_gpio32_set(mm_gc, pin_mask, value); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cpm1_gc->lock, flags); 7148c2ecf20Sopenharmony_ci} 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_cistatic int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 7198c2ecf20Sopenharmony_ci struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); 7208c2ecf20Sopenharmony_ci struct cpm_ioport32b __iomem *iop = mm_gc->regs; 7218c2ecf20Sopenharmony_ci unsigned long flags; 7228c2ecf20Sopenharmony_ci u32 pin_mask = 1 << (31 - gpio); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci spin_lock_irqsave(&cpm1_gc->lock, flags); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci setbits32(&iop->dir, pin_mask); 7278c2ecf20Sopenharmony_ci __cpm1_gpio32_set(mm_gc, pin_mask, val); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cpm1_gc->lock, flags); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci return 0; 7328c2ecf20Sopenharmony_ci} 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_cistatic int cpm1_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio) 7358c2ecf20Sopenharmony_ci{ 7368c2ecf20Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 7378c2ecf20Sopenharmony_ci struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); 7388c2ecf20Sopenharmony_ci struct cpm_ioport32b __iomem *iop = mm_gc->regs; 7398c2ecf20Sopenharmony_ci unsigned long flags; 7408c2ecf20Sopenharmony_ci u32 pin_mask = 1 << (31 - gpio); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci spin_lock_irqsave(&cpm1_gc->lock, flags); 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci clrbits32(&iop->dir, pin_mask); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cpm1_gc->lock, flags); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci return 0; 7498c2ecf20Sopenharmony_ci} 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ciint cpm1_gpiochip_add32(struct device *dev) 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 7548c2ecf20Sopenharmony_ci struct cpm1_gpio32_chip *cpm1_gc; 7558c2ecf20Sopenharmony_ci struct of_mm_gpio_chip *mm_gc; 7568c2ecf20Sopenharmony_ci struct gpio_chip *gc; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL); 7598c2ecf20Sopenharmony_ci if (!cpm1_gc) 7608c2ecf20Sopenharmony_ci return -ENOMEM; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci spin_lock_init(&cpm1_gc->lock); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci mm_gc = &cpm1_gc->mm_gc; 7658c2ecf20Sopenharmony_ci gc = &mm_gc->gc; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci mm_gc->save_regs = cpm1_gpio32_save_regs; 7688c2ecf20Sopenharmony_ci gc->ngpio = 32; 7698c2ecf20Sopenharmony_ci gc->direction_input = cpm1_gpio32_dir_in; 7708c2ecf20Sopenharmony_ci gc->direction_output = cpm1_gpio32_dir_out; 7718c2ecf20Sopenharmony_ci gc->get = cpm1_gpio32_get; 7728c2ecf20Sopenharmony_ci gc->set = cpm1_gpio32_set; 7738c2ecf20Sopenharmony_ci gc->parent = dev; 7748c2ecf20Sopenharmony_ci gc->owner = THIS_MODULE; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci return of_mm_gpiochip_add_data(np, mm_gc, cpm1_gc); 7778c2ecf20Sopenharmony_ci} 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci#endif /* CONFIG_8xx_GPIO */ 780