This is a major chunk of IXP4xx modernization:

- Fist we move some registers around to make room for
   the predetermined PCI I/O space.
 
 - Then we add some Kconfig options to make it possible
   to use the old PCI driver in parallell with the new
   shiny one.
 
 - Then we add the new PCI driver and some bindings for
   it.
 
 - On top of this we add an (ages old) patch from Arnd
   that centralize the CPU/SoC detection in drivers/soc
   and make the header a standard Linux header to avoid
   the <mach/*> business in drivers.
 
 - Then we split out and modernize some platform data
   headers for pata, and hwrandom, and top it up with
   DT bindings and support for hwrandom.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEElDRnuGcz/wPCXQWMQRCzN7AZXXMFAmDMWhIACgkQQRCzN7AZ
 XXMCeA/8C3EquNZgRZkzrEUvX2Einr0djZvu/vQZkn1cybusNQxeRTupyZH2eQYG
 DzvDq+lGe/1gK72fnBSlaNRr4RunBCGDEt7pmbYPnSIuQk9YckhCtvWX6ZVjzEe/
 lY/H+zW7vWO+kajNffjRs8/Ovhlku+1VgN4+EpkHiW1UfYzdWAVRBn2s3JY5O4ht
 1ONMJu7/myy5yE+fyNfGt5iBCE4Tj2VNuOVFdyijv07GwupndZ+xbnDqTlFmdbw0
 qLaoumWSvSAhOlJHDINqfdeNJ3NXVrHejcrLERvDSn+UbqNV6+NYhAncDb+JV5Nn
 oZS5masrAOTbZHv9MGfVt3baQukDixYCvx7f/Qg3BUODkOJcUZWT8+ShRuLMrFfL
 d4uC/QKWkTbO1XOGzn3I/6Co25jC0FjLPk87AZ25i7q410gralHQwad9BmJWE1ZH
 vvQVvbE5ZELyFF13nGkk/m4cY3u07BGnLV24MbByZpUCyEE5M1X2jujBFtofacPC
 MxcJDVgewrlsgAeZVjrMW2XCFhYgU6fKLQyc80L2BHWMBI/6t7BcaaK3g+s9thOI
 19X2smU4QRXLmC8fa7IkiQv0q8J288xTBbP+N9RgZF/9FUT4BPXQNTgRueMZjfm3
 HcbKh+lsG1wtGqxHlK+7L4VCx+MjyQAFUVLHSKt0uu2q6vElFSQ=
 =k/Rp
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQJDBAABCgAtFiEElf+HevZ4QCAJmMQ+jBrnPN6EHHcFAmDT5DwPHG9sb2ZAbGl4
 b20ubmV0AAoJEIwa5zzehBx3fJ0P/3R3Eyxo7W+sUZzDDkVuHIGQ+D2Yj2SLsNF+
 hCoXlADnD37Zgjw4hEp3nW3ZuoRDH2MqhU//oMFfUScXh0giHbjaSsQRQextoo3u
 kqReKRrhU7r9KSuAloml8YXTCiBCYkHEQQ7BtMuInyJRYmIlBSUV9GpiMXGY4MOO
 Z4orN5OGio4S9VZ3hvN5efKJnqjbKvKzgXDGaHuXqEHFXpXX9gH8g/eulxOcUZ8f
 tfTdW026isqBpW1pGpEqKcyyT4TJmCs1JDx19DHjbaeVAV9vOvS2UF7xC+6nYGEA
 7PQwRMxZGMdSP/YZ8HsbHKoAHh3/3rwc0BpjlnQcnW/2l52sQM4hrbsd0vjL7zap
 S7qTIlPWEK0glbFQccXVtwmfDauE7G6GxuuAe4+zO4zNeiJyxH9UwXiNvKsRGzSi
 E1sWSAEy8h8HOvxg4D0am7n/57QYdJLtfvOxgBtmmyx5FnVj64LYtKXSb4k345cn
 qAbYb/vKJauze046Hll8dxK6JsRuzpjUy/10Q3UnXw580GeNFcHRRGBzDNFKZynZ
 YlTfd/njEr+qjQA2hE9LxshA/R6M+OyskHuNvGCZ9bPFhbJzTBxfdAPwVqjs6G0h
 BEL90S6KiURnyEsnYzmHV6nVn5reggIXCdcmPtcCHan+jw4pJ5e/op/dZPytf2Uf
 Z0iZ4QiN
 =NWGE
 -----END PGP SIGNATURE-----

Merge tag 'ixp4xx-arm-soc-v5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-nomadik into arm/soc

This is a major chunk of IXP4xx modernization:

- Fist we move some registers around to make room for
  the predetermined PCI I/O space.

- Then we add some Kconfig options to make it possible
  to use the old PCI driver in parallell with the new
  shiny one.

- Then we add the new PCI driver and some bindings for
  it.

- On top of this we add an (ages old) patch from Arnd
  that centralize the CPU/SoC detection in drivers/soc
  and make the header a standard Linux header to avoid
  the <mach/*> business in drivers.

- Then we split out and modernize some platform data
  headers for pata, and hwrandom, and top it up with
  DT bindings and support for hwrandom.

* tag 'ixp4xx-arm-soc-v5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-nomadik:
  ixp4xx: fix spelling mistake in Kconfig "Devce" -> "Device"
  hw_random: ixp4xx: Add OF support
  hw_random: ixp4xx: Add DT bindings
  hw_random: ixp4xx: Turn into a module
  hw_random: ixp4xx: Use SPDX license tag
  hw_random: ixp4xx: enable compile-testing
  pata: ixp4xx: split platform data to its own header
  soc: ixp4xx: move cpu detection to linux/soc/ixp4xx/cpu.h
  PCI: ixp4xx: Add a new driver for IXP4xx
  PCI: ixp4xx: Add device tree bindings for IXP4xx
  ARM/ixp4xx: Make NEED_MACH_IO_H optional
  ARM/ixp4xx: Move the virtual IObases

Link: https://lore.kernel.org/r/CACRpkdbw6HSpp7k6q1FYGmtafLmdAu8bFnpHQOdfBDYYsdLbkw@mail.gmail.com
Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
Olof Johansson 2021-06-23 18:47:38 -07:00
commit 95ef715236
31 changed files with 1079 additions and 175 deletions

View file

@ -0,0 +1,100 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/pci/intel,ixp4xx-pci.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Intel IXP4xx PCI controller
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
description: PCI host controller found in the Intel IXP4xx SoC series.
allOf:
- $ref: /schemas/pci/pci-bus.yaml#
properties:
compatible:
items:
- enum:
- intel,ixp42x-pci
- intel,ixp43x-pci
description: The two supported variants are ixp42x and ixp43x,
though more variants may exist.
reg:
items:
- description: IXP4xx-specific registers
interrupts:
items:
- description: Main PCI interrupt
- description: PCI DMA interrupt 1
- description: PCI DMA interrupt 2
ranges:
maxItems: 2
description: Typically one memory range of 64MB and one IO
space range of 64KB.
dma-ranges:
maxItems: 1
description: The DMA range tells the PCI host which addresses
the RAM is at. It can map only 64MB so if the RAM is bigger
than 64MB the DMA access has to be restricted to these
addresses.
"#interrupt-cells": true
interrupt-map: true
interrupt-map-mask:
items:
- const: 0xf800
- const: 0
- const: 0
- const: 7
required:
- compatible
- reg
- dma-ranges
- "#interrupt-cells"
- interrupt-map
- interrupt-map-mask
unevaluatedProperties: false
examples:
- |
pci@c0000000 {
compatible = "intel,ixp43x-pci";
reg = <0xc0000000 0x1000>;
#address-cells = <3>;
#size-cells = <2>;
device_type = "pci";
bus-range = <0x00 0xff>;
ranges =
<0x02000000 0 0x48000000 0x48000000 0 0x04000000>,
<0x01000000 0 0x00000000 0x4c000000 0 0x00010000>;
dma-ranges =
<0x02000000 0 0x00000000 0x00000000 0 0x04000000>;
#interrupt-cells = <1>;
interrupt-map-mask = <0xf800 0 0 7>;
interrupt-map =
<0x0800 0 0 1 &gpio0 11 3>, /* INT A on slot 1 is irq 11 */
<0x0800 0 0 2 &gpio0 10 3>, /* INT B on slot 1 is irq 10 */
<0x0800 0 0 3 &gpio0 9 3>, /* INT C on slot 1 is irq 9 */
<0x0800 0 0 4 &gpio0 8 3>, /* INT D on slot 1 is irq 8 */
<0x1000 0 0 1 &gpio0 10 3>, /* INT A on slot 2 is irq 10 */
<0x1000 0 0 2 &gpio0 9 3>, /* INT B on slot 2 is irq 9 */
<0x1000 0 0 3 &gpio0 8 3>, /* INT C on slot 2 is irq 8 */
<0x1000 0 0 4 &gpio0 11 3>, /* INT D on slot 2 is irq 11 */
<0x1800 0 0 1 &gpio0 9 3>, /* INT A on slot 3 is irq 9 */
<0x1800 0 0 2 &gpio0 8 3>, /* INT B on slot 3 is irq 8 */
<0x1800 0 0 3 &gpio0 11 3>, /* INT C on slot 3 is irq 11 */
<0x1800 0 0 4 &gpio0 10 3>; /* INT D on slot 3 is irq 10 */
};

View file

@ -0,0 +1,36 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/rng/intel,ixp46x-rng.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Intel IXP46x RNG bindings
description: |
The Intel IXP46x has a random number generator at a fixed physical
location in memory. Each read is guaranteed to provide a unique
32 bit random number.
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
properties:
compatible:
const: intel,ixp46x-rng
reg:
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
rng@70002100 {
compatible = "intel,ixp46x-rng";
reg = <0x70002100 4>;
};

View file

@ -9252,6 +9252,7 @@ F: include/linux/soc/ixp4xx/qmgr.h
INTEL IXP4XX RANDOM NUMBER GENERATOR SUPPORT
M: Deepak Saxena <dsaxena@plexity.net>
S: Maintained
F: Documentation/devicetree/bindings/display/intel,ixp46x-rng.yaml
F: drivers/char/hw_random/ixp4xx-rng.c
INTEL KEEM BAY DRM DRIVER
@ -14015,6 +14016,12 @@ S: Maintained
F: Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml
F: drivers/pci/controller/dwc/pcie-fu740.c
PCI DRIVER FOR INTEL IXP4XX
M: Linus Walleij <linus.walleij@linaro.org>
S: Maintained
F: Documentation/devicetree/bindings/pci/intel,ixp4xx-pci.yaml
F: drivers/pci/controller/pci-ixp4xx.c
PCI DRIVER FOR INTEL VOLUME MANAGEMENT DEVICE (VMD)
M: Jonathan Derrick <jonathan.derrick@intel.com>
L: linux-pci@vger.kernel.org

View file

@ -398,7 +398,8 @@ config ARCH_IXP4XX
select HAVE_PCI
select IXP4XX_IRQ
select IXP4XX_TIMER
select NEED_MACH_IO_H
# With the new PCI driver this is not needed
select NEED_MACH_IO_H if PCI_IXP4XX_LEGACY
select USB_EHCI_BIG_ENDIAN_DESC
select USB_EHCI_BIG_ENDIAN_MMIO
help

View file

@ -1813,8 +1813,8 @@ config DEBUG_UART_VIRT
default 0xfedc0000 if DEBUG_EP93XX
default 0xfee003f8 if DEBUG_FOOTBRIDGE_COM1
default 0xfee20000 if DEBUG_NSPIRE_CLASSIC_UART || DEBUG_NSPIRE_CX_UART
default 0xfef00000 if ARCH_IXP4XX && !CPU_BIG_ENDIAN
default 0xfef00003 if ARCH_IXP4XX && CPU_BIG_ENDIAN
default 0xfec00000 if ARCH_IXP4XX && !CPU_BIG_ENDIAN
default 0xfec00003 if ARCH_IXP4XX && CPU_BIG_ENDIAN
default 0xfef36000 if DEBUG_HIGHBANK_UART
default 0xfefb0000 if DEBUG_OMAP1UART1 || DEBUG_OMAP7XXUART1
default 0xfefb0800 if DEBUG_OMAP1UART2 || DEBUG_OMAP7XXUART2

View file

@ -7,7 +7,7 @@ comment "IXP4xx Platforms"
config MACH_IXP4XX_OF
bool
prompt "Devce Tree IXP4xx boards"
prompt "Device Tree IXP4xx boards"
default y
select ARM_APPENDED_DTB # Old Redboot bootloaders deployed
select I2C
@ -20,7 +20,7 @@ config MACH_IXP4XX_OF
config MACH_NSLU2
bool
prompt "Linksys NSLU2"
select FORCE_PCI
depends on IXP4XX_PCI_LEGACY
help
Say 'Y' here if you want your kernel to support Linksys's
NSLU2 NAS device. For more information on this platform,
@ -28,7 +28,7 @@ config MACH_NSLU2
config MACH_AVILA
bool "Avila"
select FORCE_PCI
depends on IXP4XX_PCI_LEGACY
help
Say 'Y' here if you want your kernel to support the Gateworks
Avila Network Platform. For more information on this platform,
@ -44,7 +44,7 @@ config MACH_LOFT
config ARCH_ADI_COYOTE
bool "Coyote"
select FORCE_PCI
depends on IXP4XX_PCI_LEGACY
help
Say 'Y' here if you want your kernel to support the ADI
Engineering Coyote Gateway Reference Platform. For more
@ -52,7 +52,7 @@ config ARCH_ADI_COYOTE
config MACH_GATEWAY7001
bool "Gateway 7001"
select FORCE_PCI
depends on IXP4XX_PCI_LEGACY
help
Say 'Y' here if you want your kernel to support Gateway's
7001 Access Point. For more information on this platform,
@ -60,7 +60,7 @@ config MACH_GATEWAY7001
config MACH_WG302V2
bool "Netgear WG302 v2 / WAG302 v2"
select FORCE_PCI
depends on IXP4XX_PCI_LEGACY
help
Say 'Y' here if you want your kernel to support Netgear's
WG302 v2 or WAG302 v2 Access Points. For more information
@ -68,6 +68,7 @@ config MACH_WG302V2
config ARCH_IXDP425
bool "IXDP425"
depends on IXP4XX_PCI_LEGACY
help
Say 'Y' here if you want your kernel to support Intel's
IXDP425 Development Platform (Also known as Richfield).
@ -75,6 +76,7 @@ config ARCH_IXDP425
config MACH_IXDPG425
bool "IXDPG425"
depends on IXP4XX_PCI_LEGACY
help
Say 'Y' here if you want your kernel to support Intel's
IXDPG425 Development Platform (Also known as Montajade).
@ -120,7 +122,7 @@ config ARCH_PRPMC1100
config MACH_NAS100D
bool
prompt "NAS100D"
select FORCE_PCI
depends on IXP4XX_PCI_LEGACY
help
Say 'Y' here if you want your kernel to support Iomega's
NAS 100d device. For more information on this platform,
@ -129,7 +131,7 @@ config MACH_NAS100D
config MACH_DSMG600
bool
prompt "D-Link DSM-G600 RevA"
select FORCE_PCI
depends on IXP4XX_PCI_LEGACY
help
Say 'Y' here if you want your kernel to support D-Link's
DSM-G600 RevA device. For more information on this platform,
@ -143,7 +145,7 @@ config ARCH_IXDP4XX
config MACH_FSG
bool
prompt "Freecom FSG-3"
select FORCE_PCI
depends on IXP4XX_PCI_LEGACY
help
Say 'Y' here if you want your kernel to support Freecom's
FSG-3 device. For more information on this platform,
@ -152,7 +154,7 @@ config MACH_FSG
config MACH_ARCOM_VULCAN
bool
prompt "Arcom/Eurotech Vulcan"
select FORCE_PCI
depends on IXP4XX_PCI_LEGACY
help
Say 'Y' here if you want your kernel to support Arcom's
Vulcan board.
@ -173,7 +175,7 @@ config CPU_IXP43X
config MACH_GTWX5715
bool "Gemtek WX5715 (Linksys WRV54G)"
depends on ARCH_IXP4XX
select FORCE_PCI
depends on IXP4XX_PCI_LEGACY
help
This board is currently inside the Linksys WRV54G Gateways.
@ -196,7 +198,7 @@ config MACH_DEVIXP
config MACH_MICCPT
bool "Omicron MICCPT"
select FORCE_PCI
depends on IXP4XX_PCI_LEGACY
help
Say 'Y' here if you want your kernel to support the MICCPT
board from OMICRON electronics GmbH.
@ -209,9 +211,16 @@ config MACH_MIC256
comment "IXP4xx Options"
config IXP4XX_PCI_LEGACY
bool "IXP4xx legacy PCI driver support"
depends on PCI
help
Selects legacy PCI driver.
Not recommended for new development.
config IXP4XX_INDIRECT_PCI
bool "Use indirect PCI memory access"
depends on PCI
depends on IXP4XX_PCI_LEGACY
help
IXP4xx provides two methods of accessing PCI memory space:

View file

@ -19,6 +19,7 @@
#include <linux/tty.h>
#include <linux/serial_8250.h>
#include <linux/gpio/machine.h>
#include <linux/platform_data/pata_ixp4xx_cf.h>
#include <asm/types.h>
#include <asm/setup.h>
#include <asm/memory.h>

View file

@ -27,12 +27,12 @@
#include <linux/cpu.h>
#include <linux/pci.h>
#include <linux/sched_clock.h>
#include <linux/soc/ixp4xx/cpu.h>
#include <linux/irqchip/irq-ixp4xx.h>
#include <linux/platform_data/timer-ixp4xx.h>
#include <linux/dma-map-ops.h>
#include <mach/udc.h>
#include <mach/hardware.h>
#include <mach/io.h>
#include <linux/uaccess.h>
#include <asm/page.h>
#include <asm/exception.h>
@ -44,6 +44,27 @@
#include "irqs.h"
u32 ixp4xx_read_feature_bits(void)
{
u32 val = ~__raw_readl(IXP4XX_EXP_CFG2);
if (cpu_is_ixp42x_rev_a0())
return IXP42X_FEATURE_MASK & ~(IXP4XX_FEATURE_RCOMP |
IXP4XX_FEATURE_AES);
if (cpu_is_ixp42x())
return val & IXP42X_FEATURE_MASK;
if (cpu_is_ixp43x())
return val & IXP43X_FEATURE_MASK;
return val & IXP46X_FEATURE_MASK;
}
EXPORT_SYMBOL(ixp4xx_read_feature_bits);
void ixp4xx_write_feature_bits(u32 value)
{
__raw_writel(~value, IXP4XX_EXP_CFG2);
}
EXPORT_SYMBOL(ixp4xx_write_feature_bits);
#define IXP4XX_TIMER_FREQ 66666000
/*************************************************************************
@ -215,6 +236,27 @@ static struct resource ixp46x_i2c_resources[] = {
}
};
/* A single 32-bit register on IXP46x */
#define IXP4XX_HWRANDOM_BASE_PHYS 0x70002100
static struct resource ixp46x_hwrandom_resource[] = {
{
.start = IXP4XX_HWRANDOM_BASE_PHYS,
.end = IXP4XX_HWRANDOM_BASE_PHYS + 0x3,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device ixp46x_hwrandom_device = {
.name = "ixp4xx-hwrandom",
.id = -1,
.dev = {
.coherent_dma_mask = DMA_BIT_MASK(32),
},
.resource = ixp46x_hwrandom_resource,
.num_resources = ARRAY_SIZE(ixp46x_hwrandom_resource),
};
/*
* I2C controller. The IXP46x uses the same block as the IOP3xx, so
* we just use the same device name.
@ -227,7 +269,8 @@ static struct platform_device ixp46x_i2c_controller = {
};
static struct platform_device *ixp46x_devices[] __initdata = {
&ixp46x_i2c_controller
&ixp46x_hwrandom_device,
&ixp46x_i2c_controller,
};
unsigned long ixp4xx_exp_bus_size;

View file

@ -28,6 +28,7 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
#include <mach/hardware.h>
#include "irqs.h"

View file

@ -1,54 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* arch/arm/mach-ixp4xx/include/mach/cpu.h
*
* IXP4XX cpu type detection
*
* Copyright (C) 2007 MontaVista Software, Inc.
*/
#ifndef __ASM_ARCH_CPU_H__
#define __ASM_ARCH_CPU_H__
#include <linux/io.h>
#include <asm/cputype.h>
/* Processor id value in CP15 Register 0 */
#define IXP42X_PROCESSOR_ID_VALUE 0x690541c0 /* including unused 0x690541Ex */
#define IXP42X_PROCESSOR_ID_MASK 0xffffffc0
#define IXP43X_PROCESSOR_ID_VALUE 0x69054040
#define IXP43X_PROCESSOR_ID_MASK 0xfffffff0
#define IXP46X_PROCESSOR_ID_VALUE 0x69054200 /* including IXP455 */
#define IXP46X_PROCESSOR_ID_MASK 0xfffffff0
#define cpu_is_ixp42x_rev_a0() ((read_cpuid_id() & (IXP42X_PROCESSOR_ID_MASK | 0xF)) == \
IXP42X_PROCESSOR_ID_VALUE)
#define cpu_is_ixp42x() ((read_cpuid_id() & IXP42X_PROCESSOR_ID_MASK) == \
IXP42X_PROCESSOR_ID_VALUE)
#define cpu_is_ixp43x() ((read_cpuid_id() & IXP43X_PROCESSOR_ID_MASK) == \
IXP43X_PROCESSOR_ID_VALUE)
#define cpu_is_ixp46x() ((read_cpuid_id() & IXP46X_PROCESSOR_ID_MASK) == \
IXP46X_PROCESSOR_ID_VALUE)
static inline u32 ixp4xx_read_feature_bits(void)
{
u32 val = ~__raw_readl(IXP4XX_EXP_CFG2);
if (cpu_is_ixp42x_rev_a0())
return IXP42X_FEATURE_MASK & ~(IXP4XX_FEATURE_RCOMP |
IXP4XX_FEATURE_AES);
if (cpu_is_ixp42x())
return val & IXP42X_FEATURE_MASK;
if (cpu_is_ixp43x())
return val & IXP43X_FEATURE_MASK;
return val & IXP46X_FEATURE_MASK;
}
static inline void ixp4xx_write_feature_bits(u32 value)
{
__raw_writel(~value, IXP4XX_EXP_CFG2);
}
#endif /* _ASM_ARCH_CPU_H */

View file

@ -23,7 +23,7 @@
#include "ixp4xx-regs.h"
#ifndef __ASSEMBLER__
#include <mach/cpu.h>
#include <linux/soc/ixp4xx/cpu.h>
#endif
/* Platform helper functions and definitions */

View file

@ -45,21 +45,21 @@
* it can be used with the low-level debug code.
*/
#define IXP4XX_PERIPHERAL_BASE_PHYS 0xC8000000
#define IXP4XX_PERIPHERAL_BASE_VIRT IOMEM(0xFEF00000)
#define IXP4XX_PERIPHERAL_BASE_VIRT IOMEM(0xFEC00000)
#define IXP4XX_PERIPHERAL_REGION_SIZE 0x00013000
/*
* PCI Config registers
*/
#define IXP4XX_PCI_CFG_BASE_PHYS 0xC0000000
#define IXP4XX_PCI_CFG_BASE_VIRT IOMEM(0xFEF13000)
#define IXP4XX_PCI_CFG_BASE_VIRT IOMEM(0xFEC13000)
#define IXP4XX_PCI_CFG_REGION_SIZE 0x00001000
/*
* Expansion BUS Configuration registers
*/
#define IXP4XX_EXP_CFG_BASE_PHYS 0xC4000000
#define IXP4XX_EXP_CFG_BASE_VIRT 0xFEF14000
#define IXP4XX_EXP_CFG_BASE_VIRT 0xFEC14000
#define IXP4XX_EXP_CFG_REGION_SIZE 0x00001000
#define IXP4XX_EXP_CS0_OFFSET 0x00
@ -120,6 +120,7 @@
#define IXP4XX_SSP_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0x12000)
/* The UART is explicitly put in the beginning of fixmap */
#define IXP4XX_UART1_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x0000)
#define IXP4XX_UART2_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x1000)
#define IXP4XX_PMU_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x2000)
@ -299,58 +300,4 @@
#define DCMD_LENGTH 0x01fff /* length mask (max = 8K - 1) */
/* "fuse" bits of IXP_EXP_CFG2 */
/* All IXP4xx CPUs */
#define IXP4XX_FEATURE_RCOMP (1 << 0)
#define IXP4XX_FEATURE_USB_DEVICE (1 << 1)
#define IXP4XX_FEATURE_HASH (1 << 2)
#define IXP4XX_FEATURE_AES (1 << 3)
#define IXP4XX_FEATURE_DES (1 << 4)
#define IXP4XX_FEATURE_HDLC (1 << 5)
#define IXP4XX_FEATURE_AAL (1 << 6)
#define IXP4XX_FEATURE_HSS (1 << 7)
#define IXP4XX_FEATURE_UTOPIA (1 << 8)
#define IXP4XX_FEATURE_NPEB_ETH0 (1 << 9)
#define IXP4XX_FEATURE_NPEC_ETH (1 << 10)
#define IXP4XX_FEATURE_RESET_NPEA (1 << 11)
#define IXP4XX_FEATURE_RESET_NPEB (1 << 12)
#define IXP4XX_FEATURE_RESET_NPEC (1 << 13)
#define IXP4XX_FEATURE_PCI (1 << 14)
#define IXP4XX_FEATURE_UTOPIA_PHY_LIMIT (3 << 16)
#define IXP4XX_FEATURE_XSCALE_MAX_FREQ (3 << 22)
#define IXP42X_FEATURE_MASK (IXP4XX_FEATURE_RCOMP | \
IXP4XX_FEATURE_USB_DEVICE | \
IXP4XX_FEATURE_HASH | \
IXP4XX_FEATURE_AES | \
IXP4XX_FEATURE_DES | \
IXP4XX_FEATURE_HDLC | \
IXP4XX_FEATURE_AAL | \
IXP4XX_FEATURE_HSS | \
IXP4XX_FEATURE_UTOPIA | \
IXP4XX_FEATURE_NPEB_ETH0 | \
IXP4XX_FEATURE_NPEC_ETH | \
IXP4XX_FEATURE_RESET_NPEA | \
IXP4XX_FEATURE_RESET_NPEB | \
IXP4XX_FEATURE_RESET_NPEC | \
IXP4XX_FEATURE_PCI | \
IXP4XX_FEATURE_UTOPIA_PHY_LIMIT | \
IXP4XX_FEATURE_XSCALE_MAX_FREQ)
/* IXP43x/46x CPUs */
#define IXP4XX_FEATURE_ECC_TIMESYNC (1 << 15)
#define IXP4XX_FEATURE_USB_HOST (1 << 18)
#define IXP4XX_FEATURE_NPEA_ETH (1 << 19)
#define IXP43X_FEATURE_MASK (IXP42X_FEATURE_MASK | \
IXP4XX_FEATURE_ECC_TIMESYNC | \
IXP4XX_FEATURE_USB_HOST | \
IXP4XX_FEATURE_NPEA_ETH)
/* IXP46x CPU (including IXP455) only */
#define IXP4XX_FEATURE_NPEB_ETH_1_TO_3 (1 << 20)
#define IXP4XX_FEATURE_RSA (1 << 21)
#define IXP46X_FEATURE_MASK (IXP43X_FEATURE_MASK | \
IXP4XX_FEATURE_NPEB_ETH_1_TO_3 | \
IXP4XX_FEATURE_RSA)
#endif

View file

@ -79,20 +79,6 @@ extern unsigned long ixp4xx_exp_bus_size;
#define IXP4XX_PERIPHERAL_BUS_CLOCK (66) /* 66MHzi APB BUS */
#define IXP4XX_UART_XTAL 14745600
/*
* This structure provide a means for the board setup code
* to give information to th pata_ixp4xx driver. It is
* passed as platform_data.
*/
struct ixp4xx_pata_data {
volatile u32 *cs0_cfg;
volatile u32 *cs1_cfg;
unsigned long cs0_bits;
unsigned long cs1_bits;
void __iomem *cs0;
void __iomem *cs1;
};
/*
* Frequency of clock used for primary clocksource
*/

View file

@ -9,8 +9,12 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <mach/hardware.h>
#include <mach/ixp4xx-regs.h>
/*
* These are the only fixed phys to virt mappings we ever need
* we put it right after the UART mapping at 0xffc80000-0xffc81fff
*/
#define IXP4XX_EXP_CFG_BASE_PHYS 0xC4000000
#define IXP4XX_EXP_CFG_BASE_VIRT 0xFEC14000
static struct map_desc ixp4xx_of_io_desc[] __initdata = {
/*

View file

@ -33,6 +33,7 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
#include <mach/hardware.h>
#include "irqs.h"

View file

@ -31,6 +31,7 @@
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
#include <asm/mach/time.h>
#include <mach/hardware.h>
#include "irqs.h"

View file

@ -1058,7 +1058,7 @@ config PATA_ISAPNP
config PATA_IXP4XX_CF
tristate "IXP4XX Compact Flash support"
depends on ARCH_IXP4XX
depends on ARCH_IXP4XX || COMPILE_TEST
help
This option enables support for a Compact Flash connected on
the ixp4xx expansion bus. This driver had been written for

View file

@ -17,6 +17,7 @@
#include <linux/libata.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/platform_data/pata_ixp4xx_cf.h>
#include <scsi/scsi_host.h>
#define DRV_NAME "pata_ixp4xx_cf"

View file

@ -152,7 +152,7 @@ config HW_RANDOM_VIA
config HW_RANDOM_IXP4XX
tristate "Intel IXP4xx NPU HW Pseudo-Random Number Generator support"
depends on ARCH_IXP4XX
depends on ARCH_IXP4XX || COMPILE_TEST
default HW_RANDOM
help
This driver provides kernel-side support for the Pseudo-Random

View file

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/*
* drivers/char/hw_random/ixp4xx-rng.c
*
@ -8,23 +9,20 @@
* Copyright 2005 (c) MontaVista Software, Inc.
*
* Fixes by Michael Buesch
*
* 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/kernel.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/hw_random.h>
#include <linux/of.h>
#include <linux/soc/ixp4xx/cpu.h>
#include <asm/io.h>
#include <mach/hardware.h>
static int ixp4xx_rng_data_read(struct hwrng *rng, u32 *buffer)
{
@ -40,35 +38,40 @@ static struct hwrng ixp4xx_rng_ops = {
.data_read = ixp4xx_rng_data_read,
};
static int __init ixp4xx_rng_init(void)
static int ixp4xx_rng_probe(struct platform_device *pdev)
{
void __iomem * rng_base;
int err;
struct device *dev = &pdev->dev;
struct resource *res;
if (!cpu_is_ixp46x()) /* includes IXP455 */
return -ENOSYS;
rng_base = ioremap(0x70002100, 4);
if (!rng_base)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
rng_base = devm_ioremap_resource(dev, res);
if (IS_ERR(rng_base))
return PTR_ERR(rng_base);
ixp4xx_rng_ops.priv = (unsigned long)rng_base;
err = hwrng_register(&ixp4xx_rng_ops);
if (err)
iounmap(rng_base);
return err;
return devm_hwrng_register(dev, &ixp4xx_rng_ops);
}
static void __exit ixp4xx_rng_exit(void)
{
void __iomem * rng_base = (void __iomem *)ixp4xx_rng_ops.priv;
static const struct of_device_id ixp4xx_rng_of_match[] = {
{
.compatible = "intel,ixp46x-rng",
},
{},
};
MODULE_DEVICE_TABLE(of, ixp4xx_rng_of_match);
hwrng_unregister(&ixp4xx_rng_ops);
iounmap(rng_base);
}
module_init(ixp4xx_rng_init);
module_exit(ixp4xx_rng_exit);
static struct platform_driver ixp4xx_rng_driver = {
.driver = {
.name = "ixp4xx-hwrandom",
.of_match_table = ixp4xx_rng_of_match,
},
.probe = ixp4xx_rng_probe,
};
module_platform_driver(ixp4xx_rng_driver);
MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
MODULE_DESCRIPTION("H/W Pseudo-Random Number Generator (RNG) driver for IXP45x/46x");

View file

@ -30,6 +30,10 @@
#include <linux/soc/ixp4xx/npe.h>
#include <linux/soc/ixp4xx/qmgr.h>
/* Intermittent includes, delete this after v5.14-rc1 */
#include <linux/soc/ixp4xx/cpu.h>
#include <mach/ixp4xx-regs.h>
#define MAX_KEYLEN 32
/* hash: cfgword + 2 * digestlen; crypt: keylen + cfgword */

View file

@ -37,6 +37,8 @@
#include <linux/module.h>
#include <linux/soc/ixp4xx/npe.h>
#include <linux/soc/ixp4xx/qmgr.h>
#include <mach/hardware.h>
#include <linux/soc/ixp4xx/cpu.h>
#include "ixp46x_ts.h"

View file

@ -12,9 +12,8 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/soc/ixp4xx/cpu.h>
#include "ixp46x_ts.h"

View file

@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/soc/ixp4xx/npe.h>
#include <linux/soc/ixp4xx/qmgr.h>
#include <linux/soc/ixp4xx/cpu.h>
#define DEBUG_DESC 0
#define DEBUG_RX 0

View file

@ -37,6 +37,14 @@ config PCI_FTPCI100
depends on OF
default ARCH_GEMINI
config PCI_IXP4XX
bool "Intel IXP4xx PCI controller"
depends on ARM && OF
default ARCH_IXP4XX
help
Say Y here if you want support for the PCI host controller found
in the Intel IXP4xx XScale-based network processor SoC.
config PCI_TEGRA
bool "NVIDIA Tegra PCIe controller"
depends on ARCH_TEGRA || COMPILE_TEST

View file

@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_PCIE_CADENCE) += cadence/
obj-$(CONFIG_PCI_FTPCI100) += pci-ftpci100.o
obj-$(CONFIG_PCI_IXP4XX) += pci-ixp4xx.o
obj-$(CONFIG_PCI_HYPERV) += pci-hyperv.o
obj-$(CONFIG_PCI_HYPERV_INTERFACE) += pci-hyperv-intf.o
obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o

View file

@ -0,0 +1,671 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Support for Intel IXP4xx PCI host controller
*
* Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
*
* Based on the IXP4xx arch/arm/mach-ixp4xx/common-pci.c driver
* Copyright (C) 2002 Intel Corporation
* Copyright (C) 2003 Greg Ungerer <gerg@linux-m68k.org>
* Copyright (C) 2003-2004 MontaVista Software, Inc.
* Copyright (C) 2005 Deepak Saxena <dsaxena@plexity.net>
* Copyright (C) 2005 Alessandro Zummo <a.zummo@towertech.it>
*
* TODO:
* - Test IO-space access
* - DMA support
*/
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_pci.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/bits.h>
/* Register offsets */
#define IXP4XX_PCI_NP_AD 0x00
#define IXP4XX_PCI_NP_CBE 0x04
#define IXP4XX_PCI_NP_WDATA 0x08
#define IXP4XX_PCI_NP_RDATA 0x0c
#define IXP4XX_PCI_CRP_AD_CBE 0x10
#define IXP4XX_PCI_CRP_WDATA 0x14
#define IXP4XX_PCI_CRP_RDATA 0x18
#define IXP4XX_PCI_CSR 0x1c
#define IXP4XX_PCI_ISR 0x20
#define IXP4XX_PCI_INTEN 0x24
#define IXP4XX_PCI_DMACTRL 0x28
#define IXP4XX_PCI_AHBMEMBASE 0x2c
#define IXP4XX_PCI_AHBIOBASE 0x30
#define IXP4XX_PCI_PCIMEMBASE 0x34
#define IXP4XX_PCI_AHBDOORBELL 0x38
#define IXP4XX_PCI_PCIDOORBELL 0x3c
#define IXP4XX_PCI_ATPDMA0_AHBADDR 0x40
#define IXP4XX_PCI_ATPDMA0_PCIADDR 0x44
#define IXP4XX_PCI_ATPDMA0_LENADDR 0x48
#define IXP4XX_PCI_ATPDMA1_AHBADDR 0x4c
#define IXP4XX_PCI_ATPDMA1_PCIADDR 0x50
#define IXP4XX_PCI_ATPDMA1_LENADDR 0x54
/* CSR bit definitions */
#define IXP4XX_PCI_CSR_HOST BIT(0)
#define IXP4XX_PCI_CSR_ARBEN BIT(1)
#define IXP4XX_PCI_CSR_ADS BIT(2)
#define IXP4XX_PCI_CSR_PDS BIT(3)
#define IXP4XX_PCI_CSR_ABE BIT(4)
#define IXP4XX_PCI_CSR_DBT BIT(5)
#define IXP4XX_PCI_CSR_ASE BIT(8)
#define IXP4XX_PCI_CSR_IC BIT(15)
#define IXP4XX_PCI_CSR_PRST BIT(16)
/* ISR (Interrupt status) Register bit definitions */
#define IXP4XX_PCI_ISR_PSE BIT(0)
#define IXP4XX_PCI_ISR_PFE BIT(1)
#define IXP4XX_PCI_ISR_PPE BIT(2)
#define IXP4XX_PCI_ISR_AHBE BIT(3)
#define IXP4XX_PCI_ISR_APDC BIT(4)
#define IXP4XX_PCI_ISR_PADC BIT(5)
#define IXP4XX_PCI_ISR_ADB BIT(6)
#define IXP4XX_PCI_ISR_PDB BIT(7)
/* INTEN (Interrupt Enable) Register bit definitions */
#define IXP4XX_PCI_INTEN_PSE BIT(0)
#define IXP4XX_PCI_INTEN_PFE BIT(1)
#define IXP4XX_PCI_INTEN_PPE BIT(2)
#define IXP4XX_PCI_INTEN_AHBE BIT(3)
#define IXP4XX_PCI_INTEN_APDC BIT(4)
#define IXP4XX_PCI_INTEN_PADC BIT(5)
#define IXP4XX_PCI_INTEN_ADB BIT(6)
#define IXP4XX_PCI_INTEN_PDB BIT(7)
/* Shift value for byte enable on NP cmd/byte enable register */
#define IXP4XX_PCI_NP_CBE_BESL 4
/* PCI commands supported by NP access unit */
#define NP_CMD_IOREAD 0x2
#define NP_CMD_IOWRITE 0x3
#define NP_CMD_CONFIGREAD 0xa
#define NP_CMD_CONFIGWRITE 0xb
#define NP_CMD_MEMREAD 0x6
#define NP_CMD_MEMWRITE 0x7
/* Constants for CRP access into local config space */
#define CRP_AD_CBE_BESL 20
#define CRP_AD_CBE_WRITE 0x00010000
/* Special PCI configuration space registers for this controller */
#define IXP4XX_PCI_RTOTTO 0x40
struct ixp4xx_pci {
struct device *dev;
void __iomem *base;
bool errata_hammer;
bool host_mode;
};
/*
* The IXP4xx has a peculiar address bus that will change the
* byte order on SoC peripherals depending on whether the device
* operates in big-endian or little-endian mode. That means that
* readl() and writel() that always use little-endian access
* will not work for SoC peripherals such as the PCI controller
* when used in big-endian mode. The accesses to the individual
* PCI devices on the other hand, are always little-endian and
* can use readl() and writel().
*
* For local AHB bus access we need to use __raw_[readl|writel]()
* to make sure that we access the SoC devices in the CPU native
* endianness.
*/
static inline u32 ixp4xx_readl(struct ixp4xx_pci *p, u32 reg)
{
return __raw_readl(p->base + reg);
}
static inline void ixp4xx_writel(struct ixp4xx_pci *p, u32 reg, u32 val)
{
__raw_writel(val, p->base + reg);
}
static int ixp4xx_pci_check_master_abort(struct ixp4xx_pci *p)
{
u32 isr = ixp4xx_readl(p, IXP4XX_PCI_ISR);
if (isr & IXP4XX_PCI_ISR_PFE) {
/* Make sure the master abort bit is reset */
ixp4xx_writel(p, IXP4XX_PCI_ISR, IXP4XX_PCI_ISR_PFE);
dev_dbg(p->dev, "master abort detected\n");
return -EINVAL;
}
return 0;
}
static int ixp4xx_pci_read(struct ixp4xx_pci *p, u32 addr, u32 cmd, u32 *data)
{
ixp4xx_writel(p, IXP4XX_PCI_NP_AD, addr);
if (p->errata_hammer) {
int i;
/*
* PCI workaround - only works if NP PCI space reads have
* no side effects. Hammer the register and read twice 8
* times. last one will be good.
*/
for (i = 0; i < 8; i++) {
ixp4xx_writel(p, IXP4XX_PCI_NP_CBE, cmd);
*data = ixp4xx_readl(p, IXP4XX_PCI_NP_RDATA);
*data = ixp4xx_readl(p, IXP4XX_PCI_NP_RDATA);
}
} else {
ixp4xx_writel(p, IXP4XX_PCI_NP_CBE, cmd);
*data = ixp4xx_readl(p, IXP4XX_PCI_NP_RDATA);
}
return ixp4xx_pci_check_master_abort(p);
}
static int ixp4xx_pci_write(struct ixp4xx_pci *p, u32 addr, u32 cmd, u32 data)
{
ixp4xx_writel(p, IXP4XX_PCI_NP_AD, addr);
/* Set up the write */
ixp4xx_writel(p, IXP4XX_PCI_NP_CBE, cmd);
/* Execute the write by writing to NP_WDATA */
ixp4xx_writel(p, IXP4XX_PCI_NP_WDATA, data);
return ixp4xx_pci_check_master_abort(p);
}
static u32 ixp4xx_config_addr(u8 bus_num, u16 devfn, int where)
{
/* Root bus is always 0 in this hardware */
if (bus_num == 0) {
/* type 0 */
return BIT(32-PCI_SLOT(devfn)) | ((PCI_FUNC(devfn)) << 8) |
(where & ~3);
} else {
/* type 1 */
return (bus_num << 16) | ((PCI_SLOT(devfn)) << 11) |
((PCI_FUNC(devfn)) << 8) | (where & ~3) | 1;
}
}
/*
* CRP functions are "Controller Configuration Port" accesses
* initiated from within this driver itself to read/write PCI
* control information in the config space.
*/
static u32 ixp4xx_crp_byte_lane_enable_bits(u32 n, int size)
{
if (size == 1)
return (0xf & ~BIT(n)) << CRP_AD_CBE_BESL;
if (size == 2)
return (0xf & ~(BIT(n) | BIT(n+1))) << CRP_AD_CBE_BESL;
if (size == 4)
return 0;
return 0xffffffff;
}
static int ixp4xx_crp_read_config(struct ixp4xx_pci *p, int where, int size,
u32 *value)
{
u32 n, cmd, val;
n = where % 4;
cmd = where & ~3;
dev_dbg(p->dev, "%s from %d size %d cmd %08x\n",
__func__, where, size, cmd);
ixp4xx_writel(p, IXP4XX_PCI_CRP_AD_CBE, cmd);
val = ixp4xx_readl(p, IXP4XX_PCI_CRP_RDATA);
val >>= (8*n);
switch (size) {
case 1:
val &= U8_MAX;
dev_dbg(p->dev, "%s read byte %02x\n", __func__, val);
break;
case 2:
val &= U16_MAX;
dev_dbg(p->dev, "%s read word %04x\n", __func__, val);
break;
case 4:
val &= U32_MAX;
dev_dbg(p->dev, "%s read long %08x\n", __func__, val);
break;
default:
/* Should not happen */
dev_err(p->dev, "%s illegal size\n", __func__);
return PCIBIOS_DEVICE_NOT_FOUND;
}
*value = val;
return PCIBIOS_SUCCESSFUL;
}
static int ixp4xx_crp_write_config(struct ixp4xx_pci *p, int where, int size,
u32 value)
{
u32 n, cmd, val;
n = where % 4;
cmd = ixp4xx_crp_byte_lane_enable_bits(n, size);
if (cmd == 0xffffffff)
return PCIBIOS_BAD_REGISTER_NUMBER;
cmd |= where & ~3;
cmd |= CRP_AD_CBE_WRITE;
val = value << (8*n);
dev_dbg(p->dev, "%s to %d size %d cmd %08x val %08x\n",
__func__, where, size, cmd, val);
ixp4xx_writel(p, IXP4XX_PCI_CRP_AD_CBE, cmd);
ixp4xx_writel(p, IXP4XX_PCI_CRP_WDATA, val);
return PCIBIOS_SUCCESSFUL;
}
/*
* Then follows the functions that read and write from the common PCI
* configuration space.
*/
static u32 ixp4xx_byte_lane_enable_bits(u32 n, int size)
{
if (size == 1)
return (0xf & ~BIT(n)) << 4;
if (size == 2)
return (0xf & ~(BIT(n) | BIT(n+1))) << 4;
if (size == 4)
return 0;
return 0xffffffff;
}
static int ixp4xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 *value)
{
struct ixp4xx_pci *p = bus->sysdata;
u32 n, addr, val, cmd;
u8 bus_num = bus->number;
int ret;
*value = 0xffffffff;
n = where % 4;
cmd = ixp4xx_byte_lane_enable_bits(n, size);
if (cmd == 0xffffffff)
return PCIBIOS_BAD_REGISTER_NUMBER;
addr = ixp4xx_config_addr(bus_num, devfn, where);
cmd |= NP_CMD_CONFIGREAD;
dev_dbg(p->dev, "read_config from %d size %d dev %d:%d:%d address: %08x cmd: %08x\n",
where, size, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn), addr, cmd);
ret = ixp4xx_pci_read(p, addr, cmd, &val);
if (ret)
return PCIBIOS_DEVICE_NOT_FOUND;
val >>= (8*n);
switch (size) {
case 1:
val &= U8_MAX;
dev_dbg(p->dev, "%s read byte %02x\n", __func__, val);
break;
case 2:
val &= U16_MAX;
dev_dbg(p->dev, "%s read word %04x\n", __func__, val);
break;
case 4:
val &= U32_MAX;
dev_dbg(p->dev, "%s read long %08x\n", __func__, val);
break;
default:
/* Should not happen */
dev_err(p->dev, "%s illegal size\n", __func__);
return PCIBIOS_DEVICE_NOT_FOUND;
}
*value = val;
return PCIBIOS_SUCCESSFUL;
}
static int ixp4xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 value)
{
struct ixp4xx_pci *p = bus->sysdata;
u32 n, addr, val, cmd;
u8 bus_num = bus->number;
int ret;
n = where % 4;
cmd = ixp4xx_byte_lane_enable_bits(n, size);
if (cmd == 0xffffffff)
return PCIBIOS_BAD_REGISTER_NUMBER;
addr = ixp4xx_config_addr(bus_num, devfn, where);
cmd |= NP_CMD_CONFIGWRITE;
val = value << (8*n);
dev_dbg(p->dev, "write_config_byte %#x to %d size %d dev %d:%d:%d addr: %08x cmd %08x\n",
value, where, size, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn), addr, cmd);
ret = ixp4xx_pci_write(p, addr, cmd, val);
if (ret)
return PCIBIOS_DEVICE_NOT_FOUND;
return PCIBIOS_SUCCESSFUL;
}
static struct pci_ops ixp4xx_pci_ops = {
.read = ixp4xx_pci_read_config,
.write = ixp4xx_pci_write_config,
};
static u32 ixp4xx_pci_addr_to_64mconf(phys_addr_t addr)
{
u8 base;
base = ((addr & 0xff000000) >> 24);
return (base << 24) | ((base + 1) << 16)
| ((base + 2) << 8) | (base + 3);
}
static int ixp4xx_pci_parse_map_ranges(struct ixp4xx_pci *p)
{
struct device *dev = p->dev;
struct pci_host_bridge *bridge = pci_host_bridge_from_priv(p);
struct resource_entry *win;
struct resource *res;
phys_addr_t addr;
win = resource_list_first_type(&bridge->windows, IORESOURCE_MEM);
if (win) {
u32 pcimembase;
res = win->res;
addr = res->start - win->offset;
if (res->flags & IORESOURCE_PREFETCH)
res->name = "IXP4xx PCI PRE-MEM";
else
res->name = "IXP4xx PCI NON-PRE-MEM";
dev_dbg(dev, "%s window %pR, bus addr %pa\n",
res->name, res, &addr);
if (resource_size(res) != SZ_64M) {
dev_err(dev, "memory range is not 64MB\n");
return -EINVAL;
}
pcimembase = ixp4xx_pci_addr_to_64mconf(addr);
/* Commit configuration */
ixp4xx_writel(p, IXP4XX_PCI_PCIMEMBASE, pcimembase);
} else {
dev_err(dev, "no AHB memory mapping defined\n");
}
win = resource_list_first_type(&bridge->windows, IORESOURCE_IO);
if (win) {
res = win->res;
addr = pci_pio_to_address(res->start);
if (addr & 0xff) {
dev_err(dev, "IO mem at uneven address: %pa\n", &addr);
return -EINVAL;
}
res->name = "IXP4xx PCI IO MEM";
/*
* Setup I/O space location for PCI->AHB access, the
* upper 24 bits of the address goes into the lower
* 24 bits of this register.
*/
ixp4xx_writel(p, IXP4XX_PCI_AHBIOBASE, (addr >> 8));
} else {
dev_info(dev, "no IO space AHB memory mapping defined\n");
}
return 0;
}
static int ixp4xx_pci_parse_map_dma_ranges(struct ixp4xx_pci *p)
{
struct device *dev = p->dev;
struct pci_host_bridge *bridge = pci_host_bridge_from_priv(p);
struct resource_entry *win;
struct resource *res;
phys_addr_t addr;
u32 ahbmembase;
win = resource_list_first_type(&bridge->dma_ranges, IORESOURCE_MEM);
if (win) {
res = win->res;
addr = res->start - win->offset;
if (resource_size(res) != SZ_64M) {
dev_err(dev, "DMA memory range is not 64MB\n");
return -EINVAL;
}
dev_dbg(dev, "DMA MEM BASE: %pa\n", &addr);
/*
* 4 PCI-to-AHB windows of 16 MB each, write the 8 high bits
* into each byte of the PCI_AHBMEMBASE register.
*/
ahbmembase = ixp4xx_pci_addr_to_64mconf(addr);
/* Commit AHB membase */
ixp4xx_writel(p, IXP4XX_PCI_AHBMEMBASE, ahbmembase);
} else {
dev_err(dev, "no DMA memory range defined\n");
}
return 0;
}
/* Only used to get context for abort handling */
static struct ixp4xx_pci *ixp4xx_pci_abort_singleton;
static int ixp4xx_pci_abort_handler(unsigned long addr, unsigned int fsr,
struct pt_regs *regs)
{
struct ixp4xx_pci *p = ixp4xx_pci_abort_singleton;
u32 isr, status;
int ret;
isr = ixp4xx_readl(p, IXP4XX_PCI_ISR);
ret = ixp4xx_crp_read_config(p, PCI_STATUS, 2, &status);
if (ret) {
dev_err(p->dev, "unable to read abort status\n");
return -EINVAL;
}
dev_err(p->dev,
"PCI: abort_handler addr = %#lx, isr = %#x, status = %#x\n",
addr, isr, status);
/* Make sure the Master Abort bit is reset */
ixp4xx_writel(p, IXP4XX_PCI_ISR, IXP4XX_PCI_ISR_PFE);
status |= PCI_STATUS_REC_MASTER_ABORT;
ret = ixp4xx_crp_write_config(p, PCI_STATUS, 2, status);
if (ret)
dev_err(p->dev, "unable to clear abort status bit\n");
/*
* If it was an imprecise abort, then we need to correct the
* return address to be _after_ the instruction.
*/
if (fsr & (1 << 10)) {
dev_err(p->dev, "imprecise abort\n");
regs->ARM_pc += 4;
}
return 0;
}
static int __init ixp4xx_pci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct ixp4xx_pci *p;
struct pci_host_bridge *host;
int ret;
u32 val;
phys_addr_t addr;
u32 basereg[4] = {
PCI_BASE_ADDRESS_0,
PCI_BASE_ADDRESS_1,
PCI_BASE_ADDRESS_2,
PCI_BASE_ADDRESS_3,
};
int i;
host = devm_pci_alloc_host_bridge(dev, sizeof(*p));
if (!host)
return -ENOMEM;
host->ops = &ixp4xx_pci_ops;
p = pci_host_bridge_priv(host);
host->sysdata = p;
p->dev = dev;
dev_set_drvdata(dev, p);
/*
* Set up quirk for erratic behaviour in the 42x variant
* when accessing config space.
*/
if (of_device_is_compatible(np, "intel,ixp42x-pci")) {
p->errata_hammer = true;
dev_info(dev, "activate hammering errata\n");
}
p->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(p->base))
return PTR_ERR(p->base);
val = ixp4xx_readl(p, IXP4XX_PCI_CSR);
p->host_mode = !!(val & IXP4XX_PCI_CSR_HOST);
dev_info(dev, "controller is in %s mode\n",
p->host_mode ? "host" : "option");
/* Hook in our fault handler for PCI errors */
ixp4xx_pci_abort_singleton = p;
hook_fault_code(16+6, ixp4xx_pci_abort_handler, SIGBUS, 0,
"imprecise external abort");
ret = ixp4xx_pci_parse_map_ranges(p);
if (ret)
return ret;
ret = ixp4xx_pci_parse_map_dma_ranges(p);
if (ret)
return ret;
/* This is only configured in host mode */
if (p->host_mode) {
addr = __pa(PAGE_OFFSET);
/* This is a noop (0x00) but explains what is going on */
addr |= PCI_BASE_ADDRESS_SPACE_MEMORY;
for (i = 0; i < 4; i++) {
/* Write this directly into the config space */
ret = ixp4xx_crp_write_config(p, basereg[i], 4, addr);
if (ret)
dev_err(dev, "failed to set up PCI_BASE_ADDRESS_%d\n", i);
else
dev_info(dev, "set PCI_BASE_ADDR_%d to %pa\n", i, &addr);
addr += SZ_16M;
}
/*
* Enable CSR window at 64 MiB to allow PCI masters to continue
* prefetching past the 64 MiB boundary, if all AHB to PCI
* windows are consecutive.
*/
ret = ixp4xx_crp_write_config(p, PCI_BASE_ADDRESS_4, 4, addr);
if (ret)
dev_err(dev, "failed to set up PCI_BASE_ADDRESS_4\n");
else
dev_info(dev, "set PCI_BASE_ADDR_4 to %pa\n", &addr);
/*
* Put the IO memory window at the very end of physical memory
* at 0xfffffc00. This is when the system is trying to access IO
* memory over AHB.
*/
addr = 0xfffffc00;
addr |= PCI_BASE_ADDRESS_SPACE_IO;
ret = ixp4xx_crp_write_config(p, PCI_BASE_ADDRESS_5, 4, addr);
if (ret)
dev_err(dev, "failed to set up PCI_BASE_ADDRESS_5\n");
else
dev_info(dev, "set PCI_BASE_ADDR_5 to %pa\n", &addr);
/*
* Retry timeout to 0x80
* Transfer ready timeout to 0xff
*/
ret = ixp4xx_crp_write_config(p, IXP4XX_PCI_RTOTTO, 4,
0x000080ff);
if (ret)
dev_err(dev, "failed to set up TRDY limit\n");
else
dev_info(dev, "set TRDY limit to 0x80ff\n");
}
/* Clear interrupts */
val = IXP4XX_PCI_ISR_PSE | IXP4XX_PCI_ISR_PFE | IXP4XX_PCI_ISR_PPE | IXP4XX_PCI_ISR_AHBE;
ixp4xx_writel(p, IXP4XX_PCI_ISR, val);
/*
* Set Initialize Complete in PCI Control Register: allow IXP4XX to
* generate PCI configuration cycles. Specify that the AHB bus is
* operating in big-endian mode. Set up byte lane swapping between
* little-endian PCI and the big-endian AHB bus.
*/
val = IXP4XX_PCI_CSR_IC | IXP4XX_PCI_CSR_ABE;
if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
val |= (IXP4XX_PCI_CSR_PDS | IXP4XX_PCI_CSR_ADS);
ixp4xx_writel(p, IXP4XX_PCI_CSR, val);
ret = ixp4xx_crp_write_config(p, PCI_COMMAND, 2, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
if (ret)
dev_err(dev, "unable to initialize master and command memory\n");
else
dev_info(dev, "initialized as master\n");
pci_host_probe(host);
return 0;
}
static const struct of_device_id ixp4xx_pci_of_match[] = {
{
.compatible = "intel,ixp42x-pci",
},
{
.compatible = "intel,ixp43x-pci",
},
{},
};
/*
* This driver needs to be a builtin module with suppressed bind
* attributes since the probe() is initializing a hard exception
* handler and this can only be done from __init-tagged code
* sections. This module cannot be removed and inserted at all.
*/
static struct platform_driver ixp4xx_pci_driver = {
.driver = {
.name = "ixp4xx-pci",
.suppress_bind_attrs = true,
.of_match_table = ixp4xx_pci_of_match,
},
};
builtin_platform_driver_probe(ixp4xx_pci_driver, ixp4xx_pci_probe);

View file

@ -20,6 +20,8 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/soc/ixp4xx/npe.h>
#include <mach/hardware.h>
#include <linux/soc/ixp4xx/cpu.h>
#define DEBUG_MSG 0
#define DEBUG_FW 0

View file

@ -12,6 +12,8 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/soc/ixp4xx/qmgr.h>
#include <mach/hardware.h>
#include <linux/soc/ixp4xx/cpu.h>
static struct qmgr_regs __iomem *qmgr_regs;
static int qmgr_irq_1;

View file

@ -0,0 +1,21 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __PLATFORM_DATA_PATA_IXP4XX_H
#define __PLATFORM_DATA_PATA_IXP4XX_H
#include <linux/types.h>
/*
* This structure provide a means for the board setup code
* to give information to th pata_ixp4xx driver. It is
* passed as platform_data.
*/
struct ixp4xx_pata_data {
volatile u32 *cs0_cfg;
volatile u32 *cs1_cfg;
unsigned long cs0_bits;
unsigned long cs1_bits;
void __iomem *cs0;
void __iomem *cs1;
};
#endif

View file

@ -0,0 +1,106 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* IXP4XX cpu type detection
*
* Copyright (C) 2007 MontaVista Software, Inc.
*/
#ifndef __SOC_IXP4XX_CPU_H__
#define __SOC_IXP4XX_CPU_H__
#include <linux/io.h>
#ifdef CONFIG_ARM
#include <asm/cputype.h>
#endif
/* Processor id value in CP15 Register 0 */
#define IXP42X_PROCESSOR_ID_VALUE 0x690541c0 /* including unused 0x690541Ex */
#define IXP42X_PROCESSOR_ID_MASK 0xffffffc0
#define IXP43X_PROCESSOR_ID_VALUE 0x69054040
#define IXP43X_PROCESSOR_ID_MASK 0xfffffff0
#define IXP46X_PROCESSOR_ID_VALUE 0x69054200 /* including IXP455 */
#define IXP46X_PROCESSOR_ID_MASK 0xfffffff0
/* "fuse" bits of IXP_EXP_CFG2 */
/* All IXP4xx CPUs */
#define IXP4XX_FEATURE_RCOMP (1 << 0)
#define IXP4XX_FEATURE_USB_DEVICE (1 << 1)
#define IXP4XX_FEATURE_HASH (1 << 2)
#define IXP4XX_FEATURE_AES (1 << 3)
#define IXP4XX_FEATURE_DES (1 << 4)
#define IXP4XX_FEATURE_HDLC (1 << 5)
#define IXP4XX_FEATURE_AAL (1 << 6)
#define IXP4XX_FEATURE_HSS (1 << 7)
#define IXP4XX_FEATURE_UTOPIA (1 << 8)
#define IXP4XX_FEATURE_NPEB_ETH0 (1 << 9)
#define IXP4XX_FEATURE_NPEC_ETH (1 << 10)
#define IXP4XX_FEATURE_RESET_NPEA (1 << 11)
#define IXP4XX_FEATURE_RESET_NPEB (1 << 12)
#define IXP4XX_FEATURE_RESET_NPEC (1 << 13)
#define IXP4XX_FEATURE_PCI (1 << 14)
#define IXP4XX_FEATURE_UTOPIA_PHY_LIMIT (3 << 16)
#define IXP4XX_FEATURE_XSCALE_MAX_FREQ (3 << 22)
#define IXP42X_FEATURE_MASK (IXP4XX_FEATURE_RCOMP | \
IXP4XX_FEATURE_USB_DEVICE | \
IXP4XX_FEATURE_HASH | \
IXP4XX_FEATURE_AES | \
IXP4XX_FEATURE_DES | \
IXP4XX_FEATURE_HDLC | \
IXP4XX_FEATURE_AAL | \
IXP4XX_FEATURE_HSS | \
IXP4XX_FEATURE_UTOPIA | \
IXP4XX_FEATURE_NPEB_ETH0 | \
IXP4XX_FEATURE_NPEC_ETH | \
IXP4XX_FEATURE_RESET_NPEA | \
IXP4XX_FEATURE_RESET_NPEB | \
IXP4XX_FEATURE_RESET_NPEC | \
IXP4XX_FEATURE_PCI | \
IXP4XX_FEATURE_UTOPIA_PHY_LIMIT | \
IXP4XX_FEATURE_XSCALE_MAX_FREQ)
/* IXP43x/46x CPUs */
#define IXP4XX_FEATURE_ECC_TIMESYNC (1 << 15)
#define IXP4XX_FEATURE_USB_HOST (1 << 18)
#define IXP4XX_FEATURE_NPEA_ETH (1 << 19)
#define IXP43X_FEATURE_MASK (IXP42X_FEATURE_MASK | \
IXP4XX_FEATURE_ECC_TIMESYNC | \
IXP4XX_FEATURE_USB_HOST | \
IXP4XX_FEATURE_NPEA_ETH)
/* IXP46x CPU (including IXP455) only */
#define IXP4XX_FEATURE_NPEB_ETH_1_TO_3 (1 << 20)
#define IXP4XX_FEATURE_RSA (1 << 21)
#define IXP46X_FEATURE_MASK (IXP43X_FEATURE_MASK | \
IXP4XX_FEATURE_NPEB_ETH_1_TO_3 | \
IXP4XX_FEATURE_RSA)
#ifdef CONFIG_ARCH_IXP4XX
#define cpu_is_ixp42x_rev_a0() ((read_cpuid_id() & (IXP42X_PROCESSOR_ID_MASK | 0xF)) == \
IXP42X_PROCESSOR_ID_VALUE)
#define cpu_is_ixp42x() ((read_cpuid_id() & IXP42X_PROCESSOR_ID_MASK) == \
IXP42X_PROCESSOR_ID_VALUE)
#define cpu_is_ixp43x() ((read_cpuid_id() & IXP43X_PROCESSOR_ID_MASK) == \
IXP43X_PROCESSOR_ID_VALUE)
#define cpu_is_ixp46x() ((read_cpuid_id() & IXP46X_PROCESSOR_ID_MASK) == \
IXP46X_PROCESSOR_ID_VALUE)
u32 ixp4xx_read_feature_bits(void);
void ixp4xx_write_feature_bits(u32 value);
#else
#define cpu_is_ixp42x_rev_a0() 0
#define cpu_is_ixp42x() 0
#define cpu_is_ixp43x() 0
#define cpu_is_ixp46x() 0
static inline u32 ixp4xx_read_feature_bits(void)
{
return 0;
}
static inline void ixp4xx_write_feature_bits(u32 value)
{
}
#endif
#endif /* _ASM_ARCH_CPU_H */