Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,206 @@
# SPDX-License-Identifier: GPL-2.0
config CPM1
bool
select CPM
choice
prompt "8xx Machine Type"
depends on PPC_8xx
default MPC885ADS
config MPC8XXFADS
bool "FADS"
config MPC86XADS
bool "MPC86XADS"
select CPM1
help
MPC86x Application Development System by Freescale Semiconductor.
The MPC86xADS is meant to serve as a platform for s/w and h/w
development around the MPC86X processor families.
config MPC885ADS
bool "MPC885ADS"
select CPM1
select OF_DYNAMIC
help
Freescale Semiconductor MPC885 Application Development System (ADS).
Also known as DUET.
The MPC885ADS is meant to serve as a platform for s/w and h/w
development around the MPC885 processor family.
config PPC_EP88XC
bool "Embedded Planet EP88xC (a.k.a. CWH-PPC-885XN-VE)"
select CPM1
help
This enables support for the Embedded Planet EP88xC board.
This board is also resold by Freescale as the QUICCStart
MPC885 Evaluation System and/or the CWH-PPC-885XN-VE.
config PPC_ADDER875
bool "Analogue & Micro Adder 875"
select CPM1
help
This enables support for the Analogue & Micro Adder 875
board.
config TQM8XX
bool "TQM8XX"
select CPM1
help
support for the mpc8xx based boards from TQM.
endchoice
menu "Freescale Ethernet driver platform-specific options"
depends on (FS_ENET && MPC885ADS)
config MPC8xx_SECOND_ETH
bool "Second Ethernet channel"
depends on MPC885ADS
default y
help
This enables support for second Ethernet on MPC885ADS and MPC86xADS boards.
The latter will use SCC1, for 885ADS you can select it below.
choice
prompt "Second Ethernet channel"
depends on MPC8xx_SECOND_ETH
default MPC8xx_SECOND_ETH_FEC2
config MPC8xx_SECOND_ETH_FEC2
bool "FEC2"
depends on MPC885ADS
help
Enable FEC2 to serve as 2-nd Ethernet channel. Note that SMC2
(often 2-nd UART) will not work if this is enabled.
config MPC8xx_SECOND_ETH_SCC3
bool "SCC3"
depends on MPC885ADS
help
Enable SCC3 to serve as 2-nd Ethernet channel. Note that SMC1
(often 1-nd UART) will not work if this is enabled.
endchoice
endmenu
#
# MPC8xx Communication options
#
menu "MPC8xx CPM Options"
depends on PPC_8xx
# This doesn't really belong here, but it is convenient to ask
# 8xx specific questions.
comment "Generic MPC8xx Options"
config 8xx_GPIO
bool "GPIO API Support"
select GPIOLIB
help
Saying Y here will cause the ports on an MPC8xx processor to be used
with the GPIO API. If you say N here, the kernel needs less memory.
If in doubt, say Y here.
config 8xx_CPU15
bool "CPU15 Silicon Errata"
depends on !HUGETLB_PAGE
default y
help
This enables a workaround for erratum CPU15 on MPC8xx chips.
This bug can cause incorrect code execution under certain
circumstances. This workaround adds some overhead (a TLB miss
every time execution crosses a page boundary), and you may wish
to disable it if you have worked around the bug in the compiler
(by not placing conditional branches or branches to LR or CTR
in the last word of a page, with a target of the last cache
line in the next page), or if you have used some other
workaround.
If in doubt, say Y here.
choice
prompt "Microcode patch selection"
default NO_UCODE_PATCH
help
Help not implemented yet, coming soon.
config NO_UCODE_PATCH
bool "None"
config USB_SOF_UCODE_PATCH
bool "USB SOF patch"
help
Help not implemented yet, coming soon.
config I2C_SPI_UCODE_PATCH
bool "I2C/SPI relocation patch"
help
Help not implemented yet, coming soon.
config I2C_SPI_SMC1_UCODE_PATCH
bool "I2C/SPI/SMC1 relocation 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
bool
default y
depends on !NO_UCODE_PATCH
menu "8xx advanced setup"
depends on PPC_8xx
config PIN_TLB
bool "Pinned Kernel TLBs"
depends on ADVANCED_OPTIONS
help
On the 8xx, we have 32 instruction TLBs and 32 data TLBs. In each
table 4 TLBs can be pinned.
It reduces the amount of usable TLBs to 28 (ie by 12%). That's the
reason why we make it selectable.
This option does nothing, it just activate the selection of what
to pin.
config PIN_TLB_DATA
bool "Pinned TLB for DATA"
depends on PIN_TLB
default y
help
This pins the first 32 Mbytes of memory with 8M pages.
config PIN_TLB_IMMR
bool "Pinned TLB for IMMR"
depends on PIN_TLB
default y
help
This pins the IMMR area with a 512kbytes page. In case
CONFIG_PIN_TLB_DATA is also selected, it will reduce
CONFIG_PIN_TLB_DATA to 24 Mbytes.
config PIN_TLB_TEXT
bool "Pinned TLB for TEXT"
depends on PIN_TLB
default y
help
This pins kernel text with 8M pages.
endmenu
endmenu
@@ -0,0 +1,12 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the PowerPC 8xx linux kernel.
#
obj-y += m8xx_setup.o machine_check.o pic.o
obj-$(CONFIG_CPM1) += cpm1.o cpm1-ic.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
obj-$(CONFIG_PPC_ADDER875) += adder875.o
obj-$(CONFIG_TQM8XX) += tqm8xx_setup.o
@@ -0,0 +1,105 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Analogue & Micro Adder MPC875 board support
*
* Author: Scott Wood <scottwood@freescale.com>
*
* Copyright (c) 2007 Freescale Semiconductor, Inc.
*/
#include <linux/init.h>
#include <linux/of_platform.h>
#include <asm/time.h>
#include <asm/machdep.h>
#include <asm/cpm1.h>
#include <asm/8xx_immap.h>
#include <asm/udbg.h>
#include "mpc8xx.h"
#include "pic.h"
struct cpm_pin {
int port, pin, flags;
};
static __initdata struct cpm_pin adder875_pins[] = {
/* SMC1 */
{CPM_PORTB, 24, CPM_PIN_INPUT}, /* RX */
{CPM_PORTB, 25, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TX */
/* MII1 */
{CPM_PORTA, 0, CPM_PIN_INPUT},
{CPM_PORTA, 1, CPM_PIN_INPUT},
{CPM_PORTA, 2, CPM_PIN_INPUT},
{CPM_PORTA, 3, CPM_PIN_INPUT},
{CPM_PORTA, 4, CPM_PIN_OUTPUT},
{CPM_PORTA, 10, CPM_PIN_OUTPUT},
{CPM_PORTA, 11, CPM_PIN_OUTPUT},
{CPM_PORTB, 19, CPM_PIN_INPUT},
{CPM_PORTB, 31, CPM_PIN_INPUT},
{CPM_PORTC, 12, CPM_PIN_INPUT},
{CPM_PORTC, 13, CPM_PIN_INPUT},
{CPM_PORTE, 30, CPM_PIN_OUTPUT},
{CPM_PORTE, 31, CPM_PIN_OUTPUT},
/* MII2 */
{CPM_PORTE, 14, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
{CPM_PORTE, 15, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
{CPM_PORTE, 16, CPM_PIN_OUTPUT},
{CPM_PORTE, 17, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
{CPM_PORTE, 18, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
{CPM_PORTE, 19, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
{CPM_PORTE, 20, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
{CPM_PORTE, 21, CPM_PIN_OUTPUT},
{CPM_PORTE, 22, CPM_PIN_OUTPUT},
{CPM_PORTE, 23, CPM_PIN_OUTPUT},
{CPM_PORTE, 24, CPM_PIN_OUTPUT},
{CPM_PORTE, 25, CPM_PIN_OUTPUT},
{CPM_PORTE, 26, CPM_PIN_OUTPUT},
{CPM_PORTE, 27, CPM_PIN_OUTPUT},
{CPM_PORTE, 28, CPM_PIN_OUTPUT},
{CPM_PORTE, 29, CPM_PIN_OUTPUT},
};
static void __init init_ioports(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(adder875_pins); i++) {
const struct cpm_pin *pin = &adder875_pins[i];
cpm1_set_pin(pin->port, pin->pin, pin->flags);
}
cpm1_clk_setup(CPM_CLK_SMC1, CPM_BRG1, CPM_CLK_RTX);
/* Set FEC1 and FEC2 to MII mode */
clrbits32(&mpc8xx_immr->im_cpm.cp_cptr, 0x00000180);
}
static void __init adder875_setup(void)
{
cpm_reset();
init_ioports();
}
static const struct of_device_id of_bus_ids[] __initconst = {
{ .compatible = "simple-bus", },
{},
};
static int __init declare_of_platform_devices(void)
{
of_platform_bus_probe(NULL, of_bus_ids, NULL);
return 0;
}
machine_device_initcall(adder875, declare_of_platform_devices);
define_machine(adder875) {
.name = "Adder MPC875",
.compatible = "analogue-and-micro,adder875",
.setup_arch = adder875_setup,
.init_IRQ = mpc8xx_pic_init,
.get_irq = mpc8xx_get_irq,
.restart = mpc8xx_restart,
.progress = udbg_progress,
};
@@ -0,0 +1,188 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Interrupt controller for the
* Communication Processor Module.
* Copyright (c) 1997 Dan error_act (dmalek@jlc.net)
*/
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
#include <linux/platform_device.h>
#include <asm/cpm1.h>
struct cpm_pic_data {
cpic8xx_t __iomem *reg;
struct irq_domain *host;
};
static void cpm_mask_irq(struct irq_data *d)
{
struct cpm_pic_data *data = irq_data_get_irq_chip_data(d);
unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d);
clrbits32(&data->reg->cpic_cimr, (1 << cpm_vec));
}
static void cpm_unmask_irq(struct irq_data *d)
{
struct cpm_pic_data *data = irq_data_get_irq_chip_data(d);
unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d);
setbits32(&data->reg->cpic_cimr, (1 << cpm_vec));
}
static void cpm_end_irq(struct irq_data *d)
{
struct cpm_pic_data *data = irq_data_get_irq_chip_data(d);
unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d);
out_be32(&data->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,
};
static int cpm_get_irq(struct irq_desc *desc)
{
struct cpm_pic_data *data = irq_desc_get_handler_data(desc);
int cpm_vec;
/*
* Get the vector by setting the ACK bit and then reading
* the register.
*/
out_be16(&data->reg->cpic_civr, 1);
cpm_vec = in_be16(&data->reg->cpic_civr);
cpm_vec >>= 11;
return irq_find_mapping(data->host, cpm_vec);
}
static void cpm_cascade(struct irq_desc *desc)
{
generic_handle_irq(cpm_get_irq(desc));
}
static int cpm_pic_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
irq_set_chip_data(virq, h->host_data);
irq_set_status_flags(virq, IRQ_LEVEL);
irq_set_chip_and_handler(virq, &cpm_pic, handle_fasteoi_irq);
return 0;
}
static const struct irq_domain_ops cpm_pic_host_ops = {
.map = cpm_pic_host_map,
};
static int cpm_pic_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
int irq;
struct cpm_pic_data *data;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->reg = devm_ioremap(dev, res->start, resource_size(res));
if (!data->reg)
return -ENODEV;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
/* Initialize the CPM interrupt controller. */
out_be32(&data->reg->cpic_cicr,
(CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) |
((virq_to_hw(irq) / 2) << 13) | CICR_HP_MASK);
out_be32(&data->reg->cpic_cimr, 0);
data->host = irq_domain_create_linear(dev_fwnode(dev), 64, &cpm_pic_host_ops, data);
if (!data->host)
return -ENODEV;
irq_set_handler_data(irq, data);
irq_set_chained_handler(irq, cpm_cascade);
setbits32(&data->reg->cpic_cicr, CICR_IEN);
return 0;
}
static const struct of_device_id cpm_pic_match[] = {
{
.compatible = "fsl,cpm1-pic",
}, {
.type = "cpm-pic",
.compatible = "CPM",
}, {},
};
static struct platform_driver cpm_pic_driver = {
.driver = {
.name = "cpm-pic",
.of_match_table = cpm_pic_match,
},
.probe = cpm_pic_probe,
};
static int __init cpm_pic_init(void)
{
return platform_driver_register(&cpm_pic_driver);
}
arch_initcall(cpm_pic_init);
/*
* 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 int cpm_error_probe(struct platform_device *pdev)
{
int irq;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
return request_irq(irq, cpm_error_interrupt, IRQF_NO_THREAD, "error", NULL);
}
static const struct of_device_id cpm_error_ids[] = {
{ .compatible = "fsl,cpm1" },
{ .type = "cpm" },
{},
};
static struct platform_driver cpm_error_driver = {
.driver = {
.name = "cpm-error",
.of_match_table = cpm_error_ids,
},
.probe = cpm_error_probe,
};
static int __init cpm_error_init(void)
{
return platform_driver_register(&cpm_error_driver);
}
subsys_initcall(cpm_error_init);
@@ -0,0 +1,668 @@
// 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 <linux/of_irq.h>
#include <asm/page.h>
#include <asm/8xx_immap.h>
#include <asm/cpm1.h>
#include <asm/io.h>
#include <asm/rheap.h>
#include <asm/cpm.h>
#include <asm/fixmap.h>
#include <sysdev/fsl_soc.h>
#ifdef CONFIG_8xx_GPIO
#include <linux/gpio/driver.h>
#endif
#define CPM_MAP_SIZE (0x4000)
cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */
immap_t __iomem *mpc8xx_immr = (void __iomem *)VIRT_IMMR_BASE;
void __init cpm_reset(void)
{
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).
*/
if ((mfspr(SPRN_IMMR) & 0xffff) == 0x0900) /* MPC885 */
out_be32(&mpc8xx_immr->im_siu_conf.sc_sdcr, 0x40);
else
out_be32(&mpc8xx_immr->im_siu_conf.sc_sdcr, 1);
}
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 & 0xffffff03)
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);
}
EXPORT_SYMBOL(cpm_setbrg);
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 __init 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 __init 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 __init 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 __init 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 gpio_chip gc;
void __iomem *regs;
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 cpm1_gpio16_chip *cpm1_gc)
{
struct cpm_ioport16 __iomem *iop = cpm1_gc->regs;
cpm1_gc->cpdata = in_be16(&iop->dat);
}
static int cpm1_gpio16_get(struct gpio_chip *gc, unsigned int gpio)
{
struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(gc);
struct cpm_ioport16 __iomem *iop = cpm1_gc->regs;
u16 pin_mask;
pin_mask = 1 << (15 - gpio);
return !!(in_be16(&iop->dat) & pin_mask);
}
static void __cpm1_gpio16_set(struct cpm1_gpio16_chip *cpm1_gc, u16 pin_mask, int value)
{
struct cpm_ioport16 __iomem *iop = cpm1_gc->regs;
if (value)
cpm1_gc->cpdata |= pin_mask;
else
cpm1_gc->cpdata &= ~pin_mask;
out_be16(&iop->dat, cpm1_gc->cpdata);
}
static int cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value)
{
struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(gc);
unsigned long flags;
u16 pin_mask = 1 << (15 - gpio);
spin_lock_irqsave(&cpm1_gc->lock, flags);
__cpm1_gpio16_set(cpm1_gc, pin_mask, value);
spin_unlock_irqrestore(&cpm1_gc->lock, flags);
return 0;
}
static int cpm1_gpio16_to_irq(struct gpio_chip *gc, unsigned int gpio)
{
struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(gc);
return cpm1_gc->irq[gpio] ? : -ENXIO;
}
static int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(gc);
struct cpm_ioport16 __iomem *iop = cpm1_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(cpm1_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 cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(gc);
struct cpm_ioport16 __iomem *iop = cpm1_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;
}
static int cpm1_gpio16_get_direction(struct gpio_chip *gc, unsigned int gpio)
{
struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(gc);
struct cpm_ioport16 __iomem *iop = cpm1_gc->regs;
u16 pin_mask = 1 << (15 - gpio);
if (in_be16(&iop->dir) & pin_mask)
return GPIO_LINE_DIRECTION_OUT;
return GPIO_LINE_DIRECTION_IN;
}
int cpm1_gpiochip_add16(struct device *dev)
{
struct device_node *np = dev->of_node;
struct cpm1_gpio16_chip *cpm1_gc;
struct gpio_chip *gc;
u32 mask;
cpm1_gc = devm_kzalloc(dev, sizeof(*cpm1_gc), GFP_KERNEL);
if (!cpm1_gc)
return -ENOMEM;
spin_lock_init(&cpm1_gc->lock);
if (!of_property_read_u32(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++);
}
gc = &cpm1_gc->gc;
gc->base = -1;
gc->ngpio = 16;
gc->direction_input = cpm1_gpio16_dir_in;
gc->direction_output = cpm1_gpio16_dir_out;
gc->get_direction = cpm1_gpio16_get_direction;
gc->get = cpm1_gpio16_get;
gc->set = cpm1_gpio16_set;
gc->to_irq = cpm1_gpio16_to_irq;
gc->parent = dev;
gc->owner = THIS_MODULE;
gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", np);
if (!gc->label)
return -ENOMEM;
cpm1_gc->regs = devm_of_iomap(dev, np, 0, NULL);
if (IS_ERR(cpm1_gc->regs))
return PTR_ERR(cpm1_gc->regs);
cpm1_gpio16_save_regs(cpm1_gc);
return devm_gpiochip_add_data(dev, gc, cpm1_gc);
}
struct cpm1_gpio32_chip {
struct gpio_chip gc;
void __iomem *regs;
spinlock_t lock;
/* shadowed data register to clear/set bits safely */
u32 cpdata;
};
static void cpm1_gpio32_save_regs(struct cpm1_gpio32_chip *cpm1_gc)
{
struct cpm_ioport32b __iomem *iop = cpm1_gc->regs;
cpm1_gc->cpdata = in_be32(&iop->dat);
}
static int cpm1_gpio32_get(struct gpio_chip *gc, unsigned int gpio)
{
struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(gc);
struct cpm_ioport32b __iomem *iop = cpm1_gc->regs;
u32 pin_mask;
pin_mask = 1 << (31 - gpio);
return !!(in_be32(&iop->dat) & pin_mask);
}
static void __cpm1_gpio32_set(struct cpm1_gpio32_chip *cpm1_gc, u32 pin_mask, int value)
{
struct cpm_ioport32b __iomem *iop = cpm1_gc->regs;
if (value)
cpm1_gc->cpdata |= pin_mask;
else
cpm1_gc->cpdata &= ~pin_mask;
out_be32(&iop->dat, cpm1_gc->cpdata);
}
static int cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
{
struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(gc);
unsigned long flags;
u32 pin_mask = 1 << (31 - gpio);
spin_lock_irqsave(&cpm1_gc->lock, flags);
__cpm1_gpio32_set(cpm1_gc, pin_mask, value);
spin_unlock_irqrestore(&cpm1_gc->lock, flags);
return 0;
}
static int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(gc);
struct cpm_ioport32b __iomem *iop = cpm1_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(cpm1_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 cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(gc);
struct cpm_ioport32b __iomem *iop = cpm1_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;
}
static int cpm1_gpio32_get_direction(struct gpio_chip *gc, unsigned int gpio)
{
struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(gc);
struct cpm_ioport32b __iomem *iop = cpm1_gc->regs;
u32 pin_mask = 1 << (31 - gpio);
if (in_be32(&iop->dir) & pin_mask)
return GPIO_LINE_DIRECTION_OUT;
return GPIO_LINE_DIRECTION_IN;
}
int cpm1_gpiochip_add32(struct device *dev)
{
struct device_node *np = dev->of_node;
struct cpm1_gpio32_chip *cpm1_gc;
struct gpio_chip *gc;
cpm1_gc = devm_kzalloc(dev, sizeof(*cpm1_gc), GFP_KERNEL);
if (!cpm1_gc)
return -ENOMEM;
spin_lock_init(&cpm1_gc->lock);
gc = &cpm1_gc->gc;
gc->base = -1;
gc->ngpio = 32;
gc->direction_input = cpm1_gpio32_dir_in;
gc->direction_output = cpm1_gpio32_dir_out;
gc->get_direction = cpm1_gpio32_get_direction;
gc->get = cpm1_gpio32_get;
gc->set = cpm1_gpio32_set;
gc->parent = dev;
gc->owner = THIS_MODULE;
gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", np);
if (!gc->label)
return -ENOMEM;
cpm1_gc->regs = devm_of_iomap(dev, np, 0, NULL);
if (IS_ERR(cpm1_gc->regs))
return PTR_ERR(cpm1_gc->regs);
cpm1_gpio32_save_regs(cpm1_gc);
return devm_gpiochip_add_data(dev, gc, cpm1_gc);
}
#endif /* CONFIG_8xx_GPIO */
@@ -0,0 +1,170 @@
/*
* Platform setup for the Embedded Planet EP88xC board
*
* Author: Scott Wood <scottwood@freescale.com>
* Copyright 2007 Freescale Semiconductor, Inc.
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#include <linux/init.h>
#include <linux/of_address.h>
#include <linux/of_fdt.h>
#include <linux/of_platform.h>
#include <asm/machdep.h>
#include <asm/io.h>
#include <asm/udbg.h>
#include <asm/cpm1.h>
#include "mpc8xx.h"
#include "pic.h"
struct cpm_pin {
int port, pin, flags;
};
static struct cpm_pin ep88xc_pins[] = {
/* SMC1 */
{1, 24, CPM_PIN_INPUT}, /* RX */
{1, 25, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TX */
/* SCC2 */
{0, 12, CPM_PIN_INPUT}, /* TX */
{0, 13, CPM_PIN_INPUT}, /* RX */
{2, 8, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_GPIO}, /* CD */
{2, 9, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_GPIO}, /* CTS */
{2, 14, CPM_PIN_INPUT}, /* RTS */
/* MII1 */
{0, 0, CPM_PIN_INPUT},
{0, 1, CPM_PIN_INPUT},
{0, 2, CPM_PIN_INPUT},
{0, 3, CPM_PIN_INPUT},
{0, 4, CPM_PIN_OUTPUT},
{0, 10, CPM_PIN_OUTPUT},
{0, 11, CPM_PIN_OUTPUT},
{1, 19, CPM_PIN_INPUT},
{1, 31, CPM_PIN_INPUT},
{2, 12, CPM_PIN_INPUT},
{2, 13, CPM_PIN_INPUT},
{3, 8, CPM_PIN_INPUT},
{4, 30, CPM_PIN_OUTPUT},
{4, 31, CPM_PIN_OUTPUT},
/* MII2 */
{4, 14, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
{4, 15, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
{4, 16, CPM_PIN_OUTPUT},
{4, 17, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
{4, 18, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
{4, 19, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
{4, 20, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
{4, 21, CPM_PIN_OUTPUT},
{4, 22, CPM_PIN_OUTPUT},
{4, 23, CPM_PIN_OUTPUT},
{4, 24, CPM_PIN_OUTPUT},
{4, 25, CPM_PIN_OUTPUT},
{4, 26, CPM_PIN_OUTPUT},
{4, 27, CPM_PIN_OUTPUT},
{4, 28, CPM_PIN_OUTPUT},
{4, 29, CPM_PIN_OUTPUT},
/* USB */
{0, 6, CPM_PIN_INPUT}, /* CLK2 */
{0, 14, CPM_PIN_INPUT}, /* USBOE */
{0, 15, CPM_PIN_INPUT}, /* USBRXD */
{2, 6, CPM_PIN_OUTPUT}, /* USBTXN */
{2, 7, CPM_PIN_OUTPUT}, /* USBTXP */
{2, 10, CPM_PIN_INPUT}, /* USBRXN */
{2, 11, CPM_PIN_INPUT}, /* USBRXP */
/* Misc */
{1, 26, CPM_PIN_INPUT}, /* BRGO2 */
{1, 27, CPM_PIN_INPUT}, /* BRGO1 */
};
static void __init init_ioports(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(ep88xc_pins); i++) {
struct cpm_pin *pin = &ep88xc_pins[i];
cpm1_set_pin(pin->port, pin->pin, pin->flags);
}
cpm1_clk_setup(CPM_CLK_SMC1, CPM_BRG1, CPM_CLK_RTX);
cpm1_clk_setup(CPM_CLK_SCC1, CPM_CLK2, CPM_CLK_TX); /* USB */
cpm1_clk_setup(CPM_CLK_SCC1, CPM_CLK2, CPM_CLK_RX);
cpm1_clk_setup(CPM_CLK_SCC2, CPM_BRG2, CPM_CLK_TX);
cpm1_clk_setup(CPM_CLK_SCC2, CPM_BRG2, CPM_CLK_RX);
}
static u8 __iomem *ep88xc_bcsr;
#define BCSR7_SCC2_ENABLE 0x10
#define BCSR8_PHY1_ENABLE 0x80
#define BCSR8_PHY1_POWER 0x40
#define BCSR8_PHY2_ENABLE 0x20
#define BCSR8_PHY2_POWER 0x10
#define BCSR9_USB_ENABLE 0x80
#define BCSR9_USB_POWER 0x40
#define BCSR9_USB_HOST 0x20
#define BCSR9_USB_FULL_SPEED_TARGET 0x10
static void __init ep88xc_setup_arch(void)
{
struct device_node *np;
cpm_reset();
init_ioports();
np = of_find_compatible_node(NULL, NULL, "fsl,ep88xc-bcsr");
if (!np) {
printk(KERN_CRIT "Could not find fsl,ep88xc-bcsr node\n");
return;
}
ep88xc_bcsr = of_iomap(np, 0);
of_node_put(np);
if (!ep88xc_bcsr) {
printk(KERN_CRIT "Could not remap BCSR\n");
return;
}
setbits8(&ep88xc_bcsr[7], BCSR7_SCC2_ENABLE);
setbits8(&ep88xc_bcsr[8], BCSR8_PHY1_ENABLE | BCSR8_PHY1_POWER |
BCSR8_PHY2_ENABLE | BCSR8_PHY2_POWER);
}
static const struct of_device_id of_bus_ids[] __initconst = {
{ .name = "soc", },
{ .name = "cpm", },
{ .name = "localbus", },
{},
};
static int __init declare_of_platform_devices(void)
{
/* Publish the QE devices */
of_platform_bus_probe(NULL, of_bus_ids, NULL);
return 0;
}
machine_device_initcall(ep88xc, declare_of_platform_devices);
define_machine(ep88xc) {
.name = "Embedded Planet EP88xC",
.compatible = "fsl,ep88xc",
.setup_arch = ep88xc_setup_arch,
.init_IRQ = mpc8xx_pic_init,
.get_irq = mpc8xx_get_irq,
.restart = mpc8xx_restart,
.calibrate_decr = mpc8xx_calibrate_decr,
.progress = udbg_progress,
};
@@ -0,0 +1,172 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 1995 Linus Torvalds
* Adapted from 'alpha' version by Gary Thomas
* Modified by Cort Dougan (cort@cs.nmt.edu)
* Modified for MBX using prep/chrp/pmac functions by Dan (dmalek@jlc.net)
* Further modified for generic 8xx by Dan.
*/
/*
* bootup setup stuff..
*/
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/rtc.h>
#include <linux/fsl_devices.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <asm/io.h>
#include <asm/8xx_immap.h>
#include <mm/mmu_decl.h>
#include "pic.h"
#include "mpc8xx.h"
/* A place holder for time base interrupts, if they are ever enabled. */
static irqreturn_t timebase_interrupt(int irq, void *dev)
{
printk ("timebase_interrupt()\n");
return IRQ_HANDLED;
}
static int __init get_freq(char *name, unsigned long *val)
{
struct device_node *cpu;
const unsigned int *fp;
int found = 0;
/* The cpu node should have timebase and clock frequency properties */
cpu = of_get_cpu_node(0, NULL);
if (cpu) {
fp = of_get_property(cpu, name, NULL);
if (fp) {
found = 1;
*val = *fp;
}
of_node_put(cpu);
}
return found;
}
/* The decrementer counts at the system (internal) clock frequency divided by
* sixteen, or external oscillator divided by four. We force the processor
* to use system clock divided by sixteen.
*/
void __init mpc8xx_calibrate_decr(void)
{
struct device_node *cpu;
int irq, virq;
/* Unlock the SCCR. */
out_be32(&mpc8xx_immr->im_clkrstk.cark_sccrk, ~KAPWR_KEY);
out_be32(&mpc8xx_immr->im_clkrstk.cark_sccrk, KAPWR_KEY);
/* Force all 8xx processors to use divide by 16 processor clock. */
setbits32(&mpc8xx_immr->im_clkrst.car_sccr, 0x02000000);
/* Processor frequency is MHz.
*/
ppc_proc_freq = 50000000;
if (!get_freq("clock-frequency", &ppc_proc_freq))
printk(KERN_ERR "WARNING: Estimating processor frequency "
"(not found)\n");
ppc_tb_freq = ppc_proc_freq / 16;
printk("Decrementer Frequency = 0x%lx\n", ppc_tb_freq);
/* Perform some more timer/timebase initialization. This used
* to be done elsewhere, but other changes caused it to get
* called more than once....that is a bad thing.
*
* First, unlock all of the registers we are going to modify.
* To protect them from corruption during power down, registers
* that are maintained by keep alive power are "locked". To
* modify these registers we have to write the key value to
* the key location associated with the register.
* Some boards power up with these unlocked, while others
* are locked. Writing anything (including the unlock code?)
* to the unlocked registers will lock them again. So, here
* we guarantee the registers are locked, then we unlock them
* for our use.
*/
out_be32(&mpc8xx_immr->im_sitk.sitk_tbscrk, ~KAPWR_KEY);
out_be32(&mpc8xx_immr->im_sitk.sitk_rtcsck, ~KAPWR_KEY);
out_be32(&mpc8xx_immr->im_sitk.sitk_tbk, ~KAPWR_KEY);
out_be32(&mpc8xx_immr->im_sitk.sitk_tbscrk, KAPWR_KEY);
out_be32(&mpc8xx_immr->im_sitk.sitk_rtcsck, KAPWR_KEY);
out_be32(&mpc8xx_immr->im_sitk.sitk_tbk, KAPWR_KEY);
/* Disable the RTC one second and alarm interrupts. */
clrbits16(&mpc8xx_immr->im_sit.sit_rtcsc, (RTCSC_SIE | RTCSC_ALE));
/* Enable the RTC */
setbits16(&mpc8xx_immr->im_sit.sit_rtcsc, (RTCSC_RTF | RTCSC_RTE));
/* Enabling the decrementer also enables the timebase interrupts
* (or from the other point of view, to get decrementer interrupts
* we have to enable the timebase). The decrementer interrupt
* is wired into the vector table, nothing to do here for that.
*/
cpu = of_get_cpu_node(0, NULL);
virq= irq_of_parse_and_map(cpu, 0);
of_node_put(cpu);
irq = virq_to_hw(virq);
out_be16(&mpc8xx_immr->im_sit.sit_tbscr,
((1 << (7 - (irq / 2))) << 8) | (TBSCR_TBF | TBSCR_TBE));
if (request_irq(virq, timebase_interrupt, IRQF_NO_THREAD, "tbint",
NULL))
panic("Could not allocate timer IRQ!");
}
/* The RTC on the MPC8xx is an internal register.
* We want to protect this during power down, so we need to unlock,
* modify, and re-lock.
*/
int mpc8xx_set_rtc_time(struct rtc_time *tm)
{
time64_t time;
time = rtc_tm_to_time64(tm);
out_be32(&mpc8xx_immr->im_sitk.sitk_rtck, KAPWR_KEY);
out_be32(&mpc8xx_immr->im_sit.sit_rtc, (u32)time);
out_be32(&mpc8xx_immr->im_sitk.sitk_rtck, ~KAPWR_KEY);
return 0;
}
void mpc8xx_get_rtc_time(struct rtc_time *tm)
{
unsigned long data;
/* Get time from the RTC. */
data = in_be32(&mpc8xx_immr->im_sit.sit_rtc);
rtc_time64_to_tm(data, tm);
return;
}
void __noreturn mpc8xx_restart(char *cmd)
{
local_irq_disable();
setbits32(&mpc8xx_immr->im_clkrst.car_plprcr, 0x00000080);
/* Clear the ME bit in MSR to cause checkstop on machine check
*/
mtmsr(mfmsr() & ~0x1000);
in_8(&mpc8xx_immr->im_clkrst.res[0]);
panic("Restart failed\n");
}
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
*/
#include <linux/kernel.h>
#include <linux/printk.h>
#include <linux/ptrace.h>
#include <asm/reg.h>
int machine_check_8xx(struct pt_regs *regs)
{
unsigned long reason = regs->msr;
pr_err("Machine check in kernel mode.\n");
pr_err("Caused by (from SRR1=%lx): ", reason);
if (reason & 0x40000000)
pr_cont("Fetch error at address %lx\n", regs->nip);
else
pr_cont("Data access error at address %lx\n", regs->dar);
#ifdef CONFIG_PCI
/* the qspan pci read routines can cause machine checks -- Cort
*
* yuck !!! that totally needs to go away ! There are better ways
* to deal with that than having a wart in the mcheck handler.
* -- BenH
*/
bad_page_fault(regs, SIGBUS);
return 1;
#else
return 0;
#endif
}
@@ -0,0 +1,388 @@
// 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/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;
if (IS_ENABLED(CONFIG_PPC_EARLY_DEBUG_CPM)) {
int i;
for (i = 0; i < sizeof(*smp); i += 4) {
u32 __iomem *src = (u32 __iomem *)&cp->cp_dparam[PROFF_SMC1 + i];
u32 __iomem *dst = (u32 __iomem *)&cp->cp_dparam[PROFF_DSP1 + i];
out_be32(dst, in_be32(src));
}
}
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);
}
@@ -0,0 +1,47 @@
/*
* A collection of structures, addresses, and values associated with
* the Freescale MPC86xADS board.
* Copied from the FADS stuff.
*
* Author: MontaVista Software, Inc.
* source@mvista.com
*
* 2005 (c) MontaVista Software, Inc. This file is licensed under the
* terms of the GNU General Public License version 2. This program is licensed
* "as is" without any warranty of any kind, whether express or implied.
*/
#ifdef __KERNEL__
#ifndef __ASM_MPC86XADS_H__
#define __ASM_MPC86XADS_H__
/* Bits of interest in the BCSRs.
*/
#define BCSR1_ETHEN ((uint)0x20000000)
#define BCSR1_IRDAEN ((uint)0x10000000)
#define BCSR1_RS232EN_1 ((uint)0x01000000)
#define BCSR1_PCCEN ((uint)0x00800000)
#define BCSR1_PCCVCC0 ((uint)0x00400000)
#define BCSR1_PCCVPP0 ((uint)0x00200000)
#define BCSR1_PCCVPP1 ((uint)0x00100000)
#define BCSR1_PCCVPP_MASK (BCSR1_PCCVPP0 | BCSR1_PCCVPP1)
#define BCSR1_RS232EN_2 ((uint)0x00040000)
#define BCSR1_PCCVCC1 ((uint)0x00010000)
#define BCSR1_PCCVCC_MASK (BCSR1_PCCVCC0 | BCSR1_PCCVCC1)
#define BCSR4_ETH10_RST ((uint)0x80000000) /* 10Base-T PHY reset*/
#define BCSR4_USB_LO_SPD ((uint)0x04000000)
#define BCSR4_USB_VCC ((uint)0x02000000)
#define BCSR4_USB_FULL_SPD ((uint)0x00040000)
#define BCSR4_USB_EN ((uint)0x00020000)
#define BCSR5_MII2_EN 0x40
#define BCSR5_MII2_RST 0x20
#define BCSR5_T1_RST 0x10
#define BCSR5_ATM155_RST 0x08
#define BCSR5_ATM25_RST 0x04
#define BCSR5_MII1_EN 0x02
#define BCSR5_MII1_RST 0x01
#endif /* __ASM_MPC86XADS_H__ */
#endif /* __KERNEL__ */
@@ -0,0 +1,145 @@
/*arch/powerpc/platforms/8xx/mpc86xads_setup.c
*
* Platform setup for the Freescale mpc86xads board
*
* Vitaly Bordug <vbordug@ru.mvista.com>
*
* Copyright 2005 MontaVista Software Inc.
*
* Heavily modified by Scott Wood <scottwood@freescale.com>
* Copyright 2007 Freescale Semiconductor, Inc.
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#include <linux/init.h>
#include <linux/of_address.h>
#include <linux/of_fdt.h>
#include <linux/of_platform.h>
#include <asm/io.h>
#include <asm/machdep.h>
#include <asm/time.h>
#include <asm/8xx_immap.h>
#include <asm/cpm1.h>
#include <asm/udbg.h>
#include "mpc86xads.h"
#include "mpc8xx.h"
#include "pic.h"
struct cpm_pin {
int port, pin, flags;
};
static struct cpm_pin mpc866ads_pins[] = {
/* SMC1 */
{CPM_PORTB, 24, CPM_PIN_INPUT}, /* RX */
{CPM_PORTB, 25, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TX */
/* SMC2 */
{CPM_PORTB, 21, CPM_PIN_INPUT}, /* RX */
{CPM_PORTB, 20, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TX */
/* SCC1 */
{CPM_PORTA, 6, CPM_PIN_INPUT}, /* CLK1 */
{CPM_PORTA, 7, CPM_PIN_INPUT}, /* CLK2 */
{CPM_PORTA, 14, CPM_PIN_INPUT}, /* TX */
{CPM_PORTA, 15, CPM_PIN_INPUT}, /* RX */
{CPM_PORTB, 19, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TENA */
{CPM_PORTC, 10, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_GPIO}, /* RENA */
{CPM_PORTC, 11, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_GPIO}, /* CLSN */
/* MII */
{CPM_PORTD, 3, CPM_PIN_OUTPUT},
{CPM_PORTD, 4, CPM_PIN_OUTPUT},
{CPM_PORTD, 5, CPM_PIN_OUTPUT},
{CPM_PORTD, 6, CPM_PIN_OUTPUT},
{CPM_PORTD, 7, CPM_PIN_OUTPUT},
{CPM_PORTD, 8, CPM_PIN_OUTPUT},
{CPM_PORTD, 9, CPM_PIN_OUTPUT},
{CPM_PORTD, 10, CPM_PIN_OUTPUT},
{CPM_PORTD, 11, CPM_PIN_OUTPUT},
{CPM_PORTD, 12, CPM_PIN_OUTPUT},
{CPM_PORTD, 13, CPM_PIN_OUTPUT},
{CPM_PORTD, 14, CPM_PIN_OUTPUT},
{CPM_PORTD, 15, CPM_PIN_OUTPUT},
/* I2C */
{CPM_PORTB, 26, CPM_PIN_INPUT | CPM_PIN_OPENDRAIN},
{CPM_PORTB, 27, CPM_PIN_INPUT | CPM_PIN_OPENDRAIN},
};
static void __init init_ioports(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(mpc866ads_pins); i++) {
struct cpm_pin *pin = &mpc866ads_pins[i];
cpm1_set_pin(pin->port, pin->pin, pin->flags);
}
cpm1_clk_setup(CPM_CLK_SMC1, CPM_BRG1, CPM_CLK_RTX);
cpm1_clk_setup(CPM_CLK_SMC2, CPM_BRG2, CPM_CLK_RTX);
cpm1_clk_setup(CPM_CLK_SCC1, CPM_CLK1, CPM_CLK_TX);
cpm1_clk_setup(CPM_CLK_SCC1, CPM_CLK2, CPM_CLK_RX);
/* Set FEC1 and FEC2 to MII mode */
clrbits32(&mpc8xx_immr->im_cpm.cp_cptr, 0x00000180);
}
static void __init mpc86xads_setup_arch(void)
{
struct device_node *np;
u32 __iomem *bcsr_io;
cpm_reset();
init_ioports();
np = of_find_compatible_node(NULL, NULL, "fsl,mpc866ads-bcsr");
if (!np) {
printk(KERN_CRIT "Could not find fsl,mpc866ads-bcsr node\n");
return;
}
bcsr_io = of_iomap(np, 0);
of_node_put(np);
if (bcsr_io == NULL) {
printk(KERN_CRIT "Could not remap BCSR\n");
return;
}
clrbits32(bcsr_io, BCSR1_RS232EN_1 | BCSR1_RS232EN_2 | BCSR1_ETHEN);
iounmap(bcsr_io);
}
static const struct of_device_id of_bus_ids[] __initconst = {
{ .name = "soc", },
{ .name = "cpm", },
{ .name = "localbus", },
{},
};
static int __init declare_of_platform_devices(void)
{
of_platform_bus_probe(NULL, of_bus_ids, NULL);
return 0;
}
machine_device_initcall(mpc86x_ads, declare_of_platform_devices);
define_machine(mpc86x_ads) {
.name = "MPC86x ADS",
.compatible = "fsl,mpc866ads",
.setup_arch = mpc86xads_setup_arch,
.init_IRQ = mpc8xx_pic_init,
.get_irq = mpc8xx_get_irq,
.restart = mpc8xx_restart,
.calibrate_decr = mpc8xx_calibrate_decr,
.set_rtc_time = mpc8xx_set_rtc_time,
.get_rtc_time = mpc8xx_get_rtc_time,
.progress = udbg_progress,
};
@@ -0,0 +1,49 @@
/*
* A collection of structures, addresses, and values associated with
* the Freescale MPC885ADS board.
* Copied from the FADS stuff.
*
* Author: MontaVista Software, Inc.
* source@mvista.com
*
* 2005 (c) MontaVista Software, Inc. This file is licensed under the
* terms of the GNU General Public License version 2. This program is licensed
* "as is" without any warranty of any kind, whether express or implied.
*/
#ifdef __KERNEL__
#ifndef __ASM_MPC885ADS_H__
#define __ASM_MPC885ADS_H__
#include <sysdev/fsl_soc.h>
/* Bits of interest in the BCSRs.
*/
#define BCSR1_ETHEN ((uint)0x20000000)
#define BCSR1_IRDAEN ((uint)0x10000000)
#define BCSR1_RS232EN_1 ((uint)0x01000000)
#define BCSR1_PCCEN ((uint)0x00800000)
#define BCSR1_PCCVCC0 ((uint)0x00400000)
#define BCSR1_PCCVPP0 ((uint)0x00200000)
#define BCSR1_PCCVPP1 ((uint)0x00100000)
#define BCSR1_PCCVPP_MASK (BCSR1_PCCVPP0 | BCSR1_PCCVPP1)
#define BCSR1_RS232EN_2 ((uint)0x00040000)
#define BCSR1_PCCVCC1 ((uint)0x00010000)
#define BCSR1_PCCVCC_MASK (BCSR1_PCCVCC0 | BCSR1_PCCVCC1)
#define BCSR4_ETH10_RST ((uint)0x80000000) /* 10Base-T PHY reset*/
#define BCSR4_USB_LO_SPD ((uint)0x04000000)
#define BCSR4_USB_VCC ((uint)0x02000000)
#define BCSR4_USB_FULL_SPD ((uint)0x00040000)
#define BCSR4_USB_EN ((uint)0x00020000)
#define BCSR5_MII2_EN 0x40
#define BCSR5_MII2_RST 0x20
#define BCSR5_T1_RST 0x10
#define BCSR5_ATM155_RST 0x08
#define BCSR5_ATM25_RST 0x04
#define BCSR5_MII1_EN 0x02
#define BCSR5_MII1_RST 0x01
#endif /* __ASM_MPC885ADS_H__ */
#endif /* __KERNEL__ */
@@ -0,0 +1,217 @@
/*
* Platform setup for the Freescale mpc885ads board
*
* Vitaly Bordug <vbordug@ru.mvista.com>
*
* Copyright 2005 MontaVista Software Inc.
*
* Heavily modified by Scott Wood <scottwood@freescale.com>
* Copyright 2007 Freescale Semiconductor, Inc.
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/param.h>
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/fsl_devices.h>
#include <linux/mii.h>
#include <linux/of_address.h>
#include <linux/of_fdt.h>
#include <linux/of_platform.h>
#include <asm/delay.h>
#include <asm/io.h>
#include <asm/machdep.h>
#include <asm/page.h>
#include <asm/processor.h>
#include <asm/time.h>
#include <asm/8xx_immap.h>
#include <asm/cpm1.h>
#include <asm/udbg.h>
#include "mpc885ads.h"
#include "mpc8xx.h"
#include "pic.h"
static u32 __iomem *bcsr, *bcsr5;
struct cpm_pin {
int port, pin, flags;
};
static struct cpm_pin mpc885ads_pins[] = {
/* SMC1 */
{CPM_PORTB, 24, CPM_PIN_INPUT}, /* RX */
{CPM_PORTB, 25, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TX */
/* SMC2 */
#ifndef CONFIG_MPC8xx_SECOND_ETH_FEC2
{CPM_PORTE, 21, CPM_PIN_INPUT}, /* RX */
{CPM_PORTE, 20, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TX */
#endif
/* SCC3 */
{CPM_PORTA, 9, CPM_PIN_INPUT}, /* RX */
{CPM_PORTA, 8, CPM_PIN_INPUT}, /* TX */
{CPM_PORTC, 4, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_GPIO}, /* RENA */
{CPM_PORTC, 5, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_GPIO}, /* CLSN */
{CPM_PORTE, 27, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TENA */
{CPM_PORTE, 17, CPM_PIN_INPUT}, /* CLK5 */
{CPM_PORTE, 16, CPM_PIN_INPUT}, /* CLK6 */
/* MII1 */
{CPM_PORTA, 0, CPM_PIN_INPUT},
{CPM_PORTA, 1, CPM_PIN_INPUT},
{CPM_PORTA, 2, CPM_PIN_INPUT},
{CPM_PORTA, 3, CPM_PIN_INPUT},
{CPM_PORTA, 4, CPM_PIN_OUTPUT},
{CPM_PORTA, 10, CPM_PIN_OUTPUT},
{CPM_PORTA, 11, CPM_PIN_OUTPUT},
{CPM_PORTB, 19, CPM_PIN_INPUT},
{CPM_PORTB, 31, CPM_PIN_INPUT},
{CPM_PORTC, 12, CPM_PIN_INPUT},
{CPM_PORTC, 13, CPM_PIN_INPUT},
{CPM_PORTE, 30, CPM_PIN_OUTPUT},
{CPM_PORTE, 31, CPM_PIN_OUTPUT},
/* MII2 */
#ifdef CONFIG_MPC8xx_SECOND_ETH_FEC2
{CPM_PORTE, 14, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
{CPM_PORTE, 15, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
{CPM_PORTE, 16, CPM_PIN_OUTPUT},
{CPM_PORTE, 17, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
{CPM_PORTE, 18, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
{CPM_PORTE, 19, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
{CPM_PORTE, 20, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
{CPM_PORTE, 21, CPM_PIN_OUTPUT},
{CPM_PORTE, 22, CPM_PIN_OUTPUT},
{CPM_PORTE, 23, CPM_PIN_OUTPUT},
{CPM_PORTE, 24, CPM_PIN_OUTPUT},
{CPM_PORTE, 25, CPM_PIN_OUTPUT},
{CPM_PORTE, 26, CPM_PIN_OUTPUT},
{CPM_PORTE, 27, CPM_PIN_OUTPUT},
{CPM_PORTE, 28, CPM_PIN_OUTPUT},
{CPM_PORTE, 29, CPM_PIN_OUTPUT},
#endif
/* I2C */
{CPM_PORTB, 26, CPM_PIN_INPUT | CPM_PIN_OPENDRAIN},
{CPM_PORTB, 27, CPM_PIN_INPUT | CPM_PIN_OPENDRAIN},
};
static void __init init_ioports(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(mpc885ads_pins); i++) {
struct cpm_pin *pin = &mpc885ads_pins[i];
cpm1_set_pin(pin->port, pin->pin, pin->flags);
}
cpm1_clk_setup(CPM_CLK_SMC1, CPM_BRG1, CPM_CLK_RTX);
cpm1_clk_setup(CPM_CLK_SMC2, CPM_BRG2, CPM_CLK_RTX);
cpm1_clk_setup(CPM_CLK_SCC3, CPM_CLK5, CPM_CLK_TX);
cpm1_clk_setup(CPM_CLK_SCC3, CPM_CLK6, CPM_CLK_RX);
/* Set FEC1 and FEC2 to MII mode */
clrbits32(&mpc8xx_immr->im_cpm.cp_cptr, 0x00000180);
}
static void __init mpc885ads_setup_arch(void)
{
struct device_node *np;
cpm_reset();
init_ioports();
np = of_find_compatible_node(NULL, NULL, "fsl,mpc885ads-bcsr");
if (!np) {
printk(KERN_CRIT "Could not find fsl,mpc885ads-bcsr node\n");
return;
}
bcsr = of_iomap(np, 0);
bcsr5 = of_iomap(np, 1);
of_node_put(np);
if (!bcsr || !bcsr5) {
printk(KERN_CRIT "Could not remap BCSR\n");
return;
}
clrbits32(&bcsr[1], BCSR1_RS232EN_1);
#ifdef CONFIG_MPC8xx_SECOND_ETH_FEC2
setbits32(&bcsr[1], BCSR1_RS232EN_2);
#else
clrbits32(&bcsr[1], BCSR1_RS232EN_2);
#endif
clrbits32(bcsr5, BCSR5_MII1_EN);
setbits32(bcsr5, BCSR5_MII1_RST);
udelay(1000);
clrbits32(bcsr5, BCSR5_MII1_RST);
#ifdef CONFIG_MPC8xx_SECOND_ETH_FEC2
clrbits32(bcsr5, BCSR5_MII2_EN);
setbits32(bcsr5, BCSR5_MII2_RST);
udelay(1000);
clrbits32(bcsr5, BCSR5_MII2_RST);
#else
setbits32(bcsr5, BCSR5_MII2_EN);
#endif
#ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3
clrbits32(&bcsr[4], BCSR4_ETH10_RST);
udelay(1000);
setbits32(&bcsr[4], BCSR4_ETH10_RST);
setbits32(&bcsr[1], BCSR1_ETHEN);
np = of_find_node_by_path("/soc@ff000000/cpm@9c0/serial@a80");
#else
np = of_find_node_by_path("/soc@ff000000/cpm@9c0/ethernet@a40");
#endif
/* The SCC3 enet registers overlap the SMC1 registers, so
* one of the two must be removed from the device tree.
*/
if (np) {
of_detach_node(np);
of_node_put(np);
}
}
static const struct of_device_id of_bus_ids[] __initconst = {
{ .name = "soc", },
{ .name = "cpm", },
{ .name = "localbus", },
{},
};
static int __init declare_of_platform_devices(void)
{
/* Publish the QE devices */
of_platform_bus_probe(NULL, of_bus_ids, NULL);
return 0;
}
machine_device_initcall(mpc885_ads, declare_of_platform_devices);
define_machine(mpc885_ads) {
.name = "Freescale MPC885 ADS",
.compatible = "fsl,mpc885ads",
.setup_arch = mpc885ads_setup_arch,
.init_IRQ = mpc8xx_pic_init,
.get_irq = mpc8xx_get_irq,
.restart = mpc8xx_restart,
.calibrate_decr = mpc8xx_calibrate_decr,
.progress = udbg_progress,
};
@@ -0,0 +1,20 @@
/*
* Prototypes, etc. for the Freescale MPC8xx embedded cpu chips
* May need to be cleaned as the port goes on ...
*
* Copyright (C) 2008 Jochen Friedrich <jochen@scram.de>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#ifndef __MPC8xx_H
#define __MPC8xx_H
extern void __noreturn mpc8xx_restart(char *cmd);
extern void mpc8xx_calibrate_decr(void);
extern int mpc8xx_set_rtc_time(struct rtc_time *tm);
extern void mpc8xx_get_rtc_time(struct rtc_time *tm);
extern unsigned int mpc8xx_get_irq(void);
#endif /* __MPC8xx_H */
@@ -0,0 +1,156 @@
#include <linux/kernel.h>
#include <linux/stddef.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/irq.h>
#include <linux/dma-mapping.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/8xx_immap.h>
#include "pic.h"
#define PIC_VEC_SPURRIOUS 15
static struct irq_domain *mpc8xx_pic_host;
static unsigned long mpc8xx_cached_irq_mask;
static sysconf8xx_t __iomem *siu_reg;
static inline unsigned long mpc8xx_irqd_to_bit(struct irq_data *d)
{
return 0x80000000 >> irqd_to_hwirq(d);
}
static void mpc8xx_unmask_irq(struct irq_data *d)
{
mpc8xx_cached_irq_mask |= mpc8xx_irqd_to_bit(d);
out_be32(&siu_reg->sc_simask, mpc8xx_cached_irq_mask);
}
static void mpc8xx_mask_irq(struct irq_data *d)
{
mpc8xx_cached_irq_mask &= ~mpc8xx_irqd_to_bit(d);
out_be32(&siu_reg->sc_simask, mpc8xx_cached_irq_mask);
}
static void mpc8xx_ack(struct irq_data *d)
{
out_be32(&siu_reg->sc_sipend, mpc8xx_irqd_to_bit(d));
}
static void mpc8xx_end_irq(struct irq_data *d)
{
mpc8xx_cached_irq_mask |= mpc8xx_irqd_to_bit(d);
out_be32(&siu_reg->sc_simask, mpc8xx_cached_irq_mask);
}
static int mpc8xx_set_irq_type(struct irq_data *d, unsigned int flow_type)
{
/* only external IRQ senses are programmable */
if ((flow_type & IRQ_TYPE_EDGE_FALLING) && !(irqd_to_hwirq(d) & 1)) {
unsigned int siel = in_be32(&siu_reg->sc_siel);
siel |= mpc8xx_irqd_to_bit(d);
out_be32(&siu_reg->sc_siel, siel);
irq_set_handler_locked(d, handle_edge_irq);
}
return 0;
}
static struct irq_chip mpc8xx_pic = {
.name = "8XX SIU",
.irq_unmask = mpc8xx_unmask_irq,
.irq_mask = mpc8xx_mask_irq,
.irq_ack = mpc8xx_ack,
.irq_eoi = mpc8xx_end_irq,
.irq_set_type = mpc8xx_set_irq_type,
};
unsigned int mpc8xx_get_irq(void)
{
int irq;
/* For MPC8xx, read the SIVEC register and shift the bits down
* to get the irq number.
*/
irq = in_be32(&siu_reg->sc_sivec) >> 26;
if (irq == PIC_VEC_SPURRIOUS)
return 0;
return irq_find_mapping(mpc8xx_pic_host, irq);
}
static int mpc8xx_pic_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
pr_debug("mpc8xx_pic_host_map(%d, 0x%lx)\n", virq, hw);
/* Set default irq handle */
irq_set_chip_and_handler(virq, &mpc8xx_pic, handle_level_irq);
return 0;
}
static int mpc8xx_pic_host_xlate(struct irq_domain *h, struct device_node *ct,
const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq, unsigned int *out_flags)
{
static unsigned char map_pic_senses[4] = {
IRQ_TYPE_EDGE_RISING,
IRQ_TYPE_LEVEL_LOW,
IRQ_TYPE_LEVEL_HIGH,
IRQ_TYPE_EDGE_FALLING,
};
if (intspec[0] > 0x1f)
return 0;
*out_hwirq = intspec[0];
if (intsize > 1 && intspec[1] < 4)
*out_flags = map_pic_senses[intspec[1]];
else
*out_flags = IRQ_TYPE_NONE;
return 0;
}
static const struct irq_domain_ops mpc8xx_pic_host_ops = {
.map = mpc8xx_pic_host_map,
.xlate = mpc8xx_pic_host_xlate,
};
void __init mpc8xx_pic_init(void)
{
struct resource res;
struct device_node *np;
int ret;
np = of_find_compatible_node(NULL, NULL, "fsl,pq1-pic");
if (np == NULL)
np = of_find_node_by_type(NULL, "mpc8xx-pic");
if (np == NULL) {
printk(KERN_ERR "Could not find fsl,pq1-pic node\n");
return;
}
ret = of_address_to_resource(np, 0, &res);
if (ret)
goto out;
siu_reg = ioremap(res.start, resource_size(&res));
if (!siu_reg)
goto out;
mpc8xx_pic_host = irq_domain_create_linear(of_fwnode_handle(np), 64,
&mpc8xx_pic_host_ops, NULL);
if (!mpc8xx_pic_host)
printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n");
out:
of_node_put(np);
}
@@ -0,0 +1,19 @@
#ifndef _PPC_KERNEL_MPC8xx_H
#define _PPC_KERNEL_MPC8xx_H
#include <linux/irq.h>
#include <linux/interrupt.h>
void mpc8xx_pic_init(void);
unsigned int mpc8xx_get_irq(void);
/*
* Some internal interrupt registers use an 8-bit mask for the interrupt
* level instead of a number.
*/
static inline uint mk_int_int_mask(uint mask)
{
return (1 << (7 - (mask/2)));
}
#endif /* _PPC_KERNEL_PPC8xx_H */
@@ -0,0 +1,148 @@
/*
* Platform setup for the MPC8xx based boards from TQM.
*
* Heiko Schocher <hs@denx.de>
* Copyright 2010 DENX Software Engineering GmbH
*
* based on:
* Vitaly Bordug <vbordug@ru.mvista.com>
*
* Copyright 2005 MontaVista Software Inc.
*
* Heavily modified by Scott Wood <scottwood@freescale.com>
* Copyright 2007 Freescale Semiconductor, Inc.
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#include <linux/init.h>
#include <linux/param.h>
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/fsl_devices.h>
#include <linux/mii.h>
#include <linux/of_fdt.h>
#include <linux/of_platform.h>
#include <asm/delay.h>
#include <asm/io.h>
#include <asm/machdep.h>
#include <asm/page.h>
#include <asm/processor.h>
#include <asm/time.h>
#include <asm/8xx_immap.h>
#include <asm/cpm1.h>
#include <asm/udbg.h>
#include "mpc8xx.h"
#include "pic.h"
struct cpm_pin {
int port, pin, flags;
};
static struct cpm_pin tqm8xx_pins[] __initdata = {
/* SMC1 */
{CPM_PORTB, 24, CPM_PIN_INPUT}, /* RX */
{CPM_PORTB, 25, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TX */
/* SCC1 */
{CPM_PORTA, 5, CPM_PIN_INPUT}, /* CLK1 */
{CPM_PORTA, 7, CPM_PIN_INPUT}, /* CLK2 */
{CPM_PORTA, 14, CPM_PIN_INPUT}, /* TX */
{CPM_PORTA, 15, CPM_PIN_INPUT}, /* RX */
{CPM_PORTC, 15, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TENA */
{CPM_PORTC, 10, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_GPIO},
{CPM_PORTC, 11, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_GPIO},
};
static struct cpm_pin tqm8xx_fec_pins[] __initdata = {
/* MII */
{CPM_PORTD, 3, CPM_PIN_OUTPUT},
{CPM_PORTD, 4, CPM_PIN_OUTPUT},
{CPM_PORTD, 5, CPM_PIN_OUTPUT},
{CPM_PORTD, 6, CPM_PIN_OUTPUT},
{CPM_PORTD, 7, CPM_PIN_OUTPUT},
{CPM_PORTD, 8, CPM_PIN_OUTPUT},
{CPM_PORTD, 9, CPM_PIN_OUTPUT},
{CPM_PORTD, 10, CPM_PIN_OUTPUT},
{CPM_PORTD, 11, CPM_PIN_OUTPUT},
{CPM_PORTD, 12, CPM_PIN_OUTPUT},
{CPM_PORTD, 13, CPM_PIN_OUTPUT},
{CPM_PORTD, 14, CPM_PIN_OUTPUT},
{CPM_PORTD, 15, CPM_PIN_OUTPUT},
};
static void __init init_pins(int n, struct cpm_pin *pin)
{
int i;
for (i = 0; i < n; i++) {
cpm1_set_pin(pin->port, pin->pin, pin->flags);
pin++;
}
}
static void __init init_ioports(void)
{
struct device_node *dnode;
struct property *prop;
int len;
init_pins(ARRAY_SIZE(tqm8xx_pins), &tqm8xx_pins[0]);
cpm1_clk_setup(CPM_CLK_SMC1, CPM_BRG1, CPM_CLK_RTX);
dnode = of_find_node_by_name(NULL, "aliases");
if (dnode == NULL)
return;
prop = of_find_property(dnode, "ethernet1", &len);
of_node_put(dnode);
if (prop == NULL)
return;
/* init FEC pins */
init_pins(ARRAY_SIZE(tqm8xx_fec_pins), &tqm8xx_fec_pins[0]);
}
static void __init tqm8xx_setup_arch(void)
{
cpm_reset();
init_ioports();
}
static const struct of_device_id of_bus_ids[] __initconst = {
{ .name = "soc", },
{ .name = "cpm", },
{ .name = "localbus", },
{ .compatible = "simple-bus" },
{},
};
static int __init declare_of_platform_devices(void)
{
of_platform_bus_probe(NULL, of_bus_ids, NULL);
return 0;
}
machine_device_initcall(tqm8xx, declare_of_platform_devices);
define_machine(tqm8xx) {
.name = "TQM8xx",
.compatible = "tqc,tqm8xx",
.setup_arch = tqm8xx_setup_arch,
.init_IRQ = mpc8xx_pic_init,
.get_irq = mpc8xx_get_irq,
.restart = mpc8xx_restart,
.calibrate_decr = mpc8xx_calibrate_decr,
.set_rtc_time = mpc8xx_set_rtc_time,
.get_rtc_time = mpc8xx_get_rtc_time,
.progress = udbg_progress,
};