Merge tag 'powerpc-5.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux

Pull powerpc updates from Michael Ellerman:
 "Notable changes:

   - Removal of the NPU DMA code, used by the out-of-tree Nvidia driver,
     as well as some other functions only used by drivers that haven't
     (yet?) made it upstream.

   - A fix for a bug in our handling of hardware watchpoints (eg. perf
     record -e mem: ...) which could lead to register corruption and
     kernel crashes.

   - Enable HAVE_ARCH_HUGE_VMAP, which allows us to use large pages for
     vmalloc when using the Radix MMU.

   - A large but incremental rewrite of our exception handling code to
     use gas macros rather than multiple levels of nested CPP macros.

  And the usual small fixes, cleanups and improvements.

  Thanks to: Alastair D'Silva, Alexey Kardashevskiy, Andreas Schwab,
  Aneesh Kumar K.V, Anju T Sudhakar, Anton Blanchard, Arnd Bergmann,
  Athira Rajeev, Cédric Le Goater, Christian Lamparter, Christophe
  Leroy, Christophe Lombard, Christoph Hellwig, Daniel Axtens, Denis
  Efremov, Enrico Weigelt, Frederic Barrat, Gautham R. Shenoy, Geert
  Uytterhoeven, Geliang Tang, Gen Zhang, Greg Kroah-Hartman, Greg Kurz,
  Gustavo Romero, Krzysztof Kozlowski, Madhavan Srinivasan, Masahiro
  Yamada, Mathieu Malaterre, Michael Neuling, Nathan Lynch, Naveen N.
  Rao, Nicholas Piggin, Nishad Kamdar, Oliver O'Halloran, Qian Cai, Ravi
  Bangoria, Sachin Sant, Sam Bobroff, Satheesh Rajendran, Segher
  Boessenkool, Shaokun Zhang, Shawn Anastasio, Stewart Smith, Suraj
  Jitindar Singh, Thiago Jung Bauermann, YueHaibing"

* tag 'powerpc-5.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux: (163 commits)
  powerpc/powernv/idle: Fix restore of SPRN_LDBAR for POWER9 stop state.
  powerpc/eeh: Handle hugepages in ioremap space
  ocxl: Update for AFU descriptor template version 1.1
  powerpc/boot: pass CONFIG options in a simpler and more robust way
  powerpc/boot: add {get, put}_unaligned_be32 to xz_config.h
  powerpc/irq: Don't WARN continuously in arch_local_irq_restore()
  powerpc/module64: Use symbolic instructions names.
  powerpc/module32: Use symbolic instructions names.
  powerpc: Move PPC_HA() PPC_HI() and PPC_LO() to ppc-opcode.h
  powerpc/module64: Fix comment in R_PPC64_ENTRY handling
  powerpc/boot: Add lzo support for uImage
  powerpc/boot: Add lzma support for uImage
  powerpc/boot: don't force gzipped uImage
  powerpc/8xx: Add microcode patch to move SMC parameter RAM.
  powerpc/8xx: Use IO accessors in microcode programming.
  powerpc/8xx: replace #ifdefs by IS_ENABLED() in microcode.c
  powerpc/8xx: refactor programming of microcode CPM params.
  powerpc/8xx: refactor printing of microcode patch name.
  powerpc/8xx: Refactor microcode write
  powerpc/8xx: refactor writing of CPM microcode arrays
  ...
This commit is contained in:
Linus Torvalds
2019-07-13 16:08:36 -07:00
224 ha cambiato i file con 3634 aggiunte e 3534 eliminazioni

Vedi File

@@ -157,6 +157,13 @@ config I2C_SPI_SMC1_UCODE_PATCH
help
Help not implemented yet, coming soon.
config SMC_UCODE_PATCH
bool "SMC relocation patch"
help
This microcode relocates SMC1 and SMC2 parameter RAMs at
offset 0x1ec0 and 0x1fc0 to allow extended parameter RAM
for SCC3 and SCC4.
endchoice
config UCODE_PATCH

Vedi File

@@ -3,6 +3,8 @@
# Makefile for the PowerPC 8xx linux kernel.
#
obj-y += m8xx_setup.o machine_check.o pic.o
obj-$(CONFIG_CPM1) += cpm1.o
obj-$(CONFIG_UCODE_PATCH) += micropatch.o
obj-$(CONFIG_MPC885ADS) += mpc885ads_setup.o
obj-$(CONFIG_MPC86XADS) += mpc86xads_setup.o
obj-$(CONFIG_PPC_EP88XC) += ep88xc.o

Vedi File

@@ -0,0 +1,790 @@
// SPDX-License-Identifier: GPL-2.0
/*
* General Purpose functions for the global management of the
* Communication Processor Module.
* Copyright (c) 1997 Dan error_act (dmalek@jlc.net)
*
* In addition to the individual control of the communication
* channels, there are a few functions that globally affect the
* communication processor.
*
* Buffer descriptors must be allocated from the dual ported memory
* space. The allocator for that is here. When the communication
* process is reset, we reclaim the memory available. There is
* currently no deallocator for this memory.
* The amount of space available is platform dependent. On the
* MBX, the EPPC software loads additional microcode into the
* communication processor, and uses some of the DP ram for this
* purpose. Current, the first 512 bytes and the last 256 bytes of
* memory are used. Right now I am conservative and only use the
* memory that can never be used for microcode. If there are
* applications that require more DP ram, we can expand the boundaries
* but then we have to be careful of any downloaded microcode.
*/
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/dma-mapping.h>
#include <linux/param.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/8xx_immap.h>
#include <asm/cpm1.h>
#include <asm/io.h>
#include <asm/rheap.h>
#include <asm/prom.h>
#include <asm/cpm.h>
#include <asm/fs_pd.h>
#ifdef CONFIG_8xx_GPIO
#include <linux/of_gpio.h>
#endif
#define CPM_MAP_SIZE (0x4000)
cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */
immap_t __iomem *mpc8xx_immr;
static cpic8xx_t __iomem *cpic_reg;
static struct irq_domain *cpm_pic_host;
static void cpm_mask_irq(struct irq_data *d)
{
unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d);
clrbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec));
}
static void cpm_unmask_irq(struct irq_data *d)
{
unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d);
setbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec));
}
static void cpm_end_irq(struct irq_data *d)
{
unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d);
out_be32(&cpic_reg->cpic_cisr, (1 << cpm_vec));
}
static struct irq_chip cpm_pic = {
.name = "CPM PIC",
.irq_mask = cpm_mask_irq,
.irq_unmask = cpm_unmask_irq,
.irq_eoi = cpm_end_irq,
};
int cpm_get_irq(void)
{
int cpm_vec;
/*
* Get the vector by setting the ACK bit and then reading
* the register.
*/
out_be16(&cpic_reg->cpic_civr, 1);
cpm_vec = in_be16(&cpic_reg->cpic_civr);
cpm_vec >>= 11;
return irq_linear_revmap(cpm_pic_host, cpm_vec);
}
static int cpm_pic_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
pr_debug("cpm_pic_host_map(%d, 0x%lx)\n", virq, hw);
irq_set_status_flags(virq, IRQ_LEVEL);
irq_set_chip_and_handler(virq, &cpm_pic, handle_fasteoi_irq);
return 0;
}
/*
* The CPM can generate the error interrupt when there is a race condition
* between generating and masking interrupts. All we have to do is ACK it
* and return. This is a no-op function so we don't need any special
* tests in the interrupt handler.
*/
static irqreturn_t cpm_error_interrupt(int irq, void *dev)
{
return IRQ_HANDLED;
}
static struct irqaction cpm_error_irqaction = {
.handler = cpm_error_interrupt,
.flags = IRQF_NO_THREAD,
.name = "error",
};
static const struct irq_domain_ops cpm_pic_host_ops = {
.map = cpm_pic_host_map,
};
unsigned int cpm_pic_init(void)
{
struct device_node *np = NULL;
struct resource res;
unsigned int sirq = 0, hwirq, eirq;
int ret;
pr_debug("cpm_pic_init\n");
np = of_find_compatible_node(NULL, NULL, "fsl,cpm1-pic");
if (np == NULL)
np = of_find_compatible_node(NULL, "cpm-pic", "CPM");
if (np == NULL) {
printk(KERN_ERR "CPM PIC init: can not find cpm-pic node\n");
return sirq;
}
ret = of_address_to_resource(np, 0, &res);
if (ret)
goto end;
cpic_reg = ioremap(res.start, resource_size(&res));
if (cpic_reg == NULL)
goto end;
sirq = irq_of_parse_and_map(np, 0);
if (!sirq)
goto end;
/* Initialize the CPM interrupt controller. */
hwirq = (unsigned int)virq_to_hw(sirq);
out_be32(&cpic_reg->cpic_cicr,
(CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) |
((hwirq/2) << 13) | CICR_HP_MASK);
out_be32(&cpic_reg->cpic_cimr, 0);
cpm_pic_host = irq_domain_add_linear(np, 64, &cpm_pic_host_ops, NULL);
if (cpm_pic_host == NULL) {
printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n");
sirq = 0;
goto end;
}
/* Install our own error handler. */
np = of_find_compatible_node(NULL, NULL, "fsl,cpm1");
if (np == NULL)
np = of_find_node_by_type(NULL, "cpm");
if (np == NULL) {
printk(KERN_ERR "CPM PIC init: can not find cpm node\n");
goto end;
}
eirq = irq_of_parse_and_map(np, 0);
if (!eirq)
goto end;
if (setup_irq(eirq, &cpm_error_irqaction))
printk(KERN_ERR "Could not allocate CPM error IRQ!");
setbits32(&cpic_reg->cpic_cicr, CICR_IEN);
end:
of_node_put(np);
return sirq;
}
void __init cpm_reset(void)
{
sysconf8xx_t __iomem *siu_conf;
mpc8xx_immr = ioremap(get_immrbase(), 0x4000);
if (!mpc8xx_immr) {
printk(KERN_CRIT "Could not map IMMR\n");
return;
}
cpmp = &mpc8xx_immr->im_cpm;
#ifndef CONFIG_PPC_EARLY_DEBUG_CPM
/* Perform a reset. */
out_be16(&cpmp->cp_cpcr, CPM_CR_RST | CPM_CR_FLG);
/* Wait for it. */
while (in_be16(&cpmp->cp_cpcr) & CPM_CR_FLG);
#endif
#ifdef CONFIG_UCODE_PATCH
cpm_load_patch(cpmp);
#endif
/*
* Set SDMA Bus Request priority 5.
* On 860T, this also enables FEC priority 6. I am not sure
* this is what we really want for some applications, but the
* manual recommends it.
* Bit 25, FAM can also be set to use FEC aggressive mode (860T).
*/
siu_conf = immr_map(im_siu_conf);
if ((mfspr(SPRN_IMMR) & 0xffff) == 0x0900) /* MPC885 */
out_be32(&siu_conf->sc_sdcr, 0x40);
else
out_be32(&siu_conf->sc_sdcr, 1);
immr_unmap(siu_conf);
}
static DEFINE_SPINLOCK(cmd_lock);
#define MAX_CR_CMD_LOOPS 10000
int cpm_command(u32 command, u8 opcode)
{
int i, ret;
unsigned long flags;
if (command & 0xffffff0f)
return -EINVAL;
spin_lock_irqsave(&cmd_lock, flags);
ret = 0;
out_be16(&cpmp->cp_cpcr, command | CPM_CR_FLG | (opcode << 8));
for (i = 0; i < MAX_CR_CMD_LOOPS; i++)
if ((in_be16(&cpmp->cp_cpcr) & CPM_CR_FLG) == 0)
goto out;
printk(KERN_ERR "%s(): Not able to issue CPM command\n", __func__);
ret = -EIO;
out:
spin_unlock_irqrestore(&cmd_lock, flags);
return ret;
}
EXPORT_SYMBOL(cpm_command);
/*
* Set a baud rate generator. This needs lots of work. There are
* four BRGs, any of which can be wired to any channel.
* The internal baud rate clock is the system clock divided by 16.
* This assumes the baudrate is 16x oversampled by the uart.
*/
#define BRG_INT_CLK (get_brgfreq())
#define BRG_UART_CLK (BRG_INT_CLK/16)
#define BRG_UART_CLK_DIV16 (BRG_UART_CLK/16)
void
cpm_setbrg(uint brg, uint rate)
{
u32 __iomem *bp;
/* This is good enough to get SMCs running..... */
bp = &cpmp->cp_brgc1;
bp += brg;
/*
* The BRG has a 12-bit counter. For really slow baud rates (or
* really fast processors), we may have to further divide by 16.
*/
if (((BRG_UART_CLK / rate) - 1) < 4096)
out_be32(bp, (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN);
else
out_be32(bp, (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) |
CPM_BRG_EN | CPM_BRG_DIV16);
}
struct cpm_ioport16 {
__be16 dir, par, odr_sor, dat, intr;
__be16 res[3];
};
struct cpm_ioport32b {
__be32 dir, par, odr, dat;
};
struct cpm_ioport32e {
__be32 dir, par, sor, odr, dat;
};
static void cpm1_set_pin32(int port, int pin, int flags)
{
struct cpm_ioport32e __iomem *iop;
pin = 1 << (31 - pin);
if (port == CPM_PORTB)
iop = (struct cpm_ioport32e __iomem *)
&mpc8xx_immr->im_cpm.cp_pbdir;
else
iop = (struct cpm_ioport32e __iomem *)
&mpc8xx_immr->im_cpm.cp_pedir;
if (flags & CPM_PIN_OUTPUT)
setbits32(&iop->dir, pin);
else
clrbits32(&iop->dir, pin);
if (!(flags & CPM_PIN_GPIO))
setbits32(&iop->par, pin);
else
clrbits32(&iop->par, pin);
if (port == CPM_PORTB) {
if (flags & CPM_PIN_OPENDRAIN)
setbits16(&mpc8xx_immr->im_cpm.cp_pbodr, pin);
else
clrbits16(&mpc8xx_immr->im_cpm.cp_pbodr, pin);
}
if (port == CPM_PORTE) {
if (flags & CPM_PIN_SECONDARY)
setbits32(&iop->sor, pin);
else
clrbits32(&iop->sor, pin);
if (flags & CPM_PIN_OPENDRAIN)
setbits32(&mpc8xx_immr->im_cpm.cp_peodr, pin);
else
clrbits32(&mpc8xx_immr->im_cpm.cp_peodr, pin);
}
}
static void cpm1_set_pin16(int port, int pin, int flags)
{
struct cpm_ioport16 __iomem *iop =
(struct cpm_ioport16 __iomem *)&mpc8xx_immr->im_ioport;
pin = 1 << (15 - pin);
if (port != 0)
iop += port - 1;
if (flags & CPM_PIN_OUTPUT)
setbits16(&iop->dir, pin);
else
clrbits16(&iop->dir, pin);
if (!(flags & CPM_PIN_GPIO))
setbits16(&iop->par, pin);
else
clrbits16(&iop->par, pin);
if (port == CPM_PORTA) {
if (flags & CPM_PIN_OPENDRAIN)
setbits16(&iop->odr_sor, pin);
else
clrbits16(&iop->odr_sor, pin);
}
if (port == CPM_PORTC) {
if (flags & CPM_PIN_SECONDARY)
setbits16(&iop->odr_sor, pin);
else
clrbits16(&iop->odr_sor, pin);
if (flags & CPM_PIN_FALLEDGE)
setbits16(&iop->intr, pin);
else
clrbits16(&iop->intr, pin);
}
}
void cpm1_set_pin(enum cpm_port port, int pin, int flags)
{
if (port == CPM_PORTB || port == CPM_PORTE)
cpm1_set_pin32(port, pin, flags);
else
cpm1_set_pin16(port, pin, flags);
}
int cpm1_clk_setup(enum cpm_clk_target target, int clock, int mode)
{
int shift;
int i, bits = 0;
u32 __iomem *reg;
u32 mask = 7;
u8 clk_map[][3] = {
{CPM_CLK_SCC1, CPM_BRG1, 0},
{CPM_CLK_SCC1, CPM_BRG2, 1},
{CPM_CLK_SCC1, CPM_BRG3, 2},
{CPM_CLK_SCC1, CPM_BRG4, 3},
{CPM_CLK_SCC1, CPM_CLK1, 4},
{CPM_CLK_SCC1, CPM_CLK2, 5},
{CPM_CLK_SCC1, CPM_CLK3, 6},
{CPM_CLK_SCC1, CPM_CLK4, 7},
{CPM_CLK_SCC2, CPM_BRG1, 0},
{CPM_CLK_SCC2, CPM_BRG2, 1},
{CPM_CLK_SCC2, CPM_BRG3, 2},
{CPM_CLK_SCC2, CPM_BRG4, 3},
{CPM_CLK_SCC2, CPM_CLK1, 4},
{CPM_CLK_SCC2, CPM_CLK2, 5},
{CPM_CLK_SCC2, CPM_CLK3, 6},
{CPM_CLK_SCC2, CPM_CLK4, 7},
{CPM_CLK_SCC3, CPM_BRG1, 0},
{CPM_CLK_SCC3, CPM_BRG2, 1},
{CPM_CLK_SCC3, CPM_BRG3, 2},
{CPM_CLK_SCC3, CPM_BRG4, 3},
{CPM_CLK_SCC3, CPM_CLK5, 4},
{CPM_CLK_SCC3, CPM_CLK6, 5},
{CPM_CLK_SCC3, CPM_CLK7, 6},
{CPM_CLK_SCC3, CPM_CLK8, 7},
{CPM_CLK_SCC4, CPM_BRG1, 0},
{CPM_CLK_SCC4, CPM_BRG2, 1},
{CPM_CLK_SCC4, CPM_BRG3, 2},
{CPM_CLK_SCC4, CPM_BRG4, 3},
{CPM_CLK_SCC4, CPM_CLK5, 4},
{CPM_CLK_SCC4, CPM_CLK6, 5},
{CPM_CLK_SCC4, CPM_CLK7, 6},
{CPM_CLK_SCC4, CPM_CLK8, 7},
{CPM_CLK_SMC1, CPM_BRG1, 0},
{CPM_CLK_SMC1, CPM_BRG2, 1},
{CPM_CLK_SMC1, CPM_BRG3, 2},
{CPM_CLK_SMC1, CPM_BRG4, 3},
{CPM_CLK_SMC1, CPM_CLK1, 4},
{CPM_CLK_SMC1, CPM_CLK2, 5},
{CPM_CLK_SMC1, CPM_CLK3, 6},
{CPM_CLK_SMC1, CPM_CLK4, 7},
{CPM_CLK_SMC2, CPM_BRG1, 0},
{CPM_CLK_SMC2, CPM_BRG2, 1},
{CPM_CLK_SMC2, CPM_BRG3, 2},
{CPM_CLK_SMC2, CPM_BRG4, 3},
{CPM_CLK_SMC2, CPM_CLK5, 4},
{CPM_CLK_SMC2, CPM_CLK6, 5},
{CPM_CLK_SMC2, CPM_CLK7, 6},
{CPM_CLK_SMC2, CPM_CLK8, 7},
};
switch (target) {
case CPM_CLK_SCC1:
reg = &mpc8xx_immr->im_cpm.cp_sicr;
shift = 0;
break;
case CPM_CLK_SCC2:
reg = &mpc8xx_immr->im_cpm.cp_sicr;
shift = 8;
break;
case CPM_CLK_SCC3:
reg = &mpc8xx_immr->im_cpm.cp_sicr;
shift = 16;
break;
case CPM_CLK_SCC4:
reg = &mpc8xx_immr->im_cpm.cp_sicr;
shift = 24;
break;
case CPM_CLK_SMC1:
reg = &mpc8xx_immr->im_cpm.cp_simode;
shift = 12;
break;
case CPM_CLK_SMC2:
reg = &mpc8xx_immr->im_cpm.cp_simode;
shift = 28;
break;
default:
printk(KERN_ERR "cpm1_clock_setup: invalid clock target\n");
return -EINVAL;
}
for (i = 0; i < ARRAY_SIZE(clk_map); i++) {
if (clk_map[i][0] == target && clk_map[i][1] == clock) {
bits = clk_map[i][2];
break;
}
}
if (i == ARRAY_SIZE(clk_map)) {
printk(KERN_ERR "cpm1_clock_setup: invalid clock combination\n");
return -EINVAL;
}
bits <<= shift;
mask <<= shift;
if (reg == &mpc8xx_immr->im_cpm.cp_sicr) {
if (mode == CPM_CLK_RTX) {
bits |= bits << 3;
mask |= mask << 3;
} else if (mode == CPM_CLK_RX) {
bits <<= 3;
mask <<= 3;
}
}
out_be32(reg, (in_be32(reg) & ~mask) | bits);
return 0;
}
/*
* GPIO LIB API implementation
*/
#ifdef CONFIG_8xx_GPIO
struct cpm1_gpio16_chip {
struct of_mm_gpio_chip mm_gc;
spinlock_t lock;
/* shadowed data register to clear/set bits safely */
u16 cpdata;
/* IRQ associated with Pins when relevant */
int irq[16];
};
static void cpm1_gpio16_save_regs(struct of_mm_gpio_chip *mm_gc)
{
struct cpm1_gpio16_chip *cpm1_gc =
container_of(mm_gc, struct cpm1_gpio16_chip, mm_gc);
struct cpm_ioport16 __iomem *iop = mm_gc->regs;
cpm1_gc->cpdata = in_be16(&iop->dat);
}
static int cpm1_gpio16_get(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm_ioport16 __iomem *iop = mm_gc->regs;
u16 pin_mask;
pin_mask = 1 << (15 - gpio);
return !!(in_be16(&iop->dat) & pin_mask);
}
static void __cpm1_gpio16_set(struct of_mm_gpio_chip *mm_gc, u16 pin_mask,
int value)
{
struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
struct cpm_ioport16 __iomem *iop = mm_gc->regs;
if (value)
cpm1_gc->cpdata |= pin_mask;
else
cpm1_gc->cpdata &= ~pin_mask;
out_be16(&iop->dat, cpm1_gc->cpdata);
}
static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
unsigned long flags;
u16 pin_mask = 1 << (15 - gpio);
spin_lock_irqsave(&cpm1_gc->lock, flags);
__cpm1_gpio16_set(mm_gc, pin_mask, value);
spin_unlock_irqrestore(&cpm1_gc->lock, flags);
}
static int cpm1_gpio16_to_irq(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
return cpm1_gc->irq[gpio] ? : -ENXIO;
}
static int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
struct cpm_ioport16 __iomem *iop = mm_gc->regs;
unsigned long flags;
u16 pin_mask = 1 << (15 - gpio);
spin_lock_irqsave(&cpm1_gc->lock, flags);
setbits16(&iop->dir, pin_mask);
__cpm1_gpio16_set(mm_gc, pin_mask, val);
spin_unlock_irqrestore(&cpm1_gc->lock, flags);
return 0;
}
static int cpm1_gpio16_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
struct cpm_ioport16 __iomem *iop = mm_gc->regs;
unsigned long flags;
u16 pin_mask = 1 << (15 - gpio);
spin_lock_irqsave(&cpm1_gc->lock, flags);
clrbits16(&iop->dir, pin_mask);
spin_unlock_irqrestore(&cpm1_gc->lock, flags);
return 0;
}
int cpm1_gpiochip_add16(struct device *dev)
{
struct device_node *np = dev->of_node;
struct cpm1_gpio16_chip *cpm1_gc;
struct of_mm_gpio_chip *mm_gc;
struct gpio_chip *gc;
u16 mask;
cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL);
if (!cpm1_gc)
return -ENOMEM;
spin_lock_init(&cpm1_gc->lock);
if (!of_property_read_u16(np, "fsl,cpm1-gpio-irq-mask", &mask)) {
int i, j;
for (i = 0, j = 0; i < 16; i++)
if (mask & (1 << (15 - i)))
cpm1_gc->irq[i] = irq_of_parse_and_map(np, j++);
}
mm_gc = &cpm1_gc->mm_gc;
gc = &mm_gc->gc;
mm_gc->save_regs = cpm1_gpio16_save_regs;
gc->ngpio = 16;
gc->direction_input = cpm1_gpio16_dir_in;
gc->direction_output = cpm1_gpio16_dir_out;
gc->get = cpm1_gpio16_get;
gc->set = cpm1_gpio16_set;
gc->to_irq = cpm1_gpio16_to_irq;
gc->parent = dev;
gc->owner = THIS_MODULE;
return of_mm_gpiochip_add_data(np, mm_gc, cpm1_gc);
}
struct cpm1_gpio32_chip {
struct of_mm_gpio_chip mm_gc;
spinlock_t lock;
/* shadowed data register to clear/set bits safely */
u32 cpdata;
};
static void cpm1_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc)
{
struct cpm1_gpio32_chip *cpm1_gc =
container_of(mm_gc, struct cpm1_gpio32_chip, mm_gc);
struct cpm_ioport32b __iomem *iop = mm_gc->regs;
cpm1_gc->cpdata = in_be32(&iop->dat);
}
static int cpm1_gpio32_get(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm_ioport32b __iomem *iop = mm_gc->regs;
u32 pin_mask;
pin_mask = 1 << (31 - gpio);
return !!(in_be32(&iop->dat) & pin_mask);
}
static void __cpm1_gpio32_set(struct of_mm_gpio_chip *mm_gc, u32 pin_mask,
int value)
{
struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
struct cpm_ioport32b __iomem *iop = mm_gc->regs;
if (value)
cpm1_gc->cpdata |= pin_mask;
else
cpm1_gc->cpdata &= ~pin_mask;
out_be32(&iop->dat, cpm1_gc->cpdata);
}
static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
unsigned long flags;
u32 pin_mask = 1 << (31 - gpio);
spin_lock_irqsave(&cpm1_gc->lock, flags);
__cpm1_gpio32_set(mm_gc, pin_mask, value);
spin_unlock_irqrestore(&cpm1_gc->lock, flags);
}
static int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
struct cpm_ioport32b __iomem *iop = mm_gc->regs;
unsigned long flags;
u32 pin_mask = 1 << (31 - gpio);
spin_lock_irqsave(&cpm1_gc->lock, flags);
setbits32(&iop->dir, pin_mask);
__cpm1_gpio32_set(mm_gc, pin_mask, val);
spin_unlock_irqrestore(&cpm1_gc->lock, flags);
return 0;
}
static int cpm1_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
struct cpm_ioport32b __iomem *iop = mm_gc->regs;
unsigned long flags;
u32 pin_mask = 1 << (31 - gpio);
spin_lock_irqsave(&cpm1_gc->lock, flags);
clrbits32(&iop->dir, pin_mask);
spin_unlock_irqrestore(&cpm1_gc->lock, flags);
return 0;
}
int cpm1_gpiochip_add32(struct device *dev)
{
struct device_node *np = dev->of_node;
struct cpm1_gpio32_chip *cpm1_gc;
struct of_mm_gpio_chip *mm_gc;
struct gpio_chip *gc;
cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL);
if (!cpm1_gc)
return -ENOMEM;
spin_lock_init(&cpm1_gc->lock);
mm_gc = &cpm1_gc->mm_gc;
gc = &mm_gc->gc;
mm_gc->save_regs = cpm1_gpio32_save_regs;
gc->ngpio = 32;
gc->direction_input = cpm1_gpio32_dir_in;
gc->direction_output = cpm1_gpio32_dir_out;
gc->get = cpm1_gpio32_get;
gc->set = cpm1_gpio32_set;
gc->parent = dev;
gc->owner = THIS_MODULE;
return of_mm_gpiochip_add_data(np, mm_gc, cpm1_gc);
}
#endif /* CONFIG_8xx_GPIO */

Vedi File

@@ -0,0 +1,378 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Microcode patches for the CPM as supplied by Motorola.
* This is the one for IIC/SPI. There is a newer one that
* also relocates SMC2, but this would require additional changes
* to uart.c, so I am holding off on that for a moment.
*/
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/param.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <asm/irq.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/8xx_immap.h>
#include <asm/cpm.h>
#include <asm/cpm1.h>
struct patch_params {
ushort rccr;
ushort cpmcr1;
ushort cpmcr2;
ushort cpmcr3;
ushort cpmcr4;
};
/*
* I2C/SPI relocation patch arrays.
*/
#ifdef CONFIG_I2C_SPI_UCODE_PATCH
static char patch_name[] __initdata = "I2C/SPI";
static struct patch_params patch_params __initdata = {
1, 0x802a, 0x8028, 0x802e, 0x802c,
};
static uint patch_2000[] __initdata = {
0x7FFFEFD9, 0x3FFD0000, 0x7FFB49F7, 0x7FF90000,
0x5FEFADF7, 0x5F89ADF7, 0x5FEFAFF7, 0x5F89AFF7,
0x3A9CFBC8, 0xE7C0EDF0, 0x77C1E1BB, 0xF4DC7F1D,
0xABAD932F, 0x4E08FDCF, 0x6E0FAFF8, 0x7CCF76CF,
0xFD1FF9CF, 0xABF88DC6, 0xAB5679F7, 0xB0937383,
0xDFCE79F7, 0xB091E6BB, 0xE5BBE74F, 0xB3FA6F0F,
0x6FFB76CE, 0xEE0DF9CF, 0x2BFBEFEF, 0xCFEEF9CF,
0x76CEAD24, 0x90B2DF9A, 0x7FDDD0BF, 0x4BF847FD,
0x7CCF76CE, 0xCFEF7E1F, 0x7F1D7DFD, 0xF0B6EF71,
0x7FC177C1, 0xFBC86079, 0xE722FBC8, 0x5FFFDFFF,
0x5FB2FFFB, 0xFBC8F3C8, 0x94A67F01, 0x7F1D5F39,
0xAFE85F5E, 0xFFDFDF96, 0xCB9FAF7D, 0x5FC1AFED,
0x8C1C5FC1, 0xAFDD5FC3, 0xDF9A7EFD, 0xB0B25FB2,
0xFFFEABAD, 0x5FB2FFFE, 0x5FCE600B, 0xE6BB600B,
0x5FCEDFC6, 0x27FBEFDF, 0x5FC8CFDE, 0x3A9CE7C0,
0xEDF0F3C8, 0x7F0154CD, 0x7F1D2D3D, 0x363A7570,
0x7E0AF1CE, 0x37EF2E68, 0x7FEE10EC, 0xADF8EFDE,
0xCFEAE52F, 0x7D0FE12B, 0xF1CE5F65, 0x7E0A4DF8,
0xCFEA5F72, 0x7D0BEFEE, 0xCFEA5F74, 0xE522EFDE,
0x5F74CFDA, 0x0B627385, 0xDF627E0A, 0x30D8145B,
0xBFFFF3C8, 0x5FFFDFFF, 0xA7F85F5E, 0xBFFE7F7D,
0x10D31450, 0x5F36BFFF, 0xAF785F5E, 0xBFFDA7F8,
0x5F36BFFE, 0x77FD30C0, 0x4E08FDCF, 0xE5FF6E0F,
0xAFF87E1F, 0x7E0FFD1F, 0xF1CF5F1B, 0xABF80D5E,
0x5F5EFFEF, 0x79F730A2, 0xAFDD5F34, 0x47F85F34,
0xAFED7FDD, 0x50B24978, 0x47FD7F1D, 0x7DFD70AD,
0xEF717EC1, 0x6BA47F01, 0x2D267EFD, 0x30DE5F5E,
0xFFFD5F5E, 0xFFEF5F5E, 0xFFDF0CA0, 0xAFED0A9E,
0xAFDD0C3A, 0x5F3AAFBD, 0x7FBDB082, 0x5F8247F8
};
static uint patch_2f00[] __initdata = {
0x3E303430, 0x34343737, 0xABF7BF9B, 0x994B4FBD,
0xBD599493, 0x349FFF37, 0xFB9B177D, 0xD9936956,
0xBBFDD697, 0xBDD2FD11, 0x31DB9BB3, 0x63139637,
0x93733693, 0x193137F7, 0x331737AF, 0x7BB9B999,
0xBB197957, 0x7FDFD3D5, 0x73B773F7, 0x37933B99,
0x1D115316, 0x99315315, 0x31694BF4, 0xFBDBD359,
0x31497353, 0x76956D69, 0x7B9D9693, 0x13131979,
0x79376935
};
static uint patch_2e00[] __initdata = {};
#endif
/*
* I2C/SPI/SMC1 relocation patch arrays.
*/
#ifdef CONFIG_I2C_SPI_SMC1_UCODE_PATCH
static char patch_name[] __initdata = "I2C/SPI/SMC1";
static struct patch_params patch_params __initdata = {
3, 0x8080, 0x808a, 0x8028, 0x802a,
};
static uint patch_2000[] __initdata = {
0x3fff0000, 0x3ffd0000, 0x3ffb0000, 0x3ff90000,
0x5f13eff8, 0x5eb5eff8, 0x5f88adf7, 0x5fefadf7,
0x3a9cfbc8, 0x77cae1bb, 0xf4de7fad, 0xabae9330,
0x4e08fdcf, 0x6e0faff8, 0x7ccf76cf, 0xfdaff9cf,
0xabf88dc8, 0xab5879f7, 0xb0925d8d, 0xdfd079f7,
0xb090e6bb, 0xe5bbe74f, 0x9e046f0f, 0x6ffb76ce,
0xee0cf9cf, 0x2bfbefef, 0xcfeef9cf, 0x76cead23,
0x90b3df99, 0x7fddd0c1, 0x4bf847fd, 0x7ccf76ce,
0xcfef77ca, 0x7eaf7fad, 0x7dfdf0b7, 0xef7a7fca,
0x77cafbc8, 0x6079e722, 0xfbc85fff, 0xdfff5fb3,
0xfffbfbc8, 0xf3c894a5, 0xe7c9edf9, 0x7f9a7fad,
0x5f36afe8, 0x5f5bffdf, 0xdf95cb9e, 0xaf7d5fc3,
0xafed8c1b, 0x5fc3afdd, 0x5fc5df99, 0x7efdb0b3,
0x5fb3fffe, 0xabae5fb3, 0xfffe5fd0, 0x600be6bb,
0x600b5fd0, 0xdfc827fb, 0xefdf5fca, 0xcfde3a9c,
0xe7c9edf9, 0xf3c87f9e, 0x54ca7fed, 0x2d3a3637,
0x756f7e9a, 0xf1ce37ef, 0x2e677fee, 0x10ebadf8,
0xefdecfea, 0xe52f7d9f, 0xe12bf1ce, 0x5f647e9a,
0x4df8cfea, 0x5f717d9b, 0xefeecfea, 0x5f73e522,
0xefde5f73, 0xcfda0b61, 0x5d8fdf61, 0xe7c9edf9,
0x7e9a30d5, 0x1458bfff, 0xf3c85fff, 0xdfffa7f8,
0x5f5bbffe, 0x7f7d10d0, 0x144d5f33, 0xbfffaf78,
0x5f5bbffd, 0xa7f85f33, 0xbffe77fd, 0x30bd4e08,
0xfdcfe5ff, 0x6e0faff8, 0x7eef7e9f, 0xfdeff1cf,
0x5f17abf8, 0x0d5b5f5b, 0xffef79f7, 0x309eafdd,
0x5f3147f8, 0x5f31afed, 0x7fdd50af, 0x497847fd,
0x7f9e7fed, 0x7dfd70a9, 0xef7e7ece, 0x6ba07f9e,
0x2d227efd, 0x30db5f5b, 0xfffd5f5b, 0xffef5f5b,
0xffdf0c9c, 0xafed0a9a, 0xafdd0c37, 0x5f37afbd,
0x7fbdb081, 0x5f8147f8, 0x3a11e710, 0xedf0ccdd,
0xf3186d0a, 0x7f0e5f06, 0x7fedbb38, 0x3afe7468,
0x7fedf4fc, 0x8ffbb951, 0xb85f77fd, 0xb0df5ddd,
0xdefe7fed, 0x90e1e74d, 0x6f0dcbf7, 0xe7decfed,
0xcb74cfed, 0xcfeddf6d, 0x91714f74, 0x5dd2deef,
0x9e04e7df, 0xefbb6ffb, 0xe7ef7f0e, 0x9e097fed,
0xebdbeffa, 0xeb54affb, 0x7fea90d7, 0x7e0cf0c3,
0xbffff318, 0x5fffdfff, 0xac59efea, 0x7fce1ee5,
0xe2ff5ee1, 0xaffbe2ff, 0x5ee3affb, 0xf9cc7d0f,
0xaef8770f, 0x7d0fb0c6, 0xeffbbfff, 0xcfef5ede,
0x7d0fbfff, 0x5ede4cf8, 0x7fddd0bf, 0x49f847fd,
0x7efdf0bb, 0x7fedfffd, 0x7dfdf0b7, 0xef7e7e1e,
0x5ede7f0e, 0x3a11e710, 0xedf0ccab, 0xfb18ad2e,
0x1ea9bbb8, 0x74283b7e, 0x73c2e4bb, 0x2ada4fb8,
0xdc21e4bb, 0xb2a1ffbf, 0x5e2c43f8, 0xfc87e1bb,
0xe74ffd91, 0x6f0f4fe8, 0xc7ba32e2, 0xf396efeb,
0x600b4f78, 0xe5bb760b, 0x53acaef8, 0x4ef88b0e,
0xcfef9e09, 0xabf8751f, 0xefef5bac, 0x741f4fe8,
0x751e760d, 0x7fdbf081, 0x741cafce, 0xefcc7fce,
0x751e70ac, 0x741ce7bb, 0x3372cfed, 0xafdbefeb,
0xe5bb760b, 0x53f2aef8, 0xafe8e7eb, 0x4bf8771e,
0x7e247fed, 0x4fcbe2cc, 0x7fbc30a9, 0x7b0f7a0f,
0x34d577fd, 0x308b5db7, 0xde553e5f, 0xaf78741f,
0x741f30f0, 0xcfef5e2c, 0x741f3eac, 0xafb8771e,
0x5e677fed, 0x0bd3e2cc, 0x741ccfec, 0xe5ca53cd,
0x6fcb4f74, 0x5dadde4b, 0x2ab63d38, 0x4bb3de30,
0x751f741c, 0x6c42effa, 0xefea7fce, 0x6ffc30be,
0xefec3fca, 0x30b3de2e, 0xadf85d9e, 0xaf7daefd,
0x5d9ede2e, 0x5d9eafdd, 0x761f10ac, 0x1da07efd,
0x30adfffe, 0x4908fb18, 0x5fffdfff, 0xafbb709b,
0x4ef85e67, 0xadf814ad, 0x7a0f70ad, 0xcfef50ad,
0x7a0fde30, 0x5da0afed, 0x3c12780f, 0xefef780f,
0xefef790f, 0xa7f85e0f, 0xffef790f, 0xefef790f,
0x14adde2e, 0x5d9eadfd, 0x5e2dfffb, 0xe79addfd,
0xeff96079, 0x607ae79a, 0xddfceff9, 0x60795dff,
0x607acfef, 0xefefefdf, 0xefbfef7f, 0xeeffedff,
0xebffe7ff, 0xafefafdf, 0xafbfaf7f, 0xaeffadff,
0xabffa7ff, 0x6fef6fdf, 0x6fbf6f7f, 0x6eff6dff,
0x6bff67ff, 0x2fef2fdf, 0x2fbf2f7f, 0x2eff2dff,
0x2bff27ff, 0x4e08fd1f, 0xe5ff6e0f, 0xaff87eef,
0x7e0ffdef, 0xf11f6079, 0xabf8f542, 0x7e0af11c,
0x37cfae3a, 0x7fec90be, 0xadf8efdc, 0xcfeae52f,
0x7d0fe12b, 0xf11c6079, 0x7e0a4df8, 0xcfea5dc4,
0x7d0befec, 0xcfea5dc6, 0xe522efdc, 0x5dc6cfda,
0x4e08fd1f, 0x6e0faff8, 0x7c1f761f, 0xfdeff91f,
0x6079abf8, 0x761cee24, 0xf91f2bfb, 0xefefcfec,
0xf91f6079, 0x761c27fb, 0xefdf5da7, 0xcfdc7fdd,
0xd09c4bf8, 0x47fd7c1f, 0x761ccfcf, 0x7eef7fed,
0x7dfdf093, 0xef7e7f1e, 0x771efb18, 0x6079e722,
0xe6bbe5bb, 0xae0ae5bb, 0x600bae85, 0xe2bbe2bb,
0xe2bbe2bb, 0xaf02e2bb, 0xe2bb2ff9, 0x6079e2bb
};
static uint patch_2f00[] __initdata = {
0x30303030, 0x3e3e3434, 0xabbf9b99, 0x4b4fbdbd,
0x59949334, 0x9fff37fb, 0x9b177dd9, 0x936956bb,
0xfbdd697b, 0xdd2fd113, 0x1db9f7bb, 0x36313963,
0x79373369, 0x3193137f, 0x7331737a, 0xf7bb9b99,
0x9bb19795, 0x77fdfd3d, 0x573b773f, 0x737933f7,
0xb991d115, 0x31699315, 0x31531694, 0xbf4fbdbd,
0x35931497, 0x35376956, 0xbd697b9d, 0x96931313,
0x19797937, 0x6935af78, 0xb9b3baa3, 0xb8788683,
0x368f78f7, 0x87778733, 0x3ffffb3b, 0x8e8f78b8,
0x1d118e13, 0xf3ff3f8b, 0x6bd8e173, 0xd1366856,
0x68d1687b, 0x3daf78b8, 0x3a3a3f87, 0x8f81378f,
0xf876f887, 0x77fd8778, 0x737de8d6, 0xbbf8bfff,
0xd8df87f7, 0xfd876f7b, 0x8bfff8bd, 0x8683387d,
0xb873d87b, 0x3b8fd7f8, 0xf7338883, 0xbb8ee1f8,
0xef837377, 0x3337b836, 0x817d11f8, 0x7378b878,
0xd3368b7d, 0xed731b7d, 0x833731f3, 0xf22f3f23
};
static uint patch_2e00[] __initdata = {
0x27eeeeee, 0xeeeeeeee, 0xeeeeeeee, 0xeeeeeeee,
0xee4bf4fb, 0xdbd259bb, 0x1979577f, 0xdfd2d573,
0xb773f737, 0x4b4fbdbd, 0x25b9b177, 0xd2d17376,
0x956bbfdd, 0x697bdd2f, 0xff9f79ff, 0xff9ff22f
};
#endif
/*
* USB SOF patch arrays.
*/
#ifdef CONFIG_USB_SOF_UCODE_PATCH
static char patch_name[] __initdata = "USB SOF";
static struct patch_params patch_params __initdata = {
9,
};
static uint patch_2000[] __initdata = {
0x7fff0000, 0x7ffd0000, 0x7ffb0000, 0x49f7ba5b,
0xba383ffb, 0xf9b8b46d, 0xe5ab4e07, 0xaf77bffe,
0x3f7bbf79, 0xba5bba38, 0xe7676076, 0x60750000
};
static uint patch_2f00[] __initdata = {
0x3030304c, 0xcab9e441, 0xa1aaf220
};
static uint patch_2e00[] __initdata = {};
#endif
/*
* SMC relocation patch arrays.
*/
#ifdef CONFIG_SMC_UCODE_PATCH
static char patch_name[] __initdata = "SMC";
static struct patch_params patch_params __initdata = {
2, 0x8080, 0x8088,
};
static uint patch_2000[] __initdata = {
0x3fff0000, 0x3ffd0000, 0x3ffb0000, 0x3ff90000,
0x5fefeff8, 0x5f91eff8, 0x3ff30000, 0x3ff10000,
0x3a11e710, 0xedf0ccb9, 0xf318ed66, 0x7f0e5fe2,
0x7fedbb38, 0x3afe7468, 0x7fedf4d8, 0x8ffbb92d,
0xb83b77fd, 0xb0bb5eb9, 0xdfda7fed, 0x90bde74d,
0x6f0dcbd3, 0xe7decfed, 0xcb50cfed, 0xcfeddf6d,
0x914d4f74, 0x5eaedfcb, 0x9ee0e7df, 0xefbb6ffb,
0xe7ef7f0e, 0x9ee57fed, 0xebb7effa, 0xeb30affb,
0x7fea90b3, 0x7e0cf09f, 0xbffff318, 0x5fffdfff,
0xac35efea, 0x7fce1fc1, 0xe2ff5fbd, 0xaffbe2ff,
0x5fbfaffb, 0xf9a87d0f, 0xaef8770f, 0x7d0fb0a2,
0xeffbbfff, 0xcfef5fba, 0x7d0fbfff, 0x5fba4cf8,
0x7fddd09b, 0x49f847fd, 0x7efdf097, 0x7fedfffd,
0x7dfdf093, 0xef7e7e1e, 0x5fba7f0e, 0x3a11e710,
0xedf0cc87, 0xfb18ad0a, 0x1f85bbb8, 0x74283b7e,
0x7375e4bb, 0x2ab64fb8, 0x5c7de4bb, 0x32fdffbf,
0x5f0843f8, 0x7ce3e1bb, 0xe74f7ded, 0x6f0f4fe8,
0xc7ba32be, 0x73f2efeb, 0x600b4f78, 0xe5bb760b,
0x5388aef8, 0x4ef80b6a, 0xcfef9ee5, 0xabf8751f,
0xefef5b88, 0x741f4fe8, 0x751e760d, 0x7fdb70dd,
0x741cafce, 0xefcc7fce, 0x751e7088, 0x741ce7bb,
0x334ecfed, 0xafdbefeb, 0xe5bb760b, 0x53ceaef8,
0xafe8e7eb, 0x4bf8771e, 0x7e007fed, 0x4fcbe2cc,
0x7fbc3085, 0x7b0f7a0f, 0x34b177fd, 0xb0e75e93,
0xdf313e3b, 0xaf78741f, 0x741f30cc, 0xcfef5f08,
0x741f3e88, 0xafb8771e, 0x5f437fed, 0x0bafe2cc,
0x741ccfec, 0xe5ca53a9, 0x6fcb4f74, 0x5e89df27,
0x2a923d14, 0x4b8fdf0c, 0x751f741c, 0x6c1eeffa,
0xefea7fce, 0x6ffc309a, 0xefec3fca, 0x308fdf0a,
0xadf85e7a, 0xaf7daefd, 0x5e7adf0a, 0x5e7aafdd,
0x761f1088, 0x1e7c7efd, 0x3089fffe, 0x4908fb18,
0x5fffdfff, 0xafbbf0f7, 0x4ef85f43, 0xadf81489,
0x7a0f7089, 0xcfef5089, 0x7a0fdf0c, 0x5e7cafed,
0xbc6e780f, 0xefef780f, 0xefef790f, 0xa7f85eeb,
0xffef790f, 0xefef790f, 0x1489df0a, 0x5e7aadfd,
0x5f09fffb, 0xe79aded9, 0xeff96079, 0x607ae79a,
0xded8eff9, 0x60795edb, 0x607acfef, 0xefefefdf,
0xefbfef7f, 0xeeffedff, 0xebffe7ff, 0xafefafdf,
0xafbfaf7f, 0xaeffadff, 0xabffa7ff, 0x6fef6fdf,
0x6fbf6f7f, 0x6eff6dff, 0x6bff67ff, 0x2fef2fdf,
0x2fbf2f7f, 0x2eff2dff, 0x2bff27ff, 0x4e08fd1f,
0xe5ff6e0f, 0xaff87eef, 0x7e0ffdef, 0xf11f6079,
0xabf8f51e, 0x7e0af11c, 0x37cfae16, 0x7fec909a,
0xadf8efdc, 0xcfeae52f, 0x7d0fe12b, 0xf11c6079,
0x7e0a4df8, 0xcfea5ea0, 0x7d0befec, 0xcfea5ea2,
0xe522efdc, 0x5ea2cfda, 0x4e08fd1f, 0x6e0faff8,
0x7c1f761f, 0xfdeff91f, 0x6079abf8, 0x761cee00,
0xf91f2bfb, 0xefefcfec, 0xf91f6079, 0x761c27fb,
0xefdf5e83, 0xcfdc7fdd, 0x50f84bf8, 0x47fd7c1f,
0x761ccfcf, 0x7eef7fed, 0x7dfd70ef, 0xef7e7f1e,
0x771efb18, 0x6079e722, 0xe6bbe5bb, 0x2e66e5bb,
0x600b2ee1, 0xe2bbe2bb, 0xe2bbe2bb, 0x2f5ee2bb,
0xe2bb2ff9, 0x6079e2bb,
};
static uint patch_2f00[] __initdata = {
0x30303030, 0x3e3e3030, 0xaf79b9b3, 0xbaa3b979,
0x9693369f, 0x79f79777, 0x97333fff, 0xfb3b9e9f,
0x79b91d11, 0x9e13f3ff, 0x3f9b6bd9, 0xe173d136,
0x695669d1, 0x697b3daf, 0x79b93a3a, 0x3f979f91,
0x379ff976, 0xf99777fd, 0x9779737d, 0xe9d6bbf9,
0xbfffd9df, 0x97f7fd97, 0x6f7b9bff, 0xf9bd9683,
0x397db973, 0xd97b3b9f, 0xd7f9f733, 0x9993bb9e,
0xe1f9ef93, 0x73773337, 0xb936917d, 0x11f87379,
0xb979d336, 0x8b7ded73, 0x1b7d9337, 0x31f3f22f,
0x3f2327ee, 0xeeeeeeee, 0xeeeeeeee, 0xeeeeeeee,
0xeeeeee4b, 0xf4fbdbd2, 0x58bb1878, 0x577fdfd2,
0xd573b773, 0xf7374b4f, 0xbdbd25b8, 0xb177d2d1,
0x7376856b, 0xbfdd687b, 0xdd2fff8f, 0x78ffff8f,
0xf22f0000,
};
static uint patch_2e00[] __initdata = {};
#endif
static void __init cpm_write_patch(cpm8xx_t *cp, int offset, uint *patch, int len)
{
if (!len)
return;
memcpy_toio(cp->cp_dpmem + offset, patch, len);
}
void __init cpm_load_patch(cpm8xx_t *cp)
{
out_be16(&cp->cp_rccr, 0);
cpm_write_patch(cp, 0, patch_2000, sizeof(patch_2000));
cpm_write_patch(cp, 0xf00, patch_2f00, sizeof(patch_2f00));
cpm_write_patch(cp, 0xe00, patch_2e00, sizeof(patch_2e00));
if (IS_ENABLED(CONFIG_I2C_SPI_UCODE_PATCH) ||
IS_ENABLED(CONFIG_I2C_SPI_SMC1_UCODE_PATCH)) {
u16 rpbase = 0x500;
iic_t *iip;
struct spi_pram *spp;
iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
out_be16(&iip->iic_rpbase, rpbase);
/* Put SPI above the IIC, also 32-byte aligned. */
spp = (struct spi_pram *)&cp->cp_dparam[PROFF_SPI];
out_be16(&spp->rpbase, (rpbase + sizeof(iic_t) + 31) & ~31);
if (IS_ENABLED(CONFIG_I2C_SPI_SMC1_UCODE_PATCH)) {
smc_uart_t *smp;
smp = (smc_uart_t *)&cp->cp_dparam[PROFF_SMC1];
out_be16(&smp->smc_rpbase, 0x1FC0);
}
}
if (IS_ENABLED(CONFIG_SMC_UCODE_PATCH)) {
smc_uart_t *smp;
smp = (smc_uart_t *)&cp->cp_dparam[PROFF_SMC1];
out_be16(&smp->smc_rpbase, 0x1ec0);
smp = (smc_uart_t *)&cp->cp_dparam[PROFF_SMC2];
out_be16(&smp->smc_rpbase, 0x1fc0);
}
out_be16(&cp->cp_cpmcr1, patch_params.cpmcr1);
out_be16(&cp->cp_cpmcr2, patch_params.cpmcr2);
out_be16(&cp->cp_cpmcr3, patch_params.cpmcr3);
out_be16(&cp->cp_cpmcr4, patch_params.cpmcr4);
out_be16(&cp->cp_rccr, patch_params.rccr);
pr_info("%s microcode patch installed\n", patch_name);
}