Commit 04debf21 authored by Mark Greer's avatar Mark Greer Committed by Michael Ellerman

powerpc: Remove core support for Marvell mv64x60 hostbridges

There are no longer any platforms that use Marvell's mv64x60
hostbridges so remove the supporting kernel code.

CC: Dale Farnsworth <dale@farnsworth.org>
Signed-off-by: default avatarMark Greer <mgreer@animalcreek.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 297f8314
Marvell Discovery mv64[345]6x System Controller chips
===========================================================
The Marvell mv64[345]60 series of system controller chips contain
many of the peripherals needed to implement a complete computer
system. In this section, we define device tree nodes to describe
the system controller chip itself and each of the peripherals
which it contains. Compatible string values for each node are
prefixed with the string "marvell,", for Marvell Technology Group Ltd.
1) The /system-controller node
This node is used to represent the system-controller and must be
present when the system uses a system controller chip. The top-level
system-controller node contains information that is global to all
devices within the system controller chip. The node name begins
with "system-controller" followed by the unit address, which is
the base address of the memory-mapped register set for the system
controller chip.
Required properties:
- ranges : Describes the translation of system controller addresses
for memory mapped registers.
- clock-frequency: Contains the main clock frequency for the system
controller chip.
- reg : This property defines the address and size of the
memory-mapped registers contained within the system controller
chip. The address specified in the "reg" property should match
the unit address of the system-controller node.
- #address-cells : Address representation for system controller
devices. This field represents the number of cells needed to
represent the address of the memory-mapped registers of devices
within the system controller chip.
- #size-cells : Size representation for the memory-mapped
registers within the system controller chip.
- #interrupt-cells : Defines the width of cells used to represent
interrupts.
Optional properties:
- model : The specific model of the system controller chip. Such
as, "mv64360", "mv64460", or "mv64560".
- compatible : A string identifying the compatibility identifiers
of the system controller chip.
The system-controller node contains child nodes for each system
controller device that the platform uses. Nodes should not be created
for devices which exist on the system controller chip but are not used
Example Marvell Discovery mv64360 system-controller node:
system-controller@f1000000 { /* Marvell Discovery mv64360 */
#address-cells = <1>;
#size-cells = <1>;
model = "mv64360"; /* Default */
compatible = "marvell,mv64360";
clock-frequency = <133333333>;
reg = <0xf1000000 0x10000>;
virtual-reg = <0xf1000000>;
ranges = <0x88000000 0x88000000 0x1000000 /* PCI 0 I/O Space */
0x80000000 0x80000000 0x8000000 /* PCI 0 MEM Space */
0xa0000000 0xa0000000 0x4000000 /* User FLASH */
0x00000000 0xf1000000 0x0010000 /* Bridge's regs */
0xf2000000 0xf2000000 0x0040000>;/* Integrated SRAM */
[ child node definitions... ]
}
2) Child nodes of /system-controller
a) Marvell Discovery MDIO bus
The MDIO is a bus to which the PHY devices are connected. For each
device that exists on this bus, a child node should be created. See
the definition of the PHY node below for an example of how to define
a PHY.
Required properties:
- #address-cells : Should be <1>
- #size-cells : Should be <0>
- compatible : Should be "marvell,mv64360-mdio"
Example:
mdio {
#address-cells = <1>;
#size-cells = <0>;
compatible = "marvell,mv64360-mdio";
ethernet-phy@0 {
......
};
};
b) Marvell Discovery ethernet controller
The Discover ethernet controller is described with two levels
of nodes. The first level describes an ethernet silicon block
and the second level describes up to 3 ethernet nodes within
that block. The reason for the multiple levels is that the
registers for the node are interleaved within a single set
of registers. The "ethernet-block" level describes the
shared register set, and the "ethernet" nodes describe ethernet
port-specific properties.
Ethernet block node
Required properties:
- #address-cells : <1>
- #size-cells : <0>
- compatible : "marvell,mv64360-eth-block"
- reg : Offset and length of the register set for this block
Optional properties:
- clocks : Phandle to the clock control device and gate bit
Example Discovery Ethernet block node:
ethernet-block@2000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "marvell,mv64360-eth-block";
reg = <0x2000 0x2000>;
ethernet@0 {
.......
};
};
Ethernet port node
Required properties:
- compatible : Should be "marvell,mv64360-eth".
- reg : Should be <0>, <1>, or <2>, according to which registers
within the silicon block the device uses.
- interrupts : <a> where a is the interrupt number for the port.
- interrupt-parent : the phandle for the interrupt controller
that services interrupts for this device.
- phy : the phandle for the PHY connected to this ethernet
controller.
- local-mac-address : 6 bytes, MAC address
Example Discovery Ethernet port node:
ethernet@0 {
compatible = "marvell,mv64360-eth";
reg = <0>;
interrupts = <32>;
interrupt-parent = <&PIC>;
phy = <&PHY0>;
local-mac-address = [ 00 00 00 00 00 00 ];
};
c) Marvell Discovery PHY nodes
Required properties:
- interrupts : <a> where a is the interrupt number for this phy.
- interrupt-parent : the phandle for the interrupt controller that
services interrupts for this device.
- reg : The ID number for the phy, usually a small integer
Example Discovery PHY node:
ethernet-phy@1 {
compatible = "broadcom,bcm5421";
interrupts = <76>; /* GPP 12 */
interrupt-parent = <&PIC>;
reg = <1>;
};
d) Marvell Discovery SDMA nodes
Represent DMA hardware associated with the MPSC (multiprotocol
serial controllers).
Required properties:
- compatible : "marvell,mv64360-sdma"
- reg : Offset and length of the register set for this device
- interrupts : <a> where a is the interrupt number for the DMA
device.
- interrupt-parent : the phandle for the interrupt controller
that services interrupts for this device.
Example Discovery SDMA node:
sdma@4000 {
compatible = "marvell,mv64360-sdma";
reg = <0x4000 0xc18>;
virtual-reg = <0xf1004000>;
interrupts = <36>;
interrupt-parent = <&PIC>;
};
e) Marvell Discovery BRG nodes
Represent baud rate generator hardware associated with the MPSC
(multiprotocol serial controllers).
Required properties:
- compatible : "marvell,mv64360-brg"
- reg : Offset and length of the register set for this device
- clock-src : A value from 0 to 15 which selects the clock
source for the baud rate generator. This value corresponds
to the CLKS value in the BRGx configuration register. See
the mv64x60 User's Manual.
- clock-frequence : The frequency (in Hz) of the baud rate
generator's input clock.
- current-speed : The current speed setting (presumably by
firmware) of the baud rate generator.
Example Discovery BRG node:
brg@b200 {
compatible = "marvell,mv64360-brg";
reg = <0xb200 0x8>;
clock-src = <8>;
clock-frequency = <133333333>;
current-speed = <9600>;
};
f) Marvell Discovery CUNIT nodes
Represent the Serial Communications Unit device hardware.
Required properties:
- reg : Offset and length of the register set for this device
Example Discovery CUNIT node:
cunit@f200 {
reg = <0xf200 0x200>;
};
g) Marvell Discovery MPSCROUTING nodes
Represent the Discovery's MPSC routing hardware
Required properties:
- reg : Offset and length of the register set for this device
Example Discovery CUNIT node:
mpscrouting@b500 {
reg = <0xb400 0xc>;
};
h) Marvell Discovery MPSCINTR nodes
Represent the Discovery's MPSC DMA interrupt hardware registers
(SDMA cause and mask registers).
Required properties:
- reg : Offset and length of the register set for this device
Example Discovery MPSCINTR node:
mpsintr@b800 {
reg = <0xb800 0x100>;
};
i) Marvell Discovery MPSC nodes
Represent the Discovery's MPSC (Multiprotocol Serial Controller)
serial port.
Required properties:
- compatible : "marvell,mv64360-mpsc"
- reg : Offset and length of the register set for this device
- sdma : the phandle for the SDMA node used by this port
- brg : the phandle for the BRG node used by this port
- cunit : the phandle for the CUNIT node used by this port
- mpscrouting : the phandle for the MPSCROUTING node used by this port
- mpscintr : the phandle for the MPSCINTR node used by this port
- cell-index : the hardware index of this cell in the MPSC core
- max_idle : value needed for MPSC CHR3 (Maximum Frame Length)
register
- interrupts : <a> where a is the interrupt number for the MPSC.
- interrupt-parent : the phandle for the interrupt controller
that services interrupts for this device.
Example Discovery MPSCINTR node:
mpsc@8000 {
compatible = "marvell,mv64360-mpsc";
reg = <0x8000 0x38>;
virtual-reg = <0xf1008000>;
sdma = <&SDMA0>;
brg = <&BRG0>;
cunit = <&CUNIT>;
mpscrouting = <&MPSCROUTING>;
mpscintr = <&MPSCINTR>;
cell-index = <0>;
max_idle = <40>;
interrupts = <40>;
interrupt-parent = <&PIC>;
};
j) Marvell Discovery Watch Dog Timer nodes
Represent the Discovery's watchdog timer hardware
Required properties:
- compatible : "marvell,mv64360-wdt"
- reg : Offset and length of the register set for this device
Example Discovery Watch Dog Timer node:
wdt@b410 {
compatible = "marvell,mv64360-wdt";
reg = <0xb410 0x8>;
};
k) Marvell Discovery I2C nodes
Represent the Discovery's I2C hardware
Required properties:
- device_type : "i2c"
- compatible : "marvell,mv64360-i2c"
- reg : Offset and length of the register set for this device
- interrupts : <a> where a is the interrupt number for the I2C.
- interrupt-parent : the phandle for the interrupt controller
that services interrupts for this device.
Example Discovery I2C node:
compatible = "marvell,mv64360-i2c";
reg = <0xc000 0x20>;
virtual-reg = <0xf100c000>;
interrupts = <37>;
interrupt-parent = <&PIC>;
};
l) Marvell Discovery PIC (Programmable Interrupt Controller) nodes
Represent the Discovery's PIC hardware
Required properties:
- #interrupt-cells : <1>
- #address-cells : <0>
- compatible : "marvell,mv64360-pic"
- reg : Offset and length of the register set for this device
- interrupt-controller
Example Discovery PIC node:
pic {
#interrupt-cells = <1>;
#address-cells = <0>;
compatible = "marvell,mv64360-pic";
reg = <0x0 0x88>;
interrupt-controller;
};
m) Marvell Discovery MPP (Multipurpose Pins) multiplexing nodes
Represent the Discovery's MPP hardware
Required properties:
- compatible : "marvell,mv64360-mpp"
- reg : Offset and length of the register set for this device
Example Discovery MPP node:
mpp@f000 {
compatible = "marvell,mv64360-mpp";
reg = <0xf000 0x10>;
};
n) Marvell Discovery GPP (General Purpose Pins) nodes
Represent the Discovery's GPP hardware
Required properties:
- compatible : "marvell,mv64360-gpp"
- reg : Offset and length of the register set for this device
Example Discovery GPP node:
gpp@f000 {
compatible = "marvell,mv64360-gpp";
reg = <0xf100 0x20>;
};
o) Marvell Discovery PCI host bridge node
Represents the Discovery's PCI host bridge device. The properties
for this node conform to Rev 2.1 of the PCI Bus Binding to IEEE
1275-1994. A typical value for the compatible property is
"marvell,mv64360-pci".
Example Discovery PCI host bridge node
pci@80000000 {
#address-cells = <3>;
#size-cells = <2>;
#interrupt-cells = <1>;
device_type = "pci";
compatible = "marvell,mv64360-pci";
reg = <0xcf8 0x8>;
ranges = <0x01000000 0x0 0x0
0x88000000 0x0 0x01000000
0x02000000 0x0 0x80000000
0x80000000 0x0 0x08000000>;
bus-range = <0 255>;
clock-frequency = <66000000>;
interrupt-parent = <&PIC>;
interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
interrupt-map = <
/* IDSEL 0x0a */
0x5000 0 0 1 &PIC 80
0x5000 0 0 2 &PIC 81
0x5000 0 0 3 &PIC 91
0x5000 0 0 4 &PIC 93
/* IDSEL 0x0b */
0x5800 0 0 1 &PIC 91
0x5800 0 0 2 &PIC 93
0x5800 0 0 3 &PIC 80
0x5800 0 0 4 &PIC 81
/* IDSEL 0x0c */
0x6000 0 0 1 &PIC 91
0x6000 0 0 2 &PIC 93
0x6000 0 0 3 &PIC 80
0x6000 0 0 4 &PIC 81
/* IDSEL 0x0d */
0x6800 0 0 1 &PIC 93
0x6800 0 0 2 &PIC 80
0x6800 0 0 3 &PIC 81
0x6800 0 0 4 &PIC 91
>;
};
p) Marvell Discovery CPU Error nodes
Represent the Discovery's CPU error handler device.
Required properties:
- compatible : "marvell,mv64360-cpu-error"
- reg : Offset and length of the register set for this device
- interrupts : the interrupt number for this device
- interrupt-parent : the phandle for the interrupt controller
that services interrupts for this device.
Example Discovery CPU Error node:
cpu-error@70 {
compatible = "marvell,mv64360-cpu-error";
reg = <0x70 0x10 0x128 0x28>;
interrupts = <3>;
interrupt-parent = <&PIC>;
};
q) Marvell Discovery SRAM Controller nodes
Represent the Discovery's SRAM controller device.
Required properties:
- compatible : "marvell,mv64360-sram-ctrl"
- reg : Offset and length of the register set for this device
- interrupts : the interrupt number for this device
- interrupt-parent : the phandle for the interrupt controller
that services interrupts for this device.
Example Discovery SRAM Controller node:
sram-ctrl@380 {
compatible = "marvell,mv64360-sram-ctrl";
reg = <0x380 0x80>;
interrupts = <13>;
interrupt-parent = <&PIC>;
};
r) Marvell Discovery PCI Error Handler nodes
Represent the Discovery's PCI error handler device.
Required properties:
- compatible : "marvell,mv64360-pci-error"
- reg : Offset and length of the register set for this device
- interrupts : the interrupt number for this device
- interrupt-parent : the phandle for the interrupt controller
that services interrupts for this device.
Example Discovery PCI Error Handler node:
pci-error@1d40 {
compatible = "marvell,mv64360-pci-error";
reg = <0x1d40 0x40 0xc28 0x4>;
interrupts = <12>;
interrupt-parent = <&PIC>;
};
s) Marvell Discovery Memory Controller nodes
Represent the Discovery's memory controller device.
Required properties:
- compatible : "marvell,mv64360-mem-ctrl"
- reg : Offset and length of the register set for this device
- interrupts : the interrupt number for this device
- interrupt-parent : the phandle for the interrupt controller
that services interrupts for this device.
Example Discovery Memory Controller node:
mem-ctrl@1400 {
compatible = "marvell,mv64360-mem-ctrl";
reg = <0x1400 0x60>;
interrupts = <17>;
interrupt-parent = <&PIC>;
};
......@@ -28,9 +28,6 @@ obj-$(CONFIG_FSL_85XX_CACHE_SRAM) += fsl_85xx_l2ctlr.o fsl_85xx_cache_sram.o
obj-$(CONFIG_SIMPLE_GPIO) += simple_gpio.o
obj-$(CONFIG_FSL_RIO) += fsl_rio.o fsl_rmu.o
obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
mv64x60-$(CONFIG_PCI) += mv64x60_pci.o
obj-$(CONFIG_MV64X60) += $(mv64x60-y) mv64x60_pic.o mv64x60_dev.o \
mv64x60_udbg.o
obj-$(CONFIG_RTC_DRV_CMOS) += rtc_cmos_setup.o
obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __MV64X60_H__
#define __MV64X60_H__
#include <linux/init.h>
extern void __init mv64x60_init_irq(void);
extern unsigned int mv64x60_get_irq(void);
extern void __init mv64x60_pci_init(void);
extern void __init mv64x60_init_early(void);
#endif /* __MV64X60_H__ */
/*
* Platform device setup for Marvell mv64360/mv64460 host bridges (Discovery)
*
* Author: Dale Farnsworth <dale@farnsworth.org>
*
* 2007 (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.
*/
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/mv643xx.h>
#include <linux/platform_device.h>
#include <linux/of_platform.h>
#include <linux/of_net.h>
#include <linux/dma-mapping.h>
#include <asm/prom.h>
/* These functions provide the necessary setup for the mv64x60 drivers. */
static const struct of_device_id of_mv64x60_devices[] __initconst = {
{ .compatible = "marvell,mv64306-devctrl", },
{}
};
/*
* Create MPSC platform devices
*/
static int __init mv64x60_mpsc_register_shared_pdev(struct device_node *np)
{
struct platform_device *pdev;
struct resource r[2];
struct mpsc_shared_pdata pdata;
const phandle *ph;
struct device_node *mpscrouting, *mpscintr;
int err;
ph = of_get_property(np, "mpscrouting", NULL);
mpscrouting = of_find_node_by_phandle(*ph);
if (!mpscrouting)
return -ENODEV;
err = of_address_to_resource(mpscrouting, 0, &r[0]);
of_node_put(mpscrouting);
if (err)
return err;
ph = of_get_property(np, "mpscintr", NULL);
mpscintr = of_find_node_by_phandle(*ph);
if (!mpscintr)
return -ENODEV;
err = of_address_to_resource(mpscintr, 0, &r[1]);
of_node_put(mpscintr);
if (err)
return err;
memset(&pdata, 0, sizeof(pdata));
pdev = platform_device_alloc(MPSC_SHARED_NAME, 0);
if (!pdev)
return -ENOMEM;
err = platform_device_add_resources(pdev, r, 2);
if (err)
goto error;
err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
if (err)
goto error;
err = platform_device_add(pdev);
if (err)
goto error;
return 0;
error:
platform_device_put(pdev);
return err;
}
static int __init mv64x60_mpsc_device_setup(struct device_node *np, int id)
{
struct resource r[5];
struct mpsc_pdata pdata;
struct platform_device *pdev;
const unsigned int *prop;
const phandle *ph;
struct device_node *sdma, *brg;
int err;
int port_number;
/* only register the shared platform device the first time through */
if (id == 0 && (err = mv64x60_mpsc_register_shared_pdev(np)))
return err;
memset(r, 0, sizeof(r));
err = of_address_to_resource(np, 0, &r[0]);
if (err)
return err;
of_irq_to_resource(np, 0, &r[4]);
ph = of_get_property(np, "sdma", NULL);
sdma = of_find_node_by_phandle(*ph);
if (!sdma)
return -ENODEV;
of_irq_to_resource(sdma, 0, &r[3]);
err = of_address_to_resource(sdma, 0, &r[1]);
of_node_put(sdma);
if (err)
return err;
ph = of_get_property(np, "brg", NULL);
brg = of_find_node_by_phandle(*ph);
if (!brg)
return -ENODEV;
err = of_address_to_resource(brg, 0, &r[2]);
of_node_put(brg);
if (err)
return err;
prop = of_get_property(np, "cell-index", NULL);
if (!prop)
return -ENODEV;
port_number = *(int *)prop;
memset(&pdata, 0, sizeof(pdata));
pdata.cache_mgmt = 1; /* All current revs need this set */
pdata.max_idle = 40; /* default */
prop = of_get_property(np, "max_idle", NULL);
if (prop)
pdata.max_idle = *prop;
prop = of_get_property(brg, "current-speed", NULL);
if (prop)
pdata.default_baud = *prop;
/* Default is 8 bits, no parity, no flow control */
pdata.default_bits = 8;
pdata.default_parity = 'n';
pdata.default_flow = 'n';
prop = of_get_property(np, "chr_1", NULL);
if (prop)
pdata.chr_1_val = *prop;
prop = of_get_property(np, "chr_2", NULL);
if (prop)
pdata.chr_2_val = *prop;
prop = of_get_property(np, "chr_10", NULL);
if (prop)
pdata.chr_10_val = *prop;
prop = of_get_property(np, "mpcr", NULL);
if (prop)
pdata.mpcr_val = *prop;
prop = of_get_property(brg, "bcr", NULL);
if (prop)
pdata.bcr_val = *prop;
pdata.brg_can_tune = 1; /* All current revs need this set */
prop = of_get_property(brg, "clock-src", NULL);
if (prop)
pdata.brg_clk_src = *prop;
prop = of_get_property(brg, "clock-frequency", NULL);
if (prop)
pdata.brg_clk_freq = *prop;
pdev = platform_device_alloc(MPSC_CTLR_NAME, port_number);
if (!pdev)
return -ENOMEM;
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
err = platform_device_add_resources(pdev, r, 5);
if (err)
goto error;
err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
if (err)
goto error;
err = platform_device_add(pdev);
if (err)
goto error;
return 0;
error:
platform_device_put(pdev);
return err;
}
/*
* Create mv64x60_eth platform devices
*/
static struct platform_device * __init mv64x60_eth_register_shared_pdev(
struct device_node *np, int id)
{
struct platform_device *pdev;
struct resource r[2];
int err;
err = of_address_to_resource(np, 0, &r[0]);
if (err)
return ERR_PTR(err);
/* register an orion mdio bus driver */
r[1].start = r[0].start + 0x4;
r[1].end = r[0].start + 0x84 - 1;
r[1].flags = IORESOURCE_MEM;
if (id == 0) {
pdev = platform_device_register_simple("orion-mdio", -1, &r[1], 1);
if (IS_ERR(pdev))
return pdev;
}
pdev = platform_device_register_simple(MV643XX_ETH_SHARED_NAME, id,
&r[0], 1);
return pdev;
}
static int __init mv64x60_eth_device_setup(struct device_node *np, int id,
struct platform_device *shared_pdev)
{
struct resource r[1];
struct mv643xx_eth_platform_data pdata;
struct platform_device *pdev;
struct device_node *phy;
const u8 *mac_addr;
const int *prop;
const phandle *ph;
int err;
memset(r, 0, sizeof(r));
of_irq_to_resource(np, 0, &r[0]);
memset(&pdata, 0, sizeof(pdata));
pdata.shared = shared_pdev;
prop = of_get_property(np, "reg", NULL);
if (!prop)
return -ENODEV;
pdata.port_number = *prop;
mac_addr = of_get_mac_address(np);
if (mac_addr)
memcpy(pdata.mac_addr, mac_addr, 6);
prop = of_get_property(np, "speed", NULL);
if (prop)
pdata.speed = *prop;
prop = of_get_property(np, "tx_queue_size", NULL);
if (prop)
pdata.tx_queue_size = *prop;
prop = of_get_property(np, "rx_queue_size", NULL);
if (prop)
pdata.rx_queue_size = *prop;
prop = of_get_property(np, "tx_sram_addr", NULL);
if (prop)
pdata.tx_sram_addr = *prop;
prop = of_get_property(np, "tx_sram_size", NULL);
if (prop)
pdata.tx_sram_size = *prop;
prop = of_get_property(np, "rx_sram_addr", NULL);
if (prop)
pdata.rx_sram_addr = *prop;
prop = of_get_property(np, "rx_sram_size", NULL);
if (prop)
pdata.rx_sram_size = *prop;
ph = of_get_property(np, "phy", NULL);
if (!ph)
return -ENODEV;
phy = of_find_node_by_phandle(*ph);
if (phy == NULL)
return -ENODEV;
prop = of_get_property(phy, "reg", NULL);
if (prop)
pdata.phy_addr = MV643XX_ETH_PHY_ADDR(*prop);
of_node_put(phy);
pdev = platform_device_alloc(MV643XX_ETH_NAME, id);
if (!pdev)
return -ENOMEM;
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
err = platform_device_add_resources(pdev, r, 1);
if (err)
goto error;
err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
if (err)
goto error;
err = platform_device_add(pdev);
if (err)
goto error;
return 0;
error:
platform_device_put(pdev);
return err;
}
/*
* Create mv64x60_i2c platform devices
*/
static int __init mv64x60_i2c_device_setup(struct device_node *np, int id)
{
struct resource r[2];
struct platform_device *pdev;
struct mv64xxx_i2c_pdata pdata;
const unsigned int *prop;
int err;
memset(r, 0, sizeof(r));
err = of_address_to_resource(np, 0, &r[0]);
if (err)
return err;
of_irq_to_resource(np, 0, &r[1]);
memset(&pdata, 0, sizeof(pdata));
pdata.freq_m = 8; /* default */
prop = of_get_property(np, "freq_m", NULL);
if (prop)
pdata.freq_m = *prop;
pdata.freq_n = 3; /* default */
prop = of_get_property(np, "freq_n", NULL);
if (prop)
pdata.freq_n = *prop;
pdata.timeout = 1000; /* default: 1 second */
pdev = platform_device_alloc(MV64XXX_I2C_CTLR_NAME, id);
if (!pdev)
return -ENOMEM;
err = platform_device_add_resources(pdev, r, 2);
if (err)
goto error;
err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
if (err)
goto error;
err = platform_device_add(pdev);
if (err)
goto error;
return 0;
error:
platform_device_put(pdev);
return err;
}
/*
* Create mv64x60_wdt platform devices
*/
static int __init mv64x60_wdt_device_setup(struct device_node *np, int id)
{
struct resource r;
struct platform_device *pdev;
struct mv64x60_wdt_pdata pdata;
const unsigned int *prop;
int err;
err = of_address_to_resource(np, 0, &r);
if (err)
return err;
memset(&pdata, 0, sizeof(pdata));
pdata.timeout = 10; /* Default: 10 seconds */
np = of_get_parent(np);
if (!np)
return -ENODEV;
prop = of_get_property(np, "clock-frequency", NULL);
of_node_put(np);
if (!prop)
return -ENODEV;
pdata.bus_clk = *prop / 1000000; /* wdt driver wants freq in MHz */
pdev = platform_device_alloc(MV64x60_WDT_NAME, id);
if (!pdev)
return -ENOMEM;
err = platform_device_add_resources(pdev, &r, 1);
if (err)
goto error;
err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
if (err)
goto error;
err = platform_device_add(pdev);
if (err)
goto error;
return 0;
error:
platform_device_put(pdev);
return err;
}
static int __init mv64x60_device_setup(void)
{
struct device_node *np, *np2;
struct platform_device *pdev;
int id, id2;
int err;
id = 0;
for_each_compatible_node(np, NULL, "marvell,mv64360-mpsc") {
err = mv64x60_mpsc_device_setup(np, id++);
if (err)
printk(KERN_ERR "Failed to initialize MV64x60 "
"serial device %pOF: error %d.\n",
np, err);
}
id = 0;
id2 = 0;
for_each_compatible_node(np, NULL, "marvell,mv64360-eth-group") {
pdev = mv64x60_eth_register_shared_pdev(np, id++);
if (IS_ERR(pdev)) {
err = PTR_ERR(pdev);
printk(KERN_ERR "Failed to initialize MV64x60 "
"network block %pOF: error %d.\n",
np, err);
continue;
}
for_each_child_of_node(np, np2) {
if (!of_device_is_compatible(np2,
"marvell,mv64360-eth"))
continue;
err = mv64x60_eth_device_setup(np2, id2++, pdev);
if (err)
printk(KERN_ERR "Failed to initialize "
"MV64x60 network device %pOF: "
"error %d.\n",
np2, err);
}
}
id = 0;
for_each_compatible_node(np, "i2c", "marvell,mv64360-i2c") {
err = mv64x60_i2c_device_setup(np, id++);
if (err)
printk(KERN_ERR "Failed to initialize MV64x60 I2C "
"bus %pOF: error %d.\n",
np, err);
}
/* support up to one watchdog timer */
np = of_find_compatible_node(np, NULL, "marvell,mv64360-wdt");
if (np) {
if ((err = mv64x60_wdt_device_setup(np, id)))
printk(KERN_ERR "Failed to initialize MV64x60 "
"Watchdog %pOF: error %d.\n",
np, err);
of_node_put(np);
}
/* Now add every node that is on the device bus */
for_each_compatible_node(np, NULL, "marvell,mv64360")
of_platform_bus_probe(np, of_mv64x60_devices, NULL);
return 0;
}
arch_initcall(mv64x60_device_setup);
static int __init mv64x60_add_mpsc_console(void)
{
struct device_node *np = NULL;
const char *prop;
prop = of_get_property(of_chosen, "linux,stdout-path", NULL);
if (prop == NULL)
goto not_mpsc;
np = of_find_node_by_path(prop);
if (!np)
goto not_mpsc;
if (!of_device_is_compatible(np, "marvell,mv64360-mpsc"))
goto not_mpsc;
prop = of_get_property(np, "cell-index", NULL);
if (!prop)
goto not_mpsc;
add_preferred_console("ttyMM", *(int *)prop, NULL);
not_mpsc:
return 0;
}
console_initcall(mv64x60_add_mpsc_console);
/*
* PCI bus setup for Marvell mv64360/mv64460 host bridges (Discovery)
*
* Author: Dale Farnsworth <dale@farnsworth.org>
*
* 2007 (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.
*/
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/stat.h>
#include <linux/pci.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
#define PCI_HEADER_TYPE_INVALID 0x7f /* Invalid PCI header type */
#ifdef CONFIG_SYSFS
/* 32-bit hex or dec stringified number + '\n' */
#define MV64X60_VAL_LEN_MAX 11
#define MV64X60_PCICFG_CPCI_HOTSWAP 0x68
static ssize_t mv64x60_hs_reg_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
struct pci_dev *phb;
u32 v;
if (off > 0)
return 0;
if (count < MV64X60_VAL_LEN_MAX)
return -EINVAL;
phb = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0));
if (!phb)
return -ENODEV;
pci_read_config_dword(phb, MV64X60_PCICFG_CPCI_HOTSWAP, &v);
pci_dev_put(phb);
return sprintf(buf, "0x%08x\n", v);
}
static ssize_t mv64x60_hs_reg_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
struct pci_dev *phb;
u32 v;
if (off > 0)
return 0;
if (count <= 0)
return -EINVAL;
if (sscanf(buf, "%i", &v) != 1)
return -EINVAL;
phb = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0));
if (!phb)
return -ENODEV;
pci_write_config_dword(phb, MV64X60_PCICFG_CPCI_HOTSWAP, v);
pci_dev_put(phb);
return count;
}
static const struct bin_attribute mv64x60_hs_reg_attr = { /* Hotswap register */
.attr = {
.name = "hs_reg",
.mode = 0644,
},
.size = MV64X60_VAL_LEN_MAX,
.read = mv64x60_hs_reg_read,
.write = mv64x60_hs_reg_write,
};
static int __init mv64x60_sysfs_init(void)
{
struct device_node *np;
struct platform_device *pdev;
const unsigned int *prop;
np = of_find_compatible_node(NULL, NULL, "marvell,mv64360");
if (!np)
return 0;
prop = of_get_property(np, "hs_reg_valid", NULL);
of_node_put(np);
pdev = platform_device_register_simple("marvell,mv64360", 0, NULL, 0);
if (IS_ERR(pdev))
return PTR_ERR(pdev);
return sysfs_create_bin_file(&pdev->dev.kobj, &mv64x60_hs_reg_attr);
}
subsys_initcall(mv64x60_sysfs_init);
#endif /* CONFIG_SYSFS */
static void mv64x60_pci_fixup_early(struct pci_dev *dev)
{
/*
* Set the host bridge hdr_type to an invalid value so that
* pci_setup_device() will ignore the host bridge.
*/
dev->hdr_type = PCI_HEADER_TYPE_INVALID;
}
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_MV64360,
mv64x60_pci_fixup_early);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_MV64460,
mv64x60_pci_fixup_early);
static int __init mv64x60_add_bridge(struct device_node *dev)
{
int len;
struct pci_controller *hose;
struct resource rsrc;
const int *bus_range;
int primary;
memset(&rsrc, 0, sizeof(rsrc));
/* Fetch host bridge registers address */
if (of_address_to_resource(dev, 0, &rsrc)) {
printk(KERN_ERR "No PCI reg property in device tree\n");
return -ENODEV;
}
/* Get bus range if any */
bus_range = of_get_property(dev, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int))
printk(KERN_WARNING "Can't get bus-range for %pOF, assume"
" bus 0\n", dev);
hose = pcibios_alloc_controller(dev);
if (!hose)
return -ENOMEM;
hose->first_busno = bus_range ? bus_range[0] : 0;
hose->last_busno = bus_range ? bus_range[1] : 0xff;
setup_indirect_pci(hose, rsrc.start, rsrc.start + 4, 0);
hose->self_busno = hose->first_busno;
printk(KERN_INFO "Found MV64x60 PCI host bridge at 0x%016llx. "
"Firmware bus number: %d->%d\n",
(unsigned long long)rsrc.start, hose->first_busno,
hose->last_busno);
/* Interpret the "ranges" property */
/* This also maps the I/O region and sets isa_io/mem_base */
primary = (hose->first_busno == 0);
pci_process_bridge_OF_ranges(hose, dev, primary);
return 0;
}
void __init mv64x60_pci_init(void)
{
struct device_node *np;
for_each_compatible_node(np, "pci", "marvell,mv64360-pci")
mv64x60_add_bridge(np);
}
/*
* Interrupt handling for Marvell mv64360/mv64460 host bridges (Discovery)
*
* Author: Dale Farnsworth <dale@farnsworth.org>
*
* 2007 (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.
*/
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/irq.h>
#include "mv64x60.h"
/* Interrupt Controller Interface Registers */
#define MV64X60_IC_MAIN_CAUSE_LO 0x0004
#define MV64X60_IC_MAIN_CAUSE_HI 0x000c
#define MV64X60_IC_CPU0_INTR_MASK_LO 0x0014
#define MV64X60_IC_CPU0_INTR_MASK_HI 0x001c
#define MV64X60_IC_CPU0_SELECT_CAUSE 0x0024
#define MV64X60_HIGH_GPP_GROUPS 0x0f000000
#define MV64X60_SELECT_CAUSE_HIGH 0x40000000
/* General Purpose Pins Controller Interface Registers */
#define MV64x60_GPP_INTR_CAUSE 0x0008
#define MV64x60_GPP_INTR_MASK 0x000c
#define MV64x60_LEVEL1_LOW 0
#define MV64x60_LEVEL1_HIGH 1
#define MV64x60_LEVEL1_GPP 2
#define MV64x60_LEVEL1_MASK 0x00000060
#define MV64x60_LEVEL1_OFFSET 5
#define MV64x60_LEVEL2_MASK 0x0000001f
#define MV64x60_NUM_IRQS 96
static DEFINE_SPINLOCK(mv64x60_lock);
static void __iomem *mv64x60_irq_reg_base;
static void __iomem *mv64x60_gpp_reg_base;
/*
* Interrupt Controller Handling
*
* The interrupt controller handles three groups of interrupts:
* main low: IRQ0-IRQ31
* main high: IRQ32-IRQ63
* gpp: IRQ64-IRQ95
*
* This code handles interrupts in two levels. Level 1 selects the
* interrupt group, and level 2 selects an IRQ within that group.
* Each group has its own irq_chip structure.
*/
static u32 mv64x60_cached_low_mask;
static u32 mv64x60_cached_high_mask = MV64X60_HIGH_GPP_GROUPS;
static u32 mv64x60_cached_gpp_mask;
static struct irq_domain *mv64x60_irq_host;
/*
* mv64x60_chip_low functions
*/
static void mv64x60_mask_low(struct irq_data *d)
{
int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK;
unsigned long flags;
spin_lock_irqsave(&mv64x60_lock, flags);
mv64x60_cached_low_mask &= ~(1 << level2);
out_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_LO,
mv64x60_cached_low_mask);
spin_unlock_irqrestore(&mv64x60_lock, flags);
(void)in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_LO);
}
static void mv64x60_unmask_low(struct irq_data *d)
{
int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK;
unsigned long flags;
spin_lock_irqsave(&mv64x60_lock, flags);
mv64x60_cached_low_mask |= 1 << level2;
out_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_LO,
mv64x60_cached_low_mask);
spin_unlock_irqrestore(&mv64x60_lock, flags);
(void)in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_LO);
}
static struct irq_chip mv64x60_chip_low = {
.name = "mv64x60_low",
.irq_mask = mv64x60_mask_low,
.irq_mask_ack = mv64x60_mask_low,
.irq_unmask = mv64x60_unmask_low,
};
/*
* mv64x60_chip_high functions
*/
static void mv64x60_mask_high(struct irq_data *d)
{
int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK;
unsigned long flags;
spin_lock_irqsave(&mv64x60_lock, flags);
mv64x60_cached_high_mask &= ~(1 << level2);
out_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_HI,
mv64x60_cached_high_mask);
spin_unlock_irqrestore(&mv64x60_lock, flags);
(void)in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_HI);
}
static void mv64x60_unmask_high(struct irq_data *d)
{
int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK;
unsigned long flags;
spin_lock_irqsave(&mv64x60_lock, flags);
mv64x60_cached_high_mask |= 1 << level2;
out_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_HI,
mv64x60_cached_high_mask);
spin_unlock_irqrestore(&mv64x60_lock, flags);
(void)in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_HI);
}
static struct irq_chip mv64x60_chip_high = {
.name = "mv64x60_high",
.irq_mask = mv64x60_mask_high,
.irq_mask_ack = mv64x60_mask_high,
.irq_unmask = mv64x60_unmask_high,
};
/*
* mv64x60_chip_gpp functions
*/
static void mv64x60_mask_gpp(struct irq_data *d)
{
int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK;
unsigned long flags;
spin_lock_irqsave(&mv64x60_lock, flags);
mv64x60_cached_gpp_mask &= ~(1 << level2);
out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK,
mv64x60_cached_gpp_mask);
spin_unlock_irqrestore(&mv64x60_lock, flags);
(void)in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK);
}
static void mv64x60_mask_ack_gpp(struct irq_data *d)
{
int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK;
unsigned long flags;
spin_lock_irqsave(&mv64x60_lock, flags);
mv64x60_cached_gpp_mask &= ~(1 << level2);
out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK,
mv64x60_cached_gpp_mask);
out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_CAUSE,
~(1 << level2));
spin_unlock_irqrestore(&mv64x60_lock, flags);
(void)in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_CAUSE);
}
static void mv64x60_unmask_gpp(struct irq_data *d)
{
int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK;
unsigned long flags;
spin_lock_irqsave(&mv64x60_lock, flags);
mv64x60_cached_gpp_mask |= 1 << level2;
out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK,
mv64x60_cached_gpp_mask);
spin_unlock_irqrestore(&mv64x60_lock, flags);
(void)in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK);
}
static struct irq_chip mv64x60_chip_gpp = {
.name = "mv64x60_gpp",
.irq_mask = mv64x60_mask_gpp,
.irq_mask_ack = mv64x60_mask_ack_gpp,
.irq_unmask = mv64x60_unmask_gpp,
};
/*
* mv64x60_host_ops functions
*/
static struct irq_chip *mv64x60_chips[] = {
[MV64x60_LEVEL1_LOW] = &mv64x60_chip_low,
[MV64x60_LEVEL1_HIGH] = &mv64x60_chip_high,
[MV64x60_LEVEL1_GPP] = &mv64x60_chip_gpp,
};
static int mv64x60_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hwirq)
{
int level1;
irq_set_status_flags(virq, IRQ_LEVEL);
level1 = (hwirq & MV64x60_LEVEL1_MASK) >> MV64x60_LEVEL1_OFFSET;
BUG_ON(level1 > MV64x60_LEVEL1_GPP);
irq_set_chip_and_handler(virq, mv64x60_chips[level1],
handle_level_irq);
return 0;
}
static const struct irq_domain_ops mv64x60_host_ops = {
.map = mv64x60_host_map,
};
/*
* Global functions
*/
void __init mv64x60_init_irq(void)
{
struct device_node *np;
phys_addr_t paddr;
unsigned int size;
const unsigned int *reg;
unsigned long flags;
np = of_find_compatible_node(NULL, NULL, "marvell,mv64360-gpp");
reg = of_get_property(np, "reg", &size);
paddr = of_translate_address(np, reg);
mv64x60_gpp_reg_base = ioremap(paddr, reg[1]);
of_node_put(np);
np = of_find_compatible_node(NULL, NULL, "marvell,mv64360-pic");
reg = of_get_property(np, "reg", &size);
paddr = of_translate_address(np, reg);
mv64x60_irq_reg_base = ioremap(paddr, reg[1]);
mv64x60_irq_host = irq_domain_add_linear(np, MV64x60_NUM_IRQS,
&mv64x60_host_ops, NULL);
spin_lock_irqsave(&mv64x60_lock, flags);
out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK,
mv64x60_cached_gpp_mask);
out_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_LO,
mv64x60_cached_low_mask);
out_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_HI,
mv64x60_cached_high_mask);
out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_CAUSE, 0);
out_le32(mv64x60_irq_reg_base + MV64X60_IC_MAIN_CAUSE_LO, 0);
out_le32(mv64x60_irq_reg_base + MV64X60_IC_MAIN_CAUSE_HI, 0);
spin_unlock_irqrestore(&mv64x60_lock, flags);
}
unsigned int mv64x60_get_irq(void)
{
u32 cause;
int level1;
irq_hw_number_t hwirq;
int virq = 0;
cause = in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_SELECT_CAUSE);
if (cause & MV64X60_SELECT_CAUSE_HIGH) {
cause &= mv64x60_cached_high_mask;
level1 = MV64x60_LEVEL1_HIGH;
if (cause & MV64X60_HIGH_GPP_GROUPS) {
cause = in_le32(mv64x60_gpp_reg_base +
MV64x60_GPP_INTR_CAUSE);
cause &= mv64x60_cached_gpp_mask;
level1 = MV64x60_LEVEL1_GPP;
}
} else {
cause &= mv64x60_cached_low_mask;
level1 = MV64x60_LEVEL1_LOW;
}
if (cause) {
hwirq = (level1 << MV64x60_LEVEL1_OFFSET) | __ilog2(cause);
virq = irq_linear_revmap(mv64x60_irq_host, hwirq);
}
return virq;
}
/*
* udbg serial input/output routines for the Marvell MV64x60 (Discovery).
*
* Author: Dale Farnsworth <dale@farnsworth.org>
*
* 2007 (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.
*/
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/udbg.h>
#include <sysdev/mv64x60.h>
#define MPSC_0_CR1_OFFSET 0x000c
#define MPSC_0_CR2_OFFSET 0x0010
#define MPSC_CHR_2_TCS (1 << 9)
#define MPSC_0_CHR_10_OFFSET 0x0030
#define MPSC_INTR_CAUSE_OFF_0 0x0004
#define MPSC_INTR_CAUSE_OFF_1 0x000c
#define MPSC_INTR_CAUSE_RCC (1<<6)
static void __iomem *mpsc_base;
static void __iomem *mpsc_intr_cause;
static void mv64x60_udbg_putc(char c)
{
if (c == '\n')
mv64x60_udbg_putc('\r');
while(in_le32(mpsc_base + MPSC_0_CR2_OFFSET) & MPSC_CHR_2_TCS)
;
out_le32(mpsc_base + MPSC_0_CR1_OFFSET, c);
out_le32(mpsc_base + MPSC_0_CR2_OFFSET, MPSC_CHR_2_TCS);
}
static int mv64x60_udbg_testc(void)
{
return (in_le32(mpsc_intr_cause) & MPSC_INTR_CAUSE_RCC) != 0;
}
static int mv64x60_udbg_getc(void)
{
int cause = 0;
int c;
while (!mv64x60_udbg_testc())
;
c = in_8(mpsc_base + MPSC_0_CHR_10_OFFSET + 2);
out_8(mpsc_base + MPSC_0_CHR_10_OFFSET + 2, c);
out_le32(mpsc_intr_cause, cause & ~MPSC_INTR_CAUSE_RCC);
return c;
}
static int mv64x60_udbg_getc_poll(void)
{
if (!mv64x60_udbg_testc())
return -1;
return mv64x60_udbg_getc();
}
static void mv64x60_udbg_init(void)
{
struct device_node *np, *mpscintr, *stdout = NULL;
const char *path;
const phandle *ph;
struct resource r[2];
const int *block_index;
int intr_cause_offset;
int err;
path = of_get_property(of_chosen, "linux,stdout-path", NULL);
if (!path)
return;
stdout = of_find_node_by_path(path);
if (!stdout)
return;
for_each_compatible_node(np, NULL, "marvell,mv64360-mpsc") {
if (np == stdout)
break;
}
of_node_put(stdout);
if (!np)
return;
block_index = of_get_property(np, "cell-index", NULL);
if (!block_index)
goto error;
switch (*block_index) {
case 0:
intr_cause_offset = MPSC_INTR_CAUSE_OFF_0;
break;
case 1:
intr_cause_offset = MPSC_INTR_CAUSE_OFF_1;
break;
default:
goto error;
}
err = of_address_to_resource(np, 0, &r[0]);
if (err)
goto error;
ph = of_get_property(np, "mpscintr", NULL);
mpscintr = of_find_node_by_phandle(*ph);
if (!mpscintr)
goto error;
err = of_address_to_resource(mpscintr, 0, &r[1]);
of_node_put(mpscintr);
if (err)
goto error;
of_node_put(np);
mpsc_base = ioremap(r[0].start, resource_size(&r[0]));
if (!mpsc_base)
return;
mpsc_intr_cause = ioremap(r[1].start, resource_size(&r[1]));
if (!mpsc_intr_cause) {
iounmap(mpsc_base);
return;
}
mpsc_intr_cause += intr_cause_offset;
udbg_putc = mv64x60_udbg_putc;
udbg_getc = mv64x60_udbg_getc;
udbg_getc_poll = mv64x60_udbg_getc_poll;
return;
error:
of_node_put(np);
}
void mv64x60_init_early(void)
{
mv64x60_udbg_init();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment