162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * General Purpose functions for the global management of the 462306a36Sopenharmony_ci * Communication Processor Module. 562306a36Sopenharmony_ci * Copyright (c) 1997 Dan error_act (dmalek@jlc.net) 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * In addition to the individual control of the communication 862306a36Sopenharmony_ci * channels, there are a few functions that globally affect the 962306a36Sopenharmony_ci * communication processor. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Buffer descriptors must be allocated from the dual ported memory 1262306a36Sopenharmony_ci * space. The allocator for that is here. When the communication 1362306a36Sopenharmony_ci * process is reset, we reclaim the memory available. There is 1462306a36Sopenharmony_ci * currently no deallocator for this memory. 1562306a36Sopenharmony_ci * The amount of space available is platform dependent. On the 1662306a36Sopenharmony_ci * MBX, the EPPC software loads additional microcode into the 1762306a36Sopenharmony_ci * communication processor, and uses some of the DP ram for this 1862306a36Sopenharmony_ci * purpose. Current, the first 512 bytes and the last 256 bytes of 1962306a36Sopenharmony_ci * memory are used. Right now I am conservative and only use the 2062306a36Sopenharmony_ci * memory that can never be used for microcode. If there are 2162306a36Sopenharmony_ci * applications that require more DP ram, we can expand the boundaries 2262306a36Sopenharmony_ci * but then we have to be careful of any downloaded microcode. 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_ci#include <linux/errno.h> 2562306a36Sopenharmony_ci#include <linux/sched.h> 2662306a36Sopenharmony_ci#include <linux/kernel.h> 2762306a36Sopenharmony_ci#include <linux/dma-mapping.h> 2862306a36Sopenharmony_ci#include <linux/param.h> 2962306a36Sopenharmony_ci#include <linux/string.h> 3062306a36Sopenharmony_ci#include <linux/mm.h> 3162306a36Sopenharmony_ci#include <linux/interrupt.h> 3262306a36Sopenharmony_ci#include <linux/irq.h> 3362306a36Sopenharmony_ci#include <linux/module.h> 3462306a36Sopenharmony_ci#include <linux/spinlock.h> 3562306a36Sopenharmony_ci#include <linux/slab.h> 3662306a36Sopenharmony_ci#include <linux/of_irq.h> 3762306a36Sopenharmony_ci#include <asm/page.h> 3862306a36Sopenharmony_ci#include <asm/8xx_immap.h> 3962306a36Sopenharmony_ci#include <asm/cpm1.h> 4062306a36Sopenharmony_ci#include <asm/io.h> 4162306a36Sopenharmony_ci#include <asm/rheap.h> 4262306a36Sopenharmony_ci#include <asm/cpm.h> 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#include <sysdev/fsl_soc.h> 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#ifdef CONFIG_8xx_GPIO 4762306a36Sopenharmony_ci#include <linux/gpio/legacy-of-mm-gpiochip.h> 4862306a36Sopenharmony_ci#endif 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define CPM_MAP_SIZE (0x4000) 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cicpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */ 5362306a36Sopenharmony_ciimmap_t __iomem *mpc8xx_immr = (void __iomem *)VIRT_IMMR_BASE; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_civoid __init cpm_reset(void) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci cpmp = &mpc8xx_immr->im_cpm; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#ifndef CONFIG_PPC_EARLY_DEBUG_CPM 6062306a36Sopenharmony_ci /* Perform a reset. */ 6162306a36Sopenharmony_ci out_be16(&cpmp->cp_cpcr, CPM_CR_RST | CPM_CR_FLG); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* Wait for it. */ 6462306a36Sopenharmony_ci while (in_be16(&cpmp->cp_cpcr) & CPM_CR_FLG); 6562306a36Sopenharmony_ci#endif 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#ifdef CONFIG_UCODE_PATCH 6862306a36Sopenharmony_ci cpm_load_patch(cpmp); 6962306a36Sopenharmony_ci#endif 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci /* 7262306a36Sopenharmony_ci * Set SDMA Bus Request priority 5. 7362306a36Sopenharmony_ci * On 860T, this also enables FEC priority 6. I am not sure 7462306a36Sopenharmony_ci * this is what we really want for some applications, but the 7562306a36Sopenharmony_ci * manual recommends it. 7662306a36Sopenharmony_ci * Bit 25, FAM can also be set to use FEC aggressive mode (860T). 7762306a36Sopenharmony_ci */ 7862306a36Sopenharmony_ci if ((mfspr(SPRN_IMMR) & 0xffff) == 0x0900) /* MPC885 */ 7962306a36Sopenharmony_ci out_be32(&mpc8xx_immr->im_siu_conf.sc_sdcr, 0x40); 8062306a36Sopenharmony_ci else 8162306a36Sopenharmony_ci out_be32(&mpc8xx_immr->im_siu_conf.sc_sdcr, 1); 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic DEFINE_SPINLOCK(cmd_lock); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci#define MAX_CR_CMD_LOOPS 10000 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ciint cpm_command(u32 command, u8 opcode) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci int i, ret; 9162306a36Sopenharmony_ci unsigned long flags; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (command & 0xffffff03) 9462306a36Sopenharmony_ci return -EINVAL; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci spin_lock_irqsave(&cmd_lock, flags); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci ret = 0; 9962306a36Sopenharmony_ci out_be16(&cpmp->cp_cpcr, command | CPM_CR_FLG | (opcode << 8)); 10062306a36Sopenharmony_ci for (i = 0; i < MAX_CR_CMD_LOOPS; i++) 10162306a36Sopenharmony_ci if ((in_be16(&cpmp->cp_cpcr) & CPM_CR_FLG) == 0) 10262306a36Sopenharmony_ci goto out; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci printk(KERN_ERR "%s(): Not able to issue CPM command\n", __func__); 10562306a36Sopenharmony_ci ret = -EIO; 10662306a36Sopenharmony_ciout: 10762306a36Sopenharmony_ci spin_unlock_irqrestore(&cmd_lock, flags); 10862306a36Sopenharmony_ci return ret; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ciEXPORT_SYMBOL(cpm_command); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/* 11362306a36Sopenharmony_ci * Set a baud rate generator. This needs lots of work. There are 11462306a36Sopenharmony_ci * four BRGs, any of which can be wired to any channel. 11562306a36Sopenharmony_ci * The internal baud rate clock is the system clock divided by 16. 11662306a36Sopenharmony_ci * This assumes the baudrate is 16x oversampled by the uart. 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_ci#define BRG_INT_CLK (get_brgfreq()) 11962306a36Sopenharmony_ci#define BRG_UART_CLK (BRG_INT_CLK/16) 12062306a36Sopenharmony_ci#define BRG_UART_CLK_DIV16 (BRG_UART_CLK/16) 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_civoid 12362306a36Sopenharmony_cicpm_setbrg(uint brg, uint rate) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci u32 __iomem *bp; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* This is good enough to get SMCs running..... */ 12862306a36Sopenharmony_ci bp = &cpmp->cp_brgc1; 12962306a36Sopenharmony_ci bp += brg; 13062306a36Sopenharmony_ci /* 13162306a36Sopenharmony_ci * The BRG has a 12-bit counter. For really slow baud rates (or 13262306a36Sopenharmony_ci * really fast processors), we may have to further divide by 16. 13362306a36Sopenharmony_ci */ 13462306a36Sopenharmony_ci if (((BRG_UART_CLK / rate) - 1) < 4096) 13562306a36Sopenharmony_ci out_be32(bp, (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN); 13662306a36Sopenharmony_ci else 13762306a36Sopenharmony_ci out_be32(bp, (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) | 13862306a36Sopenharmony_ci CPM_BRG_EN | CPM_BRG_DIV16); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ciEXPORT_SYMBOL(cpm_setbrg); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistruct cpm_ioport16 { 14362306a36Sopenharmony_ci __be16 dir, par, odr_sor, dat, intr; 14462306a36Sopenharmony_ci __be16 res[3]; 14562306a36Sopenharmony_ci}; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistruct cpm_ioport32b { 14862306a36Sopenharmony_ci __be32 dir, par, odr, dat; 14962306a36Sopenharmony_ci}; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistruct cpm_ioport32e { 15262306a36Sopenharmony_ci __be32 dir, par, sor, odr, dat; 15362306a36Sopenharmony_ci}; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic void __init cpm1_set_pin32(int port, int pin, int flags) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci struct cpm_ioport32e __iomem *iop; 15862306a36Sopenharmony_ci pin = 1 << (31 - pin); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (port == CPM_PORTB) 16162306a36Sopenharmony_ci iop = (struct cpm_ioport32e __iomem *) 16262306a36Sopenharmony_ci &mpc8xx_immr->im_cpm.cp_pbdir; 16362306a36Sopenharmony_ci else 16462306a36Sopenharmony_ci iop = (struct cpm_ioport32e __iomem *) 16562306a36Sopenharmony_ci &mpc8xx_immr->im_cpm.cp_pedir; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (flags & CPM_PIN_OUTPUT) 16862306a36Sopenharmony_ci setbits32(&iop->dir, pin); 16962306a36Sopenharmony_ci else 17062306a36Sopenharmony_ci clrbits32(&iop->dir, pin); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (!(flags & CPM_PIN_GPIO)) 17362306a36Sopenharmony_ci setbits32(&iop->par, pin); 17462306a36Sopenharmony_ci else 17562306a36Sopenharmony_ci clrbits32(&iop->par, pin); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (port == CPM_PORTB) { 17862306a36Sopenharmony_ci if (flags & CPM_PIN_OPENDRAIN) 17962306a36Sopenharmony_ci setbits16(&mpc8xx_immr->im_cpm.cp_pbodr, pin); 18062306a36Sopenharmony_ci else 18162306a36Sopenharmony_ci clrbits16(&mpc8xx_immr->im_cpm.cp_pbodr, pin); 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (port == CPM_PORTE) { 18562306a36Sopenharmony_ci if (flags & CPM_PIN_SECONDARY) 18662306a36Sopenharmony_ci setbits32(&iop->sor, pin); 18762306a36Sopenharmony_ci else 18862306a36Sopenharmony_ci clrbits32(&iop->sor, pin); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci if (flags & CPM_PIN_OPENDRAIN) 19162306a36Sopenharmony_ci setbits32(&mpc8xx_immr->im_cpm.cp_peodr, pin); 19262306a36Sopenharmony_ci else 19362306a36Sopenharmony_ci clrbits32(&mpc8xx_immr->im_cpm.cp_peodr, pin); 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic void __init cpm1_set_pin16(int port, int pin, int flags) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci struct cpm_ioport16 __iomem *iop = 20062306a36Sopenharmony_ci (struct cpm_ioport16 __iomem *)&mpc8xx_immr->im_ioport; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci pin = 1 << (15 - pin); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (port != 0) 20562306a36Sopenharmony_ci iop += port - 1; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (flags & CPM_PIN_OUTPUT) 20862306a36Sopenharmony_ci setbits16(&iop->dir, pin); 20962306a36Sopenharmony_ci else 21062306a36Sopenharmony_ci clrbits16(&iop->dir, pin); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (!(flags & CPM_PIN_GPIO)) 21362306a36Sopenharmony_ci setbits16(&iop->par, pin); 21462306a36Sopenharmony_ci else 21562306a36Sopenharmony_ci clrbits16(&iop->par, pin); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (port == CPM_PORTA) { 21862306a36Sopenharmony_ci if (flags & CPM_PIN_OPENDRAIN) 21962306a36Sopenharmony_ci setbits16(&iop->odr_sor, pin); 22062306a36Sopenharmony_ci else 22162306a36Sopenharmony_ci clrbits16(&iop->odr_sor, pin); 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci if (port == CPM_PORTC) { 22462306a36Sopenharmony_ci if (flags & CPM_PIN_SECONDARY) 22562306a36Sopenharmony_ci setbits16(&iop->odr_sor, pin); 22662306a36Sopenharmony_ci else 22762306a36Sopenharmony_ci clrbits16(&iop->odr_sor, pin); 22862306a36Sopenharmony_ci if (flags & CPM_PIN_FALLEDGE) 22962306a36Sopenharmony_ci setbits16(&iop->intr, pin); 23062306a36Sopenharmony_ci else 23162306a36Sopenharmony_ci clrbits16(&iop->intr, pin); 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_civoid __init cpm1_set_pin(enum cpm_port port, int pin, int flags) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci if (port == CPM_PORTB || port == CPM_PORTE) 23862306a36Sopenharmony_ci cpm1_set_pin32(port, pin, flags); 23962306a36Sopenharmony_ci else 24062306a36Sopenharmony_ci cpm1_set_pin16(port, pin, flags); 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ciint __init cpm1_clk_setup(enum cpm_clk_target target, int clock, int mode) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci int shift; 24662306a36Sopenharmony_ci int i, bits = 0; 24762306a36Sopenharmony_ci u32 __iomem *reg; 24862306a36Sopenharmony_ci u32 mask = 7; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci u8 clk_map[][3] = { 25162306a36Sopenharmony_ci {CPM_CLK_SCC1, CPM_BRG1, 0}, 25262306a36Sopenharmony_ci {CPM_CLK_SCC1, CPM_BRG2, 1}, 25362306a36Sopenharmony_ci {CPM_CLK_SCC1, CPM_BRG3, 2}, 25462306a36Sopenharmony_ci {CPM_CLK_SCC1, CPM_BRG4, 3}, 25562306a36Sopenharmony_ci {CPM_CLK_SCC1, CPM_CLK1, 4}, 25662306a36Sopenharmony_ci {CPM_CLK_SCC1, CPM_CLK2, 5}, 25762306a36Sopenharmony_ci {CPM_CLK_SCC1, CPM_CLK3, 6}, 25862306a36Sopenharmony_ci {CPM_CLK_SCC1, CPM_CLK4, 7}, 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci {CPM_CLK_SCC2, CPM_BRG1, 0}, 26162306a36Sopenharmony_ci {CPM_CLK_SCC2, CPM_BRG2, 1}, 26262306a36Sopenharmony_ci {CPM_CLK_SCC2, CPM_BRG3, 2}, 26362306a36Sopenharmony_ci {CPM_CLK_SCC2, CPM_BRG4, 3}, 26462306a36Sopenharmony_ci {CPM_CLK_SCC2, CPM_CLK1, 4}, 26562306a36Sopenharmony_ci {CPM_CLK_SCC2, CPM_CLK2, 5}, 26662306a36Sopenharmony_ci {CPM_CLK_SCC2, CPM_CLK3, 6}, 26762306a36Sopenharmony_ci {CPM_CLK_SCC2, CPM_CLK4, 7}, 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci {CPM_CLK_SCC3, CPM_BRG1, 0}, 27062306a36Sopenharmony_ci {CPM_CLK_SCC3, CPM_BRG2, 1}, 27162306a36Sopenharmony_ci {CPM_CLK_SCC3, CPM_BRG3, 2}, 27262306a36Sopenharmony_ci {CPM_CLK_SCC3, CPM_BRG4, 3}, 27362306a36Sopenharmony_ci {CPM_CLK_SCC3, CPM_CLK5, 4}, 27462306a36Sopenharmony_ci {CPM_CLK_SCC3, CPM_CLK6, 5}, 27562306a36Sopenharmony_ci {CPM_CLK_SCC3, CPM_CLK7, 6}, 27662306a36Sopenharmony_ci {CPM_CLK_SCC3, CPM_CLK8, 7}, 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci {CPM_CLK_SCC4, CPM_BRG1, 0}, 27962306a36Sopenharmony_ci {CPM_CLK_SCC4, CPM_BRG2, 1}, 28062306a36Sopenharmony_ci {CPM_CLK_SCC4, CPM_BRG3, 2}, 28162306a36Sopenharmony_ci {CPM_CLK_SCC4, CPM_BRG4, 3}, 28262306a36Sopenharmony_ci {CPM_CLK_SCC4, CPM_CLK5, 4}, 28362306a36Sopenharmony_ci {CPM_CLK_SCC4, CPM_CLK6, 5}, 28462306a36Sopenharmony_ci {CPM_CLK_SCC4, CPM_CLK7, 6}, 28562306a36Sopenharmony_ci {CPM_CLK_SCC4, CPM_CLK8, 7}, 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci {CPM_CLK_SMC1, CPM_BRG1, 0}, 28862306a36Sopenharmony_ci {CPM_CLK_SMC1, CPM_BRG2, 1}, 28962306a36Sopenharmony_ci {CPM_CLK_SMC1, CPM_BRG3, 2}, 29062306a36Sopenharmony_ci {CPM_CLK_SMC1, CPM_BRG4, 3}, 29162306a36Sopenharmony_ci {CPM_CLK_SMC1, CPM_CLK1, 4}, 29262306a36Sopenharmony_ci {CPM_CLK_SMC1, CPM_CLK2, 5}, 29362306a36Sopenharmony_ci {CPM_CLK_SMC1, CPM_CLK3, 6}, 29462306a36Sopenharmony_ci {CPM_CLK_SMC1, CPM_CLK4, 7}, 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci {CPM_CLK_SMC2, CPM_BRG1, 0}, 29762306a36Sopenharmony_ci {CPM_CLK_SMC2, CPM_BRG2, 1}, 29862306a36Sopenharmony_ci {CPM_CLK_SMC2, CPM_BRG3, 2}, 29962306a36Sopenharmony_ci {CPM_CLK_SMC2, CPM_BRG4, 3}, 30062306a36Sopenharmony_ci {CPM_CLK_SMC2, CPM_CLK5, 4}, 30162306a36Sopenharmony_ci {CPM_CLK_SMC2, CPM_CLK6, 5}, 30262306a36Sopenharmony_ci {CPM_CLK_SMC2, CPM_CLK7, 6}, 30362306a36Sopenharmony_ci {CPM_CLK_SMC2, CPM_CLK8, 7}, 30462306a36Sopenharmony_ci }; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci switch (target) { 30762306a36Sopenharmony_ci case CPM_CLK_SCC1: 30862306a36Sopenharmony_ci reg = &mpc8xx_immr->im_cpm.cp_sicr; 30962306a36Sopenharmony_ci shift = 0; 31062306a36Sopenharmony_ci break; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci case CPM_CLK_SCC2: 31362306a36Sopenharmony_ci reg = &mpc8xx_immr->im_cpm.cp_sicr; 31462306a36Sopenharmony_ci shift = 8; 31562306a36Sopenharmony_ci break; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci case CPM_CLK_SCC3: 31862306a36Sopenharmony_ci reg = &mpc8xx_immr->im_cpm.cp_sicr; 31962306a36Sopenharmony_ci shift = 16; 32062306a36Sopenharmony_ci break; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci case CPM_CLK_SCC4: 32362306a36Sopenharmony_ci reg = &mpc8xx_immr->im_cpm.cp_sicr; 32462306a36Sopenharmony_ci shift = 24; 32562306a36Sopenharmony_ci break; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci case CPM_CLK_SMC1: 32862306a36Sopenharmony_ci reg = &mpc8xx_immr->im_cpm.cp_simode; 32962306a36Sopenharmony_ci shift = 12; 33062306a36Sopenharmony_ci break; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci case CPM_CLK_SMC2: 33362306a36Sopenharmony_ci reg = &mpc8xx_immr->im_cpm.cp_simode; 33462306a36Sopenharmony_ci shift = 28; 33562306a36Sopenharmony_ci break; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci default: 33862306a36Sopenharmony_ci printk(KERN_ERR "cpm1_clock_setup: invalid clock target\n"); 33962306a36Sopenharmony_ci return -EINVAL; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(clk_map); i++) { 34362306a36Sopenharmony_ci if (clk_map[i][0] == target && clk_map[i][1] == clock) { 34462306a36Sopenharmony_ci bits = clk_map[i][2]; 34562306a36Sopenharmony_ci break; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (i == ARRAY_SIZE(clk_map)) { 35062306a36Sopenharmony_ci printk(KERN_ERR "cpm1_clock_setup: invalid clock combination\n"); 35162306a36Sopenharmony_ci return -EINVAL; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci bits <<= shift; 35562306a36Sopenharmony_ci mask <<= shift; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci if (reg == &mpc8xx_immr->im_cpm.cp_sicr) { 35862306a36Sopenharmony_ci if (mode == CPM_CLK_RTX) { 35962306a36Sopenharmony_ci bits |= bits << 3; 36062306a36Sopenharmony_ci mask |= mask << 3; 36162306a36Sopenharmony_ci } else if (mode == CPM_CLK_RX) { 36262306a36Sopenharmony_ci bits <<= 3; 36362306a36Sopenharmony_ci mask <<= 3; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci out_be32(reg, (in_be32(reg) & ~mask) | bits); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci return 0; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci/* 37362306a36Sopenharmony_ci * GPIO LIB API implementation 37462306a36Sopenharmony_ci */ 37562306a36Sopenharmony_ci#ifdef CONFIG_8xx_GPIO 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistruct cpm1_gpio16_chip { 37862306a36Sopenharmony_ci struct of_mm_gpio_chip mm_gc; 37962306a36Sopenharmony_ci spinlock_t lock; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci /* shadowed data register to clear/set bits safely */ 38262306a36Sopenharmony_ci u16 cpdata; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* IRQ associated with Pins when relevant */ 38562306a36Sopenharmony_ci int irq[16]; 38662306a36Sopenharmony_ci}; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic void cpm1_gpio16_save_regs(struct of_mm_gpio_chip *mm_gc) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci struct cpm1_gpio16_chip *cpm1_gc = 39162306a36Sopenharmony_ci container_of(mm_gc, struct cpm1_gpio16_chip, mm_gc); 39262306a36Sopenharmony_ci struct cpm_ioport16 __iomem *iop = mm_gc->regs; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci cpm1_gc->cpdata = in_be16(&iop->dat); 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cistatic int cpm1_gpio16_get(struct gpio_chip *gc, unsigned int gpio) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 40062306a36Sopenharmony_ci struct cpm_ioport16 __iomem *iop = mm_gc->regs; 40162306a36Sopenharmony_ci u16 pin_mask; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci pin_mask = 1 << (15 - gpio); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci return !!(in_be16(&iop->dat) & pin_mask); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic void __cpm1_gpio16_set(struct of_mm_gpio_chip *mm_gc, u16 pin_mask, 40962306a36Sopenharmony_ci int value) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); 41262306a36Sopenharmony_ci struct cpm_ioport16 __iomem *iop = mm_gc->regs; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (value) 41562306a36Sopenharmony_ci cpm1_gc->cpdata |= pin_mask; 41662306a36Sopenharmony_ci else 41762306a36Sopenharmony_ci cpm1_gc->cpdata &= ~pin_mask; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci out_be16(&iop->dat, cpm1_gc->cpdata); 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 42562306a36Sopenharmony_ci struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); 42662306a36Sopenharmony_ci unsigned long flags; 42762306a36Sopenharmony_ci u16 pin_mask = 1 << (15 - gpio); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci spin_lock_irqsave(&cpm1_gc->lock, flags); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci __cpm1_gpio16_set(mm_gc, pin_mask, value); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci spin_unlock_irqrestore(&cpm1_gc->lock, flags); 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic int cpm1_gpio16_to_irq(struct gpio_chip *gc, unsigned int gpio) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 43962306a36Sopenharmony_ci struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci return cpm1_gc->irq[gpio] ? : -ENXIO; 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 44762306a36Sopenharmony_ci struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); 44862306a36Sopenharmony_ci struct cpm_ioport16 __iomem *iop = mm_gc->regs; 44962306a36Sopenharmony_ci unsigned long flags; 45062306a36Sopenharmony_ci u16 pin_mask = 1 << (15 - gpio); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci spin_lock_irqsave(&cpm1_gc->lock, flags); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci setbits16(&iop->dir, pin_mask); 45562306a36Sopenharmony_ci __cpm1_gpio16_set(mm_gc, pin_mask, val); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci spin_unlock_irqrestore(&cpm1_gc->lock, flags); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci return 0; 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic int cpm1_gpio16_dir_in(struct gpio_chip *gc, unsigned int gpio) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 46562306a36Sopenharmony_ci struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); 46662306a36Sopenharmony_ci struct cpm_ioport16 __iomem *iop = mm_gc->regs; 46762306a36Sopenharmony_ci unsigned long flags; 46862306a36Sopenharmony_ci u16 pin_mask = 1 << (15 - gpio); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci spin_lock_irqsave(&cpm1_gc->lock, flags); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci clrbits16(&iop->dir, pin_mask); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci spin_unlock_irqrestore(&cpm1_gc->lock, flags); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci return 0; 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ciint cpm1_gpiochip_add16(struct device *dev) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci struct device_node *np = dev->of_node; 48262306a36Sopenharmony_ci struct cpm1_gpio16_chip *cpm1_gc; 48362306a36Sopenharmony_ci struct of_mm_gpio_chip *mm_gc; 48462306a36Sopenharmony_ci struct gpio_chip *gc; 48562306a36Sopenharmony_ci u16 mask; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL); 48862306a36Sopenharmony_ci if (!cpm1_gc) 48962306a36Sopenharmony_ci return -ENOMEM; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci spin_lock_init(&cpm1_gc->lock); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (!of_property_read_u16(np, "fsl,cpm1-gpio-irq-mask", &mask)) { 49462306a36Sopenharmony_ci int i, j; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci for (i = 0, j = 0; i < 16; i++) 49762306a36Sopenharmony_ci if (mask & (1 << (15 - i))) 49862306a36Sopenharmony_ci cpm1_gc->irq[i] = irq_of_parse_and_map(np, j++); 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci mm_gc = &cpm1_gc->mm_gc; 50262306a36Sopenharmony_ci gc = &mm_gc->gc; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci mm_gc->save_regs = cpm1_gpio16_save_regs; 50562306a36Sopenharmony_ci gc->ngpio = 16; 50662306a36Sopenharmony_ci gc->direction_input = cpm1_gpio16_dir_in; 50762306a36Sopenharmony_ci gc->direction_output = cpm1_gpio16_dir_out; 50862306a36Sopenharmony_ci gc->get = cpm1_gpio16_get; 50962306a36Sopenharmony_ci gc->set = cpm1_gpio16_set; 51062306a36Sopenharmony_ci gc->to_irq = cpm1_gpio16_to_irq; 51162306a36Sopenharmony_ci gc->parent = dev; 51262306a36Sopenharmony_ci gc->owner = THIS_MODULE; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci return of_mm_gpiochip_add_data(np, mm_gc, cpm1_gc); 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_cistruct cpm1_gpio32_chip { 51862306a36Sopenharmony_ci struct of_mm_gpio_chip mm_gc; 51962306a36Sopenharmony_ci spinlock_t lock; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci /* shadowed data register to clear/set bits safely */ 52262306a36Sopenharmony_ci u32 cpdata; 52362306a36Sopenharmony_ci}; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_cistatic void cpm1_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci struct cpm1_gpio32_chip *cpm1_gc = 52862306a36Sopenharmony_ci container_of(mm_gc, struct cpm1_gpio32_chip, mm_gc); 52962306a36Sopenharmony_ci struct cpm_ioport32b __iomem *iop = mm_gc->regs; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci cpm1_gc->cpdata = in_be32(&iop->dat); 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_cistatic int cpm1_gpio32_get(struct gpio_chip *gc, unsigned int gpio) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 53762306a36Sopenharmony_ci struct cpm_ioport32b __iomem *iop = mm_gc->regs; 53862306a36Sopenharmony_ci u32 pin_mask; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci pin_mask = 1 << (31 - gpio); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci return !!(in_be32(&iop->dat) & pin_mask); 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_cistatic void __cpm1_gpio32_set(struct of_mm_gpio_chip *mm_gc, u32 pin_mask, 54662306a36Sopenharmony_ci int value) 54762306a36Sopenharmony_ci{ 54862306a36Sopenharmony_ci struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); 54962306a36Sopenharmony_ci struct cpm_ioport32b __iomem *iop = mm_gc->regs; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci if (value) 55262306a36Sopenharmony_ci cpm1_gc->cpdata |= pin_mask; 55362306a36Sopenharmony_ci else 55462306a36Sopenharmony_ci cpm1_gc->cpdata &= ~pin_mask; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci out_be32(&iop->dat, cpm1_gc->cpdata); 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_cistatic void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 56262306a36Sopenharmony_ci struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); 56362306a36Sopenharmony_ci unsigned long flags; 56462306a36Sopenharmony_ci u32 pin_mask = 1 << (31 - gpio); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci spin_lock_irqsave(&cpm1_gc->lock, flags); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci __cpm1_gpio32_set(mm_gc, pin_mask, value); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci spin_unlock_irqrestore(&cpm1_gc->lock, flags); 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_cistatic int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 57662306a36Sopenharmony_ci struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); 57762306a36Sopenharmony_ci struct cpm_ioport32b __iomem *iop = mm_gc->regs; 57862306a36Sopenharmony_ci unsigned long flags; 57962306a36Sopenharmony_ci u32 pin_mask = 1 << (31 - gpio); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci spin_lock_irqsave(&cpm1_gc->lock, flags); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci setbits32(&iop->dir, pin_mask); 58462306a36Sopenharmony_ci __cpm1_gpio32_set(mm_gc, pin_mask, val); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci spin_unlock_irqrestore(&cpm1_gc->lock, flags); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci return 0; 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_cistatic int cpm1_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 59462306a36Sopenharmony_ci struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); 59562306a36Sopenharmony_ci struct cpm_ioport32b __iomem *iop = mm_gc->regs; 59662306a36Sopenharmony_ci unsigned long flags; 59762306a36Sopenharmony_ci u32 pin_mask = 1 << (31 - gpio); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci spin_lock_irqsave(&cpm1_gc->lock, flags); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci clrbits32(&iop->dir, pin_mask); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci spin_unlock_irqrestore(&cpm1_gc->lock, flags); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci return 0; 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ciint cpm1_gpiochip_add32(struct device *dev) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci struct device_node *np = dev->of_node; 61162306a36Sopenharmony_ci struct cpm1_gpio32_chip *cpm1_gc; 61262306a36Sopenharmony_ci struct of_mm_gpio_chip *mm_gc; 61362306a36Sopenharmony_ci struct gpio_chip *gc; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL); 61662306a36Sopenharmony_ci if (!cpm1_gc) 61762306a36Sopenharmony_ci return -ENOMEM; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci spin_lock_init(&cpm1_gc->lock); 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci mm_gc = &cpm1_gc->mm_gc; 62262306a36Sopenharmony_ci gc = &mm_gc->gc; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci mm_gc->save_regs = cpm1_gpio32_save_regs; 62562306a36Sopenharmony_ci gc->ngpio = 32; 62662306a36Sopenharmony_ci gc->direction_input = cpm1_gpio32_dir_in; 62762306a36Sopenharmony_ci gc->direction_output = cpm1_gpio32_dir_out; 62862306a36Sopenharmony_ci gc->get = cpm1_gpio32_get; 62962306a36Sopenharmony_ci gc->set = cpm1_gpio32_set; 63062306a36Sopenharmony_ci gc->parent = dev; 63162306a36Sopenharmony_ci gc->owner = THIS_MODULE; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci return of_mm_gpiochip_add_data(np, mm_gc, cpm1_gc); 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci#endif /* CONFIG_8xx_GPIO */ 637