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