summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/boards/stm32mp.rst10
-rw-r--r--Documentation/devicetree/bindings/leds/common.rst7
-rwxr-xr-xDocumentation/gen_commands.py2
-rw-r--r--Documentation/user/usb.rst2
-rwxr-xr-xMAKEALL2
-rw-r--r--Makefile2
-rw-r--r--README15
-rw-r--r--arch/arm/Kconfig5
-rw-r--r--arch/arm/boards/avnet-zedboard/lowlevel.c21
-rw-r--r--arch/arm/boards/eukrea_cpuimx25/eukrea_cpuimx25.c4
-rw-r--r--arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c4
-rw-r--r--arch/arm/boards/ls1046ardb/board.c122
-rw-r--r--arch/arm/boards/phytec-som-imx6/defaultenv-physom-imx6-phycore/init/bootsource2
-rw-r--r--arch/arm/boards/phytec-som-imx6/defaultenv-physom-imx6/init/bootsource2
-rw-r--r--arch/arm/boards/stm32mp157c-dk2/board.c11
-rw-r--r--arch/arm/boards/stm32mp157c-dk2/lowlevel.c17
-rw-r--r--arch/arm/boards/wago-pfc-am35xx/board-mlo.c4
-rw-r--r--arch/arm/configs/zynqmp_defconfig4
-rw-r--r--arch/arm/cpu/Makefile3
-rw-r--r--arch/arm/cpu/common.c4
-rw-r--r--arch/arm/cpu/dtb.c2
-rw-r--r--arch/arm/cpu/mmu-early_64.c6
-rw-r--r--arch/arm/cpu/mmu_64.c7
-rw-r--r--arch/arm/cpu/mmu_64.h9
-rw-r--r--arch/arm/cpu/psci.c104
-rw-r--r--arch/arm/cpu/start.c22
-rw-r--r--arch/arm/dts/Makefile3
-rw-r--r--arch/arm/dts/fsl-ls1046a-rdb.dts46
-rw-r--r--arch/arm/dts/fsl-tqmls1046a-mbls10xxa.dts50
-rw-r--r--arch/arm/dts/imx6dl-phytec-phycore-som-emmc.dts33
-rw-r--r--arch/arm/dts/imx6dl-phytec-phycore-som-lc-emmc.dts20
-rw-r--r--arch/arm/dts/imx6dl-phytec-phycore-som-lc-nand.dts14
-rw-r--r--arch/arm/dts/imx6dl-phytec-phycore-som-nand.dts30
-rw-r--r--arch/arm/dts/imx6q-phytec-phycore-som-emmc.dts36
-rw-r--r--arch/arm/dts/imx6q-phytec-phycore-som-nand.dts36
-rw-r--r--arch/arm/dts/imx6qdl-phytec-mira.dtsi44
-rw-r--r--arch/arm/dts/imx6qdl-phytec-phycore-som.dtsi297
-rw-r--r--arch/arm/dts/imx6qp-phytec-phycore-som-nand.dts35
-rw-r--r--arch/arm/dts/stm32mp157a-dk1.dtsi4
-rw-r--r--arch/arm/dts/stm32mp157c.dtsi8
-rw-r--r--arch/arm/include/asm/barebox-arm-head.h4
-rw-r--r--arch/arm/include/asm/pgtable64.h5
-rw-r--r--arch/arm/lib32/Makefile1
-rw-r--r--arch/arm/lib32/start-kernel-optee.S (renamed from arch/arm/cpu/start-kernel-optee.S)0
-rw-r--r--arch/arm/mach-at91/Kconfig1
-rw-r--r--arch/arm/mach-davinci/Kconfig2
-rw-r--r--arch/arm/mach-imx/include/mach/vf610.h2
-rw-r--r--arch/arm/mach-imx/vf610.c8
-rw-r--r--arch/arm/mach-layerscape/Kconfig3
-rw-r--r--arch/arm/mach-layerscape/ppa.c23
-rw-r--r--arch/arm/mach-mxs/bcb.c2
-rw-r--r--arch/arm/mach-stm32mp/Makefile1
-rw-r--r--arch/arm/mach-stm32mp/ddrctrl.c155
-rw-r--r--arch/arm/mach-stm32mp/include/mach/ddr_regs.h368
-rw-r--r--arch/arm/mach-stm32mp/include/mach/entry.h19
-rw-r--r--arch/arm/mach-stm32mp/include/mach/stm32.h2
-rw-r--r--arch/arm/mach-zynq/Makefile2
-rw-r--r--arch/arm/mach-zynq/bootm-zynqimg.c49
-rw-r--r--arch/mips/Makefile4
-rw-r--r--arch/mips/mach-ath79/art.c2
-rw-r--r--arch/x86/mach-efi/elf_x86_64_efi.lds.S7
-rw-r--r--commands/Kconfig15
-rw-r--r--commands/Makefile1
-rw-r--r--commands/digest.c2
-rw-r--r--commands/gpio.c4
-rw-r--r--commands/keystore.c2
-rw-r--r--commands/nv.c5
-rw-r--r--commands/smc.c162
-rw-r--r--common/Kconfig26
-rw-r--r--common/Makefile3
-rw-r--r--common/console_simple.c11
-rw-r--r--common/efi/efi.c2
-rw-r--r--common/envfs-core.c197
-rw-r--r--common/environment.c172
-rw-r--r--common/filetype.c26
-rw-r--r--common/globalvar.c16
-rw-r--r--common/ratp/Kconfig1
-rw-r--r--common/startup.c24
-rw-r--r--drivers/Makefile4
-rw-r--r--drivers/block/efi-block-io.c11
-rw-r--r--drivers/bus/Kconfig8
-rw-r--r--drivers/bus/Makefile1
-rw-r--r--drivers/bus/acpi.c255
-rw-r--r--drivers/clk/imx/clk-imx6ul.c3
-rw-r--r--drivers/clocksource/Kconfig2
-rw-r--r--drivers/efi/efi-device.c11
-rw-r--r--drivers/firmware/zynqmp-fpga.c121
-rw-r--r--drivers/gpio/gpiolib.c47
-rw-r--r--drivers/i2c/Makefile3
-rw-r--r--drivers/i2c/busses/i2c-gpio.c4
-rw-r--r--drivers/i2c/busses/i2c-stm32.c11
-rw-r--r--drivers/input/Kconfig1
-rw-r--r--drivers/led/core.c64
-rw-r--r--drivers/led/led-triggers.c25
-rw-r--r--drivers/mci/Kconfig20
-rw-r--r--drivers/mci/Makefile6
-rw-r--r--drivers/mci/arasan-sdhci.c423
-rw-r--r--drivers/mci/dove-sdhci.c159
-rw-r--r--drivers/mci/imx-esdhc-common.c275
-rw-r--r--drivers/mci/imx-esdhc-pbl.c333
-rw-r--r--drivers/mci/imx-esdhc.c443
-rw-r--r--drivers/mci/imx-esdhc.h108
-rw-r--r--drivers/mci/mci-bcm2835.c227
-rw-r--r--drivers/mci/mci-core.c4
-rw-r--r--drivers/mci/sdhci.c140
-rw-r--r--drivers/mci/sdhci.h127
-rw-r--r--drivers/mci/tegra-sdmmc.c159
-rw-r--r--drivers/mfd/da9053.c2
-rw-r--r--drivers/mfd/da9063.c16
-rw-r--r--drivers/mfd/stpmic1.c3
-rw-r--r--drivers/mfd/superio.c4
-rw-r--r--drivers/misc/Kconfig7
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/acpi-test.c61
-rw-r--r--drivers/mtd/nand/nand_base.c4
-rw-r--r--drivers/mtd/spi-nor/spi-nor.c4
-rw-r--r--drivers/net/Kconfig3
-rw-r--r--drivers/net/designware_eqos.c18
-rw-r--r--drivers/net/designware_eqos.h4
-rw-r--r--drivers/net/designware_stm32.c32
-rw-r--r--drivers/net/designware_tegra186.c45
-rw-r--r--drivers/net/fsl-fman.c128
-rw-r--r--drivers/nvme/host/core.c2
-rw-r--r--drivers/nvmem/bsec.c4
-rw-r--r--drivers/of/address.c24
-rw-r--r--drivers/of/base.c122
-rw-r--r--drivers/pci/Kconfig7
-rw-r--r--drivers/pci/Makefile1
-rw-r--r--drivers/pci/bus.c26
-rw-r--r--drivers/pci/pci-imx6.c11
-rw-r--r--drivers/pci/pci-layerscape.c484
-rw-r--r--drivers/pci/pcie-designware-host.c16
-rw-r--r--drivers/pci/pcie-designware.c108
-rw-r--r--drivers/pci/pcie-designware.h152
-rw-r--r--drivers/pinctrl/Kconfig20
-rw-r--r--drivers/pinctrl/pinctrl-tegra30.c4
-rw-r--r--drivers/remoteproc/Kconfig10
-rw-r--r--drivers/remoteproc/Makefile1
-rw-r--r--drivers/remoteproc/remoteproc_core.c29
-rw-r--r--drivers/remoteproc/stm32_rproc.c199
-rw-r--r--drivers/serial/Kconfig8
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/serial_ns16550_pci.c5311
-rw-r--r--drivers/spi/spi.c2
-rw-r--r--drivers/usb/dwc3/Kconfig3
-rw-r--r--drivers/usb/dwc3/core.c25
-rw-r--r--drivers/usb/dwc3/core.h1
-rw-r--r--drivers/usb/gadget/f_fastboot.c2
-rw-r--r--drivers/usb/imx/Kconfig1
-rw-r--r--drivers/usb/imx/chipidea-imx.c85
-rw-r--r--drivers/usb/misc/Kconfig1
-rw-r--r--drivers/usb/musb/Kconfig1
-rw-r--r--drivers/usb/musb/musb_dsps.c44
-rw-r--r--drivers/usb/otg/Kconfig4
-rw-r--r--drivers/usb/otg/Makefile2
-rw-r--r--drivers/usb/otg/otgdev.c69
-rw-r--r--drivers/watchdog/stm32_iwdg.c3
-rw-r--r--drivers/watchdog/stpmic1_wdt.c28
-rw-r--r--drivers/watchdog/wd_core.c9
-rwxr-xr-xdts/scripts/cronjob2
-rwxr-xr-xdts/scripts/index-filter.sh2
-rwxr-xr-xdts/scripts/merge-new-release.sh2
-rw-r--r--dts/src/arm/imx6-logicpd-baseboard.dtsi4
-rw-r--r--dts/src/arm/imx6qdl-sabreauto.dtsi8
-rw-r--r--dts/src/arm/stm32mp157c-ev1.dts13
-rw-r--r--dts/src/arm/stm32mp157c.dtsi4
-rw-r--r--dts/src/arm/sun8i-a83t-tbs-a711.dts1
-rw-r--r--dts/src/arm64/freescale/fsl-ls1028a-qds.dts2
-rw-r--r--dts/src/arm64/freescale/imx8mm.dtsi6
-rw-r--r--dts/src/arm64/freescale/imx8mn.dtsi6
-rw-r--r--dts/src/arm64/freescale/imx8mq-zii-ultra.dtsi2
-rw-r--r--fs/pstore/platform.c32
-rw-r--r--fs/pstore/ram.c9
-rw-r--r--images/.gitignore1
-rw-r--r--images/Makefile.imx33
-rw-r--r--include/acpi.h73
-rw-r--r--include/common.h5
-rw-r--r--include/console.h5
-rw-r--r--include/driver.h4
-rw-r--r--include/efi.h42
-rw-r--r--include/efi/efi-device.h12
-rw-r--r--include/envfs.h5
-rw-r--r--include/filetype.h1
-rw-r--r--include/gpio.h6
-rw-r--r--include/linux/mod_devicetable.h1
-rw-r--r--include/linux/mtd/spi-nor.h2
-rw-r--r--include/linux/pci.h34
-rw-r--r--include/linux/remoteproc.h1
-rw-r--r--include/of.h83
-rw-r--r--include/param.h24
-rw-r--r--include/reset_source.h5
-rw-r--r--include/soc/fsl/fsl_fman.h3
-rw-r--r--include/usb/chipidea-imx.h8
-rw-r--r--include/usb/usb.h3
-rw-r--r--include/watchdog.h5
-rw-r--r--lib/Kconfig5
-rw-r--r--lib/gui/picopng.c60
-rw-r--r--lib/parameter.c22
-rw-r--r--lib/zstd/decompress.c10
-rw-r--r--scripts/bareboxenv.c1
-rwxr-xr-xscripts/canon-a1100-image4
-rwxr-xr-xscripts/check_size2
-rwxr-xr-xscripts/dfuboot.sh2
-rwxr-xr-xscripts/extract_symbol_offset2
-rwxr-xr-xscripts/gen-dtb-s2
-rwxr-xr-xscripts/genenv2
-rw-r--r--scripts/imx/imx.c23
-rwxr-xr-xscripts/socfpga_get_sequencer2
-rwxr-xr-xscripts/socfpga_import_preloader2
-rwxr-xr-xscripts/socfpga_xml_to_config.sh2
210 files changed, 10385 insertions, 2730 deletions
diff --git a/Documentation/boards/stm32mp.rst b/Documentation/boards/stm32mp.rst
index f93ec04..6d97b0d 100644
--- a/Documentation/boards/stm32mp.rst
+++ b/Documentation/boards/stm32mp.rst
@@ -81,3 +81,13 @@ pulled down and BOOT0 and BOOT2 are connected to a 2P DIP switch::
BOOT2 | O --O |
BOOT0 | N --O | <---- DFU on UART and USB OTG
+-------+
+
+Boot status indicator
+---------------------
+
+The ROM code on the first Cortex-A7 core pulses the PA13 pad.
+An error LED on this pad can be used to indicate boot status:
+
+* **Boot Failure:** LED lights bright
+* **UART/USB Boot:** LED blinks fast
+* **Debug access:** LED lights weak
diff --git a/Documentation/devicetree/bindings/leds/common.rst b/Documentation/devicetree/bindings/leds/common.rst
index 1f5ae42..911a55f 100644
--- a/Documentation/devicetree/bindings/leds/common.rst
+++ b/Documentation/devicetree/bindings/leds/common.rst
@@ -6,7 +6,12 @@ Common leds properties
* ``heartbeat`` - LED flashes at a constant rate
* ``panic`` - LED turns on when barebox panics
- * ``net`` - LED indicates network activity
+ * ``net`` - LED indicates network activity (tx and rx)
+ * ``net-rx`` - LED indicates network activity (rx only)
+ * ``net-tx`` - LED indicates network activity (tx only)
* ``label``: The label for this LED. If omitted, the label is taken
from the node name (excluding the unit address).
+
+* ``panic-indicator`` - This property specifies that the LED should be used as a
+ panic indicator.
diff --git a/Documentation/gen_commands.py b/Documentation/gen_commands.py
index 203a39b..a55b1ac 100755
--- a/Documentation/gen_commands.py
+++ b/Documentation/gen_commands.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
from __future__ import print_function
diff --git a/Documentation/user/usb.rst b/Documentation/user/usb.rst
index 029e463..4c1b292 100644
--- a/Documentation/user/usb.rst
+++ b/Documentation/user/usb.rst
@@ -172,7 +172,7 @@ and initrd:
.. code-block:: sh
- #!/bin/bash
+ #!/usr/bin/env bash
set -e
set -v
diff --git a/MAKEALL b/MAKEALL
index 909e170..3548739 100755
--- a/MAKEALL
+++ b/MAKEALL
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
# Print statistics when we exit
trap exit 1 2 3 15
diff --git a/Makefile b/Makefile
index b21ad5f..600ca36 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
VERSION = 2019
-PATCHLEVEL = 11
+PATCHLEVEL = 12
SUBLEVEL = 0
EXTRAVERSION =
NAME = None
diff --git a/README b/README
index dada97c..d8077d2 100644
--- a/README
+++ b/README
@@ -225,6 +225,21 @@ are the release rules:
people.
+Contributing
+------------
+
+For any questions regarding Barebox, send a mail to the mailing list at
+<barebox@lists.infradead.org>. The archives for this list are available
+publicly at <http://lists.infradead.org/pipermail/barebox/> and
+<https://www.mail-archive.com/barebox@lists.infradead.org/>.
+
+The same list should also be used to send patches. Barebox uses a similar
+process as the Linux kernel, so most of the Linux guide for submitting patches
+<https://www.kernel.org/doc/html/latest/process/submitting-patches.html> also
+applies to Barebox (except the step for selecting your recipient - we don't
+have a MAINTAINERS file, instead all patches go to the list).
+
+
License
-------
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 6eb1174..dfb1877 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -106,6 +106,9 @@ config ARCH_LAYERSCAPE
select COMMON_CLK
select CLKDEV_LOOKUP
select COMMON_CLK_OF_PROVIDER
+ select HW_HAS_PCI
+ select OFTREE
+ select OFDEVICE
config ARCH_MVEBU
bool "Marvell EBU platforms"
@@ -434,6 +437,7 @@ config ARM_SMCCC
This option enables barebox to invoke ARM secure monitor calls.
config ARM_SECURE_MONITOR
+ depends on CPU_32v7 || CPU_64v8
select ARM_SMCCC
bool
help
@@ -453,6 +457,7 @@ config ARM_PSCI
config ARM_PSCI_CLIENT
bool "Enable barebox PSCI client support"
+ depends on CPU_32v7 || CPU_64v8
select ARM_SMCCC
select ARM_PSCI_OF
help
diff --git a/arch/arm/boards/avnet-zedboard/lowlevel.c b/arch/arm/boards/avnet-zedboard/lowlevel.c
index 93e4da9..9b90ef1 100644
--- a/arch/arm/boards/avnet-zedboard/lowlevel.c
+++ b/arch/arm/boards/avnet-zedboard/lowlevel.c
@@ -29,10 +29,17 @@
extern char __dtb_zynq_zed_start[];
-ENTRY_FUNCTION(start_avnet_zedboard, r0, r1, r2)
+static void avnet_zedboard_ps7_init(void)
{
-
- void *fdt = __dtb_zynq_zed_start + get_runtime_offset();
+ /*
+ * Read OCM mapping configuration, if only the upper 64 KByte are
+ * mapped to the high address, it's very likely that we just got control
+ * from the BootROM. If the mapping is changed something other than the
+ * BootROM was running before us. Skip PS7 init to avoid cutting the
+ * branch we are sitting on in that case.
+ */
+ if ((readl(0xf8000910) & 0xf) != 0x8)
+ return;
/* open sesame */
writel(0x0000DF0D, ZYNQ_SLCR_UNLOCK);
@@ -260,8 +267,16 @@ ENTRY_FUNCTION(start_avnet_zedboard, r0, r1, r2)
/* lock up. secure, secure */
writel(0x0000767B, ZYNQ_SLCR_LOCK);
+}
+
+ENTRY_FUNCTION(start_avnet_zedboard, r0, r1, r2)
+{
+
+ void *fdt = __dtb_zynq_zed_start + get_runtime_offset();
arm_cpu_lowlevel_init();
+ avnet_zedboard_ps7_init();
+
barebox_arm_entry(0, SZ_512M, fdt);
}
diff --git a/arch/arm/boards/eukrea_cpuimx25/eukrea_cpuimx25.c b/arch/arm/boards/eukrea_cpuimx25/eukrea_cpuimx25.c
index 76d6f5b..77d92f0 100644
--- a/arch/arm/boards/eukrea_cpuimx25/eukrea_cpuimx25.c
+++ b/arch/arm/boards/eukrea_cpuimx25/eukrea_cpuimx25.c
@@ -145,14 +145,14 @@ static iomux_v3_cfg_t eukrea_cpuimx25_pads[] = {
#ifndef CONFIG_USB_GADGET
struct imxusb_platformdata otg_pdata = {
.flags = MXC_EHCI_INTERFACE_DIFF_UNI,
- .mode = IMX_USB_MODE_HOST,
+ .mode = USB_DR_MODE_HOST,
.phymode = USBPHY_INTERFACE_MODE_UTMI,
};
#endif
struct imxusb_platformdata hs_pdata = {
.flags = MXC_EHCI_INTERFACE_SINGLE_UNI | MXC_EHCI_INTERNAL_PHY | MXC_EHCI_IPPUE_DOWN,
- .mode = IMX_USB_MODE_HOST,
+ .mode = USB_DR_MODE_HOST,
};
#endif
diff --git a/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c b/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c
index a107637..220a484 100644
--- a/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c
+++ b/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c
@@ -95,14 +95,14 @@ static struct imx_ipu_fb_platform_data ipu_fb_data = {
#ifndef CONFIG_USB_GADGET
struct imxusb_platformdata otg_pdata = {
.flags = MXC_EHCI_INTERFACE_DIFF_UNI,
- .mode = IMX_USB_MODE_HOST,
+ .mode = USB_DR_MODE_HOST,
.phymode = USBPHY_INTERFACE_MODE_UTMI,
};
#endif
struct imxusb_platformdata hs_pdata = {
.flags = MXC_EHCI_INTERFACE_SINGLE_UNI | MXC_EHCI_INTERNAL_PHY | MXC_EHCI_IPPUE_DOWN,
- .mode = IMX_USB_MODE_HOST,
+ .mode = USB_DR_MODE_HOST,
};
#endif
diff --git a/arch/arm/boards/ls1046ardb/board.c b/arch/arm/boards/ls1046ardb/board.c
index 0846df9..ef68e9c 100644
--- a/arch/arm/boards/ls1046ardb/board.c
+++ b/arch/arm/boards/ls1046ardb/board.c
@@ -2,13 +2,132 @@
#include <common.h>
#include <init.h>
+#include <bbu.h>
+#include <net.h>
+#include <crc.h>
+#include <fs.h>
#include <envfs.h>
+#include <libfile.h>
#include <asm/memory.h>
#include <linux/sizes.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <asm/system.h>
#include <mach/layerscape.h>
+#include <mach/bbu.h>
+
+#define MAX_NUM_PORTS 16
+struct nxid {
+ u8 id[4]; /* 0x00 - 0x03 EEPROM Tag 'NXID' */
+ u8 sn[12]; /* 0x04 - 0x0F Serial Number */
+ u8 errata[5]; /* 0x10 - 0x14 Errata Level */
+ u8 date[6]; /* 0x15 - 0x1a Build Date */
+ u8 res_0; /* 0x1b Reserved */
+ u32 version; /* 0x1c - 0x1f NXID Version */
+ u8 tempcal[8]; /* 0x20 - 0x27 Temperature Calibration Factors */
+ u8 tempcalsys[2]; /* 0x28 - 0x29 System Temperature Calibration Factors */
+ u8 tempcalflags; /* 0x2a Temperature Calibration Flags */
+ u8 res_1[21]; /* 0x2b - 0x3f Reserved */
+ u8 mac_count; /* 0x40 Number of MAC addresses */
+ u8 mac_flag; /* 0x41 MAC table flags */
+ u8 mac[MAX_NUM_PORTS][6]; /* 0x42 - 0xa1 MAC addresses */
+ u8 res_2[90]; /* 0xa2 - 0xfb Reserved */
+ u32 crc; /* 0xfc - 0xff CRC32 checksum */
+} __packed;
+
+static int nxid_is_valid(struct nxid *nxid)
+{
+ unsigned char id[] = { 'N', 'X', 'I', 'D' };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(id); i++)
+ if (nxid->id[i] != id[i])
+ return false;
+ return true;
+}
+
+static struct nxid *nxp_nxid_read(const char *filename, unsigned int offset)
+{
+ struct nxid *nxid;
+ int fd, ret, i, n;
+ struct device_node *root;
+ u32 crc, crc_expected;
+
+ nxid = xzalloc(sizeof(*nxid));
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ ret = -errno;
+ goto out;
+ }
+
+ ret = pread(fd, nxid, sizeof(*nxid), offset);
+ if (ret < 0) {
+ close(fd);
+ goto out;
+ }
+
+ if (!nxid_is_valid(nxid)) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ crc = crc32(0, nxid, 256 - 4);
+ crc_expected = be32_to_cpu(nxid->crc);
+ if (crc != crc_expected) {
+ pr_err("CRC mismatch (%08x != %08x)\n", crc, crc_expected);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ root = of_get_root_node();
+
+ i = n = 0;
+
+ /*
+ * The MAC addresses in the nxid structure are in the order of enabled
+ * network interfaces. We have to find the network interfaces by their
+ * aliases and skip assigning MAC addresses to disabled devices.
+ */
+ while (1) {
+ struct device_node *np;
+ char alias[sizeof("ethernetxxx")];
+
+ sprintf(alias, "ethernet%d", n);
+
+ np = of_find_node_by_alias(root, alias);
+ if (!np)
+ goto out;
+
+ n++;
+ if (!of_device_is_available(np))
+ continue;
+
+ of_eth_register_ethaddr(np, (char *)nxid->mac[i]);
+
+ i++;
+
+ if (i == nxid->mac_count)
+ break;
+ }
+
+ ret = 0;
+out:
+ if (ret) {
+ free(nxid);
+ nxid = ERR_PTR(ret);
+ }
+
+ return nxid;
+}
+
+static int rdb_late_init(void)
+{
+ nxp_nxid_read("/dev/eeprom", 256);
+
+ return 0;
+}
+late_initcall(rdb_late_init);
static int rdb_mem_init(void)
{
@@ -35,6 +154,9 @@ static int rdb_postcore_init(void)
defaultenv_append_directory(defaultenv_ls1046ardb);
+ ls1046a_bbu_mmc_register_handler("sd", "/dev/mmc0.barebox",
+ BBU_HANDLER_FLAG_DEFAULT);
+
return 0;
}
diff --git a/arch/arm/boards/phytec-som-imx6/defaultenv-physom-imx6-phycore/init/bootsource b/arch/arm/boards/phytec-som-imx6/defaultenv-physom-imx6-phycore/init/bootsource
index 515613b..fa5f7f2 100644
--- a/arch/arm/boards/phytec-som-imx6/defaultenv-physom-imx6-phycore/init/bootsource
+++ b/arch/arm/boards/phytec-som-imx6/defaultenv-physom-imx6-phycore/init/bootsource
@@ -12,7 +12,7 @@ if [ $bootsource = mmc ]; then
fi
elif [ $bootsource = nand ]; then
global.boot.default="nand spi emmc mmc net"
-elif [ $bootsource = spi ]; then
+elif [ $bootsource = spi-nor ]; then
global.boot.default="spi nand emmc mmc net"
elif [ $bootsource = net ]; then
global.boot.default="net nand spi emmc mmc"
diff --git a/arch/arm/boards/phytec-som-imx6/defaultenv-physom-imx6/init/bootsource b/arch/arm/boards/phytec-som-imx6/defaultenv-physom-imx6/init/bootsource
index 3f2ff4b..9c9f0ec 100644
--- a/arch/arm/boards/phytec-som-imx6/defaultenv-physom-imx6/init/bootsource
+++ b/arch/arm/boards/phytec-som-imx6/defaultenv-physom-imx6/init/bootsource
@@ -8,7 +8,7 @@ if [ $bootsource = mmc ]; then
global.boot.default="mmc nand spi net"
elif [ $bootsource = nand ]; then
global.boot.default="nand spi mmc net"
-elif [ $bootsource = spi ]; then
+elif [ $bootsource = spi-nor ]; then
global.boot.default="spi nand mmc net"
elif [ $bootsource = net ]; then
global.boot.default="net nand spi mmc"
diff --git a/arch/arm/boards/stm32mp157c-dk2/board.c b/arch/arm/boards/stm32mp157c-dk2/board.c
index f15ae0b..9cd5b4e 100644
--- a/arch/arm/boards/stm32mp157c-dk2/board.c
+++ b/arch/arm/boards/stm32mp157c-dk2/board.c
@@ -6,17 +6,6 @@
#include <mach/stm32.h>
#include <mach/bbu.h>
-static int dk2_mem_init(void)
-{
- if (!of_machine_is_compatible("st,stm32mp157c-dk2"))
- return 0;
-
- arm_add_mem_device("ram0", STM32_DDR_BASE, SZ_512M);
-
- return 0;
-}
-mem_initcall(dk2_mem_init);
-
static int dk2_postcore_init(void)
{
if (!of_machine_is_compatible("st,stm32mp157c-dk2"))
diff --git a/arch/arm/boards/stm32mp157c-dk2/lowlevel.c b/arch/arm/boards/stm32mp157c-dk2/lowlevel.c
index 566ace7..7261d7a 100644
--- a/arch/arm/boards/stm32mp157c-dk2/lowlevel.c
+++ b/arch/arm/boards/stm32mp157c-dk2/lowlevel.c
@@ -1,19 +1,26 @@
// SPDX-License-Identifier: GPL-2.0+
#include <common.h>
-#include <asm/barebox-arm-head.h>
-#include <asm/barebox-arm.h>
-#include <mach/stm32.h>
+#include <mach/entry.h>
#include <debug_ll.h>
extern char __dtb_z_stm32mp157c_dk2_start[];
+static void setup_uart(void)
+{
+ /* first stage has set up the UART, so nothing to do here */
+ putc_ll('>');
+}
+
ENTRY_FUNCTION(start_stm32mp157c_dk2, r0, r1, r2)
{
void *fdt;
- arm_cpu_lowlevel_init();
+ stm32mp_cpu_lowlevel_init();
+
+ if (IS_ENABLED(CONFIG_DEBUG_LL))
+ setup_uart();
fdt = __dtb_z_stm32mp157c_dk2_start + get_runtime_offset();
- barebox_arm_entry(STM32_DDR_BASE, SZ_512M, fdt);
+ stm32mp1_barebox_entry(fdt);
}
diff --git a/arch/arm/boards/wago-pfc-am35xx/board-mlo.c b/arch/arm/boards/wago-pfc-am35xx/board-mlo.c
index 7925c71..c940565 100644
--- a/arch/arm/boards/wago-pfc-am35xx/board-mlo.c
+++ b/arch/arm/boards/wago-pfc-am35xx/board-mlo.c
@@ -48,7 +48,7 @@ static int pfc200_mem_init(void)
}
mem_initcall(pfc200_mem_init);
-static struct gpmc_nand_platform_data nand_plat = {
+__maybe_unused static struct gpmc_nand_platform_data nand_plat = {
.cs = 0,
.device_width = 8,
.ecc_mode = OMAP_ECC_BCH8_CODE_HW_ROMCODE,
@@ -62,8 +62,8 @@ static int pfc200_init_devices(void)
* WP is made high and WAIT1 active Low
*/
gpmc_generic_init(0x10);
-#endif
omap_add_gpmc_nand_device(&nand_plat);
+#endif
omap_set_barebox_part(&pfc200_mlo_part);
omap3_add_mmc1(NULL);
diff --git a/arch/arm/configs/zynqmp_defconfig b/arch/arm/configs/zynqmp_defconfig
index 834212e..762103c 100644
--- a/arch/arm/configs/zynqmp_defconfig
+++ b/arch/arm/configs/zynqmp_defconfig
@@ -33,7 +33,9 @@ CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_CLK=y
CONFIG_CMD_OFTREE=y
CONFIG_CMD_TIME=y
+CONFIG_NET=y
CONFIG_DRIVER_SERIAL_CADENCE=y
+CONFIG_DRIVER_NET_MACB=y
# CONFIG_SPI is not set
-CONFIG_FIRMWARE_ZYNQMP_PL=y
+CONFIG_FIRMWARE_ZYNQMP_FPGA=y
CONFIG_DIGEST=y
diff --git a/arch/arm/cpu/Makefile b/arch/arm/cpu/Makefile
index 09b3bc2..63cf35c 100644
--- a/arch/arm/cpu/Makefile
+++ b/arch/arm/cpu/Makefile
@@ -2,7 +2,7 @@ obj-y += cpu.o
obj-$(CONFIG_ARM_EXCEPTIONS) += exceptions$(S64).o interrupts$(S64).o
obj-$(CONFIG_MMU) += mmu$(S64).o mmu-common.o
-lwl-y += lowlevel$(S64).o
+obj-pbl-y += lowlevel$(S64).o
obj-pbl-$(CONFIG_MMU) += mmu-early$(S64).o
obj-pbl-$(CONFIG_CPU_32v7) += hyp.o
AFLAGS_hyp.o :=-Wa,-march=armv7-a -Wa,-mcpu=all
@@ -15,7 +15,6 @@ pbl-$(CONFIG_BOARD_ARM_GENERIC_DT_AARCH64) += board-dt-2nd-aarch64.o
obj-pbl-y += setupc$(S64).o cache$(S64).o
-obj-$(CONFIG_BOOTM_OPTEE) += start-kernel-optee.o
obj-$(CONFIG_ARM_PSCI_CLIENT) += psci-client.o
#
diff --git a/arch/arm/cpu/common.c b/arch/arm/cpu/common.c
index c81b2b3..c7d1709 100644
--- a/arch/arm/cpu/common.c
+++ b/arch/arm/cpu/common.c
@@ -51,7 +51,11 @@ void pbl_barebox_break(void)
{
__asm__ __volatile__ (
#ifdef CONFIG_PBL_BREAK
+#ifdef CONFIG_CPU_V8
+ "brk #17\n"
+#else
"bkpt #17\n"
+#endif
"nop\n"
#else
"nop\n"
diff --git a/arch/arm/cpu/dtb.c b/arch/arm/cpu/dtb.c
index 1ba5aa4..c43474e 100644
--- a/arch/arm/cpu/dtb.c
+++ b/arch/arm/cpu/dtb.c
@@ -19,8 +19,6 @@
#include <of.h>
#include <asm/barebox-arm.h>
-extern char __dtb_start[];
-
static int of_arm_init(void)
{
struct device_node *root;
diff --git a/arch/arm/cpu/mmu-early_64.c b/arch/arm/cpu/mmu-early_64.c
index f07d107..94e3726 100644
--- a/arch/arm/cpu/mmu-early_64.c
+++ b/arch/arm/cpu/mmu-early_64.c
@@ -48,6 +48,8 @@ static void create_sections(void *ttb, uint64_t virt, uint64_t phys,
}
}
+#define EARLY_BITS_PER_VA 39
+
void mmu_early_enable(unsigned long membase, unsigned long memsize,
unsigned long ttb)
{
@@ -64,8 +66,8 @@ void mmu_early_enable(unsigned long membase, unsigned long memsize,
memset((void *)ttb, 0, GRANULE_SIZE);
el = current_el();
- set_ttbr_tcr_mair(el, ttb, calc_tcr(el), MEMORY_ATTRIBUTES);
- create_sections((void *)ttb, 0, 0, 1UL << (BITS_PER_VA - 1), UNCACHED_MEM);
+ set_ttbr_tcr_mair(el, ttb, calc_tcr(el, EARLY_BITS_PER_VA), MEMORY_ATTRIBUTES);
+ create_sections((void *)ttb, 0, 0, 1UL << (EARLY_BITS_PER_VA - 1), UNCACHED_MEM);
create_sections((void *)ttb, membase, membase, memsize, CACHED_MEM);
tlb_invalidate();
isb();
diff --git a/arch/arm/cpu/mmu_64.c b/arch/arm/cpu/mmu_64.c
index b45a696..f7a1301 100644
--- a/arch/arm/cpu/mmu_64.c
+++ b/arch/arm/cpu/mmu_64.c
@@ -64,7 +64,7 @@ static __maybe_unused uint64_t *find_pte(uint64_t addr)
pte = ttb;
- for (i = 1; i < 4; i++) {
+ for (i = 0; i < 4; i++) {
block_shift = level2shift(i);
idx = (addr & level2mask(i)) >> block_shift;
pte += idx;
@@ -129,7 +129,7 @@ static void create_sections(uint64_t virt, uint64_t phys, uint64_t size,
while (size) {
table = ttb;
- for (level = 1; level < 4; level++) {
+ for (level = 0; level < 4; level++) {
block_shift = level2shift(level);
idx = (addr & level2mask(level)) >> block_shift;
block_size = (1ULL << block_shift);
@@ -193,7 +193,8 @@ void __mmu_init(bool mmu_on)
ttb = create_table();
el = current_el();
- set_ttbr_tcr_mair(el, (uint64_t)ttb, calc_tcr(el), MEMORY_ATTRIBUTES);
+ set_ttbr_tcr_mair(el, (uint64_t)ttb, calc_tcr(el, BITS_PER_VA),
+ MEMORY_ATTRIBUTES);
pr_debug("ttb: 0x%p\n", ttb);
diff --git a/arch/arm/cpu/mmu_64.h b/arch/arm/cpu/mmu_64.h
index e2e1256..a2a5477 100644
--- a/arch/arm/cpu/mmu_64.h
+++ b/arch/arm/cpu/mmu_64.h
@@ -75,7 +75,9 @@ static inline uint64_t level2mask(int level)
{
uint64_t mask = -EINVAL;
- if (level == 1)
+ if (level == 0)
+ mask = L0_ADDR_MASK;
+ else if (level == 1)
mask = L1_ADDR_MASK;
else if (level == 2)
mask = L2_ADDR_MASK;
@@ -85,13 +87,12 @@ static inline uint64_t level2mask(int level)
return mask;
}
-static inline uint64_t calc_tcr(int el)
+static inline uint64_t calc_tcr(int el, int va_bits)
{
- u64 ips, va_bits;
+ u64 ips;
u64 tcr;
ips = 2;
- va_bits = BITS_PER_VA;
if (el == 1)
tcr = (ips << 32) | TCR_EPD1_DISABLE;
diff --git a/arch/arm/cpu/psci.c b/arch/arm/cpu/psci.c
index 22ce1df..5a69aaa 100644
--- a/arch/arm/cpu/psci.c
+++ b/arch/arm/cpu/psci.c
@@ -228,107 +228,3 @@ static int armv7_psci_init(void)
}
device_initcall(armv7_psci_init);
-#ifdef CONFIG_ARM_PSCI_DEBUG
-
-#include <command.h>
-#include <getopt.h>
-#include "mmu.h"
-
-void second_entry(void)
-{
- struct arm_smccc_res res;
-
- psci_printf("2nd CPU online, now turn off again\n");
-
- arm_smccc_smc(ARM_PSCI_0_2_FN_CPU_OFF,
- 0, 0, 0, 0, 0, 0, 0, &res);
-
- psci_printf("2nd CPU still alive?\n");
-
- while (1);
-}
-
-static const char *psci_xlate_str(long err)
-{
- static char errno_string[sizeof "error 0x123456789ABCDEF0"];
-
- switch(err)
- {
- case ARM_PSCI_RET_SUCCESS:
- return "Success";
- case ARM_PSCI_RET_NOT_SUPPORTED:
- return "Operation not supported";
- case ARM_PSCI_RET_INVAL:
- return "Invalid argument";
- case ARM_PSCI_RET_DENIED:
- return "Operation not permitted";
- case ARM_PSCI_RET_ALREADY_ON:
- return "CPU already on";
- case ARM_PSCI_RET_ON_PENDING:
- return "CPU_ON in progress";
- case ARM_PSCI_RET_INTERNAL_FAILURE:
- return "Internal failure";
- case ARM_PSCI_RET_NOT_PRESENT:
- return "Trusted OS not present on core";
- case ARM_PSCI_RET_DISABLED:
- return "CPU is disabled";
- case ARM_PSCI_RET_INVALID_ADDRESS:
- return "Bad address";
- }
-
- sprintf(errno_string, "error 0x%lx", err);
- return errno_string;
-}
-
-static int do_smc(int argc, char *argv[])
-{
- long ret;
- int opt;
- struct arm_smccc_res res = {
- .a0 = 0xdeadbee0,
- .a1 = 0xdeadbee1,
- .a2 = 0xdeadbee2,
- .a3 = 0xdeadbee3,
- };
-
- if (argc < 2)
- return COMMAND_ERROR_USAGE;
-
- while ((opt = getopt(argc, argv, "nic")) > 0) {
- switch (opt) {
- case 'n':
- armv7_secure_monitor_install();
- break;
- case 'i':
- arm_smccc_smc(ARM_PSCI_0_2_FN_PSCI_VERSION,
- 0, 0, 0, 0, 0, 0, 0, &res);
- printf("found psci version %ld.%ld\n", res.a0 >> 16, res.a0 & 0xffff);
- break;
- case 'c':
- arm_smccc_smc(ARM_PSCI_0_2_FN_CPU_ON,
- 1, (unsigned long)second_entry, 0, 0, 0, 0, 0, &res);
- ret = (long)res.a0;
- printf("CPU_ON returns with: %s\n", psci_xlate_str(ret));
- if (ret)
- return COMMAND_ERROR;
- }
- }
-
-
- return 0;
-}
-BAREBOX_CMD_HELP_START(smc)
-BAREBOX_CMD_HELP_TEXT("Secure monitor code test command")
-BAREBOX_CMD_HELP_TEXT("")
-BAREBOX_CMD_HELP_TEXT("Options:")
-BAREBOX_CMD_HELP_OPT ("-n", "Install secure monitor and switch to nonsecure mode")
-BAREBOX_CMD_HELP_OPT ("-i", "Show information about installed PSCI version")
-BAREBOX_CMD_HELP_OPT ("-c", "Start secondary CPU core")
-BAREBOX_CMD_HELP_END
-
-BAREBOX_CMD_START(smc)
- .cmd = do_smc,
- BAREBOX_CMD_DESC("secure monitor test command")
- BAREBOX_CMD_GROUP(CMD_GRP_MISC)
-BAREBOX_CMD_END
-#endif
diff --git a/arch/arm/cpu/start.c b/arch/arm/cpu/start.c
index 44d974e..d99dd14 100644
--- a/arch/arm/cpu/start.c
+++ b/arch/arm/cpu/start.c
@@ -193,7 +193,17 @@ __noreturn void barebox_non_pbl_start(unsigned long membase,
uint32_t totalsize = 0;
const char *name;
- if ((unsigned long)boarddata < 8192) {
+ if (blob_is_fdt(boarddata)) {
+ totalsize = get_unaligned_be32(boarddata + 4);
+ name = "DTB";
+ } else if (blob_is_compressed_fdt(boarddata)) {
+ struct barebox_arm_boarddata_compressed_dtb *bd = boarddata;
+ totalsize = bd->datalen + sizeof(*bd);
+ name = "Compressed DTB";
+ } else if (blob_is_arm_boarddata(boarddata)) {
+ totalsize = sizeof(struct barebox_arm_boarddata);
+ name = "machine type";
+ } else if ((unsigned long)boarddata < 8192) {
struct barebox_arm_boarddata *bd;
uint32_t machine_type = (unsigned long)boarddata;
unsigned long mem = arm_mem_boarddata(membase, endmem,
@@ -205,16 +215,6 @@ __noreturn void barebox_non_pbl_start(unsigned long membase,
bd->magic = BAREBOX_ARM_BOARDDATA_MAGIC;
bd->machine = machine_type;
malloc_end = mem;
- } else if (blob_is_fdt(boarddata)) {
- totalsize = get_unaligned_be32(boarddata + 4);
- name = "DTB";
- } else if (blob_is_compressed_fdt(boarddata)) {
- struct barebox_arm_boarddata_compressed_dtb *bd = boarddata;
- totalsize = bd->datalen + sizeof(*bd);
- name = "Compressed DTB";
- } else if (blob_is_arm_boarddata(boarddata)) {
- totalsize = sizeof(struct barebox_arm_boarddata);
- name = "machine type";
}
if (totalsize) {
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index c097c10..5c9a311 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -33,7 +33,8 @@ lwl-dtb-$(CONFIG_MACH_GW_VENTANA) += imx6q-gw54xx.dtb.o
lwl-dtb-$(CONFIG_MACH_KONTRON_SAMX6I) += imx6q-samx6i.dtb.o \
imx6dl-samx6i.dtb.o
lwl-dtb-$(CONFIG_MACH_LENOVO_IX4_300D) += armada-xp-lenovo-ix4-300d-bb.dtb.o
-lwl-dtb-$(CONFIG_MACH_MARVELL_ARMADA_XP_GP) += armada-xp-gp-bb.dtb.o armada-xp-db-bb.dtb.o
+lwl-dtb-$(CONFIG_MACH_MARVELL_ARMADA_XP_GP) += armada-xp-gp-bb.dtb.o
+lwl-dtb-$(CONFIG_MACH_MARVELL_ARMADA_XP_DB) += armada-xp-db-bb.dtb.o
lwl-dtb-$(CONFIG_MACH_MB7707) += module-mb7707.dtb.o
lwl-dtb-$(CONFIG_MACH_MX28EVK) += imx28-evk.dtb.o
lwl-dtb-$(CONFIG_MACH_NETGEAR_RN104) += armada-370-rn104-bb.dtb.o
diff --git a/arch/arm/dts/fsl-ls1046a-rdb.dts b/arch/arm/dts/fsl-ls1046a-rdb.dts
index 842d684..32b3f40 100644
--- a/arch/arm/dts/fsl-ls1046a-rdb.dts
+++ b/arch/arm/dts/fsl-ls1046a-rdb.dts
@@ -5,6 +5,10 @@
#include <arm64/freescale/fsl-ls1046a-rdb.dts>
/ {
+ aliases {
+ eeprom = &eeprom;
+ };
+
chosen {
stdout-path = &duart0;
@@ -23,9 +27,14 @@
#address-cells = <1>;
#size-cells = <1>;
- environment_sd: partition@200000 {
+ partition@1000 {
+ label = "barebox";
+ reg = <0x1000 0xdf000>;
+ };
+
+ environment_sd: partition@e0000 {
label = "barebox-environment";
- reg = <0x200000 0x20000>;
+ reg = <0xe0000 0x20000>;
};
};
@@ -41,6 +50,17 @@
status = "okay";
};
+&i2c0 {
+ eeprom: eeprom@52 {
+ compatible = "atmel,24c04";
+ };
+
+ non_existent_eeprom: eeprom@53 {
+ };
+};
+
+/delete-node/ &non_existent_eeprom;
+
&fman0 {
ethernet@e0000 {
status = "disabled";
@@ -109,6 +129,14 @@
};
};
+&qflash0 {
+ compatible = "jedec,spi-nor";
+};
+
+&qflash1 {
+ compatible = "jedec,spi-nor";
+};
+
&usb0 {
dr_mode = "host";
};
@@ -122,3 +150,17 @@
&usb2 {
dr_mode = "host";
};
+
+&soc {
+ pcie1: pcie@3400000 {
+ status = "okay";
+ };
+
+ pcie2: pcie@3500000 {
+ status = "okay";
+ };
+
+ pcie3: pcie@3600000 {
+ status = "okay";
+ };
+};
diff --git a/arch/arm/dts/fsl-tqmls1046a-mbls10xxa.dts b/arch/arm/dts/fsl-tqmls1046a-mbls10xxa.dts
index f0332e3..7b17fe2 100644
--- a/arch/arm/dts/fsl-tqmls1046a-mbls10xxa.dts
+++ b/arch/arm/dts/fsl-tqmls1046a-mbls10xxa.dts
@@ -84,7 +84,7 @@
compatible = "fixed-partitions";
- partition@0 {
+ partition@1000 {
label = "barebox";
reg = <0x1000 0xdf000>;
};
@@ -131,6 +131,22 @@
reg = <0x20>;
gpio-controller;
#gpio-cells = <2>;
+ gpio-line-names = "sd1_3_lane_a_mux",
+ "sd1_2_lane_b_mux",
+ "sd1_0_lane_d_mux",
+ "sd2_1_lane_b_mux",
+ "sd2_3_lane_d_mux1",
+ "sd2_3_lane_d_mux2",
+ "sd_mux_shdn",
+ "sd1_ref_clk2_sel",
+ "mpcie1_disable_n",
+ "mpcie1_wake_n",
+ "mpcie2_disable_n",
+ "mpcie2_wake_n",
+ "prsnt_n",
+ "pcie_pwr_en",
+ "dcdc_pwr_en",
+ "dcdc_pgood_1v8";
};
gpioexp2: pca9555@21 {
@@ -138,6 +154,22 @@
reg = <0x21>;
gpio-controller;
#gpio-cells = <2>;
+ gpio-line-names = "xfi1_tx_dis",
+ "xfi1_tx_fault",
+ "xfi1_moddef_det",
+ "xfi1_rx_loss",
+ "retimer1_loss",
+ "xfi1_ensmb",
+ "qsgmii1_clk_sel0",
+ "qsgmii_phy1_config3",
+ "xfi2_tx_fault",
+ "xfi2_tx_dis",
+ "xfi2_moddef_det",
+ "xfi2_rx_loss",
+ "retimer2_loss",
+ "xfi2_ensmb",
+ "qsgmii2_clk_sel0",
+ "qsgmii_phy2_config3";
};
gpioexp3: pca9555@22 {
@@ -145,6 +177,22 @@
reg = <0x22>;
gpio-controller;
#gpio-cells = <2>;
+ gpio-line-names = "ec1_phy_pwdn",
+ "ec2_phy_pwdn",
+ "usb_c_pwron",
+ "usb_en_oc_3v3_n",
+ "usb_h_grst_n",
+ "gpio_button0",
+ "gpio_button1",
+ "sda_pwr_en",
+ "qsgmii_phy1_int_n",
+ "qsgmii_phy2_int_n",
+ "spi_clko_sof",
+ "spi_int",
+ "can_sel",
+ "led_n",
+ "pcie_rst_3v3_n",
+ "pcie_wake_3v3_n";
};
};
diff --git a/arch/arm/dts/imx6dl-phytec-phycore-som-emmc.dts b/arch/arm/dts/imx6dl-phytec-phycore-som-emmc.dts
index 25d73ce..03df77f 100644
--- a/arch/arm/dts/imx6dl-phytec-phycore-som-emmc.dts
+++ b/arch/arm/dts/imx6dl-phytec-phycore-som-emmc.dts
@@ -1,13 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later)
/*
* Copyright (C) 2015 PHYTEC Messtechnik GmbH,
* Author: Stefan Christ <s.christ@phytec.de>
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
*/
/dts-v1/;
@@ -17,17 +11,14 @@
#include <arm/imx6dl.dtsi>
#include "imx6dl.dtsi"
#include "imx6qdl-phytec-phycore-som.dtsi"
+#include "imx6qdl-phytec-mira.dtsi"
#include "imx6qdl-phytec-state.dtsi"
/ {
- model = "Phytec phyCORE-i.MX6 DualLite/SOLO with eMMC";
+ model = "PHYTEC phyCORE-i.MX6 DualLite/SOLO with eMMC";
compatible = "phytec,imx6dl-pcm058-emmc", "fsl,imx6dl";
};
-&ecspi1 {
- status = "okay";
-};
-
&eeprom {
status = "okay";
};
@@ -40,7 +31,7 @@
status = "okay";
};
-&flash {
+&m25p80 {
status = "okay";
};
@@ -54,22 +45,6 @@
&usdhc1 {
status = "okay";
-
- partitions {
- compatible = "fixed-partitions";
- #address-cells = <1>;
- #size-cells = <1>;
-
- partition@0 {
- label = "barebox";
- reg = <0x0 0xe0000>;
- };
-
- partition@e0000 {
- label = "barebox-environment";
- reg = <0xe0000 0x20000>;
- };
- };
};
&usdhc4 {
diff --git a/arch/arm/dts/imx6dl-phytec-phycore-som-lc-emmc.dts b/arch/arm/dts/imx6dl-phytec-phycore-som-lc-emmc.dts
index a6b0e94..0ef6f96 100644
--- a/arch/arm/dts/imx6dl-phytec-phycore-som-lc-emmc.dts
+++ b/arch/arm/dts/imx6dl-phytec-phycore-som-lc-emmc.dts
@@ -11,6 +11,7 @@
#include <arm/imx6dl.dtsi>
#include "imx6dl.dtsi"
#include "imx6qdl-phytec-phycore-som.dtsi"
+#include "imx6qdl-phytec-mira.dtsi"
#include "imx6qdl-phytec-state.dtsi"
/ {
@@ -18,10 +19,6 @@
compatible = "phytec,imx6dl-pcm058-emmc", "fsl,imx6dl";
};
-&ecspi1 {
- status = "okay";
-};
-
&eeprom {
status = "okay";
};
@@ -34,7 +31,7 @@
status = "okay";
};
-&flash {
+&m25p80 {
status = "okay";
};
@@ -48,19 +45,6 @@
&usdhc1 {
status = "okay";
-
- #address-cells = <1>;
- #size-cells = <1>;
-
- partition@0 {
- label = "barebox";
- reg = <0x0 0xe0000>;
- };
-
- partition@e0000 {
- label = "barebox-environment";
- reg = <0xe0000 0x20000>;
- };
};
&usdhc4 {
diff --git a/arch/arm/dts/imx6dl-phytec-phycore-som-lc-nand.dts b/arch/arm/dts/imx6dl-phytec-phycore-som-lc-nand.dts
index 195c3ed..0a4c2e6 100644
--- a/arch/arm/dts/imx6dl-phytec-phycore-som-lc-nand.dts
+++ b/arch/arm/dts/imx6dl-phytec-phycore-som-lc-nand.dts
@@ -11,6 +11,7 @@
#include <arm/imx6dl.dtsi>
#include "imx6dl.dtsi"
#include "imx6qdl-phytec-phycore-som.dtsi"
+#include "imx6qdl-phytec-mira.dtsi"
#include "imx6qdl-phytec-state.dtsi"
/ {
@@ -44,17 +45,4 @@
&usdhc1 {
status = "okay";
-
- #address-cells = <1>;
- #size-cells = <1>;
-
- partition@0 {
- label = "barebox";
- reg = <0x0 0xe0000>;
- };
-
- partition@e0000 {
- label = "barebox-environment";
- reg = <0xe0000 0x20000>;
- };
};
diff --git a/arch/arm/dts/imx6dl-phytec-phycore-som-nand.dts b/arch/arm/dts/imx6dl-phytec-phycore-som-nand.dts
index dfc33e4..fa51828 100644
--- a/arch/arm/dts/imx6dl-phytec-phycore-som-nand.dts
+++ b/arch/arm/dts/imx6dl-phytec-phycore-som-nand.dts
@@ -1,12 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later)
/*
- * Copyright 2015 Christian Hemp, Phytec Messtechnik GmbH
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * Copyright (C) 2015 PHYTEC Messtechnik GmbH
+ * Author: Christian Hemp <c.hemp@phytec.de>
*/
/dts-v1/;
@@ -16,10 +11,11 @@
#include <arm/imx6dl.dtsi>
#include "imx6dl.dtsi"
#include "imx6qdl-phytec-phycore-som.dtsi"
+#include "imx6qdl-phytec-mira.dtsi"
#include "imx6qdl-phytec-state.dtsi"
/ {
- model = "Phytec phyCORE-i.MX6 Duallite/SOLO with NAND";
+ model = "PHYTEC phyCORE-i.MX6 Duallite/SOLO with NAND";
compatible = "phytec,imx6dl-pcm058-nand", "fsl,imx6dl";
};
@@ -49,20 +45,4 @@
&usdhc1 {
status = "okay";
-
- partitions {
- compatible = "fixed-partitions";
- #address-cells = <1>;
- #size-cells = <1>;
-
- partition@0 {
- label = "barebox";
- reg = <0x0 0xe0000>;
- };
-
- partition@e0000 {
- label = "barebox-environment";
- reg = <0xe0000 0x20000>;
- };
- };
};
diff --git a/arch/arm/dts/imx6q-phytec-phycore-som-emmc.dts b/arch/arm/dts/imx6q-phytec-phycore-som-emmc.dts
index 268b1cd..2414bef 100644
--- a/arch/arm/dts/imx6q-phytec-phycore-som-emmc.dts
+++ b/arch/arm/dts/imx6q-phytec-phycore-som-emmc.dts
@@ -1,12 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later)
/*
- * Copyright 2015 Christian Hemp, Phytec Messtechnik GmbH
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * Copyright (C) 2015 PHYTEC Messtechnik GmbH
+ * Author: Christian Hemp <c.hemp@phytec.de>
*/
/dts-v1/;
@@ -16,17 +11,14 @@
#include <arm/imx6q.dtsi>
#include "imx6q.dtsi"
#include "imx6qdl-phytec-phycore-som.dtsi"
+#include "imx6qdl-phytec-mira.dtsi"
#include "imx6qdl-phytec-state.dtsi"
/ {
- model = "Phytec phyCORE-i.MX6 Quad with eMMC";
+ model = "PHYTEC phyCORE-i.MX6 Quad with eMMC";
compatible = "phytec,imx6q-pcm058-emmc", "fsl,imx6q";
};
-&ecspi1 {
- status = "okay";
-};
-
&eeprom {
status = "okay";
};
@@ -39,7 +31,7 @@
status = "okay";
};
-&flash {
+&m25p80 {
status = "okay";
};
@@ -53,22 +45,6 @@
&usdhc1 {
status = "okay";
-
- partitions {
- compatible = "fixed-partitions";
- #address-cells = <1>;
- #size-cells = <1>;
-
- partition@0 {
- label = "barebox";
- reg = <0x0 0xe0000>;
- };
-
- partition@e0000 {
- label = "barebox-environment";
- reg = <0xe0000 0x20000>;
- };
- };
};
&usdhc4 {
diff --git a/arch/arm/dts/imx6q-phytec-phycore-som-nand.dts b/arch/arm/dts/imx6q-phytec-phycore-som-nand.dts
index d138c41..864dc19 100644
--- a/arch/arm/dts/imx6q-phytec-phycore-som-nand.dts
+++ b/arch/arm/dts/imx6q-phytec-phycore-som-nand.dts
@@ -1,12 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later)
/*
- * Copyright 2015 Christian Hemp, Phytec Messtechnik GmbH
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * Copyright (C) 2015 PHYTEC Messtechnik GmbH
+ * Author: Christian Hemp <c.hemp@phytec.de>
*/
/dts-v1/;
@@ -16,18 +11,15 @@
#include <arm/imx6q.dtsi>
#include "imx6q.dtsi"
#include "imx6qdl-phytec-phycore-som.dtsi"
+#include "imx6qdl-phytec-mira.dtsi"
#include "imx6qdl-phytec-state.dtsi"
/ {
- model = "Phytec phyCORE-i.MX6 Quad with NAND";
+ model = "PHYTEC phyCORE-i.MX6 Quad with NAND";
compatible = "phytec,imx6q-pcm058-nand", "fsl,imx6q";
};
-&ecspi1 {
- status = "okay";
-};
-
&eeprom {
status = "okay";
};
@@ -40,7 +32,7 @@
status = "okay";
};
-&flash {
+&m25p80 {
status = "okay";
};
@@ -58,20 +50,4 @@
&usdhc1 {
status = "okay";
-
- partitions {
- compatible = "fixed-partitions";
- #address-cells = <1>;
- #size-cells = <1>;
-
- partition@0 {
- label = "barebox";
- reg = <0x0 0xe0000>;
- };
-
- partition@e0000 {
- label = "barebox-environment";
- reg = <0xe0000 0x20000>;
- };
- };
};
diff --git a/arch/arm/dts/imx6qdl-phytec-mira.dtsi b/arch/arm/dts/imx6qdl-phytec-mira.dtsi
new file mode 100644
index 0000000..49cbd25
--- /dev/null
+++ b/arch/arm/dts/imx6qdl-phytec-mira.dtsi
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
+/*
+ * Copyright (C) 2019 PHYTEC Messtechnik GmbH
+ * Author: Stefan Riedmueller <s.riedmueller@phytec.de>
+ */
+
+#include <arm/imx6qdl-phytec-mira.dtsi>
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ chosen {
+ stdout-path = &uart2;
+ };
+};
+
+&backlight {
+ status = "disabled";
+};
+
+&ldb {
+ status = "disabled";
+};
+
+&pwm1 {
+ status = "disabled";
+};
+
+&usdhc1 {
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "barebox";
+ reg = <0x0 0xe0000>;
+ };
+
+ partition@e0000 {
+ label = "barebox-environment";
+ reg = <0xe0000 0x20000>;
+ };
+ };
+};
diff --git a/arch/arm/dts/imx6qdl-phytec-phycore-som.dtsi b/arch/arm/dts/imx6qdl-phytec-phycore-som.dtsi
index 1d39368..69f252b 100644
--- a/arch/arm/dts/imx6qdl-phytec-phycore-som.dtsi
+++ b/arch/arm/dts/imx6qdl-phytec-phycore-som.dtsi
@@ -1,20 +1,14 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later)
/*
- * Copyright 2015 Christian Hemp, Phytec Messtechnik GmbH
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * Copyright (C) 2015 PHYTEC Messtechnik GmbH
+ * Author: Christian Hemp <c.hemp@phytec.de>
*/
+#include <arm/imx6qdl-phytec-phycore-som.dtsi>
#include <dt-bindings/gpio/gpio.h>
/ {
chosen {
- stdout-path = &uart2;
-
environment-sd1 {
compatible = "barebox,environment";
device-path = &usdhc1, "partname:barebox-environment";
@@ -35,102 +29,20 @@
environment-spinor {
compatible = "barebox,environment";
- device-path = &flash, "partname:barebox-environment";
+ device-path = &m25p80, "partname:barebox-environment";
status = "disabled";
};
};
- reg_usbh1_vbus: regulator-usbh1 {
- compatible = "regulator-fixed";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_usbh1_vbus>;
- regulator-name = "usbh1_vbus";
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <5000000>;
- gpio = <&gpio2 18 GPIO_ACTIVE_HIGH>;
- enable-active-high;
- };
-
- reg_usbotg_vbus: regulator-usbotg {
- compatible = "regulator-fixed";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_usbotg_vbus>;
- regulator-name = "usbotg_vbus";
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <5000000>;
- gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
- enable-active-high;
- };
-};
-
-&ecspi1 {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_ecspi1>;
- fsl,spi-num-chipselects = <1>;
- cs-gpios = <&gpio3 19 0>;
- status = "disabled";
-
- flash: flash@0 {
- compatible = "jedec,spi-nor";
- spi-max-frequency = <20000000>;
- reg = <0>;
- status = "disabled";
-
- partitions {
- compatible = "fixed-partitions";
- #address-cells = <1>;
- #size-cells = <1>;
-
- partition@0 {
- label = "barebox";
- reg = <0x0 0x100000>;
- };
-
- partition@100000 {
- label = "barebox-environment";
- reg = <0x100000 0x20000>;
- };
-
- partition@120000 {
- label = "oftree";
- reg = <0x120000 0x20000>;
- };
-
- partition@140000 {
- label = "kernel";
- reg = <0x140000 0x0>;
- };
- };
- };
+ /delete-node/ memory@10000000;
};
&fec {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_enet>;
- phy-handle = <&ethphy>;
- phy-mode = "rgmii";
- phy-reset-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
+ /delete-property/ phy-supply;
phy-reset-duration = <10>; /* in msecs */
- status = "disabled";
-
- mdio {
- #address-cells = <1>;
- #size-cells = <0>;
-
- ethphy: ethernet-phy@3 {
- reg = <3>;
- txc-skew-ps = <1680>;
- rxc-skew-ps = <1860>;
- };
- };
};
&gpmi {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_gpmi_nand>;
- nand-on-flash-bbt;
- status = "disabled";
-
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
@@ -154,141 +66,44 @@
};
&i2c3 {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c3>;
- clock-frequency = <400000>;
- status = "okay";
-
eeprom: eeprom@50 {
status = "disabled";
- compatible = "24c32";
- reg = <0x50>;
};
pmic@58 {
- compatible = "dlg,da9062";
- reg = <0x58>;
- status = "okay";
-
watchdog-priority = <500>;
restart-priority = <500>;
reset-source-priority = <500>;
};
};
-&iomuxc {
- pinctrl_ecspi1: ecspi1grp {
- fsl,pins = <
- MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1
- MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1
- MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1
- MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x80000000
- >;
- };
-
- pinctrl_enet: enetgrp {
- fsl,pins = <
- MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0
- MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0
- MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0
- MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0
- MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0
- MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0
- MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0
- MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0
- MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0
- MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0
- MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0
- MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0
- MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0
- MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0
- MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0
- MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN 0x1b0b0
- MX6QDL_PAD_SD2_DAT1__GPIO1_IO14 0x80000000
- >;
- };
-
- pinctrl_gpmi_nand: gpmigrp {
- fsl,pins = <
- MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1
- MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1
- MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1
- MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000
- MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1
- MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1
- MX6QDL_PAD_NANDF_CS2__NAND_CE2_B 0xb0b1
- MX6QDL_PAD_NANDF_CS3__NAND_CE3_B 0xb0b1
- MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1
- MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1
- MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1
- MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1
- MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1
- MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1
- MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1
- MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1
- MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1
- MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1
- MX6QDL_PAD_SD4_DAT0__NAND_DQS 0x00b1
- >;
- };
-
- pinctrl_i2c3: i2c3grp {
- fsl,pins = <
- MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1
- MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1
- >;
- };
-
- pinctrl_uart2: uart2grp {
- fsl,pins = <
- MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1
- MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1
- >;
- };
+&m25p80 {
+ status = "disabled";
- pinctrl_usbh1_vbus: usbh1vbusgrp {
- fsl,pins = <
- MX6QDL_PAD_EIM_A20__GPIO2_IO18 0xb0b1
- >;
- };
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
- pinctrl_usbotg: usbotggrp {
- fsl,pins = <
- MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059
- >;
- };
+ partition@0 {
+ label = "barebox";
+ reg = <0x0 0x100000>;
+ };
- pinctrl_usbotg_vbus: usbotgvbusgrp {
- fsl,pins = <
- MX6QDL_PAD_EIM_A19__GPIO2_IO19 0xb0b1
- >;
- };
+ partition@100000 {
+ label = "barebox-environment";
+ reg = <0x100000 0x20000>;
+ };
- pinctrl_usdhc1: usdhc1grp {
- fsl,pins = <
- MX6QDL_PAD_SD1_CMD__SD1_CMD 0x170f9
- MX6QDL_PAD_SD1_CLK__SD1_CLK 0x100f9
- MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x170f9
- MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x170f9
- MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x170f9
- MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x170f9
- MX6QDL_PAD_EIM_BCLK__GPIO6_IO31 0x80000000 /* CD */
- >;
- };
+ partition@120000 {
+ label = "oftree";
+ reg = <0x120000 0x20000>;
+ };
- pinctrl_usdhc4: usdhc4grp {
- fsl,pins = <
- MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059
- MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059
- MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059
- MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059
- MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059
- MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059
- MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059
- MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059
- MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059
- MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059
- >;
+ partition@140000 {
+ label = "kernel";
+ reg = <0x140000 0x0>;
+ };
};
};
@@ -296,50 +111,20 @@
barebox,provide-mac-address = <&fec 0x620>;
};
-&uart2 {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart2>;
- status = "okay";
-};
-
-&usbh1 {
- vbus-supply = <&reg_usbh1_vbus>;
- disable-over-current;
- status = "disabled";
-};
-
-&usbotg {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_usbotg>;
- vbus-supply = <&reg_usbotg_vbus>;
- disable-over-current;
- status = "disabled";
-};
-
-&usdhc1 {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_usdhc1>;
- cd-gpios = <&gpio6 31 0>;
- status = "disabled";
-};
-
&usdhc4 {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_usdhc4>;
- bus-width = <8>;
- non-removable;
- status = "disabled";
-
- #address-cells = <1>;
- #size-cells = <1>;
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
- partition@0 {
- label = "barebox";
- reg = <0x0 0xe0000>;
- };
+ partition@0 {
+ label = "barebox";
+ reg = <0x0 0xe0000>;
+ };
- partition@e0000 {
- label = "barebox-environment";
- reg = <0xe0000 0x20000>;
+ partition@e0000 {
+ label = "barebox-environment";
+ reg = <0xe0000 0x20000>;
+ };
};
};
diff --git a/arch/arm/dts/imx6qp-phytec-phycore-som-nand.dts b/arch/arm/dts/imx6qp-phytec-phycore-som-nand.dts
index 1f39fb3..378806d 100644
--- a/arch/arm/dts/imx6qp-phytec-phycore-som-nand.dts
+++ b/arch/arm/dts/imx6qp-phytec-phycore-som-nand.dts
@@ -1,13 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later)
/*
- * Copyright (C) 2016 Phytec Messtechnik GmbH
+ * Copyright (C) 2016 PHYTEC Messtechnik GmbH
* Author: Christian Hemp <c.hemp@phytec.de>
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
*/
/dts-v1/;
@@ -16,16 +10,13 @@
#endif
#include <arm/imx6qp.dtsi>
#include "imx6qdl-phytec-phycore-som.dtsi"
+#include "imx6qdl-phytec-mira.dtsi"
/ {
- model = "Phytec phyCORE-i.MX6 Quad with NAND";
+ model = "PHYTEC phyCORE-i.MX6 QuadPlus with NAND";
compatible = "phytec,imx6qp-pcm058-nand", "fsl,imx6qp";
};
-&ecspi1 {
- status = "okay";
-};
-
&eeprom {
status = "okay";
};
@@ -38,7 +29,7 @@
status = "okay";
};
-&flash {
+&m25p80 {
status = "okay";
};
@@ -56,20 +47,4 @@
&usdhc1 {
status = "okay";
-
- partitions {
- compatible = "fixed-partitions";
- #address-cells = <1>;
- #size-cells = <1>;
-
- partition@0 {
- label = "barebox";
- reg = <0x0 0xe0000>;
- };
-
- partition@e0000 {
- label = "barebox-environment";
- reg = <0xe0000 0x20000>;
- };
- };
};
diff --git a/arch/arm/dts/stm32mp157a-dk1.dtsi b/arch/arm/dts/stm32mp157a-dk1.dtsi
index e9e386a..6be208f 100644
--- a/arch/arm/dts/stm32mp157a-dk1.dtsi
+++ b/arch/arm/dts/stm32mp157a-dk1.dtsi
@@ -8,10 +8,6 @@
#include <dt-bindings/gpio/gpio.h>
/ {
- aliases {
- mmc0 = &sdmmc1;
- };
-
chosen {
environment {
compatible = "barebox,environment";
diff --git a/arch/arm/dts/stm32mp157c.dtsi b/arch/arm/dts/stm32mp157c.dtsi
index 97c075a..e416c89 100644
--- a/arch/arm/dts/stm32mp157c.dtsi
+++ b/arch/arm/dts/stm32mp157c.dtsi
@@ -18,11 +18,19 @@
gpio9 = &gpioj;
gpio10 = &gpiok;
gpio25 = &gpioz;
+ mmc0 = &sdmmc1;
};
psci {
compatible = "arm,psci-0.2";
};
+
+ soc {
+ memory-controller@5a003000 {
+ compatible = "st,stm32mp1-ddr";
+ reg = <0x5a003000 0x1000>;
+ };
+ };
};
&bsec {
diff --git a/arch/arm/include/asm/barebox-arm-head.h b/arch/arm/include/asm/barebox-arm-head.h
index 83a22c4..8409a77 100644
--- a/arch/arm/include/asm/barebox-arm-head.h
+++ b/arch/arm/include/asm/barebox-arm-head.h
@@ -65,7 +65,11 @@ static inline void __barebox_arm_head(void)
".endr\n"
"2:\n"
#ifdef CONFIG_PBL_BREAK
+#ifdef CONFIG_CPU_V8
+ "brk #17\n"
+#else
"bkpt #17\n"
+#endif
"nop\n"
#else
"nop\n"
diff --git a/arch/arm/include/asm/pgtable64.h b/arch/arm/include/asm/pgtable64.h
index d838250..d142612 100644
--- a/arch/arm/include/asm/pgtable64.h
+++ b/arch/arm/include/asm/pgtable64.h
@@ -21,7 +21,7 @@
#define UNUSED_DESC 0x6EbAAD0BBADbA6E0
#define VA_START 0x0
-#define BITS_PER_VA 39
+#define BITS_PER_VA 48
/* Granule size of 4KB is being used */
#define GRANULE_SIZE_SHIFT 12
@@ -30,11 +30,13 @@
#define GRANULE_SIZE_MASK ((1 << GRANULE_SIZE_SHIFT) - 1)
#define BITS_RESOLVED_PER_LVL (GRANULE_SIZE_SHIFT - 3)
+#define L0_ADDR_SHIFT (GRANULE_SIZE_SHIFT + BITS_RESOLVED_PER_LVL * 3)
#define L1_ADDR_SHIFT (GRANULE_SIZE_SHIFT + BITS_RESOLVED_PER_LVL * 2)
#define L2_ADDR_SHIFT (GRANULE_SIZE_SHIFT + BITS_RESOLVED_PER_LVL * 1)
#define L3_ADDR_SHIFT (GRANULE_SIZE_SHIFT + BITS_RESOLVED_PER_LVL * 0)
+#define L0_ADDR_MASK (((1UL << BITS_RESOLVED_PER_LVL) - 1) << L0_ADDR_SHIFT)
#define L1_ADDR_MASK (((1UL << BITS_RESOLVED_PER_LVL) - 1) << L1_ADDR_SHIFT)
#define L2_ADDR_MASK (((1UL << BITS_RESOLVED_PER_LVL) - 1) << L2_ADDR_SHIFT)
#define L3_ADDR_MASK (((1UL << BITS_RESOLVED_PER_LVL) - 1) << L3_ADDR_SHIFT)
@@ -44,6 +46,7 @@
#define L3_XLAT_SIZE (1UL << L3_ADDR_SHIFT)
#define L2_XLAT_SIZE (1UL << L2_ADDR_SHIFT)
#define L1_XLAT_SIZE (1UL << L1_ADDR_SHIFT)
+#define L0_XLAT_SIZE (1UL << L0_ADDR_SHIFT)
#define GRANULE_MASK GRANULE_SIZE
diff --git a/arch/arm/lib32/Makefile b/arch/arm/lib32/Makefile
index 3c02a0b..cd43147 100644
--- a/arch/arm/lib32/Makefile
+++ b/arch/arm/lib32/Makefile
@@ -1,6 +1,7 @@
obj-$(CONFIG_ARM_LINUX) += armlinux.o
obj-$(CONFIG_CMD_BOOTZ) += bootz.o
obj-$(CONFIG_BOOTM) += bootm.o
+obj-$(CONFIG_BOOTM_OPTEE) += start-kernel-optee.o
obj-$(CONFIG_CMD_BOOTU) += bootu.o
obj-y += div0.o
obj-y += findbit.o
diff --git a/arch/arm/cpu/start-kernel-optee.S b/arch/arm/lib32/start-kernel-optee.S
index 92da4b6..92da4b6 100644
--- a/arch/arm/cpu/start-kernel-optee.S
+++ b/arch/arm/lib32/start-kernel-optee.S
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 5ad1f62..5267102 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -65,6 +65,7 @@ config SOC_SAMA5D2
select HAVE_AT91_UTMI
select HAVE_AT91_USB_CLK
select HAVE_AT91_GENERATED_CLK
+ select PINCTRL
select PINCTRL_AT91PIO4
select HAS_MACB
select HAVE_MACH_ARM_HEAD
diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig
index 66d3d7a..c6d4fce 100644
--- a/arch/arm/mach-davinci/Kconfig
+++ b/arch/arm/mach-davinci/Kconfig
@@ -9,6 +9,8 @@ choice
config MACH_VIRT2REAL
bool "Virt2Real"
+ select OFTREE
+ select OFDEVICE
endchoice
diff --git a/arch/arm/mach-imx/include/mach/vf610.h b/arch/arm/mach-imx/include/mach/vf610.h
index 6d00d2e..7ac10a7 100644
--- a/arch/arm/mach-imx/include/mach/vf610.h
+++ b/arch/arm/mach-imx/include/mach/vf610.h
@@ -48,4 +48,6 @@ static inline int vf610_cpu_revision(void)
return readl(VF610_ROM_VERSION_OFFSET) & 0xff;
}
+u64 vf610_uid(void);
+
#endif
diff --git a/arch/arm/mach-imx/vf610.c b/arch/arm/mach-imx/vf610.c
index b548cbc..2fbd639 100644
--- a/arch/arm/mach-imx/vf610.c
+++ b/arch/arm/mach-imx/vf610.c
@@ -19,6 +19,7 @@
#include <mach/revision.h>
#include <mach/vf610.h>
#include <mach/reset-reason.h>
+#include <mach/ocotp.h>
static const struct imx_reset_reason vf610_reset_reasons[] = {
{ VF610_SRC_SRSR_POR_RST, RESET_POR, 0 },
@@ -30,6 +31,11 @@ static const struct imx_reset_reason vf610_reset_reasons[] = {
{ /* sentinel */ }
};
+u64 vf610_uid(void)
+{
+ return imx_ocotp_read_uid(IOMEM(VF610_OCOTP_BASE_ADDR));
+}
+
int vf610_init(void)
{
const char *cputypestr;
@@ -57,5 +63,7 @@ int vf610_init(void)
imx_set_silicon_revision(cputypestr, vf610_cpu_revision());
imx_set_reset_reason(src + IMX_SRC_SRSR, vf610_reset_reasons);
+ pr_info("%s unique ID: %llx\n", cputypestr, vf610_uid());
+
return 0;
}
diff --git a/arch/arm/mach-layerscape/Kconfig b/arch/arm/mach-layerscape/Kconfig
index 139c63f..c15d587 100644
--- a/arch/arm/mach-layerscape/Kconfig
+++ b/arch/arm/mach-layerscape/Kconfig
@@ -30,5 +30,8 @@ config MACH_LS1046ARDB
config MACH_TQMLS1046A
bool "TQ TQMLS1046A Board"
select ARCH_LS1046
+ select MCI_IMX_ESDHC_PBL
+ select DDR_FSL
+ select DDR_FSL_DDR4
endif
diff --git a/arch/arm/mach-layerscape/ppa.c b/arch/arm/mach-layerscape/ppa.c
index 6070451..477e894 100644
--- a/arch/arm/mach-layerscape/ppa.c
+++ b/arch/arm/mach-layerscape/ppa.c
@@ -14,18 +14,37 @@
#include <image-fit.h>
#include <asm/psci.h>
#include <mach/layerscape.h>
+#include <asm/cache.h>
int ppa_entry(const void *, u32 *, u32 *);
-void dma_flush_range(void *ptr, size_t size);
+
+#define SEC_JR3_OFFSET 0x40000
static int of_psci_do_fixup(struct device_node *root, void *unused)
{
unsigned long psci_version;
+ struct device_node *np;
struct arm_smccc_res res = {};
arm_smccc_smc(ARM_PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0, 0, 0, 0, 0, &res);
psci_version = res.a0;
+ for_each_compatible_node_from(np, root, NULL, "fsl,sec-v4.0-job-ring") {
+ const void *reg;
+ int na = of_n_addr_cells(np);
+ u64 offset;
+
+ reg = of_get_property(np, "reg", NULL);
+ if (!reg)
+ continue;
+
+ offset = of_read_number(reg, na);
+ if (offset != SEC_JR3_OFFSET)
+ continue;
+
+ of_delete_node(np);
+ }
+
return of_psci_fixup(root, psci_version);
}
@@ -73,7 +92,7 @@ static int ppa_init(void *ppa, size_t ppa_size, void *sec_firmware_addr)
/* Copy the secure firmware to secure memory */
memcpy(sec_firmware_addr, buf, firmware_size);
- dma_flush_range(sec_firmware_addr, ppa_size);
+ sync_caches_for_execution();
ret = ppa_entry(sec_firmware_addr, boot_loc_ptr_l, boot_loc_ptr_h);
if (ret) {
diff --git a/arch/arm/mach-mxs/bcb.c b/arch/arm/mach-mxs/bcb.c
index fce607f..860508b 100644
--- a/arch/arm/mach-mxs/bcb.c
+++ b/arch/arm/mach-mxs/bcb.c
@@ -314,7 +314,7 @@ static int write_fcb(struct mtd_info *mtd, void *buf, int block)
return ret;
}
-int update_bcb(int argc, char *argv[])
+static int update_bcb(int argc, char *argv[])
{
int ret;
int block;
diff --git a/arch/arm/mach-stm32mp/Makefile b/arch/arm/mach-stm32mp/Makefile
index 6f49528..8e14b22 100644
--- a/arch/arm/mach-stm32mp/Makefile
+++ b/arch/arm/mach-stm32mp/Makefile
@@ -1,2 +1,3 @@
obj-y := init.o
+obj-pbl-y := ddrctrl.o
obj-$(CONFIG_BOOTM) += stm32image.o
diff --git a/arch/arm/mach-stm32mp/ddrctrl.c b/arch/arm/mach-stm32mp/ddrctrl.c
new file mode 100644
index 0000000..962d4c0
--- /dev/null
+++ b/arch/arm/mach-stm32mp/ddrctrl.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Ahmad Fatoum <a.fatoum@pengutronix.de>
+ */
+
+#include <common.h>
+#include <init.h>
+#include <mach/stm32.h>
+#include <mach/ddr_regs.h>
+#include <mach/entry.h>
+#include <mach/stm32.h>
+#include <asm/barebox-arm.h>
+#include <asm/memory.h>
+#include <pbl.h>
+#include <io.h>
+
+#define ADDRMAP1_BANK_B0 GENMASK( 5, 0)
+#define ADDRMAP1_BANK_B1 GENMASK(13, 8)
+#define ADDRMAP1_BANK_B2 GENMASK(21, 16)
+
+#define ADDRMAP2_COL_B2 GENMASK( 3, 0)
+#define ADDRMAP2_COL_B3 GENMASK(11, 8)
+#define ADDRMAP2_COL_B4 GENMASK(19, 16)
+#define ADDRMAP2_COL_B5 GENMASK(27, 24)
+
+#define ADDRMAP3_COL_B6 GENMASK( 3, 0)
+#define ADDRMAP3_COL_B7 GENMASK(12, 8)
+#define ADDRMAP3_COL_B8 GENMASK(20, 16)
+#define ADDRMAP3_COL_B9 GENMASK(28, 24)
+
+#define ADDRMAP4_COL_B10 GENMASK( 4, 0)
+#define ADDRMAP4_COL_B11 GENMASK(12, 8)
+
+#define ADDRMAP5_ROW_B0 GENMASK( 3, 0)
+#define ADDRMAP5_ROW_B1 GENMASK(11, 8)
+#define ADDRMAP5_ROW_B2_10 GENMASK(19, 16)
+#define ADDRMAP5_ROW_B11 GENMASK(27, 24)
+
+#define ADDRMAP6_ROW_B12 GENMASK( 3, 0)
+#define ADDRMAP6_ROW_B13 GENMASK(11, 8)
+#define ADDRMAP6_ROW_B14 GENMASK(19, 16)
+#define ADDRMAP6_ROW_B15 GENMASK(27, 24)
+
+#define ADDRMAP9_ROW_B2 GENMASK( 3, 0)
+#define ADDRMAP9_ROW_B3 GENMASK(11, 8)
+#define ADDRMAP9_ROW_B4 GENMASK(19, 16)
+#define ADDRMAP9_ROW_B5 GENMASK(27, 24)
+
+#define ADDRMAP10_ROW_B6 GENMASK( 3, 0)
+#define ADDRMAP10_ROW_B7 GENMASK(11, 8)
+#define ADDRMAP10_ROW_B8 GENMASK(19, 16)
+#define ADDRMAP10_ROW_B9 GENMASK(27, 24)
+
+#define ADDRMAP11_ROW_B10 GENMASK( 3, 0)
+
+#define LINE_UNUSED(reg, mask) (((reg) & (mask)) == (mask))
+
+enum ddrctrl_buswidth {
+ BUSWIDTH_FULL = 0,
+ BUSWIDTH_HALF = 1,
+ BUSWIDTH_QUARTER = 2
+};
+
+static unsigned long ddrctrl_addrmap_ramsize(struct stm32mp1_ddrctl __iomem *d,
+ enum ddrctrl_buswidth buswidth)
+{
+ unsigned banks = 3, cols = 12, rows = 16;
+ u32 reg;
+
+ cols += buswidth;
+
+ reg = readl(&d->addrmap1);
+ if (LINE_UNUSED(reg, ADDRMAP1_BANK_B2)) banks--;
+ if (LINE_UNUSED(reg, ADDRMAP1_BANK_B1)) banks--;
+ if (LINE_UNUSED(reg, ADDRMAP1_BANK_B0)) banks--;
+
+ reg = readl(&d->addrmap2);
+ if (LINE_UNUSED(reg, ADDRMAP2_COL_B5)) cols--;
+ if (LINE_UNUSED(reg, ADDRMAP2_COL_B4)) cols--;
+ if (LINE_UNUSED(reg, ADDRMAP2_COL_B3)) cols--;
+ if (LINE_UNUSED(reg, ADDRMAP2_COL_B2)) cols--;
+
+ reg = readl(&d->addrmap3);
+ if (LINE_UNUSED(reg, ADDRMAP3_COL_B9)) cols--;
+ if (LINE_UNUSED(reg, ADDRMAP3_COL_B8)) cols--;
+ if (LINE_UNUSED(reg, ADDRMAP3_COL_B7)) cols--;
+ if (LINE_UNUSED(reg, ADDRMAP3_COL_B6)) cols--;
+
+ reg = readl(&d->addrmap4);
+ if (LINE_UNUSED(reg, ADDRMAP4_COL_B11)) cols--;
+ if (LINE_UNUSED(reg, ADDRMAP4_COL_B10)) cols--;
+
+ reg = readl(&d->addrmap5);
+ if (LINE_UNUSED(reg, ADDRMAP5_ROW_B11)) rows--;
+
+ reg = readl(&d->addrmap6);
+ if (LINE_UNUSED(reg, ADDRMAP6_ROW_B15)) rows--;
+ if (LINE_UNUSED(reg, ADDRMAP6_ROW_B14)) rows--;
+ if (LINE_UNUSED(reg, ADDRMAP6_ROW_B13)) rows--;
+ if (LINE_UNUSED(reg, ADDRMAP6_ROW_B12)) rows--;
+
+ return memory_sdram_size(cols, rows, BIT(banks), 4 / BIT(buswidth));
+}
+
+static inline unsigned ddrctrl_ramsize(void __iomem *base)
+{
+ struct stm32mp1_ddrctl __iomem *ddrctl = base;
+ unsigned buswidth = readl(&ddrctl->mstr) & DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK;
+ buswidth >>= DDRCTRL_MSTR_DATA_BUS_WIDTH_SHIFT;
+
+ return ddrctrl_addrmap_ramsize(ddrctl, buswidth);
+}
+
+static inline unsigned stm32mp1_ddrctrl_ramsize(void)
+{
+ return ddrctrl_ramsize(IOMEM(STM32_DDRCTL_BASE));
+}
+
+void __noreturn stm32mp1_barebox_entry(void *boarddata)
+{
+ barebox_arm_entry(STM32_DDR_BASE, stm32mp1_ddrctrl_ramsize(), boarddata);
+}
+
+
+static int stm32mp1_ddr_probe(struct device_d *dev)
+{
+ struct resource *iores;
+ void __iomem *base;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+ base = IOMEM(iores->start);
+
+ arm_add_mem_device("ram0", STM32_DDR_BASE, ddrctrl_ramsize(base));
+
+ return 0;
+}
+
+static __maybe_unused struct of_device_id stm32mp1_ddr_dt_ids[] = {
+ { .compatible = "st,stm32mp1-ddr" },
+ { /* sentinel */ }
+};
+
+static struct driver_d stm32mp1_ddr_driver = {
+ .name = "stm32mp1-ddr",
+ .probe = stm32mp1_ddr_probe,
+ .of_compatible = DRV_OF_COMPAT(stm32mp1_ddr_dt_ids),
+};
+
+static int stm32mp1_ddr_init(void)
+{
+ return platform_driver_register(&stm32mp1_ddr_driver);
+}
+mem_initcall(stm32mp1_ddr_init);
diff --git a/arch/arm/mach-stm32mp/include/mach/ddr_regs.h b/arch/arm/mach-stm32mp/include/mach/ddr_regs.h
new file mode 100644
index 0000000..7d6a5b8
--- /dev/null
+++ b/arch/arm/mach-stm32mp/include/mach/ddr_regs.h
@@ -0,0 +1,368 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ */
+
+#ifndef _STM32MP1_DDR_REGS_H
+#define _STM32MP1_DDR_REGS_H
+
+/* DDR3/LPDDR2/LPDDR3 Controller (DDRCTRL) registers */
+struct stm32mp1_ddrctl {
+ u32 mstr ; /* 0x0 Master*/
+ u32 stat; /* 0x4 Operating Mode Status*/
+ u8 reserved008[0x10 - 0x8];
+ u32 mrctrl0; /* 0x10 Control 0.*/
+ u32 mrctrl1; /* 0x14 Control 1*/
+ u32 mrstat; /* 0x18 Status*/
+ u32 reserved01c; /* 0x1c */
+ u32 derateen; /* 0x20 Temperature Derate Enable*/
+ u32 derateint; /* 0x24 Temperature Derate Interval*/
+ u8 reserved028[0x30 - 0x28];
+ u32 pwrctl; /* 0x30 Low Power Control*/
+ u32 pwrtmg; /* 0x34 Low Power Timing*/
+ u32 hwlpctl; /* 0x38 Hardware Low Power Control*/
+ u8 reserved03c[0x50 - 0x3C];
+ u32 rfshctl0; /* 0x50 Refresh Control 0*/
+ u32 reserved054; /* 0x54 Refresh Control 1*/
+ u32 reserved058; /* 0x58 Refresh Control 2*/
+ u32 reserved05C;
+ u32 rfshctl3; /* 0x60 Refresh Control 0*/
+ u32 rfshtmg; /* 0x64 Refresh Timing*/
+ u8 reserved068[0xc0 - 0x68];
+ u32 crcparctl0; /* 0xc0 CRC Parity Control0*/
+ u32 reserved0c4; /* 0xc4 CRC Parity Control1*/
+ u32 reserved0c8; /* 0xc8 CRC Parity Control2*/
+ u32 crcparstat; /* 0xcc CRC Parity Status*/
+ u32 init0; /* 0xd0 SDRAM Initialization 0*/
+ u32 init1; /* 0xd4 SDRAM Initialization 1*/
+ u32 init2; /* 0xd8 SDRAM Initialization 2*/
+ u32 init3; /* 0xdc SDRAM Initialization 3*/
+ u32 init4; /* 0xe0 SDRAM Initialization 4*/
+ u32 init5; /* 0xe4 SDRAM Initialization 5*/
+ u32 reserved0e8;
+ u32 reserved0ec;
+ u32 dimmctl; /* 0xf0 DIMM Control*/
+ u8 reserved0f4[0x100 - 0xf4];
+ u32 dramtmg0; /* 0x100 SDRAM Timing 0*/
+ u32 dramtmg1; /* 0x104 SDRAM Timing 1*/
+ u32 dramtmg2; /* 0x108 SDRAM Timing 2*/
+ u32 dramtmg3; /* 0x10c SDRAM Timing 3*/
+ u32 dramtmg4; /* 0x110 SDRAM Timing 4*/
+ u32 dramtmg5; /* 0x114 SDRAM Timing 5*/
+ u32 dramtmg6; /* 0x118 SDRAM Timing 6*/
+ u32 dramtmg7; /* 0x11c SDRAM Timing 7*/
+ u32 dramtmg8; /* 0x120 SDRAM Timing 8*/
+ u8 reserved124[0x138 - 0x124];
+ u32 dramtmg14; /* 0x138 SDRAM Timing 14*/
+ u32 dramtmg15; /* 0x13C SDRAM Timing 15*/
+ u8 reserved140[0x180 - 0x140];
+ u32 zqctl0; /* 0x180 ZQ Control 0*/
+ u32 zqctl1; /* 0x184 ZQ Control 1*/
+ u32 zqctl2; /* 0x188 ZQ Control 2*/
+ u32 zqstat; /* 0x18c ZQ Status*/
+ u32 dfitmg0; /* 0x190 DFI Timing 0*/
+ u32 dfitmg1; /* 0x194 DFI Timing 1*/
+ u32 dfilpcfg0; /* 0x198 DFI Low Power Configuration 0*/
+ u32 reserved19c;
+ u32 dfiupd0; /* 0x1a0 DFI Update 0*/
+ u32 dfiupd1; /* 0x1a4 DFI Update 1*/
+ u32 dfiupd2; /* 0x1a8 DFI Update 2*/
+ u32 reserved1ac;
+ u32 dfimisc; /* 0x1b0 DFI Miscellaneous Control*/
+ u8 reserved1b4[0x1bc - 0x1b4];
+ u32 dfistat; /* 0x1bc DFI Miscellaneous Control*/
+ u8 reserved1c0[0x1c4 - 0x1c0];
+ u32 dfiphymstr; /* 0x1c4 DFI PHY Master interface*/
+ u8 reserved1c8[0x204 - 0x1c8];
+ u32 addrmap1; /* 0x204 Address Map 1*/
+ u32 addrmap2; /* 0x208 Address Map 2*/
+ u32 addrmap3; /* 0x20c Address Map 3*/
+ u32 addrmap4; /* 0x210 Address Map 4*/
+ u32 addrmap5; /* 0x214 Address Map 5*/
+ u32 addrmap6; /* 0x218 Address Map 6*/
+ u8 reserved21c[0x224 - 0x21c];
+ u32 addrmap9; /* 0x224 Address Map 9*/
+ u32 addrmap10; /* 0x228 Address Map 10*/
+ u32 addrmap11; /* 0x22C Address Map 11*/
+ u8 reserved230[0x240 - 0x230];
+ u32 odtcfg; /* 0x240 ODT Configuration*/
+ u32 odtmap; /* 0x244 ODT/Rank Map*/
+ u8 reserved248[0x250 - 0x248];
+ u32 sched; /* 0x250 Scheduler Control*/
+ u32 sched1; /* 0x254 Scheduler Control 1*/
+ u32 reserved258;
+ u32 perfhpr1; /* 0x25c High Priority Read CAM 1*/
+ u32 reserved260;
+ u32 perflpr1; /* 0x264 Low Priority Read CAM 1*/
+ u32 reserved268;
+ u32 perfwr1; /* 0x26c Write CAM 1*/
+ u8 reserved27c[0x300 - 0x270];
+ u32 dbg0; /* 0x300 Debug 0*/
+ u32 dbg1; /* 0x304 Debug 1*/
+ u32 dbgcam; /* 0x308 CAM Debug*/
+ u32 dbgcmd; /* 0x30c Command Debug*/
+ u32 dbgstat; /* 0x310 Status Debug*/
+ u8 reserved314[0x320 - 0x314];
+ u32 swctl; /* 0x320 Software Programming Control Enable*/
+ u32 swstat; /* 0x324 Software Programming Control Status*/
+ u8 reserved328[0x36c - 0x328];
+ u32 poisoncfg; /* 0x36c AXI Poison Configuration Register*/
+ u32 poisonstat; /* 0x370 AXI Poison Status Register*/
+ u8 reserved374[0x3fc - 0x374];
+
+ /* Multi Port registers */
+ u32 pstat; /* 0x3fc Port Status*/
+ u32 pccfg; /* 0x400 Port Common Configuration*/
+
+ /* PORT 0 */
+ u32 pcfgr_0; /* 0x404 Configuration Read*/
+ u32 pcfgw_0; /* 0x408 Configuration Write*/
+ u8 reserved40c[0x490 - 0x40c];
+ u32 pctrl_0; /* 0x490 Port Control Register */
+ u32 pcfgqos0_0; /* 0x494 Read QoS Configuration 0*/
+ u32 pcfgqos1_0; /* 0x498 Read QoS Configuration 1*/
+ u32 pcfgwqos0_0; /* 0x49c Write QoS Configuration 0*/
+ u32 pcfgwqos1_0; /* 0x4a0 Write QoS Configuration 1*/
+ u8 reserved4a4[0x4b4 - 0x4a4];
+
+ /* PORT 1 */
+ u32 pcfgr_1; /* 0x4b4 Configuration Read*/
+ u32 pcfgw_1; /* 0x4b8 Configuration Write*/
+ u8 reserved4bc[0x540 - 0x4bc];
+ u32 pctrl_1; /* 0x540 Port 2 Control Register */
+ u32 pcfgqos0_1; /* 0x544 Read QoS Configuration 0*/
+ u32 pcfgqos1_1; /* 0x548 Read QoS Configuration 1*/
+ u32 pcfgwqos0_1; /* 0x54c Write QoS Configuration 0*/
+ u32 pcfgwqos1_1; /* 0x550 Write QoS Configuration 1*/
+};
+
+/* DDR Physical Interface Control (DDRPHYC) registers*/
+struct stm32mp1_ddrphy {
+ u32 ridr; /* 0x00 R Revision Identification*/
+ u32 pir; /* 0x04 R/W PHY Initialization*/
+ u32 pgcr; /* 0x08 R/W PHY General Configuration*/
+ u32 pgsr; /* 0x0C PHY General Status*/
+ u32 dllgcr; /* 0x10 R/W DLL General Control*/
+ u32 acdllcr; /* 0x14 R/W AC DLL Control*/
+ u32 ptr0; /* 0x18 R/W PHY Timing 0*/
+ u32 ptr1; /* 0x1C R/W PHY Timing 1*/
+ u32 ptr2; /* 0x20 R/W PHY Timing 2*/
+ u32 aciocr; /* 0x24 AC I/O Configuration*/
+ u32 dxccr; /* 0x28 DATX8 Common Configuration*/
+ u32 dsgcr; /* 0x2C DDR System General Configuration*/
+ u32 dcr; /* 0x30 DRAM Configuration*/
+ u32 dtpr0; /* 0x34 DRAM Timing Parameters0*/
+ u32 dtpr1; /* 0x38 DRAM Timing Parameters1*/
+ u32 dtpr2; /* 0x3C DRAM Timing Parameters2*/
+ u32 mr0; /* 0x40 Mode 0*/
+ u32 mr1; /* 0x44 Mode 1*/
+ u32 mr2; /* 0x48 Mode 2*/
+ u32 mr3; /* 0x4C Mode 3*/
+ u32 odtcr; /* 0x50 ODT Configuration*/
+ u32 dtar; /* 0x54 data training address*/
+ u32 dtdr0; /* 0x58 */
+ u32 dtdr1; /* 0x5c */
+ u8 res1[0x0c0 - 0x060]; /* 0x60 */
+ u32 dcuar; /* 0xc0 Address*/
+ u32 dcudr; /* 0xc4 DCU Data*/
+ u32 dcurr; /* 0xc8 DCU Run*/
+ u32 dculr; /* 0xcc DCU Loop*/
+ u32 dcugcr; /* 0xd0 DCU General Configuration*/
+ u32 dcutpr; /* 0xd4 DCU Timing Parameters */
+ u32 dcusr0; /* 0xd8 DCU Status 0*/
+ u32 dcusr1; /* 0xdc DCU Status 1*/
+ u8 res2[0x100 - 0xe0]; /* 0xe0 */
+ u32 bistrr; /* 0x100 BIST Run*/
+ u32 bistmskr0; /* 0x104 BIST Mask 0*/
+ u32 bistmskr1; /* 0x108 BIST Mask 0*/
+ u32 bistwcr; /* 0x10c BIST Word Count*/
+ u32 bistlsr; /* 0x110 BIST LFSR Seed*/
+ u32 bistar0; /* 0x114 BIST Address 0*/
+ u32 bistar1; /* 0x118 BIST Address 1*/
+ u32 bistar2; /* 0x11c BIST Address 2*/
+ u32 bistupdr; /* 0x120 BIST User Data Pattern*/
+ u32 bistgsr; /* 0x124 BIST General Status*/
+ u32 bistwer; /* 0x128 BIST Word Error*/
+ u32 bistber0; /* 0x12c BIST Bit Error 0*/
+ u32 bistber1; /* 0x130 BIST Bit Error 1*/
+ u32 bistber2; /* 0x134 BIST Bit Error 2*/
+ u32 bistwcsr; /* 0x138 BIST Word Count Status*/
+ u32 bistfwr0; /* 0x13c BIST Fail Word 0*/
+ u32 bistfwr1; /* 0x140 BIST Fail Word 1*/
+ u8 res3[0x178 - 0x144]; /* 0x144 */
+ u32 gpr0; /* 0x178 General Purpose 0 (GPR0)*/
+ u32 gpr1; /* 0x17C General Purpose 1 (GPR1)*/
+ u32 zq0cr0; /* 0x180 zq 0 control 0 */
+ u32 zq0cr1; /* 0x184 zq 0 control 1 */
+ u32 zq0sr0; /* 0x188 zq 0 status 0 */
+ u32 zq0sr1; /* 0x18C zq 0 status 1 */
+ u8 res4[0x1C0 - 0x190]; /* 0x190 */
+ u32 dx0gcr; /* 0x1c0 Byte lane 0 General Configuration*/
+ u32 dx0gsr0; /* 0x1c4 Byte lane 0 General Status 0*/
+ u32 dx0gsr1; /* 0x1c8 Byte lane 0 General Status 1*/
+ u32 dx0dllcr; /* 0x1cc Byte lane 0 DLL Control*/
+ u32 dx0dqtr; /* 0x1d0 Byte lane 0 DQ Timing*/
+ u32 dx0dqstr; /* 0x1d4 Byte lane 0 DQS Timing*/
+ u8 res5[0x200 - 0x1d8]; /* 0x1d8 */
+ u32 dx1gcr; /* 0x200 Byte lane 1 General Configuration*/
+ u32 dx1gsr0; /* 0x204 Byte lane 1 General Status 0*/
+ u32 dx1gsr1; /* 0x208 Byte lane 1 General Status 1*/
+ u32 dx1dllcr; /* 0x20c Byte lane 1 DLL Control*/
+ u32 dx1dqtr; /* 0x210 Byte lane 1 DQ Timing*/
+ u32 dx1dqstr; /* 0x214 Byte lane 1 QS Timing*/
+ u8 res6[0x240 - 0x218]; /* 0x218 */
+ u32 dx2gcr; /* 0x240 Byte lane 2 General Configuration*/
+ u32 dx2gsr0; /* 0x244 Byte lane 2 General Status 0*/
+ u32 dx2gsr1; /* 0x248 Byte lane 2 General Status 1*/
+ u32 dx2dllcr; /* 0x24c Byte lane 2 DLL Control*/
+ u32 dx2dqtr; /* 0x250 Byte lane 2 DQ Timing*/
+ u32 dx2dqstr; /* 0x254 Byte lane 2 QS Timing*/
+ u8 res7[0x280 - 0x258]; /* 0x258 */
+ u32 dx3gcr; /* 0x280 Byte lane 3 General Configuration*/
+ u32 dx3gsr0; /* 0x284 Byte lane 3 General Status 0*/
+ u32 dx3gsr1; /* 0x288 Byte lane 3 General Status 1*/
+ u32 dx3dllcr; /* 0x28c Byte lane 3 DLL Control*/
+ u32 dx3dqtr; /* 0x290 Byte lane 3 DQ Timing*/
+ u32 dx3dqstr; /* 0x294 Byte lane 3 QS Timing*/
+};
+
+#define DXN(phy, offset, byte) ((u32)(phy) + (offset) + ((u32)(byte) * 0x40))
+#define DXNGCR(phy, byte) DXN(phy, 0x1c0, byte)
+#define DXNDLLCR(phy, byte) DXN(phy, 0x1cc, byte)
+#define DXNDQTR(phy, byte) DXN(phy, 0x1d0, byte)
+#define DXNDQSTR(phy, byte) DXN(phy, 0x1d4, byte)
+
+/* DDRCTRL REGISTERS */
+#define DDRCTRL_MSTR_DDR3 BIT(0)
+#define DDRCTRL_MSTR_LPDDR2 BIT(2)
+#define DDRCTRL_MSTR_LPDDR3 BIT(3)
+#define DDRCTRL_MSTR_DATA_BUS_WIDTH_SHIFT 12
+#define DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK GENMASK(13, 12)
+#define DDRCTRL_MSTR_DATA_BUS_WIDTH_FULL (0 << 12)
+#define DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF (1 << 12)
+#define DDRCTRL_MSTR_DATA_BUS_WIDTH_QUARTER (2 << 12)
+#define DDRCTRL_MSTR_DLL_OFF_MODE BIT(15)
+
+#define DDRCTRL_STAT_OPERATING_MODE_MASK GENMASK(2, 0)
+#define DDRCTRL_STAT_OPERATING_MODE_NORMAL 1
+#define DDRCTRL_STAT_OPERATING_MODE_SR 3
+#define DDRCTRL_STAT_SELFREF_TYPE_MASK GENMASK(5, 4)
+#define DDRCTRL_STAT_SELFREF_TYPE_ASR (3 << 4)
+#define DDRCTRL_STAT_SELFREF_TYPE_SR (2 << 4)
+
+#define DDRCTRL_MRCTRL0_MR_TYPE_WRITE 0
+/* only one rank supported */
+#define DDRCTRL_MRCTRL0_MR_RANK_SHIFT 4
+#define DDRCTRL_MRCTRL0_MR_RANK_ALL \
+ (0x1 << DDRCTRL_MRCTRL0_MR_RANK_SHIFT)
+#define DDRCTRL_MRCTRL0_MR_ADDR_SHIFT 12
+#define DDRCTRL_MRCTRL0_MR_ADDR_MASK GENMASK(15, 12)
+#define DDRCTRL_MRCTRL0_MR_WR BIT(31)
+
+#define DDRCTRL_MRSTAT_MR_WR_BUSY BIT(0)
+
+#define DDRCTRL_PWRCTL_POWERDOWN_EN BIT(1)
+#define DDRCTRL_PWRCTL_SELFREF_SW BIT(5)
+
+#define DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH BIT(0)
+
+#define DDRCTRL_RFSHTMG_T_RFC_NOM_X1_X32_MASK GENMASK(27, 16)
+#define DDRCTRL_RFSHTMG_T_RFC_NOM_X1_X32_SHIFT 16
+
+#define DDRCTRL_INIT0_SKIP_DRAM_INIT_MASK (0xC0000000)
+#define DDRCTRL_INIT0_SKIP_DRAM_INIT_NORMAL (BIT(30))
+
+#define DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN BIT(0)
+
+#define DDRCTRL_DBG1_DIS_HIF BIT(1)
+
+#define DDRCTRL_DBGCAM_WR_DATA_PIPELINE_EMPTY BIT(29)
+#define DDRCTRL_DBGCAM_RD_DATA_PIPELINE_EMPTY BIT(28)
+#define DDRCTRL_DBGCAM_DBG_WR_Q_EMPTY BIT(26)
+#define DDRCTRL_DBGCAM_DBG_LPR_Q_DEPTH GENMASK(12, 8)
+#define DDRCTRL_DBGCAM_DBG_HPR_Q_DEPTH GENMASK(4, 0)
+#define DDRCTRL_DBGCAM_DATA_PIPELINE_EMPTY \
+ (DDRCTRL_DBGCAM_WR_DATA_PIPELINE_EMPTY | \
+ DDRCTRL_DBGCAM_RD_DATA_PIPELINE_EMPTY)
+#define DDRCTRL_DBGCAM_DBG_Q_DEPTH \
+ (DDRCTRL_DBGCAM_DBG_WR_Q_EMPTY | \
+ DDRCTRL_DBGCAM_DBG_LPR_Q_DEPTH | \
+ DDRCTRL_DBGCAM_DBG_HPR_Q_DEPTH)
+
+#define DDRCTRL_DBGCMD_RANK0_REFRESH BIT(0)
+
+#define DDRCTRL_DBGSTAT_RANK0_REFRESH_BUSY BIT(0)
+
+#define DDRCTRL_SWCTL_SW_DONE BIT(0)
+
+#define DDRCTRL_SWSTAT_SW_DONE_ACK BIT(0)
+
+#define DDRCTRL_PCTRL_N_PORT_EN BIT(0)
+
+/* DDRPHYC registers */
+#define DDRPHYC_PIR_INIT BIT(0)
+#define DDRPHYC_PIR_DLLSRST BIT(1)
+#define DDRPHYC_PIR_DLLLOCK BIT(2)
+#define DDRPHYC_PIR_ZCAL BIT(3)
+#define DDRPHYC_PIR_ITMSRST BIT(4)
+#define DDRPHYC_PIR_DRAMRST BIT(5)
+#define DDRPHYC_PIR_DRAMINIT BIT(6)
+#define DDRPHYC_PIR_QSTRN BIT(7)
+#define DDRPHYC_PIR_ICPC BIT(16)
+#define DDRPHYC_PIR_ZCALBYP BIT(30)
+#define DDRPHYC_PIR_INITSTEPS_MASK GENMASK(31, 7)
+
+#define DDRPHYC_PGCR_DFTCMP BIT(2)
+#define DDRPHYC_PGCR_PDDISDX BIT(24)
+#define DDRPHYC_PGCR_RFSHDT_MASK GENMASK(28, 25)
+
+#define DDRPHYC_PGSR_IDONE BIT(0)
+#define DDRPHYC_PGSR_DTERR BIT(5)
+#define DDRPHYC_PGSR_DTIERR BIT(6)
+#define DDRPHYC_PGSR_DFTERR BIT(7)
+#define DDRPHYC_PGSR_RVERR BIT(8)
+#define DDRPHYC_PGSR_RVEIRR BIT(9)
+
+#define DDRPHYC_DLLGCR_BPS200 BIT(23)
+
+#define DDRPHYC_ACDLLCR_DLLDIS BIT(31)
+
+#define DDRPHYC_ZQ0CRN_ZDATA_MASK GENMASK(27, 0)
+#define DDRPHYC_ZQ0CRN_ZDATA_SHIFT 0
+#define DDRPHYC_ZQ0CRN_ZDEN BIT(28)
+
+#define DDRPHYC_DXNGCR_DXEN BIT(0)
+
+#define DDRPHYC_DXNDLLCR_DLLSRST BIT(30)
+#define DDRPHYC_DXNDLLCR_DLLDIS BIT(31)
+#define DDRPHYC_DXNDLLCR_SDPHASE_MASK GENMASK(17, 14)
+#define DDRPHYC_DXNDLLCR_SDPHASE_SHIFT 14
+
+#define DDRPHYC_DXNDQTR_DQDLY_SHIFT(bit) (4 * (bit))
+#define DDRPHYC_DXNDQTR_DQDLY_MASK GENMASK(3, 0)
+#define DDRPHYC_DXNDQTR_DQDLY_LOW_MASK GENMASK(1, 0)
+#define DDRPHYC_DXNDQTR_DQDLY_HIGH_MASK GENMASK(3, 2)
+
+#define DDRPHYC_DXNDQSTR_DQSDLY_MASK GENMASK(22, 20)
+#define DDRPHYC_DXNDQSTR_DQSDLY_SHIFT 20
+#define DDRPHYC_DXNDQSTR_DQSNDLY_MASK GENMASK(25, 23)
+#define DDRPHYC_DXNDQSTR_DQSNDLY_SHIFT 23
+#define DDRPHYC_DXNDQSTR_R0DGSL_MASK GENMASK(2, 0)
+#define DDRPHYC_DXNDQSTR_R0DGSL_SHIFT 0
+#define DDRPHYC_DXNDQSTR_R0DGPS_MASK GENMASK(13, 12)
+#define DDRPHYC_DXNDQSTR_R0DGPS_SHIFT 12
+
+#define DDRPHYC_BISTRR_BDXSEL_MASK GENMASK(22, 19)
+#define DDRPHYC_BISTRR_BDXSEL_SHIFT 19
+
+#define DDRPHYC_BISTGSR_BDDONE BIT(0)
+#define DDRPHYC_BISTGSR_BDXERR BIT(2)
+
+#define DDRPHYC_BISTWCSR_DXWCNT_SHIFT 16
+
+/* PWR registers */
+#define PWR_CR3 0x00C
+#define PWR_CR3_DDRSRDIS BIT(11)
+#define PWR_CR3_DDRRETEN BIT(12)
+
+#endif
diff --git a/arch/arm/mach-stm32mp/include/mach/entry.h b/arch/arm/mach-stm32mp/include/mach/entry.h
new file mode 100644
index 0000000..92e15b5
--- /dev/null
+++ b/arch/arm/mach-stm32mp/include/mach/entry.h
@@ -0,0 +1,19 @@
+#ifndef _STM32MP_MACH_ENTRY_H_
+#define _STM32MP_MACH_ENTRY_H_
+
+#include <linux/kernel.h>
+#include <asm/barebox-arm.h>
+
+static __always_inline void stm32mp_cpu_lowlevel_init(void)
+{
+ unsigned long stack_top;
+ arm_cpu_lowlevel_init();
+
+ stack_top = (unsigned long)__image_end + get_runtime_offset() + 64;
+ stack_top = ALIGN(stack_top, 16);
+ arm_setup_stack(stack_top);
+}
+
+void __noreturn stm32mp1_barebox_entry(void *boarddata);
+
+#endif
diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h
index f9bdb78..adb898f 100644
--- a/arch/arm/mach-stm32mp/include/mach/stm32.h
+++ b/arch/arm/mach-stm32mp/include/mach/stm32.h
@@ -12,6 +12,8 @@
#define STM32_RCC_BASE 0x50000000
#define STM32_PWR_BASE 0x50001000
#define STM32_DBGMCU_BASE 0x50081000
+#define STM32_DDRCTL_BASE 0x5A003000
+#define STM32_DDRPHY_BASE 0x5A004000
#define STM32_BSEC_BASE 0x5C005000
#define STM32_TZC_BASE 0x5C006000
#define STM32_ETZPC_BASE 0x5C007000
diff --git a/arch/arm/mach-zynq/Makefile b/arch/arm/mach-zynq/Makefile
index 3252247..c88ab46 100644
--- a/arch/arm/mach-zynq/Makefile
+++ b/arch/arm/mach-zynq/Makefile
@@ -1 +1 @@
-obj-y += zynq.o
+obj-y += zynq.o bootm-zynqimg.o
diff --git a/arch/arm/mach-zynq/bootm-zynqimg.c b/arch/arm/mach-zynq/bootm-zynqimg.c
new file mode 100644
index 0000000..e903ab6
--- /dev/null
+++ b/arch/arm/mach-zynq/bootm-zynqimg.c
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <bootm.h>
+#include <common.h>
+#include <init.h>
+#include <memory.h>
+
+static int do_bootm_zynqimage(struct image_data *data)
+{
+ resource_size_t start, end;
+ void (*barebox)(void);
+ u32 *header;
+ int ret;
+
+ ret = memory_bank_first_find_space(&start, &end);
+ if (ret)
+ return ret;
+
+ ret = bootm_load_os(data, start);
+ if (ret)
+ return ret;
+
+ header = (u32*)start;
+ barebox = (void*)start + header[12];
+
+ if (data->verbose)
+ printf("Loaded barebox image to 0x%08lx\n",
+ (unsigned long)barebox);
+
+ shutdown_barebox();
+
+ barebox();
+
+ return -EIO;
+}
+
+static struct image_handler zynq_image_handler = {
+ .name = "Zynq image",
+ .bootm = do_bootm_zynqimage,
+ .filetype = filetype_zynq_image,
+};
+
+static int zynq_register_image_handler(void)
+{
+ register_image_handler(&zynq_image_handler);
+
+ return 0;
+}
+late_initcall(zynq_register_image_handler);
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index ee465dc..1c10db5 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -52,9 +52,7 @@ cflags-$(CONFIG_CPU_MIPS32_R1) += $(call cc-option,-march=mips32,-mips32 -U_MIPS
cflags-$(CONFIG_CPU_MIPS32_R2) += $(call cc-option,-march=mips32r2,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) -Wa,-mips32r2 -Wa,--trap
cflags-$(CONFIG_CPU_MIPS64_R1) += $(call cc-option,-march=mips64,-mips64 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) -Wa,-mips64 -Wa,--trap
cflags-$(CONFIG_CPU_MIPS64_R2) += $(call cc-option,-march=mips64r2,-mips64r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) -Wa,-mips64r2 -Wa,--trap
-cflags-$(CONFIG_CPU_LOONGSON1) += \
- $(call cc-option,-march=mips32r2,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
- -Wa,-mips32r2 -Wa,--trap
+cflags-$(CONFIG_CPU_LOONGSON1) += $(call cc-option,-march=mips32r2,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) -Wa,-mips32r2 -Wa,--trap
CPPFLAGS += -DTEXT_BASE=$(CONFIG_TEXT_BASE)
diff --git a/arch/mips/mach-ath79/art.c b/arch/mips/mach-ath79/art.c
index 2a2099e..44118c1 100644
--- a/arch/mips/mach-ath79/art.c
+++ b/arch/mips/mach-ath79/art.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2018 Oleksij Rempel <linux@rempel-privat.de>
*/
diff --git a/arch/x86/mach-efi/elf_x86_64_efi.lds.S b/arch/x86/mach-efi/elf_x86_64_efi.lds.S
index 40a9425..ed79118 100644
--- a/arch/x86/mach-efi/elf_x86_64_efi.lds.S
+++ b/arch/x86/mach-efi/elf_x86_64_efi.lds.S
@@ -58,12 +58,7 @@ SECTIONS
. = ALIGN(4096);
.rela : {
- *(.rela.data*)
- *(.rela.barebox*)
- *(.rela.initcall*)
- *(.rela.exitcall*)
- *(.rela.got)
- *(.rela.stab)
+ *(.rela*)
}
. = ALIGN(4096);
diff --git a/commands/Kconfig b/commands/Kconfig
index a6db52a..7784966 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -1867,6 +1867,21 @@ config CMD_POWEROFF
help
Turn the power off.
+config CMD_SMC
+ bool
+ depends on ARM_SMCCC
+ prompt "PSCI test command"
+ default CONFIG_ARM_PSCI_DEBUG
+ help
+ Secure monitor code test command
+
+ Usage: smc [-nic]
+
+ Options:
+ -n Install secure monitor and switch to nonsecure mode
+ -i Show information about installed PSCI version
+ -c Start secondary CPU core
+
config CMD_SPI
bool
depends on SPI
diff --git a/commands/Makefile b/commands/Makefile
index 2f09801..01082de 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_CMD_MEMSET) += memset.o
obj-$(CONFIG_CMD_EDIT) += edit.o
obj-$(CONFIG_CMD_EXEC) += exec.o
obj-$(CONFIG_CMD_SLEEP) += sleep.o
+obj-$(CONFIG_CMD_SMC) += smc.o
obj-$(CONFIG_CMD_MSLEEP) += msleep.o
obj-$(CONFIG_CMD_RESET) += reset.o
obj-$(CONFIG_CMD_POWEROFF) += poweroff.o
diff --git a/commands/digest.c b/commands/digest.c
index 99b27dc..21a0917 100644
--- a/commands/digest.c
+++ b/commands/digest.c
@@ -164,7 +164,7 @@ static int do_digest(int argc, char *argv[])
if (sig) {
digestlen = digest_length(d);
- if (siglen == 2 * digestlen) {
+ if (siglen >= 2 * digestlen) {
if (!tmp_sig)
tmp_sig = xmalloc(digestlen);
diff --git a/commands/gpio.c b/commands/gpio.c
index 951ad2c..6d88ab6 100644
--- a/commands/gpio.c
+++ b/commands/gpio.c
@@ -25,7 +25,9 @@ static int get_gpio_and_value(int argc, char *argv[],
if (argc < count)
return COMMAND_ERROR_USAGE;
- *gpio = gpio_find_by_label(argv[1]);
+ *gpio = gpio_find_by_name(argv[1]);
+ if (*gpio < 0)
+ *gpio = gpio_find_by_label(argv[1]);
if (*gpio < 0) {
ret = kstrtoint(argv[1], 0, gpio);
if (ret < 0)
diff --git a/commands/keystore.c b/commands/keystore.c
index 52c4be2..4f6a7ef 100644
--- a/commands/keystore.c
+++ b/commands/keystore.c
@@ -15,7 +15,7 @@ static int do_keystore(int argc, char *argv[])
const char *file = NULL;
char *secret_str = NULL;
void *secret;
- int s_len;
+ size_t s_len;
while ((opt = getopt(argc, argv, "rs:f:")) > 0) {
switch (opt) {
diff --git a/commands/nv.c b/commands/nv.c
index 01c25a1..3150193 100644
--- a/commands/nv.c
+++ b/commands/nv.c
@@ -50,6 +50,11 @@ static int do_nv(int argc, char *argv[])
}
if (do_save) {
+ if (!IS_ENABLED(CONFIG_ENV_HANDLING)) {
+ printf("Error: Current configuration does not support saving variables\n");
+ return COMMAND_ERROR;
+ }
+
return nvvar_save();
}
diff --git a/commands/smc.c b/commands/smc.c
new file mode 100644
index 0000000..84102f3
--- /dev/null
+++ b/commands/smc.c
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <common.h>
+#include <command.h>
+#include <getopt.h>
+#include <dma.h>
+#include <linux/iopoll.h>
+#include <asm/barebox-arm-head.h>
+
+#include <asm/psci.h>
+#include <asm/secure.h>
+#include <linux/arm-smccc.h>
+
+#define STACK_SIZE 100
+#define HANDSHAKE_MAGIC 0xBA12EB0C
+#define ERROR_MAGIC 0xDEADBEEF
+
+struct cpu_context {
+ unsigned long stack[STACK_SIZE];
+ long handshake;
+};
+
+static void noinline cpu_handshake(long *handshake)
+{
+ struct arm_smccc_res res;
+
+ writel(HANDSHAKE_MAGIC, handshake);
+
+ arm_smccc_smc(ARM_PSCI_0_2_FN_CPU_OFF,
+ 0, 0, 0, 0, 0, 0, 0, &res);
+
+ writel(ERROR_MAGIC, handshake);
+
+ while (1)
+ ;
+}
+
+static void __naked second_entry(unsigned long arg0)
+{
+ struct cpu_context *context = (void*)arg0;
+
+ arm_cpu_lowlevel_init();
+ arm_setup_stack((unsigned long)&context->stack[STACK_SIZE]);
+ barrier();
+
+ cpu_handshake(&context->handshake);
+}
+
+static const char *psci_xlate_str(long err)
+{
+ static char errno_string[sizeof "error 0x123456789ABCDEF0"];
+
+ switch(err)
+ {
+ case ARM_PSCI_RET_SUCCESS:
+ return "Success";
+ case ARM_PSCI_RET_NOT_SUPPORTED:
+ return "Operation not supported";
+ case ARM_PSCI_RET_INVAL:
+ return "Invalid argument";
+ case ARM_PSCI_RET_DENIED:
+ return "Operation not permitted";
+ case ARM_PSCI_RET_ALREADY_ON:
+ return "CPU already on";
+ case ARM_PSCI_RET_ON_PENDING:
+ return "CPU_ON in progress";
+ case ARM_PSCI_RET_INTERNAL_FAILURE:
+ return "Internal failure";
+ case ARM_PSCI_RET_NOT_PRESENT:
+ return "Trusted OS not present on core";
+ case ARM_PSCI_RET_DISABLED:
+ return "CPU is disabled";
+ case ARM_PSCI_RET_INVALID_ADDRESS:
+ return "Bad address";
+ }
+
+ sprintf(errno_string, "error 0x%lx", err);
+ return errno_string;
+}
+
+static struct cpu_context *context;
+
+static int do_smc(int argc, char *argv[])
+{
+ long ret;
+ int opt;
+ struct arm_smccc_res res = {
+ .a0 = 0xdeadbee0,
+ .a1 = 0xdeadbee1,
+ .a2 = 0xdeadbee2,
+ .a3 = 0xdeadbee3,
+ };
+
+ if (argc < 2)
+ return COMMAND_ERROR_USAGE;
+
+ while ((opt = getopt(argc, argv, "nic")) > 0) {
+ switch (opt) {
+ case 'n':
+ if (!IS_ENABLED(CONFIG_ARM_SECURE_MONITOR)) {
+ printf("secure monitor support not compiled in\n");
+ return COMMAND_ERROR;
+ }
+
+ armv7_secure_monitor_install();
+ break;
+ case 'i':
+ arm_smccc_smc(ARM_PSCI_0_2_FN_PSCI_VERSION,
+ 0, 0, 0, 0, 0, 0, 0, &res);
+ printf("found psci version %ld.%ld\n", res.a0 >> 16, res.a0 & 0xffff);
+ break;
+ case 'c':
+ if (!context)
+ context = dma_alloc_coherent(sizeof(*context),
+ DMA_ADDRESS_BROKEN);
+
+ if (!context) {
+ printf("Out of memory\n");
+ return COMMAND_ERROR;
+ }
+
+ arm_smccc_smc(ARM_PSCI_0_2_FN_CPU_ON,
+ 1, (unsigned long)second_entry, (unsigned long)context,
+ 0, 0, 0, 0, &res);
+ ret = (long)res.a0;
+ printf("CPU_ON returns with: %s\n", psci_xlate_str(ret));
+ if (ret) {
+ unsigned long magic = readl(&context->handshake);
+ if (magic == ERROR_MAGIC)
+ printf("Turning off CPU had failed\n");
+ return COMMAND_ERROR;
+ }
+
+ readl_poll_timeout(&context->handshake, ret,
+ ret != HANDSHAKE_MAGIC, USEC_PER_SEC);
+ if (ret == 0) {
+ printf("Second CPU handshake timed out.\n");
+ return COMMAND_ERROR;
+ }
+
+ printf("Second CPU handshake successful.\n");
+ }
+ }
+
+
+ return 0;
+}
+BAREBOX_CMD_HELP_START(smc)
+BAREBOX_CMD_HELP_TEXT("Secure monitor code test command")
+BAREBOX_CMD_HELP_TEXT("")
+BAREBOX_CMD_HELP_TEXT("Options:")
+BAREBOX_CMD_HELP_OPT ("-n", "Install secure monitor and switch to nonsecure mode")
+BAREBOX_CMD_HELP_OPT ("-i", "Show information about installed PSCI version")
+BAREBOX_CMD_HELP_OPT ("-c", "Start secondary CPU core")
+BAREBOX_CMD_HELP_END
+
+BAREBOX_CMD_START(smc)
+ .cmd = do_smc,
+ BAREBOX_CMD_DESC("secure monitor test command")
+ BAREBOX_CMD_HELP(cmd_smc_help)
+ BAREBOX_CMD_GROUP(CMD_GRP_MISC)
+BAREBOX_CMD_END
diff --git a/common/Kconfig b/common/Kconfig
index d397d8b..f9ef9bd 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -174,19 +174,19 @@ config GLOBALVAR
config NVVAR
bool "Non volatile global environment variables support"
- default y if !SHELL_NONE
+ default y if !SHELL_NONE && ENV_HANDLING
depends on GLOBALVAR
- depends on ENV_HANDLING
select FNMATCH
help
Non volatile environment variables begin with "nv.". They behave like
- global variables above, but their values are saved in the environment
- storage with 'saveenv' and thus are persistent over restarts. nv variables
- are coupled with global variables of the same name. Setting "nv.foo" results
- in "global.foo" changed also (but not the other way round: setting "global.foo"
- leaves "nv.foo" untouched). The idea is that nv variables can store defaults
- while global variables can be changed during runtime without changing the
- default.
+ global variables above, but when CONFIG_ENV_HANDLING is enabled, they
+ can be stored in the environment storage with 'saveenv' and thus
+ persisted over restarts. nv variables are coupled with global
+ variables of the same name. Setting "nv.foo" results in "global.foo"
+ changed also (but not the other way round: setting "global.foo" leaves
+ "nv.foo" untouched). The idea is that nv variables can store defaults
+ while global variables can be changed during runtime without changing
+ the default.
menu "memory layout"
@@ -805,12 +805,12 @@ config ENV_HANDLING
config DEFAULT_ENVIRONMENT
bool
- default y
- depends on ENV_HANDLING
+ default y if ENV_HANDLING
prompt "Compile in default environment"
help
Enabling this option will give you a default environment when
- the environment found in the environment sector is invalid
+ the environment found in the environment sector is invalid or when
+ CONFIG_ENV_HANDLING is not enabled.
choice
prompt "default compression for in-barebox binaries"
@@ -1309,7 +1309,7 @@ config DEBUG_INITCALLS
config PBL_BREAK
bool "Execute software break on pbl start"
- depends on ARM
+ depends on ARM && (!CPU_32v4T && !ARCH_TEGRA)
help
If this enabled, barebox will be compiled with BKPT instruction
on early pbl init. This option should be used only with JTAG debugger!
diff --git a/common/Makefile b/common/Makefile
index 1096016..11c91dd 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -26,7 +26,8 @@ obj-$(CONFIG_CONSOLE_FULL) += console.o
obj-$(CONFIG_CONSOLE_SIMPLE) += console_simple.o
obj-y += console_countdown.o
obj-pbl-$(CONFIG_DDR_SPD) += ddr_spd.o
-obj-$(CONFIG_ENV_HANDLING) += environment.o
+obj-$(CONFIG_ENV_HANDLING) += environment.o envfs-core.o
+obj-$(CONFIG_DEFAULT_ENVIRONMENT) += envfs-core.o
obj-$(CONFIG_ENVIRONMENT_VARIABLES) += env.o
obj-$(CONFIG_FILETYPE) += filetype.o
CFLAGS_filetype.o = -I$(srctree)/arch/
diff --git a/common/console_simple.c b/common/console_simple.c
index 6d293b2..4222484 100644
--- a/common/console_simple.c
+++ b/common/console_simple.c
@@ -64,9 +64,6 @@ void console_flush(void)
}
EXPORT_SYMBOL(console_flush);
-void ctrlc_handled(void)
-{
-}
/* test if ctrl-c was pressed */
int ctrlc (void)
{
@@ -81,14 +78,6 @@ int ctrlc (void)
}
EXPORT_SYMBOL(ctrlc);
-void console_ctrlc_allow(void)
-{
-}
-
-void console_ctrlc_forbid(void)
-{
-}
-
int console_register(struct console_device *newcdev)
{
if (console)
diff --git a/common/efi/efi.c b/common/efi/efi.c
index 73cea37..ed81583 100644
--- a/common/efi/efi.c
+++ b/common/efi/efi.c
@@ -361,7 +361,7 @@ efi_status_t efi_main(efi_handle_t image, efi_system_table_t *sys_table)
if (EFI_ERROR(efiret))
panic("failed to allocate malloc pool: %s\n",
efi_strerror(efiret));
- mem_malloc_init((void *)mem, (void *)mem + memsize);
+ mem_malloc_init((void *)mem, (void *)mem + memsize - 1);
start_barebox();
diff --git a/common/envfs-core.c b/common/envfs-core.c
new file mode 100644
index 0000000..1898c1c
--- /dev/null
+++ b/common/envfs-core.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Albert Schwarzkopf <a.schwarzkopf@phytec.de>, PHYTEC Messtechnik GmbH
+ * Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ */
+
+/**
+ * @file
+ * @brief Environment handling support (host and target)
+ *
+ * Important: This file will also be used on the host to create
+ * the default environment when building the barebox binary. So
+ * do not add any new barebox related functions here!
+ */
+#ifdef __BAREBOX__
+#include <common.h>
+#include <fs.h>
+#include <crc.h>
+#include <envfs.h>
+#include <libbb.h>
+#include <libgen.h>
+#include <environment.h>
+#include <libfile.h>
+#else
+# define errno_str(x) ("void")
+#endif
+
+static int dir_remove_action(const char *filename, struct stat *statbuf,
+ void *userdata, int depth)
+{
+ if (!depth)
+ return 1;
+
+ rmdir(filename);
+
+ return 1;
+}
+
+int envfs_check_super(struct envfs_super *super, size_t *size)
+{
+ if (ENVFS_32(super->magic) != ENVFS_MAGIC) {
+ printf("envfs: no envfs (magic mismatch) - envfs never written?\n");
+ return -EIO;
+ }
+
+ if (crc32(0, super, sizeof(*super) - 4) != ENVFS_32(super->sb_crc)) {
+ printf("wrong crc on env superblock\n");
+ return -EIO;
+ }
+
+ if (super->major < ENVFS_MAJOR)
+ printf("envfs version %d.%d loaded into %d.%d\n",
+ super->major, super->minor,
+ ENVFS_MAJOR, ENVFS_MINOR);
+
+ *size = ENVFS_32(super->size);
+
+ return 0;
+}
+
+int envfs_check_data(struct envfs_super *super, const void *buf, size_t size)
+{
+ uint32_t crc;
+
+ crc = crc32(0, buf, size);
+ if (crc != ENVFS_32(super->crc)) {
+ printf("wrong crc on env\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int envfs_load_data(struct envfs_super *super, void *buf, size_t size,
+ const char *dir, unsigned flags)
+{
+ int fd, ret = 0;
+ char *str, *tmp;
+ int headerlen_full;
+ /* for envfs < 1.0 */
+ struct envfs_inode_end inode_end_dummy;
+ struct stat s;
+
+ inode_end_dummy.mode = ENVFS_32(S_IRWXU | S_IRWXG | S_IRWXO);
+ inode_end_dummy.magic = ENVFS_32(ENVFS_INODE_END_MAGIC);
+
+ while (size) {
+ struct envfs_inode *inode;
+ struct envfs_inode_end *inode_end;
+ uint32_t inode_size, inode_headerlen, namelen;
+
+ inode = buf;
+ buf += sizeof(struct envfs_inode);
+
+ if (ENVFS_32(inode->magic) != ENVFS_INODE_MAGIC) {
+ printf("envfs: wrong magic\n");
+ ret = -EIO;
+ goto out;
+ }
+ inode_size = ENVFS_32(inode->size);
+ inode_headerlen = ENVFS_32(inode->headerlen);
+ namelen = strlen(inode->data) + 1;
+ if (super->major < 1)
+ inode_end = &inode_end_dummy;
+ else
+ inode_end = buf + PAD4(namelen);
+
+ debug("loading %s size %d namelen %d headerlen %d\n", inode->data,
+ inode_size, namelen, inode_headerlen);
+
+ str = concat_path_file(dir, inode->data);
+
+ headerlen_full = PAD4(inode_headerlen);
+ buf += headerlen_full;
+
+ if (ENVFS_32(inode_end->magic) != ENVFS_INODE_END_MAGIC) {
+ printf("envfs: wrong inode_end_magic\n");
+ ret = -EIO;
+ goto out;
+ }
+
+ tmp = strdup(str);
+ make_directory(dirname(tmp));
+ free(tmp);
+
+ ret = stat(str, &s);
+ if (!ret && (flags & ENV_FLAG_NO_OVERWRITE)) {
+ printf("skip %s\n", str);
+ goto skip;
+ }
+
+ if (S_ISLNK(ENVFS_32(inode_end->mode))) {
+ debug("symlink: %s -> %s\n", str, (char*)buf);
+ if (!strcmp(buf, basename(str))) {
+ unlink(str);
+ } else {
+ if (!ret)
+ unlink(str);
+
+ ret = symlink(buf, str);
+ if (ret < 0)
+ printf("symlink: %s -> %s : %s\n",
+ str, (char*)buf, strerror(-errno));
+ }
+ free(str);
+ } else {
+ fd = open(str, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ free(str);
+ if (fd < 0) {
+ printf("Open %s\n", errno_str());
+ ret = fd;
+ goto out;
+ }
+
+ ret = write(fd, buf, inode_size);
+ if (ret < inode_size) {
+ perror("write");
+ ret = -errno;
+ close(fd);
+ goto out;
+ }
+ close(fd);
+ }
+skip:
+ buf += PAD4(inode_size);
+ size -= headerlen_full + PAD4(inode_size) +
+ sizeof(struct envfs_inode);
+ }
+
+ recursive_action(dir, ACTION_RECURSE | ACTION_DEPTHFIRST, NULL,
+ dir_remove_action, NULL, 0);
+
+ ret = 0;
+out:
+ return ret;
+}
+
+int envfs_load_from_buf(void *buf, int len, const char *dir, unsigned flags)
+{
+ int ret;
+ size_t size;
+ struct envfs_super *super = buf;
+
+ buf = super + 1;
+
+ ret = envfs_check_super(super, &size);
+ if (ret)
+ return ret;
+
+ ret = envfs_check_data(super, buf, size);
+ if (ret)
+ return ret;
+
+ ret = envfs_load_data(super, buf, size, dir, flags);
+
+ return ret;
+}
diff --git a/common/environment.c b/common/environment.c
index aba6dcd..005caf4 100644
--- a/common/environment.c
+++ b/common/environment.c
@@ -56,7 +56,6 @@ struct action_data {
void *writep;
struct envfs_entry *env;
};
-#define PAD4(x) ((x + 3) & ~3)
#ifdef __BAREBOX__
@@ -228,17 +227,6 @@ static int file_remove_action(const char *filename, struct stat *statbuf,
}
#endif
-static int dir_remove_action(const char *filename, struct stat *statbuf,
- void *userdata, int depth)
-{
- if (!depth)
- return 1;
-
- rmdir(filename);
-
- return 1;
-}
-
/**
* Make the current environment persistent
* @param[in] filename where to store
@@ -382,166 +370,6 @@ out1:
}
EXPORT_SYMBOL(envfs_save);
-static int envfs_check_super(struct envfs_super *super, size_t *size)
-{
- if (ENVFS_32(super->magic) != ENVFS_MAGIC) {
- printf("envfs: no envfs (magic mismatch) - envfs never written?\n");
- return -EIO;
- }
-
- if (crc32(0, super, sizeof(*super) - 4) != ENVFS_32(super->sb_crc)) {
- printf("wrong crc on env superblock\n");
- return -EIO;
- }
-
- if (super->major < ENVFS_MAJOR)
- printf("envfs version %d.%d loaded into %d.%d\n",
- super->major, super->minor,
- ENVFS_MAJOR, ENVFS_MINOR);
-
- *size = ENVFS_32(super->size);
-
- return 0;
-}
-
-static int envfs_check_data(struct envfs_super *super, const void *buf, size_t size)
-{
- uint32_t crc;
-
- crc = crc32(0, buf, size);
- if (crc != ENVFS_32(super->crc)) {
- printf("wrong crc on env\n");
- return -EIO;
- }
-
- return 0;
-}
-
-static int envfs_load_data(struct envfs_super *super, void *buf, size_t size,
- const char *dir, unsigned flags)
-{
- int fd, ret = 0;
- char *str, *tmp;
- int headerlen_full;
- /* for envfs < 1.0 */
- struct envfs_inode_end inode_end_dummy;
- struct stat s;
-
- inode_end_dummy.mode = ENVFS_32(S_IRWXU | S_IRWXG | S_IRWXO);
- inode_end_dummy.magic = ENVFS_32(ENVFS_INODE_END_MAGIC);
-
- while (size) {
- struct envfs_inode *inode;
- struct envfs_inode_end *inode_end;
- uint32_t inode_size, inode_headerlen, namelen;
-
- inode = buf;
- buf += sizeof(struct envfs_inode);
-
- if (ENVFS_32(inode->magic) != ENVFS_INODE_MAGIC) {
- printf("envfs: wrong magic\n");
- ret = -EIO;
- goto out;
- }
- inode_size = ENVFS_32(inode->size);
- inode_headerlen = ENVFS_32(inode->headerlen);
- namelen = strlen(inode->data) + 1;
- if (super->major < 1)
- inode_end = &inode_end_dummy;
- else
- inode_end = buf + PAD4(namelen);
-
- debug("loading %s size %d namelen %d headerlen %d\n", inode->data,
- inode_size, namelen, inode_headerlen);
-
- str = concat_path_file(dir, inode->data);
-
- headerlen_full = PAD4(inode_headerlen);
- buf += headerlen_full;
-
- if (ENVFS_32(inode_end->magic) != ENVFS_INODE_END_MAGIC) {
- printf("envfs: wrong inode_end_magic\n");
- ret = -EIO;
- goto out;
- }
-
- tmp = strdup(str);
- make_directory(dirname(tmp));
- free(tmp);
-
- ret = stat(str, &s);
- if (!ret && (flags & ENV_FLAG_NO_OVERWRITE)) {
- printf("skip %s\n", str);
- goto skip;
- }
-
- if (S_ISLNK(ENVFS_32(inode_end->mode))) {
- debug("symlink: %s -> %s\n", str, (char*)buf);
- if (!strcmp(buf, basename(str))) {
- unlink(str);
- } else {
- if (!ret)
- unlink(str);
-
- ret = symlink(buf, str);
- if (ret < 0)
- printf("symlink: %s -> %s : %s\n",
- str, (char*)buf, strerror(-errno));
- }
- free(str);
- } else {
- fd = open(str, O_WRONLY | O_CREAT | O_TRUNC, 0644);
- free(str);
- if (fd < 0) {
- printf("Open %s\n", errno_str());
- ret = fd;
- goto out;
- }
-
- ret = write(fd, buf, inode_size);
- if (ret < inode_size) {
- perror("write");
- ret = -errno;
- close(fd);
- goto out;
- }
- close(fd);
- }
-skip:
- buf += PAD4(inode_size);
- size -= headerlen_full + PAD4(inode_size) +
- sizeof(struct envfs_inode);
- }
-
- recursive_action(dir, ACTION_RECURSE | ACTION_DEPTHFIRST, NULL,
- dir_remove_action, NULL, 0);
-
- ret = 0;
-out:
- return ret;
-}
-
-int envfs_load_from_buf(void *buf, int len, const char *dir, unsigned flags)
-{
- int ret;
- size_t size;
- struct envfs_super *super = buf;
-
- buf = super + 1;
-
- ret = envfs_check_super(super, &size);
- if (ret)
- return ret;
-
- ret = envfs_check_data(super, buf, size);
- if (ret)
- return ret;
-
- ret = envfs_load_data(super, buf, size, dir, flags);
-
- return ret;
-}
-
/**
* Restore the last environment into the current one
* @param[in] filename from where to restore
diff --git a/common/filetype.c b/common/filetype.c
index 4966c5e..fd6e8e3 100644
--- a/common/filetype.c
+++ b/common/filetype.c
@@ -80,6 +80,7 @@ static const struct filetype_str filetype_str[] = {
[filetype_ubootvar] = { "U-Boot environmemnt variable data",
"ubootvar" },
[filetype_stm32_image_v1] = { "STM32 image (v1)", "stm32-image-v1" },
+ [filetype_zynq_image] = { "Zynq image", "zynq-image" },
};
const char *file_type_to_string(enum filetype f)
@@ -316,19 +317,21 @@ enum filetype file_detect_type(const void *_buf, size_t bufsize)
buf8[0] == 0x8b || buf8[0] == 0x9c) &&
buf8[0x1] == 0 && buf8[0x2] == 0 && buf8[0x3] == 0 &&
buf8[0x18] == 0 && buf8[0x1b] == 0 && buf8[0x1c] == 0) {
- unsigned char sum = 0;
- int i;
- for (i = 0; i <= 0x1e; ++i)
- sum += buf8[i];
+ if (buf8[0x8] == 0) {
+ unsigned char sum = 0;
+ int i;
- if (sum == buf8[0x1f] && buf8[0x8] == 0)
- return filetype_kwbimage_v0;
+ for (i = 0; i <= 0x1e; ++i)
+ sum += buf8[i];
- if (sum == buf8[0x1f] &&
- buf8[0x8] == 1 && buf8[0x1d] == 0 &&
- (buf8[0x1e] == 0 || buf8[0x1e] == 1))
- return filetype_kwbimage_v1;
+ if (sum == buf8[0x1f])
+ return filetype_kwbimage_v0;
+ } else if (buf8[0x8] == 1) {
+ if (buf8[0x1d] == 0 &&
+ (buf8[0x1e] == 0 || buf8[0x1e] == 1))
+ return filetype_kwbimage_v1;
+ }
}
if (is_sparse_image(_buf))
@@ -390,6 +393,9 @@ enum filetype file_detect_type(const void *_buf, size_t bufsize)
if (is_imx_flash_header_v2(_buf))
return filetype_imx_image_v2;
+ if (buf[8] == 0xAA995566 && buf[9] == 0x584C4E58)
+ return filetype_zynq_image;
+
return filetype_unknown;
}
diff --git a/common/globalvar.c b/common/globalvar.c
index 1bea742..a826e1b 100644
--- a/common/globalvar.c
+++ b/common/globalvar.c
@@ -75,13 +75,19 @@ static int nv_save(const char *name, const char *val)
if (ret)
return ret;
- if (once) {
- pr_info("nv variable modified, will save nv variables on shutdown\n");
- once = 0;
+ if (IS_ENABLED(CONFIG_ENV_HANDLING)) {
+ if (once) {
+ pr_info("nv variable modified, will save nv variables on shutdown\n");
+ once = 0;
+ }
+ nv_dirty = 1;
+ } else {
+ if (once) {
+ pr_info("nv variable modified, but won't be saved in this configuration\n");
+ once = 0;
+ }
}
- nv_dirty = 1;
-
return 0;
}
diff --git a/common/ratp/Kconfig b/common/ratp/Kconfig
index 30462c6..25150ad 100644
--- a/common/ratp/Kconfig
+++ b/common/ratp/Kconfig
@@ -6,6 +6,7 @@ config CONSOLE_RATP
select POLLER
select CMDLINE_EDITING
depends on CONSOLE_FULL
+ depends on !SHELL_NONE
prompt "RATP console support"
help
This option adds support for remote controlling barebox via serial
diff --git a/common/startup.c b/common/startup.c
index c6e1199..c417a4d 100644
--- a/common/startup.c
+++ b/common/startup.c
@@ -122,29 +122,39 @@ conflict:
return -EINVAL;
}
+#else
+static int check_overlap(const char *path)
+{
+ return 0;
+}
+#endif
static int load_environment(void)
{
const char *default_environment_path;
- int ret;
+ int __maybe_unused ret = 0;
default_environment_path = default_environment_path_get();
if (IS_ENABLED(CONFIG_DEFAULT_ENVIRONMENT))
defaultenv_load("/env", 0);
- ret = check_overlap(default_environment_path);
- if (ret)
- default_environment_path_set(NULL);
- else
- envfs_load(default_environment_path, "/env", 0);
+ if (IS_ENABLED(CONFIG_ENV_HANDLING)) {
+ ret = check_overlap(default_environment_path);
+ if (ret)
+ default_environment_path_set(NULL);
+ else
+ envfs_load(default_environment_path, "/env", 0);
+ } else {
+ if (IS_ENABLED(CONFIG_DEFAULT_ENVIRONMENT))
+ pr_notice("No support for persistent environment. Using default environment");
+ }
nvvar_load();
return 0;
}
environment_initcall(load_environment);
-#endif
static int global_autoboot_abort_key;
static const char * const global_autoboot_abort_keys[] = {
diff --git a/drivers/Makefile b/drivers/Makefile
index 5a52225..08a17ff 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -8,8 +8,8 @@ obj-y += mtd/
obj-y += usb/
obj-$(CONFIG_DISK) += ata/
obj-$(CONFIG_SPI) += spi/
-obj-$(CONFIG_I2C) += i2c/
-obj-$(CONFIG_MCI) += mci/
+obj-y += i2c/
+obj-y += mci/
obj-$(CONFIG_VIDEO) += video/
obj-y += clk/
obj-y += clocksource/
diff --git a/drivers/block/efi-block-io.c b/drivers/block/efi-block-io.c
index 39dbfb0..30db486 100644
--- a/drivers/block/efi-block-io.c
+++ b/drivers/block/efi-block-io.c
@@ -131,16 +131,9 @@ static void efi_bio_print_info(struct efi_bio_priv *priv)
media->optimal_transfer_length_granularity);
}
-static int is_bio_usbdev(struct efi_device *efidev)
+static bool is_bio_usbdev(struct efi_device *efidev)
{
- int i;
-
- for (i = 0; i < efidev->num_guids; i++) {
- if (!efi_guidcmp(efidev->guids[i], EFI_USB_IO_PROTOCOL_GUID))
- return 1;
- }
-
- return 0;
+ return efi_device_has_guid(efidev, EFI_USB_IO_PROTOCOL_GUID);
}
static int efi_bio_probe(struct efi_device *efidev)
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 219982d..1a2ff91 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -25,4 +25,12 @@ config MVEBU_MBUS
Driver needed for the MBus configuration on Marvell EBU SoCs
(Kirkwood, Dove, Orion5x, MV78XX0 and Armada 370/XP).
+config ACPI
+ bool "Advanced Configuration and Power Interface (ACPI)"
+ default y
+ depends on EFI_BOOTUP
+ help
+ Driver needed for supporting drivers probed from ACPI tables.
+ The root SDT is found via UEFI.
+
endmenu
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
index ba5cee4..518689a 100644
--- a/drivers/bus/Makefile
+++ b/drivers/bus/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_BUS_OMAP_GPMC) += omap-gpmc.o
obj-$(CONFIG_IMX_WEIM) += imx-weim.o
obj-$(CONFIG_MVEBU_MBUS) += mvebu-mbus.o
obj-$(CONFIG_TI_SYSC) += ti-sysc.o
+obj-$(CONFIG_ACPI) += acpi.o
diff --git a/drivers/bus/acpi.c b/drivers/bus/acpi.c
new file mode 100644
index 0000000..2515b66
--- /dev/null
+++ b/drivers/bus/acpi.c
@@ -0,0 +1,255 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Ahmad Fatoum
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <init.h>
+#include <efi/efi.h>
+#include <efi/efi-device.h>
+#include <acpi.h>
+
+static struct sig_desc {
+ const char sig[4];
+ const char *desc;
+} signatures[] = {
+ /* ACPI 6.3 Table 5-29, Defined DESCRIPTION_HEADER Signatures */
+ { "APIC", "Multiple APIC Description" },
+ { "BERT", "Boot Error Record" },
+ { "BGRT", "Boot Graphics Resource" },
+ { "CPEP", "Corrected Platform Error Polling" },
+ { "DSDT", "Differentiated System Description" },
+ { "ECDT", "Embedded Controller Boot Resource" },
+ { "EINJ", "Error Injection" },
+ { "ERST", "Error Record Serialization" },
+ { "FACP", "Fixed ACPI Description" },
+ { "FACS", "Firmware ACPI Control Structure" },
+ { "FPDT", "Firmware Performance Data" },
+ { "GTDT", "Generic Timer Description" },
+ { "HEST", "Hardware Error Source" },
+ { "MSCT", "Maximum System Characteristics" },
+ { "MPST", "Memory Power State" },
+ { "NFIT", "NVDIMM Firmware Interface" },
+ { "OEM\0", "OEM Specific Information" },
+ { "PCCT", "Platform Communications Channel" },
+ { "PMTT", "Platform Memory Topology" },
+ { "PSDT", "Persistent System Description" },
+ { "RASF", "ACPI RAS Feature" },
+ { "RSDT", "Root System Description" },
+ { "SBST", "Smart Battery Specification" },
+ { "SDEV", "Secure Devices" },
+ { "SLIT", "System Locality Distance Information" },
+ { "SRAT", "System Resource Affinity" },
+ { "SSDT", "Secondary System Description" },
+ { "XSDT", "Extended System Description" },
+
+ /* ACPI 6.3 Table 5-30, Reserved DESCRIPTION_HEADER Signatures */
+ { "BOOT", "Simple BOOT Flag" },
+ { "CSRT", "Core System Resource" },
+ { "DBG2", "Microsoft Debug Port 2" },
+ { "DBGP", "Debug Port" },
+ { "DMAR", "DMA Remapping" },
+ { "DPPT", "DMA Protection Policy" },
+ { "DRTM", "Dynamic Root of Trust for Measurement" },
+ { "ETDT", "(Obsolete) Event Timer Description" },
+ { "HPET", "IA-PC High Precision Event Timer" },
+ { "IBFT", "iSCSI Boot Firmware" },
+ { "IORT", "I/O Remapping" },
+ { "IVRS", "I/O Virtualization Reporting Structure" },
+ { "LPIT", "Low Power Idle" },
+ { "MCFG", "PCI Express memory mapped configuration" },
+ { "MCHI", "Management Controller Host Interface" },
+ { "MSDM", "Microsoft Data Management" },
+ { "SDEI", "Software Delegated Exceptions Interface" },
+ { "SLIC", "Microsoft Software Licensing Specification" },
+ { "SPCR", "Serial Port Console Redirection" },
+ { "SPMI", "Server Platform Management Interface" },
+ { "STAO", "_STA Override" },
+ { "TCPA", "Trusted Computing Platform Alliance Capabilities" },
+ { "TPM2", "Trusted Platform Module 2" },
+ { "UEFI", "UEFI ACPI Data" },
+ { "WAET", "Windows ACPI Emulated Devices" },
+ { "WDAT", "Watch Dog Action" },
+ { "WDRT", "Watchdog Resource" },
+ { "WPBT", "Platform Binary" },
+ { "WSMT", "Windows SMM Security Mitigation" },
+ { "XENV", "Xen Project" },
+
+ /* Others */
+ { "NHLT", "Non-HD Audio" },
+ { "ASF!", "Alert Standard Format" },
+
+ { /* sentinel */ }
+};
+
+static struct acpi_sdt *acpi_get_dev_sdt(struct device_d *dev)
+{
+ int i;
+
+ for (i = 0; i < dev->num_resources; i++) {
+ if (!strcmp(dev->resource[i].name, "SDT"))
+ return (struct acpi_sdt *)dev->resource[i].start;
+ }
+
+ return NULL;
+}
+
+static void acpi_devinfo(struct device_d *dev)
+{
+ struct acpi_sdt *sdt = acpi_get_dev_sdt(dev);
+ struct sig_desc *sig_desc;
+
+ printf("Signature: %.4s", sdt->signature);
+
+ for (sig_desc = signatures; sig_desc->desc; sig_desc++) {
+ size_t len = strnlen(sig_desc->sig, 4);
+
+ if (!memcmp(sdt->signature, sig_desc->sig, len)) {
+ printf(" (%s Table)", sig_desc->desc);
+ break;
+ }
+ }
+
+ printf("\nRevision: %u\n", sdt->revision);
+ printf("OemId: %.6s\n", sdt->oem_id);
+ printf("OemTableId: %.8s\n", sdt->oem_table_id);
+ printf("OemRevision: %u\n", sdt->oem_revision);
+ printf("CreatorId: 0x%08x\n", sdt->creator_id);
+ printf("CreatorRevision: %u\n", sdt->creator_revision);
+}
+
+static int acpi_register_device(struct device_d *dev, struct acpi_sdt *sdt)
+{
+ int ret;
+
+ ret = register_device(dev);
+ if (ret)
+ return ret;
+
+ device_add_resource(dev, "SDT", (resource_size_t)sdt, sdt->len,
+ IORESOURCE_MEM | IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY);
+
+ dev_dbg(dev, "registered as ACPI device\n");
+
+ return 0;
+}
+
+static struct device_d *acpi_add_device(struct bus_type *bus,
+ acpi_sig_t signature)
+{
+ struct device_d *dev;
+
+ dev = xzalloc(sizeof(*dev));
+
+ dev->bus = bus;
+ dev->parent = bus->dev;
+ dev->id = DEVICE_ID_DYNAMIC;
+ dev->info = acpi_devinfo;
+
+ dev_set_name(dev, "acpi-%.4s", signature);
+
+ return dev;
+}
+
+static int acpi_register_devices(struct bus_type *bus)
+{
+ efi_config_table_t *table = bus->dev->priv;
+ struct acpi_rsdp *rsdp;
+ struct acpi_rsdt *root;
+ size_t entry_count;
+ const char *sig;
+ int i;
+
+ rsdp = (struct acpi_rsdp *)table->table;
+
+ if (!rsdp)
+ return -EFAULT;
+
+ /* ACPI specification v6.3
+ * 5.2.5.2 Finding the RSDP on UEFI Enabled Systems
+ */
+ if (memcmp("RSD PTR ", rsdp->signature, sizeof(rsdp->signature))) {
+ dev_dbg(bus->dev, "unexpected signature at start of config table: '%.8s'\n",
+ rsdp->signature);
+ return -ENODEV;
+ }
+
+ if (rsdp->revision < 0x02) {
+ sig = "RSDT";
+ root = (struct acpi_rsdt *)(unsigned long)rsdp->rsdt_addr;
+ entry_count = (root->sdt.len - sizeof(struct acpi_rsdt)) / sizeof(u32);
+ } else {
+ sig = "XSDT";
+ root = (struct acpi_rsdt *)((struct acpi2_rsdp *)rsdp)->xsdt_addr;
+ entry_count = (root->sdt.len - sizeof(struct acpi_rsdt)) / sizeof(u64);
+ }
+
+ if (acpi_sigcmp(sig, root->sdt.signature)) {
+ dev_err(bus->dev, "Expected %s, but found '%.4s'.\n",
+ sig, root->sdt.signature);
+ return -EIO;
+ }
+
+ dev_info(bus->dev, "Found %s (OEM: %.8s) with %lu entries\n",
+ sig, root->sdt.oem_id, entry_count);
+
+ for (i = 0; i < entry_count; i++) {
+ struct acpi_sdt *sdt = root->entries[i];
+ acpi_register_device(acpi_add_device(bus, sdt->signature), sdt);
+ }
+
+ return 0;
+}
+
+static int acpi_bus_match(struct device_d *dev, struct driver_d *drv)
+{
+ struct acpi_driver *acpidrv = to_acpi_driver(drv);
+ struct acpi_sdt *sdt = acpi_get_dev_sdt(dev);
+
+ return acpi_sigcmp(acpidrv->signature, sdt->signature);
+}
+
+static int acpi_bus_probe(struct device_d *dev)
+{
+ return dev->driver->probe(dev);
+}
+
+static void acpi_bus_remove(struct device_d *dev)
+{
+ if (dev->driver->remove)
+ dev->driver->remove(dev);
+}
+
+struct bus_type acpi_bus = {
+ .match = acpi_bus_match,
+ .probe = acpi_bus_probe,
+ .remove = acpi_bus_remove,
+};
+
+static int efi_acpi_probe(void)
+{
+ efi_config_table_t *table = NULL;
+ int i;
+
+ for (i = 0; i < efi_sys_table->nr_tables; i++) {
+ efi_config_table_t *ect = &efi_sys_table->tables[i];
+ /* take ACPI < 2 table only if no ACPI 2.0 is available */
+ if (!efi_guidcmp(ect->guid, EFI_ACPI_20_TABLE_GUID)) {
+ acpi_bus.name = "acpi2";
+ table = ect;
+ } else if (!table && !efi_guidcmp(ect->guid, EFI_ACPI_TABLE_GUID)) {
+ acpi_bus.name = "acpi";
+ table = ect;
+ }
+ }
+
+ if (!table)
+ return 0;
+
+ bus_register(&acpi_bus);
+ acpi_bus.dev->priv = table;
+
+ return acpi_register_devices(&acpi_bus);
+}
+postcore_initcall(efi_acpi_probe);
diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c
index b0a6bb0..35483ef 100644
--- a/drivers/clk/imx/clk-imx6ul.c
+++ b/drivers/clk/imx/clk-imx6ul.c
@@ -450,6 +450,9 @@ static int imx6_ccm_probe(struct device_d *dev)
clk_set_parent(clks[IMX6ULL_CLK_EPDC_PRE_SEL],
clks[IMX6UL_CLK_PLL3_PFD2]);
+ /* Disable GPMI_IO clk before reparenting to avoid glitches */
+ clks[IMX6UL_CLK_GPMI_IO]->ops->disable(clks[IMX6UL_CLK_GPMI_IO]);
+
clk_set_parent(clks[IMX6UL_CLK_ENFC_SEL], clks[IMX6UL_CLK_PLL2_PFD2]);
return 0;
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 43c5bfc..44a6cef 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -73,7 +73,7 @@ config CLOCKSOURCE_ATMEL_PIT
config CLOCKSOURCE_ARMV8_TIMER
bool
default y
- depends on ARM && (CPU_64v8 || CPU_V7)
+ depends on ARM && CPU_V8
config CLOCKSOURCE_ARM_GLOBAL_TIMER
bool
diff --git a/drivers/efi/efi-device.c b/drivers/efi/efi-device.c
index a1aac2d..ac035dc 100644
--- a/drivers/efi/efi-device.c
+++ b/drivers/efi/efi-device.c
@@ -386,16 +386,9 @@ static int efi_is_setup_mode(void)
return ret != 1;
}
-static int is_bio_usbdev(struct efi_device *efidev)
+static bool is_bio_usbdev(struct efi_device *efidev)
{
- int i;
-
- for (i = 0; i < efidev->num_guids; i++) {
- if (!efi_guidcmp(efidev->guids[i], EFI_USB_IO_PROTOCOL_GUID))
- return 1;
- }
-
- return 0;
+ return efi_device_has_guid(efidev, EFI_USB_IO_PROTOCOL_GUID);
}
static struct efi_device *bootdev;
diff --git a/drivers/firmware/zynqmp-fpga.c b/drivers/firmware/zynqmp-fpga.c
index 8878658..e026673 100644
--- a/drivers/firmware/zynqmp-fpga.c
+++ b/drivers/firmware/zynqmp-fpga.c
@@ -24,11 +24,32 @@
#define ZYNQMP_PM_VERSION_1_1_FEATURES (ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL | \
ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED)
+/*
+ * Xilinx KU040 Bitstream Composition:
+ *
+ * Bitstream can be provided with an optinal header (`struct bs_header`).
+ * The true bitstream starts with the binary-header composed of 21 words:
+ *
+ * 0: 0xFFFFFFFF (Dummy pad word)
+ * ...
+ * 15: 0xFFFFFFFF (Dummy pad word)
+ * 16: 0x000000BB (Bus width auto detect word 1)
+ * 17: 0x11220044 (Bus width auto detect word 2)
+ * 18: 0xFFFFFFFF (Dummy pad word)
+ * 19: 0xFFFFFFFF (Dummy pad word)
+ * 20: 0xAA995566 (Sync word)
+ *
+ * See Xilinx UG570 (v1.11) September 30 2019, Chapter 9 "Configuration
+ * Details - Bitstream Composition" for further details.
+ */
#define DUMMY_WORD 0xFFFFFFFF
-#define BUS_WIDTH_WORD_1 0x000000BB
-#define BUS_WIDTH_WORD_2 0x11220044
+#define BUS_WIDTH_AUTO_DETECT1_OFFSET 16
+#define BUS_WIDTH_AUTO_DETECT1 0x000000BB
+#define BUS_WIDTH_AUTO_DETECT2_OFFSET 17
+#define BUS_WIDTH_AUTO_DETECT2 0x11220044
+#define SYNC_WORD_OFFSET 20
#define SYNC_WORD 0xAA995566
-#define SYNC_WORD_OFFS 20
+#define BIN_HEADER_LENGTH 21
enum xilinx_byte_order {
XILINX_BYTE_ORDER_BIT,
@@ -58,48 +79,6 @@ struct bs_header_entry {
char data[0];
} __attribute__ ((packed));
-/*
- * Xilinx KU040 Bitstream Composition:
- * Bitstream can be provided with an optinal header (`struct bs_header`).
- * The true bitstream starts with the binary-header composed of 21 words:
- *
- * 1: 0xFFFFFFFF (Dummy pad word)
- * ...
- * 16: 0xFFFFFFFF (Dummy pad word)
- * 17: 0x000000BB (Bus width auto detect word 1)
- * 18: 0x11220044 (Bus width auto detect word 2)
- * 19: 0xFFFFFFFF (Dummy pad word)
- * 20: 0xFFFFFFFF (Dummy pad word)
- * 21: 0xAA995566 (Sync word)
- *
- * Please refer to Xilinx UG570 (v1.11) September 30 2019,
- * Chapter 9 Configuration Details - Bitstream Composition
- * for further details!
- */
-static const u32 bin_format[] = {
- DUMMY_WORD,
- DUMMY_WORD,
- DUMMY_WORD,
- DUMMY_WORD,
- DUMMY_WORD,
- DUMMY_WORD,
- DUMMY_WORD,
- DUMMY_WORD,
- DUMMY_WORD,
- DUMMY_WORD,
- DUMMY_WORD,
- DUMMY_WORD,
- DUMMY_WORD,
- DUMMY_WORD,
- DUMMY_WORD,
- DUMMY_WORD,
- BUS_WIDTH_WORD_1,
- BUS_WIDTH_WORD_2,
- DUMMY_WORD,
- DUMMY_WORD,
- SYNC_WORD,
-};
-
static void copy_words_swapped(u32 *dst, const u32 *src, size_t size)
{
int i;
@@ -111,36 +90,59 @@ static void copy_words_swapped(u32 *dst, const u32 *src, size_t size)
static int get_byte_order(const u32 *bin_header, size_t size,
enum xilinx_byte_order *byte_order)
{
- if (size < sizeof(bin_format))
+ if (size < BIN_HEADER_LENGTH * sizeof(*bin_header))
return -EINVAL;
- if (bin_header[SYNC_WORD_OFFS] == SYNC_WORD) {
+ if (bin_header[SYNC_WORD_OFFSET] == SYNC_WORD) {
*byte_order = XILINX_BYTE_ORDER_BIT;
return 0;
}
- if (bin_header[SYNC_WORD_OFFS] == __swab32(SYNC_WORD)) {
- *byte_order = XILINX_BYTE_ORDER_BIN;
+ if (bin_header[SYNC_WORD_OFFSET] == __swab32(SYNC_WORD)) {
+ *byte_order = XILINX_BYTE_ORDER_BIN;
return 0;
}
return -EINVAL;
}
-static int is_bin_header_valid(const u32 *bin_header, size_t size,
- enum xilinx_byte_order byte_order)
+static bool is_bin_header_valid(const u32 *bin_header, size_t size,
+ enum xilinx_byte_order byte_order)
{
- int i;
+ size_t i;
- if (size < ARRAY_SIZE(bin_format))
- return 0;
+ if (size < BIN_HEADER_LENGTH * sizeof(*bin_header))
+ return false;
+
+ for (i = 0; i < BIN_HEADER_LENGTH; i++, bin_header++) {
+ u32 current;
+ u32 expected;
+
+ if (byte_order == XILINX_BYTE_ORDER_BIT)
+ current = *bin_header;
+ else
+ current = __swab32(*bin_header);
- for (i = 0; i < ARRAY_SIZE(bin_format); i++)
- if (bin_header != (byte_order == XILINX_BYTE_ORDER_BIT) ?
- bin_format[i] : __swab32(bin_format[i]))
- return 0;
+ switch (i) {
+ case BUS_WIDTH_AUTO_DETECT1_OFFSET:
+ expected = BUS_WIDTH_AUTO_DETECT1;
+ break;
+ case BUS_WIDTH_AUTO_DETECT2_OFFSET:
+ expected = BUS_WIDTH_AUTO_DETECT2;
+ break;
+ case SYNC_WORD_OFFSET:
+ expected = SYNC_WORD;
+ break;
+ default:
+ expected = DUMMY_WORD;
+ break;
+ }
+
+ if (current != expected)
+ return false;
+ }
- return 1;
+ return true;
}
static int get_header_length(const char *header, size_t size)
@@ -227,6 +229,7 @@ static int fpgamgr_program_finish(struct firmware_handler *fh)
goto err_free;
if (!is_bin_header_valid(body, body_length, byte_order)) {
+ dev_err(&mgr->dev, "Invalid bitstream header\n");
status = -EINVAL;
goto err_free;
}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index f960098..9764ddf 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -16,6 +16,7 @@ struct gpio_info {
bool requested;
bool active_low;
char *label;
+ char *name;
};
static struct gpio_info *gpio_desc;
@@ -108,6 +109,23 @@ int gpio_find_by_label(const char *label)
return -ENOENT;
}
+int gpio_find_by_name(const char *name)
+{
+ int i;
+
+ for (i = 0; i < ARCH_NR_GPIOS; i++) {
+ struct gpio_info *info = &gpio_desc[i];
+
+ if (!info->chip || !info->name)
+ continue;
+
+ if (!strcmp(info->name, name))
+ return i;
+ }
+
+ return -ENOENT;
+}
+
void gpio_free(unsigned gpio)
{
struct gpio_info *gi = gpio_to_desc(gpio);
@@ -410,11 +428,25 @@ static int of_hog_gpio(struct device_node *np, struct gpio_chip *chip,
static int of_gpiochip_scan_hogs(struct gpio_chip *chip)
{
struct device_node *np;
- int ret, i;
+ int ret, i, count;
if (!IS_ENABLED(CONFIG_OFDEVICE) || !chip->dev->device_node)
return 0;
+ count = of_property_count_strings(chip->dev->device_node, "gpio-line-names");
+
+ if (count > 0) {
+ const char **arr = xzalloc(count * sizeof(char *));
+
+ of_property_read_string_array(chip->dev->device_node,
+ "gpio-line-names", arr, count);
+
+ for (i = 0; i < chip->ngpio && i < count; i++)
+ gpio_desc[chip->base + i].name = xstrdup(arr[i]);
+
+ free(arr);
+ }
+
for_each_available_child_of_node(chip->dev->device_node, np) {
if (!of_property_read_bool(np, "gpio-hog"))
continue;
@@ -500,7 +532,7 @@ static int do_gpiolib(int argc, char *argv[])
gi->chip->base,
gi->chip->base + gi->chip->ngpio - 1,
gi->chip->dev->name);
- printf("%*cdir val requested label\n", 13, ' ');
+ printf(" %-3s %-3s %-9s %-20s %-20s\n", "dir", "val", "requested", "name", "label");
}
if (gi->chip->ops->get_direction)
@@ -510,11 +542,12 @@ static int do_gpiolib(int argc, char *argv[])
val = gi->chip->ops->get(gi->chip,
i - gi->chip->base);
- printf(" GPIO %*d: %*s %*s %*s %s\n", 4, i,
- 3, (dir < 0) ? "unk" : ((dir == GPIOF_DIR_IN) ? "in" : "out"),
- 3, (val < 0) ? "unk" : ((val == 0) ? "lo" : "hi"),
- 12, gi->requested ? (gi->active_low ? "active low" : "true") : "false",
- (gi->requested && gi->label) ? gi->label : "");
+ printf(" GPIO %4d: %-3s %-3s %-9s %-20s %-20s\n", i,
+ (dir < 0) ? "unk" : ((dir == GPIOF_DIR_IN) ? "in" : "out"),
+ (val < 0) ? "unk" : ((val == 0) ? "lo" : "hi"),
+ gi->requested ? (gi->active_low ? "active low" : "true") : "false",
+ gi->name ? gi->name : "",
+ gi->label ? gi->label : "");
}
return 0;
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index c936534..b887e75 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -1,2 +1,3 @@
-obj-$(CONFIG_I2C) += i2c.o i2c-smbus.o busses/ algos/ muxes/
+obj-y += busses/
+obj-$(CONFIG_I2C) += i2c.o i2c-smbus.o algos/ muxes/
obj-$(CONFIG_I2C_MUX) += i2c-mux.o
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
index 5ab43fe..7ccdb0b 100644
--- a/drivers/i2c/busses/i2c-gpio.c
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -94,8 +94,8 @@ static int of_i2c_gpio_probe(struct device_node *np,
if (!IS_ENABLED(CONFIG_OFDEVICE))
return -ENODEV;
- pdata->sda_pin = of_get_named_gpio_flags(np, "sda-gpios", 0, NULL);
- pdata->scl_pin = of_get_named_gpio_flags(np, "scl-gpios", 0, NULL);
+ pdata->sda_pin = of_get_named_gpio(np, "sda-gpios", 0);
+ pdata->scl_pin = of_get_named_gpio(np, "scl-gpios", 0);
if ((!gpio_is_valid(pdata->sda_pin) || !gpio_is_valid(pdata->scl_pin))
&& (of_gpio_count(np) >= 2)) {
diff --git a/drivers/i2c/busses/i2c-stm32.c b/drivers/i2c/busses/i2c-stm32.c
index 6af55fb..9f34760 100644
--- a/drivers/i2c/busses/i2c-stm32.c
+++ b/drivers/i2c/busses/i2c-stm32.c
@@ -785,7 +785,6 @@ static int __init stm32_i2c_probe(struct device_d *dev)
struct resource *iores;
struct stm32_i2c *stm32_i2c;
struct i2c_platform_data *pdata;
- struct reset_control *rst;
const struct stm32_i2c_setup *setup;
struct i2c_timings *timings;
int ret;
@@ -799,13 +798,9 @@ static int __init stm32_i2c_probe(struct device_d *dev)
return PTR_ERR(stm32_i2c->clk);
clk_enable(stm32_i2c->clk);
- rst = reset_control_get(dev, NULL);
- if (IS_ERR(rst))
- return PTR_ERR(rst);
-
- reset_control_assert(rst);
- udelay(2);
- reset_control_deassert(rst);
+ ret = device_reset_us(dev, 2);
+ if (ret)
+ return ret;
ret = dev_get_drvdata(dev, (const void **)&setup);
if (ret)
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index be06168..e40032d 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -66,6 +66,7 @@ config KEYBOARD_USB
config INPUT_SPECIALKEYS
bool "Special keys handler"
+ select POLLER
select INPUT
help
Say Y here to handle key events like KEY_RESTART and KEY_POWER.
diff --git a/drivers/led/core.c b/drivers/led/core.c
index 431966d..e727148 100644
--- a/drivers/led/core.c
+++ b/drivers/led/core.c
@@ -256,37 +256,55 @@ void led_unregister(struct led *led)
list_del(&led->list);
}
-struct led_trg {
- const char *str;
- enum led_trigger trg;
+static char *trigger_names[] = {
+ [LED_TRIGGER_PANIC] = "panic",
+ [LED_TRIGGER_HEARTBEAT] = "heartbeat",
+ [LED_TRIGGER_NET_RX] = "net-rx",
+ [LED_TRIGGER_NET_TX] = "net-tx",
+ [LED_TRIGGER_NET_TXRX] = "net",
+ [LED_TRIGGER_DEFAULT_ON] = "default-on",
};
-static struct led_trg triggers[] = {
- { .str = "heartbeat", LED_TRIGGER_HEARTBEAT, },
- { .str = "panic", LED_TRIGGER_PANIC, },
- { .str = "net", LED_TRIGGER_NET_TXRX, },
- { .str = "default-on", LED_TRIGGER_DEFAULT_ON, },
-};
+const char *trigger_name(enum led_trigger trigger)
+{
+ return trigger_names[trigger];
+}
+
+enum led_trigger trigger_by_name(const char *name)
+{
+ int i;
+
+ if (!name)
+ return LED_TRIGGER_MAX;
+
+ for (i = 0; i < LED_TRIGGER_MAX; i++)
+ if (!strcmp(name, trigger_names[i]))
+ return i;
+
+ return LED_TRIGGER_MAX;
+}
void led_of_parse_trigger(struct led *led, struct device_node *np)
{
+ enum led_trigger trg = LED_TRIGGER_MAX;
const char *trigger;
- int i;
- trigger = of_get_property(np, "linux,default-trigger", NULL);
- if (!trigger)
- trigger = of_get_property(np, "barebox,default-trigger", NULL);
+ if (of_property_read_bool(np, "panic-indicator"))
+ trg = LED_TRIGGER_PANIC;
+
+ if (trg == LED_TRIGGER_MAX) {
+ trigger = of_get_property(np, "linux,default-trigger", NULL);
+ trg = trigger_by_name(trigger);
+ }
- if (!trigger)
- return;
+ if (trg == LED_TRIGGER_MAX) {
+ trigger = of_get_property(np, "barebox,default-trigger", NULL);
+ trg = trigger_by_name(trigger);
+ }
- for (i = 0; i < ARRAY_SIZE(triggers); i++) {
- struct led_trg *trg = &triggers[i];
- if (!strcmp(trg->str, trigger)) {
- /* disable LED before installing trigger */
- led_set(led, 0);
- led_set_trigger(trg->trg, led);
- return;
- }
+ if (trg != LED_TRIGGER_MAX) {
+ /* disable LED before installing trigger */
+ led_set(led, 0);
+ led_set_trigger(trg, led);
}
}
diff --git a/drivers/led/led-triggers.c b/drivers/led/led-triggers.c
index 76a1481..216c863 100644
--- a/drivers/led/led-triggers.c
+++ b/drivers/led/led-triggers.c
@@ -143,31 +143,6 @@ int led_set_trigger(enum led_trigger trigger, struct led *led)
return 0;
}
-static char *trigger_names[] = {
- [LED_TRIGGER_PANIC] = "panic",
- [LED_TRIGGER_HEARTBEAT] = "heartbeat",
- [LED_TRIGGER_NET_RX] = "net-rx",
- [LED_TRIGGER_NET_TX] = "net-tx",
- [LED_TRIGGER_NET_TXRX] = "net",
- [LED_TRIGGER_DEFAULT_ON] = "default-on",
-};
-
-const char *trigger_name(enum led_trigger trigger)
-{
- return trigger_names[trigger];
-}
-
-enum led_trigger trigger_by_name(const char *name)
-{
- int i;
-
- for (i = 0; i < LED_TRIGGER_MAX; i++)
- if (!strcmp(name, trigger_names[i]))
- return i;
-
- return LED_TRIGGER_MAX;
-}
-
/**
* led_triggers_show_info - Show information about all registered
* triggers
diff --git a/drivers/mci/Kconfig b/drivers/mci/Kconfig
index 4a71a46..80b3a26 100644
--- a/drivers/mci/Kconfig
+++ b/drivers/mci/Kconfig
@@ -1,3 +1,6 @@
+config MCI_SDHCI
+ bool
+
menuconfig MCI
bool "MCI drivers"
select DISK
@@ -69,10 +72,12 @@ config MCI_BCM283X
config MCI_BCM283X_SDHOST
bool "BCM283X sdhost"
depends on ARCH_BCM283X
+ select MCI_SDHCI
config MCI_DOVE
bool "Marvell Dove SDHCI"
depends on ARCH_DOVE
+ select MCI_SDHCI
help
Enable this entry to add support to read and write SD cards on a
Marvell Dove SoC based system.
@@ -87,6 +92,7 @@ config MCI_IMX
config MCI_IMX_ESDHC
bool "i.MX esdhc"
depends on ARCH_IMX || ARCH_LAYERSCAPE
+ select MCI_SDHCI
help
Enable this entry to add support to read and write SD cards on a
Freescale i.MX25/35/51 based system.
@@ -97,9 +103,6 @@ config MCI_IMX_ESDHC_PIO
help
mostly useful for debugging. Normally you should use DMA.
-config MCI_IMX_ESDHC_PBL
- bool
-
config MCI_OMAP_HSMMC
bool "OMAP HSMMC"
depends on ARCH_OMAP4 || ARCH_OMAP3 || ARCH_AM33XX
@@ -131,10 +134,17 @@ config MCI_MMCI
config MCI_TEGRA
bool "Tegra SD/MMC"
depends on ARCH_TEGRA
+ select MCI_SDHCI
help
Enable this to support SD and MMC card read/write on a Tegra based
systems.
+config MCI_ARASAN
+ bool "Arasan SDHCI Controller"
+ help
+ Enable this to support SD and MMC card read/write on systems with
+ the Arasan SD3.0 / SDIO3.0 / eMMC4.51 host controller.
+
config MCI_SPI
bool "MMC/SD over SPI"
select CRC7
@@ -163,3 +173,7 @@ config MCI_STM32_SDMMC2
say Y or M here.
endif
+
+config MCI_IMX_ESDHC_PBL
+ bool
+ select MCI_SDHCI
diff --git a/drivers/mci/Makefile b/drivers/mci/Makefile
index 04c1287..54eb659 100644
--- a/drivers/mci/Makefile
+++ b/drivers/mci/Makefile
@@ -1,11 +1,12 @@
obj-$(CONFIG_MCI) += mci-core.o
+obj-$(CONFIG_MCI_ARASAN) += arasan-sdhci.o
obj-$(CONFIG_MCI_ATMEL) += atmel_mci.o
obj-$(CONFIG_MCI_BCM283X) += mci-bcm2835.o
obj-$(CONFIG_MCI_BCM283X_SDHOST) += bcm2835-sdhost.o
obj-$(CONFIG_MCI_DOVE) += dove-sdhci.o
obj-$(CONFIG_MCI_IMX) += imx.o
-obj-$(CONFIG_MCI_IMX_ESDHC) += imx-esdhc.o
-pbl-$(CONFIG_MCI_IMX_ESDHC_PBL) += imx-esdhc-pbl.o
+obj-$(CONFIG_MCI_IMX_ESDHC) += imx-esdhc.o imx-esdhc-common.o
+pbl-$(CONFIG_MCI_IMX_ESDHC_PBL) += imx-esdhc-pbl.o imx-esdhc-common.o
obj-$(CONFIG_MCI_MXS) += mxs.o
obj-$(CONFIG_MCI_OMAP_HSMMC) += omap_hsmmc.o
obj-$(CONFIG_MCI_PXA) += pxamci.o
@@ -15,3 +16,4 @@ obj-$(CONFIG_MCI_SPI) += mci_spi.o
obj-$(CONFIG_MCI_DW) += dw_mmc.o
obj-$(CONFIG_MCI_MMCI) += mmci.o
obj-$(CONFIG_MCI_STM32_SDMMC2) += stm32_sdmmc2.o
+obj-pbl-$(CONFIG_MCI_SDHCI) += sdhci.o
diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c
new file mode 100644
index 0000000..b43a4f8
--- /dev/null
+++ b/drivers/mci/arasan-sdhci.c
@@ -0,0 +1,423 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <clock.h>
+#include <common.h>
+#include <driver.h>
+#include <init.h>
+#include <linux/clk.h>
+#include <mci.h>
+
+#include "sdhci.h"
+
+#define SDHCI_ARASAN_HCAP_CLK_FREQ_MASK 0xFF00
+#define SDHCI_ARASAN_HCAP_CLK_FREQ_SHIFT 8
+#define SDHCI_INT_ADMAE BIT(29)
+#define SDHCI_ARASAN_INT_DATA_MASK SDHCI_INT_XFER_COMPLETE | \
+ SDHCI_INT_DMA | \
+ SDHCI_INT_SPACE_AVAIL | \
+ SDHCI_INT_DATA_AVAIL | \
+ SDHCI_INT_DATA_TIMEOUT | \
+ SDHCI_INT_DATA_CRC | \
+ SDHCI_INT_DATA_END_BIT | \
+ SDHCI_INT_ADMAE
+
+#define SDHCI_ARASAN_INT_CMD_MASK SDHCI_INT_CMD_COMPLETE | \
+ SDHCI_INT_TIMEOUT | \
+ SDHCI_INT_CRC | \
+ SDHCI_INT_END_BIT | \
+ SDHCI_INT_INDEX
+
+#define SDHCI_ARASAN_BUS_WIDTH 4
+#define TIMEOUT_VAL 0xE
+
+struct arasan_sdhci_host {
+ struct mci_host mci;
+ struct sdhci sdhci;
+ void __iomem *ioaddr;
+ unsigned int quirks; /* Arasan deviations from spec */
+/* Controller does not have CD wired and will not function normally without */
+#define SDHCI_ARASAN_QUIRK_FORCE_CDTEST BIT(0)
+#define SDHCI_ARASAN_QUIRK_NO_1_8_V BIT(1)
+};
+
+
+static inline
+struct arasan_sdhci_host *to_arasan_sdhci_host(struct mci_host *mci)
+{
+ return container_of(mci, struct arasan_sdhci_host, mci);
+}
+
+static inline
+struct arasan_sdhci_host *sdhci_to_arasan(struct sdhci *sdhci)
+{
+ return container_of(sdhci, struct arasan_sdhci_host, sdhci);
+}
+
+static void arasan_sdhci_writel(struct sdhci *sdhci, int reg, u32 val)
+{
+ struct arasan_sdhci_host *p = sdhci_to_arasan(sdhci);
+
+ writel(val, p->ioaddr + reg);
+}
+
+static void arasan_sdhci_writew(struct sdhci *sdhci, int reg, u16 val)
+{
+ struct arasan_sdhci_host *p = sdhci_to_arasan(sdhci);
+
+ writew(val, p->ioaddr + reg);
+}
+
+static void arasan_sdhci_writeb(struct sdhci *sdhci, int reg, u8 val)
+{
+ struct arasan_sdhci_host *p = sdhci_to_arasan(sdhci);
+
+ writeb(val, p->ioaddr + reg);
+}
+
+static u32 arasan_sdhci_readl(struct sdhci *sdhci, int reg)
+{
+ struct arasan_sdhci_host *p = sdhci_to_arasan(sdhci);
+
+ return readl(p->ioaddr + reg);
+}
+
+static u16 arasan_sdhci_readw(struct sdhci *sdhci, int reg)
+{
+ struct arasan_sdhci_host *p = sdhci_to_arasan(sdhci);
+
+ return readw(p->ioaddr + reg);
+}
+
+static u8 arasan_sdhci_readb(struct sdhci *sdhci, int reg)
+{
+ struct arasan_sdhci_host *p = sdhci_to_arasan(sdhci);
+
+ return readb(p->ioaddr + reg);
+}
+
+static int arasan_sdhci_card_present(struct mci_host *mci)
+{
+ struct arasan_sdhci_host *host = to_arasan_sdhci_host(mci);
+
+ return !!(sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & SDHCI_CARD_DETECT);
+}
+
+static int arasan_sdhci_card_write_protected(struct mci_host *mci)
+{
+ struct arasan_sdhci_host *host = to_arasan_sdhci_host(mci);
+
+ return !(sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & SDHCI_WRITE_PROTECT);
+}
+
+static int arasan_sdhci_reset(struct arasan_sdhci_host *host, u8 mask)
+{
+ sdhci_write8(&host->sdhci, SDHCI_SOFTWARE_RESET, mask);
+
+ /* wait for reset completion */
+ if (wait_on_timeout(100 * MSECOND,
+ !(sdhci_read8(&host->sdhci, SDHCI_SOFTWARE_RESET) & mask))){
+ dev_err(host->mci.hw_dev, "SDHCI reset timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ if (host->quirks & SDHCI_ARASAN_QUIRK_FORCE_CDTEST) {
+ u8 ctrl;
+
+ ctrl = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL);
+ ctrl |= SDHCI_CARD_DETECT_TEST_LEVEL | SDHCI_CARD_DETECT_SIGNAL_SELECTION;
+ sdhci_write8(&host->sdhci, ctrl, SDHCI_HOST_CONTROL);
+ }
+
+ return 0;
+}
+
+static int arasan_sdhci_init(struct mci_host *mci, struct device_d *dev)
+{
+ struct arasan_sdhci_host *host = to_arasan_sdhci_host(mci);
+ int ret;
+
+ ret = arasan_sdhci_reset(host, SDHCI_RESET_ALL);
+ if (ret)
+ return ret;
+
+ sdhci_write8(&host->sdhci, SDHCI_POWER_CONTROL,
+ SDHCI_BUS_VOLTAGE_330 | SDHCI_BUS_POWER_EN);
+ udelay(400);
+
+ sdhci_write32(&host->sdhci, SDHCI_INT_ENABLE,
+ SDHCI_ARASAN_INT_DATA_MASK |
+ SDHCI_ARASAN_INT_CMD_MASK);
+ sdhci_write32(&host->sdhci, SDHCI_SIGNAL_ENABLE, 0x00);
+
+ return 0;
+}
+
+#define SDHCI_MAX_DIV_SPEC_300 2046
+
+static u16 arasan_sdhci_get_clock_divider(struct arasan_sdhci_host *host,
+ unsigned int reqclk)
+{
+ u16 div;
+
+ for (div = 1; div < SDHCI_MAX_DIV_SPEC_300; div += 2)
+ if ((host->mci.f_max / div) <= reqclk)
+ break;
+ div /= 2;
+
+ return div;
+}
+
+#define SDHCI_FREQ_SEL_10_BIT(x) (((x) & 0x300) >> 2)
+
+static void arasan_sdhci_set_ios(struct mci_host *mci, struct mci_ios *ios)
+{
+ struct arasan_sdhci_host *host = to_arasan_sdhci_host(mci);
+ u16 val;
+
+ /* stop clock */
+ sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, 0);
+
+ if (ios->clock) {
+ u64 start;
+
+ /* set & start clock */
+ val = arasan_sdhci_get_clock_divider(host, ios->clock);
+ /* Bit 6 & 7 are upperbits of 10bit divider */
+ val = SDHCI_FREQ_SEL(val) | SDHCI_FREQ_SEL_10_BIT(val);
+ val |= SDHCI_INTCLOCK_EN;
+ sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, val);
+
+ start = get_time_ns();
+ while (!(sdhci_read16(&host->sdhci, SDHCI_CLOCK_CONTROL) &
+ SDHCI_INTCLOCK_STABLE)) {
+ if (is_timeout(start, 20 * MSECOND)) {
+ dev_err(host->mci.hw_dev,
+ "SDHCI clock stable timeout\n");
+ return;
+ }
+ }
+ /* enable bus clock */
+ sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL,
+ val | SDHCI_SDCLOCK_EN);
+ }
+
+ val = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL) &
+ ~(SDHCI_DATA_WIDTH_4BIT | SDHCI_DATA_WIDTH_8BIT);
+
+ switch (ios->bus_width) {
+ case MMC_BUS_WIDTH_8:
+ val |= SDHCI_DATA_WIDTH_8BIT;
+ break;
+ case MMC_BUS_WIDTH_4:
+ val |= SDHCI_DATA_WIDTH_4BIT;
+ break;
+ }
+
+ if (ios->clock > 26000000)
+ val |= SDHCI_HIGHSPEED_EN;
+ else
+ val &= ~SDHCI_HIGHSPEED_EN;
+
+ sdhci_write8(&host->sdhci, SDHCI_HOST_CONTROL, val);
+}
+
+static int arasan_sdhci_wait_for_done(struct arasan_sdhci_host *host, u32 mask)
+{
+ u64 start = get_time_ns();
+ u16 stat;
+
+ do {
+ stat = sdhci_read16(&host->sdhci, SDHCI_INT_NORMAL_STATUS);
+ if (stat & SDHCI_INT_ERROR) {
+ dev_err(host->mci.hw_dev, "SDHCI_INT_ERROR: 0x%08x\n",
+ sdhci_read16(&host->sdhci, SDHCI_INT_ERROR_STATUS));
+ return -EPERM;
+ }
+
+ if (is_timeout(start, 1000 * MSECOND)) {
+ dev_err(host->mci.hw_dev,
+ "SDHCI timeout while waiting for done\n");
+ return -ETIMEDOUT;
+ }
+ } while ((stat & mask) != mask);
+
+ return 0;
+}
+
+static void print_error(struct arasan_sdhci_host *host, int cmdidx)
+{
+ dev_err(host->mci.hw_dev,
+ "error while transfering data for command %d\n", cmdidx);
+ dev_err(host->mci.hw_dev, "state = 0x%08x , interrupt = 0x%08x\n",
+ sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE),
+ sdhci_read32(&host->sdhci, SDHCI_INT_NORMAL_STATUS));
+}
+
+static int arasan_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
+ struct mci_data *data)
+{
+ struct arasan_sdhci_host *host = to_arasan_sdhci_host(mci);
+ u32 mask, command, xfer;
+ int ret;
+
+ /* Wait for idle before next command */
+ mask = SDHCI_CMD_INHIBIT_CMD;
+ if (cmd->cmdidx != MMC_CMD_STOP_TRANSMISSION)
+ mask |= SDHCI_CMD_INHIBIT_DATA;
+
+ ret = wait_on_timeout(10 * MSECOND,
+ !(sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & mask));
+
+ if (ret) {
+ dev_err(host->mci.hw_dev,
+ "SDHCI timeout while waiting for idle\n");
+ return ret;
+ }
+
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0);
+
+ mask = SDHCI_INT_CMD_COMPLETE;
+ if (data)
+ mask |= SDHCI_INT_XFER_COMPLETE;
+
+ sdhci_set_cmd_xfer_mode(&host->sdhci, cmd, data, false, &command, &xfer);
+
+ sdhci_write8(&host->sdhci, SDHCI_TIMEOUT_CONTROL, TIMEOUT_VAL);
+ sdhci_write16(&host->sdhci, SDHCI_TRANSFER_MODE, xfer);
+ sdhci_write16(&host->sdhci, SDHCI_BLOCK_SIZE, SDHCI_DMA_BOUNDARY_512K |
+ SDHCI_TRANSFER_BLOCK_SIZE(data->blocksize));
+ sdhci_write16(&host->sdhci, SDHCI_BLOCK_COUNT, data->blocks);
+ sdhci_write32(&host->sdhci, SDHCI_ARGUMENT, cmd->cmdarg);
+ sdhci_write16(&host->sdhci, SDHCI_COMMAND, command);
+
+ ret = arasan_sdhci_wait_for_done(host, mask);
+ if (ret == -EPERM)
+ goto error;
+ else if (ret)
+ return ret;
+
+ sdhci_read_response(&host->sdhci, cmd);
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, mask);
+
+ if (data)
+ ret = sdhci_transfer_data(&host->sdhci, data);
+
+error:
+ if (ret) {
+ print_error(host, cmd->cmdidx);
+ arasan_sdhci_reset(host, BIT(1)); // SDHCI_RESET_CMD
+ arasan_sdhci_reset(host, BIT(2)); // SDHCI_RESET_DATA
+ }
+
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0);
+ return ret;
+}
+
+
+static void arasan_sdhci_set_mci_caps(struct arasan_sdhci_host *host)
+{
+ u16 caps = sdhci_read16(&host->sdhci, SDHCI_CAPABILITIES_1);
+
+ if ((caps & SDHCI_HOSTCAP_VOLTAGE_180) &&
+ !(host->quirks & SDHCI_ARASAN_QUIRK_NO_1_8_V))
+ host->mci.voltages |= MMC_VDD_165_195;
+ if (caps & SDHCI_HOSTCAP_VOLTAGE_300)
+ host->mci.voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
+ if (caps & SDHCI_HOSTCAP_VOLTAGE_330)
+ host->mci.voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
+
+ if (caps & SDHCI_HOSTCAP_HIGHSPEED)
+ host->mci.host_caps |= (MMC_CAP_MMC_HIGHSPEED_52MHZ |
+ MMC_CAP_MMC_HIGHSPEED |
+ MMC_CAP_SD_HIGHSPEED);
+
+ /* parse board supported bus width capabilities */
+ mci_of_parse(&host->mci);
+
+ /* limit bus widths to controller capabilities */
+ if (!(caps & SDHCI_HOSTCAP_8BIT))
+ host->mci.host_caps &= ~MMC_CAP_8_BIT_DATA;
+}
+
+static int arasan_sdhci_probe(struct device_d *dev)
+{
+ struct device_node *np = dev->device_node;
+ struct arasan_sdhci_host *arasan_sdhci;
+ struct clk *clk_xin, *clk_ahb;
+ struct resource *iores;
+ struct mci_host *mci;
+ int ret;
+
+ arasan_sdhci = xzalloc(sizeof(*arasan_sdhci));
+
+ mci = &arasan_sdhci->mci;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+ arasan_sdhci->ioaddr = IOMEM(iores->start);
+
+ clk_ahb = clk_get(dev, "clk_ahb");
+ if (IS_ERR(clk_ahb)) {
+ dev_err(dev, "clk_ahb clock not found.\n");
+ return PTR_ERR(clk_ahb);
+ }
+
+ clk_xin = clk_get(dev, "clk_xin");
+ if (IS_ERR(clk_xin)) {
+ dev_err(dev, "clk_xin clock not found.\n");
+ return PTR_ERR(clk_xin);
+ }
+ ret = clk_enable(clk_ahb);
+ if (ret) {
+ dev_err(dev, "Failed to enable AHB clock: %s\n",
+ strerror(ret));
+ return ret;
+ }
+
+ ret = clk_enable(clk_xin);
+ if (ret) {
+ dev_err(dev, "Failed to enable SD clock: %s\n", strerror(ret));
+ return ret;
+ }
+
+ if (of_property_read_bool(np, "xlnx,fails-without-test-cd"))
+ arasan_sdhci->quirks |= SDHCI_ARASAN_QUIRK_FORCE_CDTEST;
+
+ if (of_property_read_bool(np, "no-1-8-v"))
+ arasan_sdhci->quirks |= SDHCI_ARASAN_QUIRK_NO_1_8_V;
+
+ arasan_sdhci->sdhci.read32 = arasan_sdhci_readl;
+ arasan_sdhci->sdhci.read16 = arasan_sdhci_readw;
+ arasan_sdhci->sdhci.read8 = arasan_sdhci_readb;
+ arasan_sdhci->sdhci.write32 = arasan_sdhci_writel;
+ arasan_sdhci->sdhci.write16 = arasan_sdhci_writew;
+ arasan_sdhci->sdhci.write8 = arasan_sdhci_writeb;
+ mci->send_cmd = arasan_sdhci_send_cmd;
+ mci->set_ios = arasan_sdhci_set_ios;
+ mci->init = arasan_sdhci_init;
+ mci->card_present = arasan_sdhci_card_present;
+ mci->card_write_protected = arasan_sdhci_card_write_protected;
+ mci->hw_dev = dev;
+
+ mci->f_max = clk_get_rate(clk_xin);
+ mci->f_min = 50000000 / 256;
+
+ arasan_sdhci_set_mci_caps(arasan_sdhci);
+
+ dev->priv = arasan_sdhci;
+
+ return mci_register(&arasan_sdhci->mci);
+}
+
+static __maybe_unused struct of_device_id arasan_sdhci_compatible[] = {
+ { .compatible = "arasan,sdhci-8.9a" },
+ { /* sentinel */ }
+};
+
+static struct driver_d arasan_sdhci_driver = {
+ .name = "arasan-sdhci",
+ .probe = arasan_sdhci_probe,
+ .of_compatible = DRV_OF_COMPAT(arasan_sdhci_compatible),
+};
+device_platform_driver(arasan_sdhci_driver);
diff --git a/drivers/mci/dove-sdhci.c b/drivers/mci/dove-sdhci.c
index caee410..bccda53 100644
--- a/drivers/mci/dove-sdhci.c
+++ b/drivers/mci/dove-sdhci.c
@@ -33,38 +33,51 @@
struct dove_sdhci {
struct mci_host mci;
void __iomem *base;
+ struct sdhci sdhci;
};
#define priv_from_mci_host(h) \
container_of(h, struct dove_sdhci, mci);
-static inline void dove_sdhci_writel(struct dove_sdhci *p, int reg, u32 val)
+static void dove_sdhci_writel(struct sdhci *sdhci, int reg, u32 val)
{
+ struct dove_sdhci *p = container_of(sdhci, struct dove_sdhci, sdhci);
+
writel(val, p->base + reg);
}
-static inline void dove_sdhci_writew(struct dove_sdhci *p, int reg, u16 val)
+static void dove_sdhci_writew(struct sdhci *sdhci, int reg, u16 val)
{
+ struct dove_sdhci *p = container_of(sdhci, struct dove_sdhci, sdhci);
+
writew(val, p->base + reg);
}
-static inline void dove_sdhci_writeb(struct dove_sdhci *p, int reg, u8 val)
+static void dove_sdhci_writeb(struct sdhci *sdhci, int reg, u8 val)
{
+ struct dove_sdhci *p = container_of(sdhci, struct dove_sdhci, sdhci);
+
writeb(val, p->base + reg);
}
-static inline u32 dove_sdhci_readl(struct dove_sdhci *p, int reg)
+static u32 dove_sdhci_readl(struct sdhci *sdhci, int reg)
{
+ struct dove_sdhci *p = container_of(sdhci, struct dove_sdhci, sdhci);
+
return readl(p->base + reg);
}
-static inline u16 dove_sdhci_readw(struct dove_sdhci *p, int reg)
+static u16 dove_sdhci_readw(struct sdhci *sdhci, int reg)
{
+ struct dove_sdhci *p = container_of(sdhci, struct dove_sdhci, sdhci);
+
return readw(p->base + reg);
}
-static inline u8 dove_sdhci_readb(struct dove_sdhci *p, int reg)
+static u8 dove_sdhci_readb(struct sdhci *sdhci, int reg)
{
+ struct dove_sdhci *p = container_of(sdhci, struct dove_sdhci, sdhci);
+
return readb(p->base + reg);
}
@@ -75,7 +88,7 @@ static int dove_sdhci_wait_for_done(struct dove_sdhci *host, u16 mask)
start = get_time_ns();
while (1) {
- status = dove_sdhci_readw(host, SDHCI_INT_NORMAL_STATUS);
+ status = sdhci_read16(&host->sdhci, SDHCI_INT_NORMAL_STATUS);
if (status & SDHCI_INT_ERROR)
return -EPERM;
/* this special quirk is necessary, as the dma
@@ -83,8 +96,8 @@ static int dove_sdhci_wait_for_done(struct dove_sdhci *host, u16 mask)
* restart after acknowledging it this way.
*/
if (status & SDHCI_INT_DMA) {
- u32 addr = dove_sdhci_readl(host, SDHCI_DMA_ADDRESS);
- dove_sdhci_writel(host, SDHCI_DMA_ADDRESS, addr);
+ u32 addr = sdhci_read32(&host->sdhci, SDHCI_DMA_ADDRESS);
+ sdhci_write32(&host->sdhci, SDHCI_DMA_ADDRESS, addr);
}
if (status & mask)
break;
@@ -100,12 +113,13 @@ static int dove_sdhci_mci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
struct mci_data *data)
{
u16 val;
+ u32 command, xfer;
u64 start;
int ret;
- unsigned int num_bytes = data->blocks * data->blocksize;
+ unsigned int num_bytes = 0;
struct dove_sdhci *host = priv_from_mci_host(mci);
- dove_sdhci_writel(host, SDHCI_INT_STATUS, ~0);
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0);
/* Do not wait for CMD_INHIBIT_DAT on stop commands */
if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
@@ -116,7 +130,7 @@ static int dove_sdhci_mci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
/* Wait for bus idle */
start = get_time_ns();
while (1) {
- if (!(dove_sdhci_readw(host, SDHCI_PRESENT_STATE) & val))
+ if (!(sdhci_read16(&host->sdhci, SDHCI_PRESENT_STATE) & val))
break;
if (is_timeout(start, 10 * MSECOND)) {
dev_err(host->mci.hw_dev, "SDHCI timeout while waiting for idle\n");
@@ -126,14 +140,15 @@ static int dove_sdhci_mci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
/* setup transfer data */
if (data) {
+ num_bytes = data->blocks * data->blocksize;
if (data->flags & MMC_DATA_READ)
- dove_sdhci_writel(host, SDHCI_DMA_ADDRESS, (u32)data->dest);
+ sdhci_write32(&host->sdhci, SDHCI_DMA_ADDRESS, (u32)data->dest);
else
- dove_sdhci_writel(host, SDHCI_DMA_ADDRESS, (u32)data->src);
- dove_sdhci_writew(host, SDHCI_BLOCK_SIZE, SDHCI_DMA_BOUNDARY_512K |
+ sdhci_write32(&host->sdhci, SDHCI_DMA_ADDRESS, (u32)data->src);
+ sdhci_write16(&host->sdhci, SDHCI_BLOCK_SIZE, SDHCI_DMA_BOUNDARY_512K |
SDHCI_TRANSFER_BLOCK_SIZE(data->blocksize));
- dove_sdhci_writew(host, SDHCI_BLOCK_COUNT, data->blocks);
- dove_sdhci_writeb(host, SDHCI_TIMEOUT_CONTROL, 0xe);
+ sdhci_write16(&host->sdhci, SDHCI_BLOCK_COUNT, data->blocks);
+ sdhci_write8(&host->sdhci, SDHCI_TIMEOUT_CONTROL, 0xe);
if (data->flags & MMC_DATA_WRITE)
@@ -145,84 +160,48 @@ static int dove_sdhci_mci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
}
/* setup transfer mode */
- val = 0;
- if (data) {
- val |= SDHCI_DMA_EN | SDHCI_BLOCK_COUNT_EN;
- if (data->blocks > 1)
- val |= SDHCI_MULTIPLE_BLOCKS;
- if (data->flags & MMC_DATA_READ)
- val |= SDHCI_DATA_TO_HOST;
- }
- dove_sdhci_writew(host, SDHCI_TRANSFER_MODE, val);
+ sdhci_set_cmd_xfer_mode(&host->sdhci, cmd, data, true, &command, &xfer);
- dove_sdhci_writel(host, SDHCI_ARGUMENT, cmd->cmdarg);
-
- if (!(cmd->resp_type & MMC_RSP_PRESENT))
- val = SDHCI_RESP_NONE;
- else if (cmd->resp_type & MMC_RSP_136)
- val = SDHCI_RESP_TYPE_136;
- else if (cmd->resp_type & MMC_RSP_BUSY)
- val = SDHCI_RESP_TYPE_48_BUSY;
- else
- val = SDHCI_RESP_TYPE_48;
-
- if (cmd->resp_type & MMC_RSP_CRC)
- val |= SDHCI_CMD_CRC_CHECK_EN;
- if (cmd->resp_type & MMC_RSP_OPCODE)
- val |= SDHCI_CMD_INDEX_CHECK_EN;
- if (data)
- val |= SDHCI_DATA_PRESENT;
- val |= SDHCI_CMD_INDEX(cmd->cmdidx);
-
- dove_sdhci_writew(host, SDHCI_COMMAND, val);
+ sdhci_write16(&host->sdhci, SDHCI_TRANSFER_MODE, xfer);
+ sdhci_write32(&host->sdhci, SDHCI_ARGUMENT, cmd->cmdarg);
+ sdhci_write16(&host->sdhci, SDHCI_COMMAND, command);
ret = dove_sdhci_wait_for_done(host, SDHCI_INT_CMD_COMPLETE);
if (ret) {
dev_err(host->mci.hw_dev, "error on command %d\n", cmd->cmdidx);
dev_err(host->mci.hw_dev, "state = %04x %04x, interrupt = %04x %04x\n",
- dove_sdhci_readw(host, SDHCI_PRESENT_STATE),
- dove_sdhci_readw(host, SDHCI_PRESENT_STATE1),
- dove_sdhci_readw(host, SDHCI_INT_NORMAL_STATUS),
- dove_sdhci_readw(host, SDHCI_INT_ERROR_STATUS));
+ sdhci_read16(&host->sdhci, SDHCI_PRESENT_STATE),
+ sdhci_read16(&host->sdhci, SDHCI_PRESENT_STATE1),
+ sdhci_read16(&host->sdhci, SDHCI_INT_NORMAL_STATUS),
+ sdhci_read16(&host->sdhci, SDHCI_INT_ERROR_STATUS));
goto cmd_error;
}
- /* CRC is stripped so we need to do some shifting. */
- if (cmd->resp_type & MMC_RSP_136) {
- int i;
- for (i = 0; i < 4; i++) {
- cmd->response[i] = dove_sdhci_readl(host,
- SDHCI_RESPONSE_0 + 4*(3-i)) << 8;
- if (i != 3)
- cmd->response[i] |= dove_sdhci_readb(host,
- SDHCI_RESPONSE_0 + 4*(3-i) - 1);
- }
- } else
- cmd->response[0] = dove_sdhci_readl(host, SDHCI_RESPONSE_0);
+ sdhci_read_response(&host->sdhci, cmd);
- if (data->flags & MMC_DATA_WRITE)
- dma_sync_single_for_cpu((unsigned long)data->src,
- num_bytes, DMA_TO_DEVICE);
- else
- dma_sync_single_for_cpu((unsigned long)data->dest,
+ if (data) {
+ if (data->flags & MMC_DATA_WRITE)
+ dma_sync_single_for_cpu((unsigned long)data->src,
+ num_bytes, DMA_TO_DEVICE);
+ else
+ dma_sync_single_for_cpu((unsigned long)data->dest,
num_bytes, DMA_FROM_DEVICE);
- if (data) {
ret = dove_sdhci_wait_for_done(host, SDHCI_INT_XFER_COMPLETE);
if (ret) {
dev_err(host->mci.hw_dev, "error while transfering data for command %d\n",
cmd->cmdidx);
dev_err(host->mci.hw_dev, "state = %04x %04x, interrupt = %04x %04x\n",
- dove_sdhci_readw(host, SDHCI_PRESENT_STATE),
- dove_sdhci_readw(host, SDHCI_PRESENT_STATE1),
- dove_sdhci_readw(host, SDHCI_INT_NORMAL_STATUS),
- dove_sdhci_readw(host, SDHCI_INT_ERROR_STATUS));
+ sdhci_read16(&host->sdhci, SDHCI_PRESENT_STATE),
+ sdhci_read16(&host->sdhci, SDHCI_PRESENT_STATE1),
+ sdhci_read16(&host->sdhci, SDHCI_INT_NORMAL_STATUS),
+ sdhci_read16(&host->sdhci, SDHCI_INT_ERROR_STATUS));
goto cmd_error;
}
}
cmd_error:
- dove_sdhci_writel(host, SDHCI_INT_STATUS, ~0);
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0);
return ret;
}
@@ -252,11 +231,11 @@ static void dove_sdhci_mci_set_ios(struct mci_host *mci, struct mci_ios *ios)
/* enable bus power */
val = SDHCI_BUS_VOLTAGE_330;
- dove_sdhci_writeb(host, SDHCI_POWER_CONTROL, val | SDHCI_BUS_POWER_EN);
+ sdhci_write8(&host->sdhci, SDHCI_POWER_CONTROL, val | SDHCI_BUS_POWER_EN);
udelay(400);
/* set bus width */
- val = dove_sdhci_readb(host, SDHCI_HOST_CONTROL) &
+ val = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL) &
~(SDHCI_DATA_WIDTH_4BIT | SDHCI_DATA_WIDTH_8BIT);
switch (ios->bus_width) {
case MMC_BUS_WIDTH_8:
@@ -272,17 +251,17 @@ static void dove_sdhci_mci_set_ios(struct mci_host *mci, struct mci_ios *ios)
else
val &= ~SDHCI_HIGHSPEED_EN;
- dove_sdhci_writeb(host, SDHCI_HOST_CONTROL, val);
+ sdhci_write8(&host->sdhci, SDHCI_HOST_CONTROL, val);
/* set bus clock */
- dove_sdhci_writew(host, SDHCI_CLOCK_CONTROL, 0);
+ sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, 0);
val = dove_sdhci_get_clock_divider(host, ios->clock);
val = SDHCI_INTCLOCK_EN | SDHCI_FREQ_SEL(val);
- dove_sdhci_writew(host, SDHCI_CLOCK_CONTROL, val);
+ sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, val);
/* wait for internal clock stable */
start = get_time_ns();
- while (!(dove_sdhci_readw(host, SDHCI_CLOCK_CONTROL) &
+ while (!(sdhci_read16(&host->sdhci, SDHCI_CLOCK_CONTROL) &
SDHCI_INTCLOCK_STABLE)) {
if (is_timeout(start, 20 * MSECOND)) {
dev_err(host->mci.hw_dev, "SDHCI clock stable timeout\n");
@@ -291,7 +270,7 @@ static void dove_sdhci_mci_set_ios(struct mci_host *mci, struct mci_ios *ios)
}
/* enable bus clock */
- dove_sdhci_writew(host, SDHCI_CLOCK_CONTROL, val | SDHCI_SDCLOCK_EN);
+ sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, val | SDHCI_SDCLOCK_EN);
}
static int dove_sdhci_mci_init(struct mci_host *mci, struct device_d *dev)
@@ -300,12 +279,12 @@ static int dove_sdhci_mci_init(struct mci_host *mci, struct device_d *dev)
struct dove_sdhci *host = priv_from_mci_host(mci);
/* reset sdhci controller */
- dove_sdhci_writeb(host, SDHCI_SOFTWARE_RESET, SDHCI_RESET_ALL);
+ sdhci_write8(&host->sdhci, SDHCI_SOFTWARE_RESET, SDHCI_RESET_ALL);
/* wait for reset completion */
start = get_time_ns();
while (1) {
- if ((dove_sdhci_readb(host, SDHCI_SOFTWARE_RESET) &
+ if ((sdhci_read8(&host->sdhci, SDHCI_SOFTWARE_RESET) &
SDHCI_RESET_ALL) == 0)
break;
if (is_timeout(start, 100 * MSECOND)) {
@@ -314,9 +293,9 @@ static int dove_sdhci_mci_init(struct mci_host *mci, struct device_d *dev)
}
}
- dove_sdhci_writel(host, SDHCI_INT_STATUS, ~0);
- dove_sdhci_writel(host, SDHCI_INT_ENABLE, ~0);
- dove_sdhci_writel(host, SDHCI_SIGNAL_ENABLE, ~0);
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0);
+ sdhci_write32(&host->sdhci, SDHCI_INT_ENABLE, ~0);
+ sdhci_write32(&host->sdhci, SDHCI_SIGNAL_ENABLE, ~0);
return 0;
}
@@ -325,8 +304,8 @@ static void dove_sdhci_set_mci_caps(struct dove_sdhci *host)
{
u16 caps[2];
- caps[0] = dove_sdhci_readw(host, SDHCI_CAPABILITIES);
- caps[1] = dove_sdhci_readw(host, SDHCI_CAPABILITIES_1);
+ caps[0] = sdhci_read16(&host->sdhci, SDHCI_CAPABILITIES);
+ caps[1] = sdhci_read16(&host->sdhci, SDHCI_CAPABILITIES_1);
if (caps[1] & SDHCI_HOSTCAP_VOLTAGE_180)
host->mci.voltages |= MMC_VDD_165_195;
@@ -368,6 +347,12 @@ static int dove_sdhci_probe(struct device_d *dev)
host->mci.init = dove_sdhci_mci_init;
host->mci.f_max = 50000000;
host->mci.f_min = host->mci.f_max / 256;
+ host->sdhci.read32 = dove_sdhci_readl;
+ host->sdhci.read16 = dove_sdhci_readw;
+ host->sdhci.read8 = dove_sdhci_readb;
+ host->sdhci.write32 = dove_sdhci_writel;
+ host->sdhci.write16 = dove_sdhci_writew;
+ host->sdhci.write8 = dove_sdhci_writeb;
dev->priv = host;
dev->detect = dove_sdhci_detect;
diff --git a/drivers/mci/imx-esdhc-common.c b/drivers/mci/imx-esdhc-common.c
new file mode 100644
index 0000000..d0bef94
--- /dev/null
+++ b/drivers/mci/imx-esdhc-common.c
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <common.h>
+#include <io.h>
+#include <mci.h>
+#include <pbl.h>
+
+#include "sdhci.h"
+#include "imx-esdhc.h"
+
+#define PRSSTAT_DAT0 0x01000000
+
+struct fsl_esdhc_dma_transfer {
+ dma_addr_t dma;
+ unsigned int size;
+ enum dma_data_direction dir;
+};
+
+static u32 esdhc_op_read32_le(struct sdhci *sdhci, int reg)
+{
+ struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
+
+ return readl(host->regs + reg);
+}
+
+static u32 esdhc_op_read32_be(struct sdhci *sdhci, int reg)
+{
+ struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
+
+ return in_be32(host->regs + reg);
+}
+
+static void esdhc_op_write32_le(struct sdhci *sdhci, int reg, u32 val)
+{
+ struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
+
+ writel(val, host->regs + reg);
+}
+
+static void esdhc_op_write32_be(struct sdhci *sdhci, int reg, u32 val)
+{
+ struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
+
+ out_be32(host->regs + reg, val);
+}
+
+void esdhc_populate_sdhci(struct fsl_esdhc_host *host)
+{
+ if (host->socdata->flags & ESDHC_FLAG_BIGENDIAN) {
+ host->sdhci.read32 = esdhc_op_read32_be;
+ host->sdhci.write32 = esdhc_op_write32_be;
+ } else {
+ host->sdhci.read32 = esdhc_op_read32_le;
+ host->sdhci.write32 = esdhc_op_write32_le;
+ }
+}
+
+static bool esdhc_use_pio_mode(void)
+{
+ return IN_PBL || IS_ENABLED(CONFIG_MCI_IMX_ESDHC_PIO);
+}
+static int esdhc_setup_data(struct fsl_esdhc_host *host, struct mci_data *data,
+ struct fsl_esdhc_dma_transfer *tr)
+{
+ u32 wml_value;
+ void *ptr;
+
+ if (!esdhc_use_pio_mode()) {
+ wml_value = data->blocksize/4;
+
+ if (data->flags & MMC_DATA_READ) {
+ if (wml_value > 0x10)
+ wml_value = 0x10;
+
+ esdhc_clrsetbits32(host, IMX_SDHCI_WML, WML_RD_WML_MASK, wml_value);
+ } else {
+ if (wml_value > 0x80)
+ wml_value = 0x80;
+
+ esdhc_clrsetbits32(host, IMX_SDHCI_WML, WML_WR_WML_MASK,
+ wml_value << 16);
+ }
+
+ tr->size = data->blocks * data->blocksize;
+
+ if (data->flags & MMC_DATA_WRITE) {
+ ptr = (void *)data->src;
+ tr->dir = DMA_TO_DEVICE;
+ } else {
+ ptr = data->dest;
+ tr->dir = DMA_FROM_DEVICE;
+ }
+
+ tr->dma = dma_map_single(host->dev, ptr, tr->size, tr->dir);
+ if (dma_mapping_error(host->dev, tr->dma))
+ return -EFAULT;
+
+
+ sdhci_write32(&host->sdhci, SDHCI_DMA_ADDRESS, tr->dma);
+ }
+
+ sdhci_write32(&host->sdhci, SDHCI_BLOCK_SIZE__BLOCK_COUNT, data->blocks << 16 | data->blocksize);
+
+ return 0;
+}
+
+static int esdhc_do_data(struct fsl_esdhc_host *host, struct mci_data *data,
+ struct fsl_esdhc_dma_transfer *tr)
+{
+ u32 irqstat;
+
+ if (esdhc_use_pio_mode())
+ return sdhci_transfer_data(&host->sdhci, data);
+
+ do {
+ irqstat = sdhci_read32(&host->sdhci, SDHCI_INT_STATUS);
+
+ if (irqstat & DATA_ERR)
+ return -EIO;
+
+ if (irqstat & SDHCI_INT_DATA_TIMEOUT)
+ return -ETIMEDOUT;
+ } while (!(irqstat & SDHCI_INT_XFER_COMPLETE) &&
+ (sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & SDHCI_DATA_LINE_ACTIVE));
+
+ dma_unmap_single(host->dev, tr->dma, tr->size, tr->dir);
+
+ return 0;
+}
+
+static bool esdhc_match32(struct fsl_esdhc_host *host, unsigned int off,
+ unsigned int mask, unsigned int val)
+{
+ const unsigned int reg = sdhci_read32(&host->sdhci, off) & mask;
+
+ return reg == val;
+}
+
+#ifdef __PBL__
+/*
+ * Stubs to make timeout logic below work in PBL
+ */
+
+#define get_time_ns() 0
+/*
+ * Use time in us (approx) as a busy counter timeout value
+ */
+#define is_timeout(s, t) ((s)++ > ((t) / 1024))
+
+static void __udelay(int us)
+{
+ volatile int i;
+
+ for (i = 0; i < us * 4; i++);
+}
+
+#define udelay(n) __udelay(n)
+#undef dev_err
+#define dev_err(d, ...) pr_err(__VA_ARGS__)
+
+#endif
+
+int esdhc_poll(struct fsl_esdhc_host *host, unsigned int off,
+ unsigned int mask, unsigned int val,
+ uint64_t timeout)
+{
+ return wait_on_timeout(timeout,
+ esdhc_match32(host, off, mask, val));
+}
+
+int __esdhc_send_cmd(struct fsl_esdhc_host *host, struct mci_cmd *cmd,
+ struct mci_data *data)
+{
+ u32 xfertyp, mixctrl, command;
+ u32 irqstat;
+ struct fsl_esdhc_dma_transfer tr = { 0 };
+ int ret;
+
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, -1);
+
+ /* Wait at least 8 SD clock cycles before the next command */
+ udelay(1);
+
+ /* Set up for a data transfer if we have one */
+ if (data) {
+ ret = esdhc_setup_data(host, data, &tr);
+ if (ret)
+ return ret;
+ }
+
+ sdhci_set_cmd_xfer_mode(&host->sdhci, cmd, data,
+ !esdhc_use_pio_mode(), &command, &xfertyp);
+
+ if ((host->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT) &&
+ (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION))
+ command |= SDHCI_COMMAND_CMDTYP_ABORT;
+
+ /* Send the command */
+ sdhci_write32(&host->sdhci, SDHCI_ARGUMENT, cmd->cmdarg);
+
+ if (esdhc_is_usdhc(host)) {
+ /* write lower-half of xfertyp to mixctrl */
+ mixctrl = xfertyp;
+ /* Keep the bits 22-25 of the register as is */
+ mixctrl |= (sdhci_read32(&host->sdhci, IMX_SDHCI_MIXCTRL) & (0xF << 22));
+ sdhci_write32(&host->sdhci, IMX_SDHCI_MIXCTRL, mixctrl);
+ }
+
+ sdhci_write32(&host->sdhci, SDHCI_TRANSFER_MODE__COMMAND,
+ command << 16 | xfertyp);
+
+ /* Wait for the command to complete */
+ ret = esdhc_poll(host, SDHCI_INT_STATUS,
+ SDHCI_INT_CMD_COMPLETE, SDHCI_INT_CMD_COMPLETE,
+ 100 * MSECOND);
+ if (ret) {
+ dev_err(host->dev, "timeout 1\n");
+ return -ETIMEDOUT;
+ }
+
+ irqstat = sdhci_read32(&host->sdhci, SDHCI_INT_STATUS);
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, irqstat);
+
+ if (irqstat & CMD_ERR)
+ return -EIO;
+
+ if (irqstat & SDHCI_INT_TIMEOUT)
+ return -ETIMEDOUT;
+
+ /* Workaround for ESDHC errata ENGcm03648 / ENGcm12360 */
+ if (!data && (cmd->resp_type & MMC_RSP_BUSY)) {
+ /*
+ * Poll on DATA0 line for cmd with busy signal for
+ * timout / 10 usec since DLA polling can be insecure.
+ */
+ ret = esdhc_poll(host, SDHCI_PRESENT_STATE,
+ PRSSTAT_DAT0, PRSSTAT_DAT0,
+ 2500 * MSECOND);
+ if (ret) {
+ dev_err(host->dev, "timeout PRSSTAT_DAT0\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ sdhci_read_response(&host->sdhci, cmd);
+
+ /* Wait until all of the blocks are transferred */
+ if (data) {
+ ret = esdhc_do_data(host, data, &tr);
+ if (ret)
+ return ret;
+ }
+
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, -1);
+
+ /* Wait for the bus to be idle */
+ ret = esdhc_poll(host, SDHCI_PRESENT_STATE,
+ SDHCI_CMD_INHIBIT_CMD | SDHCI_CMD_INHIBIT_DATA, 0,
+ SECOND);
+ if (ret) {
+ dev_err(host->dev, "timeout 2\n");
+ return -ETIMEDOUT;
+ }
+
+ ret = esdhc_poll(host, SDHCI_PRESENT_STATE,
+ SDHCI_DATA_LINE_ACTIVE, 0,
+ 100 * MSECOND);
+ if (ret) {
+ dev_err(host->dev, "timeout 3\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
diff --git a/drivers/mci/imx-esdhc-pbl.c b/drivers/mci/imx-esdhc-pbl.c
index f93ddfa..c0d27fb 100644
--- a/drivers/mci/imx-esdhc-pbl.c
+++ b/drivers/mci/imx-esdhc-pbl.c
@@ -30,206 +30,24 @@
#define SECTOR_SIZE 512
#define SECTOR_WML (SECTOR_SIZE / sizeof(u32))
-struct esdhc {
- void __iomem *regs;
- bool is_mx6;
- bool is_be;
- bool wrap_wml;
-};
-
-static uint32_t esdhc_read32(struct esdhc *esdhc, int reg)
-{
- if (esdhc->is_be)
- return in_be32(esdhc->regs + reg);
- else
- return readl(esdhc->regs + reg);
-}
+#define esdhc_send_cmd __esdhc_send_cmd
-static void esdhc_write32(struct esdhc *esdhc, int reg, uint32_t val)
-{
- if (esdhc->is_be)
- out_be32(esdhc->regs + reg, val);
- else
- writel(val, esdhc->regs + reg);
-}
-
-static void __udelay(int us)
-{
- volatile int i;
-
- for (i = 0; i < us * 4; i++);
-}
-
-static u32 esdhc_xfertyp(struct mci_cmd *cmd, struct mci_data *data)
-{
- u32 xfertyp = 0;
-
- if (data)
- xfertyp |= COMMAND_DPSEL | TRANSFER_MODE_MSBSEL |
- TRANSFER_MODE_BCEN |TRANSFER_MODE_DTDSEL;
-
- if (cmd->resp_type & MMC_RSP_CRC)
- xfertyp |= COMMAND_CCCEN;
- if (cmd->resp_type & MMC_RSP_OPCODE)
- xfertyp |= COMMAND_CICEN;
- if (cmd->resp_type & MMC_RSP_136)
- xfertyp |= COMMAND_RSPTYP_136;
- else if (cmd->resp_type & MMC_RSP_BUSY)
- xfertyp |= COMMAND_RSPTYP_48_BUSY;
- else if (cmd->resp_type & MMC_RSP_PRESENT)
- xfertyp |= COMMAND_RSPTYP_48;
-
- return COMMAND_CMD(cmd->cmdidx) | xfertyp;
-}
-
-static int esdhc_do_data(struct esdhc *esdhc, struct mci_data *data)
-{
- char *buffer;
- u32 databuf;
- u32 size;
- u32 irqstat;
- u32 present;
-
- buffer = data->dest;
-
- size = data->blocksize * data->blocks;
- irqstat = esdhc_read32(esdhc, SDHCI_INT_STATUS);
-
- while (size) {
- int i;
- int timeout = 1000000;
-
- while (1) {
- present = esdhc_read32(esdhc, SDHCI_PRESENT_STATE) & PRSSTAT_BREN;
- if (present)
- break;
- if (!--timeout) {
- pr_err("read time out\n");
- return -ETIMEDOUT;
- }
- }
-
- for (i = 0; i < SECTOR_WML; i++) {
- databuf = esdhc_read32(esdhc, SDHCI_BUFFER);
- *((u32 *)buffer) = databuf;
- buffer += 4;
- size -= 4;
- }
- }
-
- return 0;
-}
-
-static int
-esdhc_send_cmd(struct esdhc *esdhc, struct mci_cmd *cmd, struct mci_data *data)
-{
- u32 xfertyp, mixctrl;
- u32 irqstat;
- int ret;
- int timeout;
-
- esdhc_write32(esdhc, SDHCI_INT_STATUS, -1);
-
- /* Wait at least 8 SD clock cycles before the next command */
- __udelay(1);
-
- if (data) {
- unsigned long dest = (unsigned long)data->dest;
-
- if (dest > 0xffffffff)
- return -EINVAL;
-
- /* Set up for a data transfer if we have one */
- esdhc_write32(esdhc, SDHCI_DMA_ADDRESS, (u32)dest);
- esdhc_write32(esdhc, SDHCI_BLOCK_SIZE__BLOCK_COUNT, data->blocks << 16 | SECTOR_SIZE);
- }
-
- /* Figure out the transfer arguments */
- xfertyp = esdhc_xfertyp(cmd, data);
-
- /* Send the command */
- esdhc_write32(esdhc, SDHCI_ARGUMENT, cmd->cmdarg);
-
- if (esdhc->is_mx6) {
- /* write lower-half of xfertyp to mixctrl */
- mixctrl = xfertyp & 0xFFFF;
- /* Keep the bits 22-25 of the register as is */
- mixctrl |= (esdhc_read32(esdhc, IMX_SDHCI_MIXCTRL) & (0xF << 22));
- esdhc_write32(esdhc, IMX_SDHCI_MIXCTRL, mixctrl);
- }
-
- esdhc_write32(esdhc, SDHCI_TRANSFER_MODE__COMMAND, xfertyp);
-
- /* Wait for the command to complete */
- timeout = 10000;
- while (!(esdhc_read32(esdhc, SDHCI_INT_STATUS) & IRQSTAT_CC)) {
- __udelay(1);
- if (!timeout--)
- return -ETIMEDOUT;
- }
-
- irqstat = esdhc_read32(esdhc, SDHCI_INT_STATUS);
- esdhc_write32(esdhc, SDHCI_INT_STATUS, irqstat);
-
- if (irqstat & CMD_ERR)
- return -EIO;
-
- if (irqstat & IRQSTAT_CTOE)
- return -ETIMEDOUT;
-
- /* Copy the response to the response buffer */
- cmd->response[0] = esdhc_read32(esdhc, SDHCI_RESPONSE_0);
-
- /* Wait until all of the blocks are transferred */
- if (data) {
- ret = esdhc_do_data(esdhc, data);
- if (ret)
- return ret;
- }
-
- esdhc_write32(esdhc, SDHCI_INT_STATUS, -1);
-
- /* Wait for the bus to be idle */
- timeout = 10000;
- while (esdhc_read32(esdhc, SDHCI_PRESENT_STATE) &
- (PRSSTAT_CICHB | PRSSTAT_CIDHB | PRSSTAT_DLA)) {
- __udelay(1);
- if (!timeout--)
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
-static int esdhc_read_blocks(struct esdhc *esdhc, void *dst, size_t len)
+static int esdhc_read_blocks(struct fsl_esdhc_host *host, void *dst, size_t len)
{
struct mci_cmd cmd;
struct mci_data data;
- u32 val, wml;
+ u32 val;
int ret;
- esdhc_write32(esdhc, SDHCI_INT_ENABLE,
- IRQSTATEN_CC | IRQSTATEN_TC | IRQSTATEN_CINT | IRQSTATEN_CTOE |
- IRQSTATEN_CCE | IRQSTATEN_CEBE | IRQSTATEN_CIE |
- IRQSTATEN_DTOE | IRQSTATEN_DCE | IRQSTATEN_DEBE |
- IRQSTATEN_DINT);
-
- wml = FIELD_PREP(WML_WR_BRST_LEN, 16) |
- FIELD_PREP(WML_WR_WML_MASK, SECTOR_WML) |
- FIELD_PREP(WML_RD_BRST_LEN, 16) |
- FIELD_PREP(WML_RD_WML_MASK, SECTOR_WML);
- /*
- * Some SoCs intrpret 0 as MAX value so for those cases the
- * above value translates to zero
- */
- if (esdhc->wrap_wml)
- wml = 0;
-
- esdhc_write32(esdhc, IMX_SDHCI_WML, wml);
+ sdhci_write32(&host->sdhci, SDHCI_INT_ENABLE,
+ SDHCI_INT_CMD_COMPLETE | SDHCI_INT_XFER_COMPLETE |
+ SDHCI_INT_CARD_INT | SDHCI_INT_TIMEOUT | SDHCI_INT_CRC |
+ SDHCI_INT_END_BIT | SDHCI_INT_INDEX | SDHCI_INT_DATA_TIMEOUT |
+ SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT | SDHCI_INT_DMA);
- val = esdhc_read32(esdhc, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET);
+ val = sdhci_read32(&host->sdhci, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET);
val |= SYSCTL_HCKEN | SYSCTL_IPGEN;
- esdhc_write32(esdhc, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, val);
+ sdhci_write32(&host->sdhci, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, val);
cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
cmd.cmdarg = 0;
@@ -240,7 +58,7 @@ static int esdhc_read_blocks(struct esdhc *esdhc, void *dst, size_t len)
data.blocksize = SECTOR_SIZE;
data.flags = MMC_DATA_READ;
- ret = esdhc_send_cmd(esdhc, &cmd, &data);
+ ret = esdhc_send_cmd(host, &cmd, &data);
if (ret) {
pr_debug("send command failed with %d\n", ret);
return ret;
@@ -250,13 +68,13 @@ static int esdhc_read_blocks(struct esdhc *esdhc, void *dst, size_t len)
cmd.cmdarg = 0;
cmd.resp_type = MMC_RSP_R1b;
- esdhc_send_cmd(esdhc, &cmd, NULL);
+ esdhc_send_cmd(host, &cmd, NULL);
return 0;
}
#ifdef CONFIG_ARCH_IMX
-static int esdhc_search_header(struct esdhc *esdhc,
+static int esdhc_search_header(struct fsl_esdhc_host *host,
struct imx_flash_header_v2 **header_pointer,
void *buffer, u32 *offset)
{
@@ -266,7 +84,7 @@ static int esdhc_search_header(struct esdhc *esdhc,
struct imx_flash_header_v2 *hdr;
for (i = 0; i < header_count; i++) {
- ret = esdhc_read_blocks(esdhc, buf,
+ ret = esdhc_read_blocks(host, buf,
*offset + SZ_1K + SECTOR_SIZE);
if (ret)
return ret;
@@ -303,7 +121,7 @@ static int esdhc_search_header(struct esdhc *esdhc,
}
static int
-esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, ptrdiff_t entry,
+esdhc_start_image(struct fsl_esdhc_host *host, ptrdiff_t address, ptrdiff_t entry,
u32 offset)
{
@@ -316,7 +134,7 @@ esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, ptrdiff_t entry,
len = imx_image_size();
len = ALIGN(len, SECTOR_SIZE);
- ret = esdhc_search_header(esdhc, &hdr, buf, &offset);
+ ret = esdhc_search_header(host, &hdr, buf, &offset);
if (ret)
return ret;
@@ -351,7 +169,7 @@ esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, ptrdiff_t entry,
buf = (void *)(entry - ofs);
}
- ret = esdhc_read_blocks(esdhc, buf, offset + len);
+ ret = esdhc_read_blocks(host, buf, offset + len);
if (ret) {
pr_err("Loading image failed with %d\n", ret);
return ret;
@@ -366,6 +184,40 @@ esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, ptrdiff_t entry,
bb();
}
+static void imx_esdhc_init(struct fsl_esdhc_host *host,
+ struct esdhc_soc_data *data)
+{
+ data->flags = ESDHC_FLAG_USDHC;
+ host->socdata = data;
+ esdhc_populate_sdhci(host);
+
+ sdhci_write32(&host->sdhci, IMX_SDHCI_WML,
+ FIELD_PREP(WML_WR_BRST_LEN, 16) |
+ FIELD_PREP(WML_WR_WML_MASK, SECTOR_WML) |
+ FIELD_PREP(WML_RD_BRST_LEN, 16) |
+ FIELD_PREP(WML_RD_WML_MASK, SECTOR_WML));
+}
+
+static int imx8_esdhc_init(struct fsl_esdhc_host *host,
+ struct esdhc_soc_data *data,
+ int instance)
+{
+ switch (instance) {
+ case 0:
+ host->regs = IOMEM(MX8MQ_USDHC1_BASE_ADDR);
+ break;
+ case 1:
+ host->regs = IOMEM(MX8MQ_USDHC2_BASE_ADDR);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ imx_esdhc_init(host, data);
+
+ return 0;
+}
+
/**
* imx6_esdhc_start_image - Load and start an image from USDHC controller
* @instance: The USDHC controller instance (0..4)
@@ -380,30 +232,29 @@ esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, ptrdiff_t entry,
*/
int imx6_esdhc_start_image(int instance)
{
- struct esdhc esdhc;
+ struct esdhc_soc_data data;
+ struct fsl_esdhc_host host;
switch (instance) {
case 0:
- esdhc.regs = IOMEM(MX6_USDHC1_BASE_ADDR);
+ host.regs = IOMEM(MX6_USDHC1_BASE_ADDR);
break;
case 1:
- esdhc.regs = IOMEM(MX6_USDHC2_BASE_ADDR);
+ host.regs = IOMEM(MX6_USDHC2_BASE_ADDR);
break;
case 2:
- esdhc.regs = IOMEM(MX6_USDHC3_BASE_ADDR);
+ host.regs = IOMEM(MX6_USDHC3_BASE_ADDR);
break;
case 3:
- esdhc.regs = IOMEM(MX6_USDHC4_BASE_ADDR);
+ host.regs = IOMEM(MX6_USDHC4_BASE_ADDR);
break;
default:
return -EINVAL;
}
- esdhc.is_be = 0;
- esdhc.is_mx6 = 1;
- esdhc.wrap_wml = false;
+ imx_esdhc_init(&host, &data);
- return esdhc_start_image(&esdhc, 0x10000000, 0x10000000, 0);
+ return esdhc_start_image(&host, 0x10000000, 0x10000000, 0);
}
/**
@@ -420,24 +271,15 @@ int imx6_esdhc_start_image(int instance)
*/
int imx8_esdhc_start_image(int instance)
{
- struct esdhc esdhc;
-
- switch (instance) {
- case 0:
- esdhc.regs = IOMEM(MX8MQ_USDHC1_BASE_ADDR);
- break;
- case 1:
- esdhc.regs = IOMEM(MX8MQ_USDHC2_BASE_ADDR);
- break;
- default:
- return -EINVAL;
- }
+ struct esdhc_soc_data data;
+ struct fsl_esdhc_host host;
+ int ret;
- esdhc.is_be = 0;
- esdhc.is_mx6 = 1;
- esdhc.wrap_wml = false;
+ ret = imx8_esdhc_init(&host, &data, instance);
+ if (ret)
+ return ret;
- return esdhc_start_image(&esdhc, MX8MQ_DDR_CSD1_BASE_ADDR,
+ return esdhc_start_image(&host, MX8MQ_DDR_CSD1_BASE_ADDR,
MX8MQ_ATF_BL33_BASE_ADDR, SZ_32K);
}
@@ -445,24 +287,14 @@ int imx8_esdhc_load_piggy(int instance)
{
void *buf, *piggy;
struct imx_flash_header_v2 *hdr = NULL;
- struct esdhc esdhc;
+ struct esdhc_soc_data data;
+ struct fsl_esdhc_host host;
int ret, len;
int offset = SZ_32K;
- switch (instance) {
- case 0:
- esdhc.regs = IOMEM(MX8MQ_USDHC1_BASE_ADDR);
- break;
- case 1:
- esdhc.regs = IOMEM(MX8MQ_USDHC2_BASE_ADDR);
- break;
- default:
- return -EINVAL;
- }
-
- esdhc.is_be = 0;
- esdhc.is_mx6 = 1;
- esdhc.wrap_wml = false;
+ ret = imx8_esdhc_init(&host, &data, instance);
+ if (ret)
+ return ret;
/*
* We expect to be running at MX8MQ_ATF_BL33_BASE_ADDR where the atf
@@ -471,14 +303,14 @@ int imx8_esdhc_load_piggy(int instance)
*/
buf = (void *)MX8MQ_ATF_BL33_BASE_ADDR + SZ_32M;
- ret = esdhc_search_header(&esdhc, &hdr, buf, &offset);
+ ret = esdhc_search_header(&host, &hdr, buf, &offset);
if (ret)
return ret;
len = offset + hdr->boot_data.size + piggydata_size();
len = ALIGN(len, SECTOR_SIZE);
- ret = esdhc_read_blocks(&esdhc, buf, len);
+ ret = esdhc_read_blocks(&host, buf, len);
/*
* Calculate location of the piggydata at the offset loaded into RAM
@@ -516,28 +348,33 @@ int ls1046a_esdhc_start_image(unsigned long r0, unsigned long r1, unsigned long
{
int ret;
uint32_t val;
- struct esdhc esdhc = {
+ struct esdhc_soc_data data = {
+ .flags = ESDHC_FLAG_BIGENDIAN,
+ };
+ struct fsl_esdhc_host host = {
.regs = IOMEM(0x01560000),
- .is_be = true,
- .wrap_wml = true,
+ .socdata = &data,
};
unsigned long sdram = 0x80000000;
void (*barebox)(unsigned long, unsigned long, unsigned long) =
(void *)(sdram + LS1046A_SD_IMAGE_OFFSET);
+ esdhc_populate_sdhci(&host);
+ sdhci_write32(&host.sdhci, IMX_SDHCI_WML, 0);
+
/*
* The ROM leaves us here with a clock frequency of around 400kHz. Speed
* this up a bit. FIXME: The resulting frequency has not yet been verified
* to work on all cards.
*/
- val = esdhc_read32(&esdhc, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET);
+ val = sdhci_read32(&host.sdhci, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET);
val &= ~0x0000fff0;
val |= (8 << 8) | (3 << 4);
- esdhc_write32(&esdhc, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, val);
+ sdhci_write32(&host.sdhci, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, val);
- esdhc_write32(&esdhc, ESDHC_DMA_SYSCTL, ESDHC_SYSCTL_DMA_SNOOP);
+ sdhci_write32(&host.sdhci, ESDHC_DMA_SYSCTL, ESDHC_SYSCTL_DMA_SNOOP);
- ret = esdhc_read_blocks(&esdhc, (void *)sdram,
+ ret = esdhc_read_blocks(&host, (void *)sdram,
ALIGN(barebox_image_size + LS1046A_SD_IMAGE_OFFSET, 512));
if (ret) {
pr_err("%s: reading blocks failed with: %d\n", __func__, ret);
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index db3450a..6a9f119 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -39,267 +39,12 @@
#include "sdhci.h"
#include "imx-esdhc.h"
-/*
- * The CMDTYPE of the CMD register (offset 0xE) should be set to
- * "11" when the STOP CMD12 is issued on imx53 to abort one
- * open ended multi-blk IO. Otherwise the TC INT wouldn't
- * be generated.
- * In exact block transfer, the controller doesn't complete the
- * operations automatically as required at the end of the
- * transfer and remains on hold if the abort command is not sent.
- * As a result, the TC flag is not asserted and SW received timeout
- * exeception. Bit1 of Vendor Spec registor is used to fix it.
- */
-#define ESDHC_FLAG_MULTIBLK_NO_INT BIT(1)
-/*
- * The flag enables the workaround for ESDHC errata ENGcm07207 which
- * affects i.MX25 and i.MX35.
- */
-#define ESDHC_FLAG_ENGCM07207 BIT(2)
-/*
- * The flag tells that the ESDHC controller is an USDHC block that is
- * integrated on the i.MX6 series.
- */
-#define ESDHC_FLAG_USDHC BIT(3)
-/* The IP supports manual tuning process */
-#define ESDHC_FLAG_MAN_TUNING BIT(4)
-/* The IP supports standard tuning process */
-#define ESDHC_FLAG_STD_TUNING BIT(5)
-/* The IP has SDHCI_CAPABILITIES_1 register */
-#define ESDHC_FLAG_HAVE_CAP1 BIT(6)
-/*
- * The IP has errata ERR004536
- * uSDHC: ADMA Length Mismatch Error occurs if the AHB read access is slow,
- * when reading data from the card
- */
-#define ESDHC_FLAG_ERR004536 BIT(7)
-/* The IP supports HS200 mode */
-#define ESDHC_FLAG_HS200 BIT(8)
-/* The IP supports HS400 mode */
-#define ESDHC_FLAG_HS400 BIT(9)
-
-/* Need to access registers in bigendian mode */
-#define ESDHC_FLAG_BIGENDIAN BIT(10)
-/* Enable cache snooping */
-#define ESDHC_FLAG_CACHE_SNOOPING BIT(11)
-
-struct esdhc_soc_data {
- u32 flags;
- const char *clkidx;
-};
+#define PRSSTAT_SDSTB 0x00000008
-struct fsl_esdhc_host {
- struct mci_host mci;
- void __iomem *regs;
- struct device_d *dev;
- struct clk *clk;
- const struct esdhc_soc_data *socdata;
-};
#define to_fsl_esdhc(mci) container_of(mci, struct fsl_esdhc_host, mci)
-#define SDHCI_CMD_ABORTCMD (0xC0 << 16)
-
-static inline int esdhc_is_usdhc(struct fsl_esdhc_host *data)
-{
- return !!(data->socdata->flags & ESDHC_FLAG_USDHC);
-}
-
-static inline u32 esdhc_read32(struct fsl_esdhc_host *host, unsigned int reg)
-{
- if (host->socdata->flags & ESDHC_FLAG_BIGENDIAN)
- return in_be32(host->regs + reg);
- else
- return readl(host->regs + reg);
-}
-
-static inline void esdhc_write32(struct fsl_esdhc_host *host, unsigned int reg,
- u32 val)
-{
- if (host->socdata->flags & ESDHC_FLAG_BIGENDIAN)
- out_be32(host->regs + reg, val);
- else
- writel(val, host->regs + reg);
-}
-
-static inline void esdhc_clrsetbits32(struct fsl_esdhc_host *host, unsigned int reg,
- u32 clear, u32 set)
-{
- u32 val;
-
- val = esdhc_read32(host, reg);
- val &= ~clear;
- val |= set;
- esdhc_write32(host, reg, val);
-}
-
-static inline void esdhc_clrbits32(struct fsl_esdhc_host *host, unsigned int reg,
- u32 clear)
-{
- esdhc_clrsetbits32(host, reg, clear, 0);
-}
-
-static inline void esdhc_setbits32(struct fsl_esdhc_host *host, unsigned int reg,
- u32 set)
-{
- esdhc_clrsetbits32(host, reg, 0, set);
-}
-
-/* Return the XFERTYP flags for a given command and data packet */
-static u32 esdhc_xfertyp(struct fsl_esdhc_host *host,
- struct mci_cmd *cmd, struct mci_data *data)
-{
- u32 xfertyp = 0;
-
- if (data) {
- xfertyp |= COMMAND_DPSEL;
-
- if (!IS_ENABLED(CONFIG_MCI_IMX_ESDHC_PIO))
- xfertyp |= TRANSFER_MODE_DMAEN;
-
- if (data->blocks > 1) {
- xfertyp |= TRANSFER_MODE_MSBSEL;
- xfertyp |= TRANSFER_MODE_BCEN;
- }
-
- if (data->flags & MMC_DATA_READ)
- xfertyp |= TRANSFER_MODE_DTDSEL;
- }
-
- if (cmd->resp_type & MMC_RSP_CRC)
- xfertyp |= COMMAND_CCCEN;
- if (cmd->resp_type & MMC_RSP_OPCODE)
- xfertyp |= COMMAND_CICEN;
- if (cmd->resp_type & MMC_RSP_136)
- xfertyp |= COMMAND_RSPTYP_136;
- else if (cmd->resp_type & MMC_RSP_BUSY)
- xfertyp |= COMMAND_RSPTYP_48_BUSY;
- else if (cmd->resp_type & MMC_RSP_PRESENT)
- xfertyp |= COMMAND_RSPTYP_48;
- if ((host->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT) &&
- (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION))
- xfertyp |= SDHCI_CMD_ABORTCMD;
-
- return COMMAND_CMD(cmd->cmdidx) | xfertyp;
-}
-
-/*
- * PIO Read/Write Mode reduce the performace as DMA is not used in this mode.
- */
-static int
-esdhc_pio_read_write(struct mci_host *mci, struct mci_data *data)
-{
- struct fsl_esdhc_host *host = to_fsl_esdhc(mci);
- u32 blocks;
- char *buffer;
- u32 databuf;
- u32 size;
- u32 irqstat;
- u32 timeout;
-
- if (data->flags & MMC_DATA_READ) {
- blocks = data->blocks;
- buffer = data->dest;
- while (blocks) {
- timeout = PIO_TIMEOUT;
- size = data->blocksize;
- irqstat = esdhc_read32(host, SDHCI_INT_STATUS);
- while (!(esdhc_read32(host, SDHCI_PRESENT_STATE) & PRSSTAT_BREN)
- && --timeout);
- if (timeout <= 0) {
- dev_err(host->dev, "Data Read Failed\n");
- return -ETIMEDOUT;
- }
- while (size && (!(irqstat & IRQSTAT_TC))) {
- udelay(100); /* Wait before last byte transfer complete */
- irqstat = esdhc_read32(host, SDHCI_INT_STATUS);
- databuf = esdhc_read32(host, SDHCI_BUFFER);
- *((u32 *)buffer) = databuf;
- buffer += 4;
- size -= 4;
- }
- blocks--;
- }
- } else {
- blocks = data->blocks;
- buffer = (char *)data->src;
- while (blocks) {
- timeout = PIO_TIMEOUT;
- size = data->blocksize;
- irqstat = esdhc_read32(host, SDHCI_INT_STATUS);
- while (!(esdhc_read32(host, SDHCI_PRESENT_STATE) & PRSSTAT_BWEN)
- && --timeout);
- if (timeout <= 0) {
- dev_err(host->dev, "Data Write Failed\n");
- return -ETIMEDOUT;
- }
- while (size && (!(irqstat & IRQSTAT_TC))) {
- udelay(100); /* Wait before last byte transfer complete */
- databuf = *((u32 *)buffer);
- buffer += 4;
- size -= 4;
- irqstat = esdhc_read32(host, SDHCI_INT_STATUS);
- esdhc_write32(host, SDHCI_BUFFER, databuf);
- }
- blocks--;
- }
- }
-
- return 0;
-}
-
-static int esdhc_setup_data(struct mci_host *mci, struct mci_data *data,
- dma_addr_t dma)
-{
- struct fsl_esdhc_host *host = to_fsl_esdhc(mci);
- u32 wml_value;
-
- if (!IS_ENABLED(CONFIG_MCI_IMX_ESDHC_PIO)) {
- wml_value = data->blocksize/4;
-
- if (data->flags & MMC_DATA_READ) {
- if (wml_value > 0x10)
- wml_value = 0x10;
-
- esdhc_clrsetbits32(host, IMX_SDHCI_WML, WML_RD_WML_MASK, wml_value);
- } else {
- if (wml_value > 0x80)
- wml_value = 0x80;
-
- esdhc_clrsetbits32(host, IMX_SDHCI_WML, WML_WR_WML_MASK,
- wml_value << 16);
- }
- esdhc_write32(host, SDHCI_DMA_ADDRESS, dma);
- }
-
- esdhc_write32(host, SDHCI_BLOCK_SIZE__BLOCK_COUNT, data->blocks << 16 | data->blocksize);
-
- return 0;
-}
-
-static int esdhc_do_data(struct mci_host *mci, struct mci_data *data)
-{
- struct fsl_esdhc_host *host = to_fsl_esdhc(mci);
- u32 irqstat;
-
- if (IS_ENABLED(CONFIG_MCI_IMX_ESDHC_PIO))
- return esdhc_pio_read_write(mci, data);
-
- do {
- irqstat = esdhc_read32(host, SDHCI_INT_STATUS);
-
- if (irqstat & DATA_ERR)
- return -EIO;
-
- if (irqstat & IRQSTAT_DTOE)
- return -ETIMEDOUT;
- } while (!(irqstat & IRQSTAT_TC) &&
- (esdhc_read32(host, SDHCI_PRESENT_STATE) & PRSSTAT_DLA));
-
- return 0;
-}
-
/*
* Sends a command out on the bus. Takes the mci pointer,
* a command pointer, and an optional data pointer.
@@ -307,137 +52,9 @@ static int esdhc_do_data(struct mci_host *mci, struct mci_data *data)
static int
esdhc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data)
{
- u32 xfertyp, mixctrl;
- u32 irqstat;
struct fsl_esdhc_host *host = to_fsl_esdhc(mci);
- unsigned int num_bytes = 0;
- int ret;
- void *ptr;
- enum dma_data_direction dir = 0;
- dma_addr_t dma = 0;
-
- esdhc_write32(host, SDHCI_INT_STATUS, -1);
-
- /* Wait at least 8 SD clock cycles before the next command */
- udelay(1);
-
- /* Set up for a data transfer if we have one */
- if (data) {
- int err;
-
- if (!IS_ENABLED(CONFIG_MCI_IMX_ESDHC_PIO)) {
- num_bytes = data->blocks * data->blocksize;
-
- if (data->flags & MMC_DATA_WRITE) {
- ptr = (void *)data->src;
- dir = DMA_TO_DEVICE;
- } else {
- ptr = data->dest;
- dir = DMA_FROM_DEVICE;
- }
-
- dma = dma_map_single(host->dev, ptr, num_bytes, dir);
- if (dma_mapping_error(host->dev, dma))
- return -EFAULT;
- }
-
- err = esdhc_setup_data(mci, data, dma);
- if(err)
- return err;
- }
-
- /* Figure out the transfer arguments */
- xfertyp = esdhc_xfertyp(host, cmd, data);
-
- /* Send the command */
- esdhc_write32(host, SDHCI_ARGUMENT, cmd->cmdarg);
-
- if (esdhc_is_usdhc(host)) {
- /* write lower-half of xfertyp to mixctrl */
- mixctrl = xfertyp & 0xFFFF;
- /* Keep the bits 22-25 of the register as is */
- mixctrl |= (esdhc_read32(host, IMX_SDHCI_MIXCTRL) & (0xF << 22));
- esdhc_write32(host, IMX_SDHCI_MIXCTRL, mixctrl);
- }
-
- esdhc_write32(host, SDHCI_TRANSFER_MODE__COMMAND, xfertyp);
-
- /* Wait for the command to complete */
- ret = wait_on_timeout(100 * MSECOND,
- esdhc_read32(host, SDHCI_INT_STATUS) & IRQSTAT_CC);
- if (ret) {
- dev_dbg(host->dev, "timeout 1\n");
- return -ETIMEDOUT;
- }
-
- irqstat = esdhc_read32(host, SDHCI_INT_STATUS);
- esdhc_write32(host, SDHCI_INT_STATUS, irqstat);
-
- if (irqstat & CMD_ERR)
- return -EIO;
-
- if (irqstat & IRQSTAT_CTOE)
- return -ETIMEDOUT;
-
- /* Workaround for ESDHC errata ENGcm03648 / ENGcm12360 */
- if (!data && (cmd->resp_type & MMC_RSP_BUSY)) {
- /*
- * Poll on DATA0 line for cmd with busy signal for
- * timout / 10 usec since DLA polling can be insecure.
- */
- ret = wait_on_timeout(2500 * MSECOND,
- (esdhc_read32(host, SDHCI_PRESENT_STATE) & PRSSTAT_DAT0));
-
- if (ret) {
- dev_err(host->dev, "timeout PRSSTAT_DAT0\n");
- return -ETIMEDOUT;
- }
- }
-
- /* Copy the response to the response buffer */
- if (cmd->resp_type & MMC_RSP_136) {
- u32 cmdrsp3, cmdrsp2, cmdrsp1, cmdrsp0;
-
- cmdrsp3 = esdhc_read32(host, SDHCI_RESPONSE_3);
- cmdrsp2 = esdhc_read32(host, SDHCI_RESPONSE_2);
- cmdrsp1 = esdhc_read32(host, SDHCI_RESPONSE_1);
- cmdrsp0 = esdhc_read32(host, SDHCI_RESPONSE_0);
- cmd->response[0] = (cmdrsp3 << 8) | (cmdrsp2 >> 24);
- cmd->response[1] = (cmdrsp2 << 8) | (cmdrsp1 >> 24);
- cmd->response[2] = (cmdrsp1 << 8) | (cmdrsp0 >> 24);
- cmd->response[3] = (cmdrsp0 << 8);
- } else
- cmd->response[0] = esdhc_read32(host, SDHCI_RESPONSE_0);
-
- /* Wait until all of the blocks are transferred */
- if (data) {
- ret = esdhc_do_data(mci, data);
- if (ret)
- return ret;
- if (!IS_ENABLED(CONFIG_MCI_IMX_ESDHC_PIO))
- dma_unmap_single(host->dev, dma, num_bytes, dir);
- }
-
- esdhc_write32(host, SDHCI_INT_STATUS, -1);
-
- /* Wait for the bus to be idle */
- ret = wait_on_timeout(SECOND,
- !(esdhc_read32(host, SDHCI_PRESENT_STATE) &
- (PRSSTAT_CICHB | PRSSTAT_CIDHB)));
- if (ret) {
- dev_err(host->dev, "timeout 2\n");
- return -ETIMEDOUT;
- }
-
- ret = wait_on_timeout(100 * MSECOND,
- !(esdhc_read32(host, SDHCI_PRESENT_STATE) & PRSSTAT_DLA));
- if (ret) {
- dev_err(host->dev, "timeout 3\n");
- return -ETIMEDOUT;
- }
-
- return 0;
+ return __esdhc_send_cmd(host, cmd, data);
}
static void set_sysctl(struct mci_host *mci, u32 clock)
@@ -486,16 +103,18 @@ static void set_sysctl(struct mci_host *mci, u32 clock)
esdhc_clrsetbits32(host, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET,
SYSCTL_CLOCK_MASK, clk);
- wait_on_timeout(10 * MSECOND,
- esdhc_read32(host, SDHCI_PRESENT_STATE) & PRSSTAT_SDSTB);
+ esdhc_poll(host, SDHCI_PRESENT_STATE,
+ PRSSTAT_SDSTB, PRSSTAT_SDSTB,
+ 10 * MSECOND);
clk = SYSCTL_PEREN | SYSCTL_CKEN | SYSCTL_INITA;
esdhc_setbits32(host, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET,
clk);
- wait_on_timeout(1 * MSECOND,
- !(esdhc_read32(host, SDHCI_CLOCK_CONTROL) & SYSCTL_INITA));
+ esdhc_poll(host, SDHCI_CLOCK_CONTROL,
+ SYSCTL_INITA, SYSCTL_INITA,
+ 10 * MSECOND);
}
static void esdhc_set_ios(struct mci_host *mci, struct mci_ios *ios)
@@ -540,7 +159,7 @@ static int esdhc_card_present(struct mci_host *mci)
case ESDHC_CD_PERMANENT:
return 1;
case ESDHC_CD_CONTROLLER:
- return !(esdhc_read32(host, SDHCI_PRESENT_STATE) & PRSSTAT_WPSPL);
+ return !(sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & SDHCI_WRITE_PROTECT);
case ESDHC_CD_GPIO:
ret = gpio_direction_input(pdata->cd_gpio);
if (ret)
@@ -553,34 +172,29 @@ static int esdhc_card_present(struct mci_host *mci)
static int esdhc_reset(struct fsl_esdhc_host *host)
{
- uint64_t start;
int val;
/* reset the controller */
- esdhc_write32(host, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET,
+ sdhci_write32(&host->sdhci, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET,
SYSCTL_RSTA);
/* extra register reset for i.MX6 Solo/DualLite */
if (esdhc_is_usdhc(host)) {
/* reset bit FBCLK_SEL */
- val = esdhc_read32(host, IMX_SDHCI_MIXCTRL);
+ val = sdhci_read32(&host->sdhci, IMX_SDHCI_MIXCTRL);
val &= ~IMX_SDHCI_MIX_CTRL_FBCLK_SEL;
- esdhc_write32(host, IMX_SDHCI_MIXCTRL, val);
+ sdhci_write32(&host->sdhci, IMX_SDHCI_MIXCTRL, val);
/* reset delay line settings in IMX_SDHCI_DLL_CTRL */
- esdhc_write32(host, IMX_SDHCI_DLL_CTRL, 0x0);
+ sdhci_write32(&host->sdhci, IMX_SDHCI_DLL_CTRL, 0x0);
}
- start = get_time_ns();
/* hardware clears the bit when it is done */
- while (1) {
- if (!(esdhc_read32(host, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET)
- & SYSCTL_RSTA))
- break;
- if (is_timeout(start, 100 * MSECOND)) {
- dev_err(host->dev, "Reset never completed.\n");
- return -EIO;
- }
+ if (esdhc_poll(host,
+ SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET,
+ SYSCTL_RSTA, 0, 100 * MSECOND)) {
+ dev_err(host->dev, "Reset never completed.\n");
+ return -EIO;
}
return 0;
@@ -595,11 +209,11 @@ static int esdhc_init(struct mci_host *mci, struct device_d *dev)
if (ret)
return ret;
- esdhc_write32(host, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET,
+ sdhci_write32(&host->sdhci, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET,
SYSCTL_HCKEN | SYSCTL_IPGEN);
/* RSTA doesn't reset MMC_BOOT register, so manually reset it */
- esdhc_write32(host, SDHCI_MMC_BOOT, 0);
+ sdhci_write32(&host->sdhci, SDHCI_MMC_BOOT, 0);
/* Enable cache snooping */
if (host->socdata->flags & ESDHC_FLAG_CACHE_SNOOPING)
@@ -608,13 +222,14 @@ static int esdhc_init(struct mci_host *mci, struct device_d *dev)
/* Set the initial clock speed */
set_sysctl(mci, 400000);
- esdhc_write32(host, SDHCI_INT_ENABLE, IRQSTATEN_CC | IRQSTATEN_TC |
- IRQSTATEN_CINT | IRQSTATEN_CTOE | IRQSTATEN_CCE |
- IRQSTATEN_CEBE | IRQSTATEN_CIE | IRQSTATEN_DTOE |
- IRQSTATEN_DCE | IRQSTATEN_DEBE | IRQSTATEN_DINT);
+ sdhci_write32(&host->sdhci, SDHCI_INT_ENABLE, SDHCI_INT_CMD_COMPLETE |
+ SDHCI_INT_XFER_COMPLETE | SDHCI_INT_CARD_INT |
+ SDHCI_INT_TIMEOUT | SDHCI_INT_CRC | SDHCI_INT_END_BIT |
+ SDHCI_INT_INDEX | SDHCI_INT_DATA_TIMEOUT |
+ SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT | SDHCI_INT_DMA);
/* Put the PROCTL reg back to the default */
- esdhc_write32(host, SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL,
+ sdhci_write32(&host->sdhci, SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL,
PROCTL_INIT);
/* Set timout to the maximum value */
@@ -673,7 +288,9 @@ static int fsl_esdhc_probe(struct device_d *dev)
}
host->regs = IOMEM(iores->start);
- caps = esdhc_read32(host, SDHCI_CAPABILITIES);
+ esdhc_populate_sdhci(host);
+
+ caps = sdhci_read32(&host->sdhci, SDHCI_CAPABILITIES);
if (caps & ESDHC_HOSTCAPBLT_VS18)
mci->voltages |= MMC_VDD_165_195;
@@ -697,7 +314,7 @@ static int fsl_esdhc_probe(struct device_d *dev)
host->mci.card_present = esdhc_card_present;
host->mci.hw_dev = dev;
- dev->detect = fsl_esdhc_detect,
+ dev->detect = fsl_esdhc_detect;
rate = clk_get_rate(host->clk);
host->mci.f_min = rate >> 12;
diff --git a/drivers/mci/imx-esdhc.h b/drivers/mci/imx-esdhc.h
index 2d54719..4bf890e 100644
--- a/drivers/mci/imx-esdhc.h
+++ b/drivers/mci/imx-esdhc.h
@@ -22,6 +22,7 @@
#ifndef __FSL_ESDHC_H__
#define __FSL_ESDHC_H__
+#include <dma.h>
#include <errno.h>
#include <asm/byteorder.h>
#include <linux/bitfield.h>
@@ -35,8 +36,8 @@
#define SYSCTL_HCKEN 0x00000002
#define SYSCTL_IPGEN 0x00000001
-#define CMD_ERR (IRQSTAT_CIE | IRQSTAT_CEBE | IRQSTAT_CCE)
-#define DATA_ERR (IRQSTAT_DEBE | IRQSTAT_DCE | IRQSTAT_DTOE)
+#define CMD_ERR (SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC)
+#define DATA_ERR (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT)
#define PROCTL_INIT 0x00000020
#define PROCTL_DTW_4 0x00000002
@@ -69,9 +70,106 @@
#define ESDHC_DMA_SYSCTL 0x40c /* Layerscape specific */
#define ESDHC_SYSCTL_DMA_SNOOP BIT(6)
-struct fsl_esdhc_cfg {
- u32 esdhc_base;
- u32 no_snoop;
+
+/*
+ * The CMDTYPE of the CMD register (offset 0xE) should be set to
+ * "11" when the STOP CMD12 is issued on imx53 to abort one
+ * open ended multi-blk IO. Otherwise the TC INT wouldn't
+ * be generated.
+ * In exact block transfer, the controller doesn't complete the
+ * operations automatically as required at the end of the
+ * transfer and remains on hold if the abort command is not sent.
+ * As a result, the TC flag is not asserted and SW received timeout
+ * exeception. Bit1 of Vendor Spec registor is used to fix it.
+ */
+#define ESDHC_FLAG_MULTIBLK_NO_INT BIT(1)
+/*
+ * The flag enables the workaround for ESDHC errata ENGcm07207 which
+ * affects i.MX25 and i.MX35.
+ */
+#define ESDHC_FLAG_ENGCM07207 BIT(2)
+/*
+ * The flag tells that the ESDHC controller is an USDHC block that is
+ * integrated on the i.MX6 series.
+ */
+#define ESDHC_FLAG_USDHC BIT(3)
+/* The IP supports manual tuning process */
+#define ESDHC_FLAG_MAN_TUNING BIT(4)
+/* The IP supports standard tuning process */
+#define ESDHC_FLAG_STD_TUNING BIT(5)
+/* The IP has SDHCI_CAPABILITIES_1 register */
+#define ESDHC_FLAG_HAVE_CAP1 BIT(6)
+
+/*
+ * The IP has errata ERR004536
+ * uSDHC: ADMA Length Mismatch Error occurs if the AHB read access is slow,
+ * when reading data from the card
+ */
+#define ESDHC_FLAG_ERR004536 BIT(7)
+/* The IP supports HS200 mode */
+#define ESDHC_FLAG_HS200 BIT(8)
+/* The IP supports HS400 mode */
+#define ESDHC_FLAG_HS400 BIT(9)
+/* Need to access registers in bigendian mode */
+#define ESDHC_FLAG_BIGENDIAN BIT(10)
+/* Enable cache snooping */
+#define ESDHC_FLAG_CACHE_SNOOPING BIT(11)
+
+struct esdhc_soc_data {
+ u32 flags;
+ const char *clkidx;
+};
+
+struct fsl_esdhc_host {
+ struct mci_host mci;
+ struct clk *clk;
+ struct device_d *dev;
+ void __iomem *regs;
+ const struct esdhc_soc_data *socdata;
+ struct sdhci sdhci;
};
+static inline int esdhc_is_usdhc(struct fsl_esdhc_host *data)
+{
+ return !!(data->socdata->flags & ESDHC_FLAG_USDHC);
+}
+
+static inline struct fsl_esdhc_host *sdhci_to_esdhc(struct sdhci *sdhci)
+{
+ return container_of(sdhci, struct fsl_esdhc_host, sdhci);
+}
+
+static inline void
+esdhc_clrsetbits32(struct fsl_esdhc_host *host, unsigned int reg,
+ u32 clear, u32 set)
+{
+ u32 val;
+
+ val = sdhci_read32(&host->sdhci, reg);
+ val &= ~clear;
+ val |= set;
+ sdhci_write32(&host->sdhci, reg, val);
+}
+
+static inline void
+esdhc_clrbits32(struct fsl_esdhc_host *host, unsigned int reg,
+ u32 clear)
+{
+ esdhc_clrsetbits32(host, reg, clear, 0);
+}
+
+static inline void
+esdhc_setbits32(struct fsl_esdhc_host *host, unsigned int reg,
+ u32 set)
+{
+ esdhc_clrsetbits32(host, reg, 0, set);
+}
+
+void esdhc_populate_sdhci(struct fsl_esdhc_host *host);
+int esdhc_poll(struct fsl_esdhc_host *host, unsigned int off,
+ unsigned int mask, unsigned int val,
+ uint64_t timeout);
+int __esdhc_send_cmd(struct fsl_esdhc_host *host, struct mci_cmd *cmd,
+ struct mci_data *data);
+
#endif /* __FSL_ESDHC_H__ */
diff --git a/drivers/mci/mci-bcm2835.c b/drivers/mci/mci-bcm2835.c
index 2ed1251..b18d681 100644
--- a/drivers/mci/mci-bcm2835.c
+++ b/drivers/mci/mci-bcm2835.c
@@ -51,10 +51,13 @@ struct bcm2835_mci_host {
u32 max_clock;
u32 version;
uint64_t last_write;
+ struct sdhci sdhci;
};
-static void bcm2835_mci_write(struct bcm2835_mci_host *host, u32 reg, u32 val)
+static void bcm2835_sdhci_write32(struct sdhci *sdhci, int reg, u32 val)
{
+ struct bcm2835_mci_host *host = container_of(sdhci, struct bcm2835_mci_host, sdhci);
+
/*
* The Arasan has a bugette whereby it may lose the content of
* successive writes to registers that are within two SD-card clock
@@ -64,95 +67,21 @@ static void bcm2835_mci_write(struct bcm2835_mci_host *host, u32 reg, u32 val)
* too)
*/
- if (host->last_write != 0)
- while ((get_time_ns() - host->last_write) < twoticks_delay)
- ;
- host->last_write = get_time_ns();
- writel(val, host->regs + reg);
-}
-
-static u32 bcm2835_mci_read(struct bcm2835_mci_host *host, u32 reg)
-{
- return readl(host->regs + reg);
-}
+ if (reg != SDHCI_BUFFER) {
+ if (host->last_write != 0)
+ while ((get_time_ns() - host->last_write) < twoticks_delay)
+ ;
+ host->last_write = get_time_ns();
+ }
-/* Create special write data function since the data
- * register is not affected by the twoticks_delay bug
- * and we can thus get better speed here
- */
-static void bcm2835_mci_write_data(struct bcm2835_mci_host *host, u32 *p)
-{
- writel(*p, host->regs + SDHCI_BUFFER);
+ writel(val, host->regs + reg);
}
-/* Make a read data functions as well just to keep structure */
-static void bcm2835_mci_read_data(struct bcm2835_mci_host *host, u32 *p)
+static u32 bcm2835_sdhci_read32(struct sdhci *sdhci, int reg)
{
- *p = readl(host->regs + SDHCI_BUFFER);
-}
+ struct bcm2835_mci_host *host = container_of(sdhci, struct bcm2835_mci_host, sdhci);
-static int bcm2835_mci_transfer_data(struct bcm2835_mci_host *host,
- struct mci_cmd *cmd, struct mci_data *data) {
- u32 *p;
- u32 data_size, status, intr_status = 0;
- u32 data_ready_intr_mask;
- u32 data_ready_status_mask;
- int i = 0;
- void (*read_write_func)(struct bcm2835_mci_host*, u32*);
-
- data_size = data->blocksize * data->blocks;
-
- if (data->flags & MMC_DATA_READ) {
- p = (u32 *) data->dest;
- data_ready_intr_mask = IRQSTAT_BRR;
- data_ready_status_mask = PRSSTAT_BREN;
- read_write_func = &bcm2835_mci_read_data;
- } else {
- p = (u32 *) data->src;
- data_ready_intr_mask = IRQSTAT_BWR;
- data_ready_status_mask = PRSSTAT_BWEN;
- read_write_func = &bcm2835_mci_write_data;
- }
- do {
- intr_status = bcm2835_mci_read(host, SDHCI_INT_STATUS);
- if (intr_status & IRQSTAT_CIE) {
- dev_err(host->hw_dev,
- "Error occured while transferring data: 0x%X\n",
- intr_status);
- return -EPERM;
- }
- if (intr_status & data_ready_intr_mask) {
- status = bcm2835_mci_read(host, SDHCI_PRESENT_STATE);
- if ((status & data_ready_status_mask) == 0)
- continue;
- /*Clear latest int and transfer one block size of data*/
- bcm2835_mci_write(host, SDHCI_INT_STATUS,
- data_ready_intr_mask);
- for (i = 0; i < data->blocksize; i += 4) {
- read_write_func(host, p);
- p++;
- data_size -= 4;
- }
- }
- } while ((intr_status & IRQSTAT_TC) == 0);
-
- if (data_size != 0) {
- if (data->flags & MMC_DATA_READ)
- dev_err(host->hw_dev, "Error while reading:\n");
- else
- dev_err(host->hw_dev, "Error while writing:\n");
-
- dev_err(host->hw_dev, "Transferred %d bytes of data, wanted %d\n",
- (data->blocksize * data->blocks) - data_size,
- data->blocksize * data->blocks);
-
- dev_err(host->hw_dev, "Status: 0x%X, Interrupt: 0x%X\n",
- bcm2835_mci_read(host, SDHCI_PRESENT_STATE),
- bcm2835_mci_read(host, SDHCI_INT_STATUS));
-
- return -EPERM;
- }
- return 0;
+ return readl(host->regs + reg);
}
static u32 bcm2835_mci_wait_command_done(struct bcm2835_mci_host *host)
@@ -160,11 +89,10 @@ static u32 bcm2835_mci_wait_command_done(struct bcm2835_mci_host *host)
u32 interrupt = 0;
while (true) {
- interrupt = bcm2835_mci_read(
- host, SDHCI_INT_STATUS);
- if (interrupt & IRQSTAT_CIE)
+ interrupt = sdhci_read32(&host->sdhci, SDHCI_INT_STATUS);
+ if (interrupt & SDHCI_INT_INDEX)
return -EPERM;
- if (interrupt & IRQSTAT_CC)
+ if (interrupt & SDHCI_INT_CMD_COMPLETE)
break;
}
return 0;
@@ -174,15 +102,15 @@ static void bcm2835_mci_reset_emmc(struct bcm2835_mci_host *host, u32 reset,
u32 wait_for)
{
u32 ret;
- u32 current = bcm2835_mci_read(host,
+ u32 current = sdhci_read32(&host->sdhci,
SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET);
- bcm2835_mci_write(host,
+ sdhci_write32(&host->sdhci,
SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET,
current | reset);
while (true) {
- ret = bcm2835_mci_read(host,
+ ret = sdhci_read32(&host->sdhci,
SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET);
if (ret & wait_for)
continue;
@@ -199,31 +127,14 @@ static void bcm2835_mci_reset_emmc(struct bcm2835_mci_host *host, u32 reset,
*/
static int bcm2835_mci_request(struct mci_host *mci, struct mci_cmd *cmd,
struct mci_data *data) {
- u32 command, block_data = 0, ret = 0;
- u32 wait_inhibit_mask = PRSSTAT_CICHB | PRSSTAT_CIDHB;
+ u32 command, block_data = 0, ret = 0, transfer_mode = 0;
+ u32 wait_inhibit_mask = SDHCI_CMD_INHIBIT_CMD | SDHCI_CMD_INHIBIT_DATA;
struct bcm2835_mci_host *host = to_bcm2835_host(mci);
- command = COMMAND_CMD(cmd->cmdidx);
-
- if (cmd->resp_type != MMC_RSP_NONE) {
- if (cmd->resp_type & MMC_RSP_136)
- command |= COMMAND_RSPTYP_136;
- else if (cmd->resp_type & MMC_RSP_BUSY)
- command |= COMMAND_RSPTYP_48_BUSY;
- else
- command |= COMMAND_RSPTYP_48;
- if (cmd->resp_type & MMC_RSP_CRC)
- command |= COMMAND_CCCEN;
- }
- if (data != NULL) {
- command |= COMMAND_DPSEL | TRANSFER_MODE_BCEN;
-
- if (data->blocks > 1)
- command |= TRANSFER_MODE_MSBSEL;
-
- if (data->flags & MMC_DATA_READ)
- command |= TRANSFER_MODE_DTDSEL;
+ sdhci_set_cmd_xfer_mode(&host->sdhci, cmd, data, false,
+ &command, &transfer_mode);
+ if (data != NULL) {
block_data = (data->blocks << BLOCK_SHIFT);
block_data |= data->blocksize;
}
@@ -231,55 +142,39 @@ static int bcm2835_mci_request(struct mci_host *mci, struct mci_cmd *cmd,
/* We shouldn't wait for data inihibit for stop commands, even
though they might use busy signaling */
if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
- wait_inhibit_mask = PRSSTAT_CICHB;
+ wait_inhibit_mask = SDHCI_CMD_INHIBIT_CMD;
/*Wait for old command*/
- while (bcm2835_mci_read(host, SDHCI_PRESENT_STATE)
+ while (sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE)
& wait_inhibit_mask)
;
- bcm2835_mci_write(host, SDHCI_INT_ENABLE, 0xFFFFFFFF);
- bcm2835_mci_write(host, SDHCI_INT_STATUS, 0xFFFFFFFF);
+ sdhci_write32(&host->sdhci, SDHCI_INT_ENABLE, 0xFFFFFFFF);
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, 0xFFFFFFFF);
- bcm2835_mci_write(host, SDHCI_BLOCK_SIZE__BLOCK_COUNT, block_data);
- bcm2835_mci_write(host, SDHCI_ARGUMENT, cmd->cmdarg);
- bcm2835_mci_write(host, SDHCI_TRANSFER_MODE__COMMAND, command);
+ sdhci_write32(&host->sdhci, SDHCI_BLOCK_SIZE__BLOCK_COUNT, block_data);
+ sdhci_write32(&host->sdhci, SDHCI_ARGUMENT, cmd->cmdarg);
+ sdhci_write32(&host->sdhci, SDHCI_TRANSFER_MODE__COMMAND,
+ command << 16 | transfer_mode);
ret = bcm2835_mci_wait_command_done(host);
if (ret) {
dev_err(host->hw_dev, "Error while executing command %d\n",
cmd->cmdidx);
dev_err(host->hw_dev, "Status: 0x%X, Interrupt: 0x%X\n",
- bcm2835_mci_read(host, SDHCI_PRESENT_STATE),
- bcm2835_mci_read(host, SDHCI_INT_STATUS));
+ sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE),
+ sdhci_read32(&host->sdhci, SDHCI_INT_STATUS));
}
if (cmd->resp_type != 0 && ret != -1) {
- int i = 0;
-
- /* CRC is stripped so we need to do some shifting. */
- if (cmd->resp_type & MMC_RSP_136) {
- for (i = 0; i < 4; i++) {
- cmd->response[i] = bcm2835_mci_read(
- host,
- SDHCI_RESPONSE_0 + (3 - i) * 4) << 8;
- if (i != 3)
- cmd->response[i] |=
- readb((u32) (host->regs) +
- SDHCI_RESPONSE_0 +
- (3 - i) * 4 - 1);
- }
- } else {
- cmd->response[0] = bcm2835_mci_read(
- host, SDHCI_RESPONSE_0);
- }
- bcm2835_mci_write(host, SDHCI_INT_STATUS,
- IRQSTAT_CC);
+ sdhci_read_response(&host->sdhci, cmd);
+
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, SDHCI_INT_CMD_COMPLETE);
}
if (!ret && data)
- ret = bcm2835_mci_transfer_data(host, cmd, data);
+ ret = sdhci_transfer_data(&host->sdhci, data);
- bcm2835_mci_write(host, SDHCI_INT_STATUS, 0xFFFFFFFF);
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, 0xFFFFFFFF);
if (ret) {
bcm2835_mci_reset_emmc(host, CONTROL1_CMDRST,
CONTROL1_CMDRST);
@@ -343,19 +238,19 @@ static void bcm2835_mci_set_ios(struct mci_host *mci, struct mci_ios *ios)
struct bcm2835_mci_host *host = to_bcm2835_host(mci);
- current_val = bcm2835_mci_read(host,
+ current_val = sdhci_read32(&host->sdhci,
SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL);
switch (ios->bus_width) {
case MMC_BUS_WIDTH_4:
- bcm2835_mci_write(host,
+ sdhci_write32(&host->sdhci,
SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL,
current_val | CONTROL0_4DATA);
host->bus_width = 1;
dev_dbg(host->hw_dev, "Changing bus width to 4\n");
break;
case MMC_BUS_WIDTH_1:
- bcm2835_mci_write(host,
+ sdhci_write32(&host->sdhci,
SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL,
current_val & ~CONTROL0_4DATA);
host->bus_width = 0;
@@ -367,15 +262,15 @@ static void bcm2835_mci_set_ios(struct mci_host *mci, struct mci_ios *ios)
return;
}
if (ios->clock != host->clock && ios->clock != 0) {
- bcm2835_mci_write(host,
+ sdhci_write32(&host->sdhci,
SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET,
0x00);
if (ios->clock > 26000000) {
- enable = bcm2835_mci_read(host,
+ enable = sdhci_read32(&host->sdhci,
SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL);
enable |= CONTROL0_HISPEED;
- bcm2835_mci_write(host,
+ sdhci_write32(&host->sdhci,
SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET,
enable);
}
@@ -388,18 +283,18 @@ static void bcm2835_mci_set_ios(struct mci_host *mci, struct mci_ios *ios)
enable |= (divider_msb << CONTROL1_CLKMSB);
enable |= CONTROL1_INTCLKENA | CONTROL1_TIMEOUT;
- bcm2835_mci_write(host,
+ sdhci_write32(&host->sdhci,
SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET,
enable);
while (true) {
- u32 ret = bcm2835_mci_read(host,
+ u32 ret = sdhci_read32(&host->sdhci,
SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET);
if (ret & CONTROL1_CLK_STABLE)
break;
}
enable |= CONTROL1_CLKENA;
- bcm2835_mci_write(host,
+ sdhci_write32(&host->sdhci,
SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET,
enable);
@@ -437,37 +332,37 @@ static int bcm2835_mci_reset(struct mci_host *mci, struct device_d *mci_dev)
bcm2835_mci_reset_emmc(host, enable | reset, CONTROL1_HOSTRST);
- bcm2835_mci_write(host,
+ sdhci_write32(&host->sdhci,
SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL,
0x00);
- bcm2835_mci_write(host, SDHCI_ACMD12_ERR__HOST_CONTROL2,
+ sdhci_write32(&host->sdhci, SDHCI_ACMD12_ERR__HOST_CONTROL2,
0x00);
- bcm2835_mci_write(host,
+ sdhci_write32(&host->sdhci,
SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET,
enable);
while (true) {
- ret = bcm2835_mci_read(host,
+ ret = sdhci_read32(&host->sdhci,
SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET);
if (ret & CONTROL1_CLK_STABLE)
break;
}
enable |= CONTROL1_CLKENA;
- bcm2835_mci_write(host,
+ sdhci_write32(&host->sdhci,
SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET,
enable);
/*Delay atelast 74 clk cycles for card init*/
mdelay(100);
- bcm2835_mci_write(host, SDHCI_INT_ENABLE,
+ sdhci_write32(&host->sdhci, SDHCI_INT_ENABLE,
0xFFFFFFFF);
- bcm2835_mci_write(host, SDHCI_INT_STATUS,
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS,
0xFFFFFFFF);
/*Now write command 0 and see if we get response*/
- bcm2835_mci_write(host, SDHCI_ARGUMENT, 0x0);
- bcm2835_mci_write(host, SDHCI_TRANSFER_MODE__COMMAND, 0x0);
+ sdhci_write32(&host->sdhci, SDHCI_ARGUMENT, 0x0);
+ sdhci_write32(&host->sdhci, SDHCI_TRANSFER_MODE__COMMAND, 0x0);
return bcm2835_mci_wait_command_done(host);
}
@@ -507,6 +402,9 @@ static int bcm2835_mci_probe(struct device_d *hw_dev)
host->hw_dev = hw_dev;
host->max_clock = clk_get_rate(clk);
+ host->sdhci.read32 = bcm2835_sdhci_read32;
+ host->sdhci.write32 = bcm2835_sdhci_write32;
+
mci_of_parse(&host->mci);
iores = dev_request_mem_resource(hw_dev, 0);
@@ -540,8 +438,7 @@ static int bcm2835_mci_probe(struct device_d *hw_dev)
twoticks_delay = ((2 * 1000000000) / MIN_FREQ) + 1;
- host->version = bcm2835_mci_read(
- host, BCM2835_MCI_SLOTISR_VER);
+ host->version = sdhci_read32(&host->sdhci, BCM2835_MCI_SLOTISR_VER);
host->version = (host->version >> 16) & 0xFF;
return mci_register(&host->mci);
}
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index 9e39cbb..67257bc 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -1819,10 +1819,6 @@ int mci_register(struct mci_host *host)
host->supply = regulator_get(host->hw_dev, "vmmc");
if (IS_ERR(host->supply)) {
- if (host->supply == ERR_PTR(-EPROBE_DEFER)) {
- ret = -EPROBE_DEFER;
- goto err_free;
- }
dev_err(&mci->dev, "Failed to get 'vmmc' regulator.\n");
host->supply = NULL;
}
diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c
new file mode 100644
index 0000000..172c834
--- /dev/null
+++ b/drivers/mci/sdhci.c
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <common.h>
+#include <driver.h>
+#include <mci.h>
+#include <io.h>
+
+#include "sdhci.h"
+
+void sdhci_read_response(struct sdhci *sdhci, struct mci_cmd *cmd)
+{
+ if (cmd->resp_type & MMC_RSP_136) {
+ u32 cmdrsp3, cmdrsp2, cmdrsp1, cmdrsp0;
+
+ cmdrsp3 = sdhci_read32(sdhci, SDHCI_RESPONSE_3);
+ cmdrsp2 = sdhci_read32(sdhci, SDHCI_RESPONSE_2);
+ cmdrsp1 = sdhci_read32(sdhci, SDHCI_RESPONSE_1);
+ cmdrsp0 = sdhci_read32(sdhci, SDHCI_RESPONSE_0);
+ cmd->response[0] = (cmdrsp3 << 8) | (cmdrsp2 >> 24);
+ cmd->response[1] = (cmdrsp2 << 8) | (cmdrsp1 >> 24);
+ cmd->response[2] = (cmdrsp1 << 8) | (cmdrsp0 >> 24);
+ cmd->response[3] = (cmdrsp0 << 8);
+ } else {
+ cmd->response[0] = sdhci_read32(sdhci, SDHCI_RESPONSE_0);
+ }
+}
+
+void sdhci_set_cmd_xfer_mode(struct sdhci *host, struct mci_cmd *cmd,
+ struct mci_data *data, bool dma, u32 *command,
+ u32 *xfer)
+{
+ *command = 0;
+ *xfer = 0;
+
+ if (!(cmd->resp_type & MMC_RSP_PRESENT))
+ *command |= SDHCI_RESP_NONE;
+ else if (cmd->resp_type & MMC_RSP_136)
+ *command |= SDHCI_RESP_TYPE_136;
+ else if (cmd->resp_type & MMC_RSP_BUSY)
+ *command |= SDHCI_RESP_TYPE_48_BUSY;
+ else
+ *command |= SDHCI_RESP_TYPE_48;
+
+ if (cmd->resp_type & MMC_RSP_CRC)
+ *command |= SDHCI_CMD_CRC_CHECK_EN;
+ if (cmd->resp_type & MMC_RSP_OPCODE)
+ *command |= SDHCI_CMD_INDEX_CHECK_EN;
+
+ *command |= SDHCI_CMD_INDEX(cmd->cmdidx);
+
+ if (data) {
+ *command |= SDHCI_DATA_PRESENT;
+
+ *xfer |= SDHCI_BLOCK_COUNT_EN;
+
+ if (data->blocks > 1)
+ *xfer |= SDHCI_MULTIPLE_BLOCKS;
+
+ if (data->flags & MMC_DATA_READ)
+ *xfer |= SDHCI_DATA_TO_HOST;
+
+ if (dma)
+ *xfer |= SDHCI_DMA_EN;
+ }
+}
+
+static void sdhci_rx_pio(struct sdhci *sdhci, struct mci_data *data,
+ unsigned int block)
+{
+ u32 *buf = (u32 *)data->dest;
+ int i;
+
+ buf += block * data->blocksize / sizeof(u32);
+
+ for (i = 0; i < data->blocksize / sizeof(u32); i++)
+ buf[i] = sdhci_read32(sdhci, SDHCI_BUFFER);
+}
+
+static void sdhci_tx_pio(struct sdhci *sdhci, struct mci_data *data,
+ unsigned int block)
+{
+ const u32 *buf = (const u32 *)data->src;
+ int i;
+
+ buf += block * data->blocksize / sizeof(u32);
+
+ for (i = 0; i < data->blocksize / sizeof(u32); i++)
+ sdhci_write32(sdhci, SDHCI_BUFFER, buf[i]);
+}
+
+#ifdef __PBL__
+/*
+ * Stubs to make timeout logic below work in PBL
+ */
+
+#define get_time_ns() 0
+/*
+ * Use time in us as a busy counter timeout value
+ */
+#define is_timeout(s, t) ((s)++ > ((t) / 1000))
+
+#endif
+
+int sdhci_transfer_data(struct sdhci *sdhci, struct mci_data *data)
+{
+ unsigned int block = 0;
+ u32 stat, prs;
+ uint64_t start = get_time_ns();
+
+ do {
+ stat = sdhci_read32(sdhci, SDHCI_INT_STATUS);
+ if (stat & SDHCI_INT_ERROR)
+ return -EIO;
+
+ if (block >= data->blocks)
+ continue;
+
+ prs = sdhci_read32(sdhci, SDHCI_PRESENT_STATE);
+
+ if (prs & SDHCI_BUFFER_READ_ENABLE &&
+ data->flags & MMC_DATA_READ) {
+ sdhci_rx_pio(sdhci, data, block);
+ block++;
+ start = get_time_ns();
+ }
+
+ if (prs & SDHCI_BUFFER_WRITE_ENABLE &&
+ !(data->flags & MMC_DATA_READ)) {
+ sdhci_tx_pio(sdhci, data, block);
+ block++;
+ start = get_time_ns();
+ }
+
+ if (is_timeout(start, 10 * SECOND))
+ return -ETIMEDOUT;
+
+ } while (!(stat & SDHCI_INT_XFER_COMPLETE));
+
+ return 0;
+}
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index 90595e6..a307dc9 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -24,6 +24,9 @@
#define SDHCI_DMA_EN BIT(0)
#define SDHCI_COMMAND 0x0e
#define SDHCI_CMD_INDEX(c) (((c) & 0x3f) << 8)
+#define SDHCI_COMMAND_CMDTYP_SUSPEND (1 << 6)
+#define SDHCI_COMMAND_CMDTYP_RESUME (2 << 6)
+#define SDHCI_COMMAND_CMDTYP_ABORT (3 << 6)
#define SDHCI_DATA_PRESENT BIT(5)
#define SDHCI_CMD_INDEX_CHECK_EN BIT(4)
#define SDHCI_CMD_CRC_CHECK_EN BIT(3)
@@ -37,11 +40,18 @@
#define SDHCI_RESPONSE_3 0x1c
#define SDHCI_BUFFER 0x20
#define SDHCI_PRESENT_STATE 0x24
+#define SDHCI_WRITE_PROTECT BIT(19)
+#define SDHCI_CARD_DETECT BIT(18)
+#define SDHCI_BUFFER_READ_ENABLE BIT(11)
+#define SDHCI_BUFFER_WRITE_ENABLE BIT(10)
+#define SDHCI_DATA_LINE_ACTIVE BIT(2)
#define SDHCI_CMD_INHIBIT_DATA BIT(1)
#define SDHCI_CMD_INHIBIT_CMD BIT(0)
#define SDHCI_PRESENT_STATE1 0x26
#define SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL 0x28
#define SDHCI_HOST_CONTROL 0x28
+#define SDHCI_CARD_DETECT_SIGNAL_SELECTION BIT(7)
+#define SDHCI_CARD_DETECT_TEST_LEVEL BIT(6)
#define SDHCI_DATA_WIDTH_8BIT BIT(5)
#define SDHCI_HIGHSPEED_EN BIT(2)
#define SDHCI_DATA_WIDTH_4BIT BIT(1)
@@ -60,7 +70,17 @@
#define SDHCI_RESET_ALL BIT(0)
#define SDHCI_INT_STATUS 0x30
#define SDHCI_INT_NORMAL_STATUS 0x30
+#define SDHCI_INT_DATA_END_BIT BIT(22)
+#define SDHCI_INT_DATA_CRC BIT(21)
+#define SDHCI_INT_DATA_TIMEOUT BIT(20)
+#define SDHCI_INT_INDEX BIT(19)
+#define SDHCI_INT_END_BIT BIT(18)
+#define SDHCI_INT_CRC BIT(17)
+#define SDHCI_INT_TIMEOUT BIT(16)
#define SDHCI_INT_ERROR BIT(15)
+#define SDHCI_INT_CARD_INT BIT(8)
+#define SDHCI_INT_DATA_AVAIL BIT(5)
+#define SDHCI_INT_SPACE_AVAIL BIT(4)
#define SDHCI_INT_DMA BIT(3)
#define SDHCI_INT_XFER_COMPLETE BIT(1)
#define SDHCI_INT_CMD_COMPLETE BIT(0)
@@ -79,74 +99,49 @@
#define SDHCI_SPEC_200_MAX_CLK_DIVIDER 256
#define SDHCI_MMC_BOOT 0xC4
-#define COMMAND_CMD(x) ((x & 0x3f) << 24)
-#define COMMAND_CMDTYP_NORMAL 0x0
-#define COMMAND_CMDTYP_SUSPEND 0x00400000
-#define COMMAND_CMDTYP_RESUME 0x00800000
-#define COMMAND_CMDTYP_ABORT 0x00c00000
-#define COMMAND_DPSEL 0x00200000
-#define COMMAND_CICEN 0x00100000
-#define COMMAND_CCCEN 0x00080000
-#define COMMAND_RSPTYP_NONE 0
-#define COMMAND_RSPTYP_136 0x00010000
-#define COMMAND_RSPTYP_48 0x00020000
-#define COMMAND_RSPTYP_48_BUSY 0x00030000
-#define TRANSFER_MODE_MSBSEL 0x00000020
-#define TRANSFER_MODE_DTDSEL 0x00000010
-#define TRANSFER_MODE_AC12EN 0x00000004
-#define TRANSFER_MODE_BCEN 0x00000002
-#define TRANSFER_MODE_DMAEN 0x00000001
+struct sdhci {
+ u32 (*read32)(struct sdhci *host, int reg);
+ u16 (*read16)(struct sdhci *host, int reg);
+ u8 (*read8)(struct sdhci *host, int reg);
+ void (*write32)(struct sdhci *host, int reg, u32 val);
+ void (*write16)(struct sdhci *host, int reg, u16 val);
+ void (*write8)(struct sdhci *host, int reg, u8 val);
+};
-#define IRQSTAT_TE 0x04000000
-#define IRQSTAT_DMAE 0x02000000
-#define IRQSTAT_AC12E 0x01000000
-#define IRQSTAT_CLE 0x00800000
-#define IRQSTAT_DEBE 0x00400000
-#define IRQSTAT_DCE 0x00200000
-#define IRQSTAT_DTOE 0x00100000
-#define IRQSTAT_CIE 0x00080000
-#define IRQSTAT_CEBE 0x00040000
-#define IRQSTAT_CCE 0x00020000
-#define IRQSTAT_CTOE 0x00010000
-#define IRQSTAT_CINT 0x00000100
-#define IRQSTAT_CRM 0x00000080
-#define IRQSTAT_CINS 0x00000040
-#define IRQSTAT_BRR 0x00000020
-#define IRQSTAT_BWR 0x00000010
-#define IRQSTAT_DINT 0x00000008
-#define IRQSTAT_BGE 0x00000004
-#define IRQSTAT_TC 0x00000002
-#define IRQSTAT_CC 0x00000001
+static inline u32 sdhci_read32(struct sdhci *host, int reg)
+{
+ return host->read32(host, reg);
+}
-#define IRQSTATEN_DMAE 0x10000000
-#define IRQSTATEN_AC12E 0x01000000
-#define IRQSTATEN_DEBE 0x00400000
-#define IRQSTATEN_DCE 0x00200000
-#define IRQSTATEN_DTOE 0x00100000
-#define IRQSTATEN_CIE 0x00080000
-#define IRQSTATEN_CEBE 0x00040000
-#define IRQSTATEN_CCE 0x00020000
-#define IRQSTATEN_CTOE 0x00010000
-#define IRQSTATEN_CINT 0x00000100
-#define IRQSTATEN_CRM 0x00000080
-#define IRQSTATEN_CINS 0x00000040
-#define IRQSTATEN_BRR 0x00000020
-#define IRQSTATEN_BWR 0x00000010
-#define IRQSTATEN_DINT 0x00000008
-#define IRQSTATEN_BGE 0x00000004
-#define IRQSTATEN_TC 0x00000002
-#define IRQSTATEN_CC 0x00000001
+static inline u32 sdhci_read16(struct sdhci *host, int reg)
+{
+ return host->read16(host, reg);
+}
-#define PRSSTAT_DAT0 0x01000000
-#define PRSSTAT_CLSL 0x00800000
-#define PRSSTAT_WPSPL 0x00080000
-#define PRSSTAT_CDPL 0x00040000
-#define PRSSTAT_CINS 0x00010000
-#define PRSSTAT_BREN 0x00000800
-#define PRSSTAT_BWEN 0x00000400
-#define PRSSTAT_SDSTB 0x00000008
-#define PRSSTAT_DLA 0x00000004
-#define PRSSTAT_CIDHB 0x00000002
-#define PRSSTAT_CICHB 0x00000001
+static inline u32 sdhci_read8(struct sdhci *host, int reg)
+{
+ return host->read8(host, reg);
+}
+
+static inline void sdhci_write32(struct sdhci *host, int reg, u32 val)
+{
+ host->write32(host, reg, val);
+}
+
+static inline void sdhci_write16(struct sdhci *host, int reg, u32 val)
+{
+ host->write16(host, reg, val);
+}
+
+static inline void sdhci_write8(struct sdhci *host, int reg, u32 val)
+{
+ host->write8(host, reg, val);
+}
+
+void sdhci_read_response(struct sdhci *host, struct mci_cmd *cmd);
+void sdhci_set_cmd_xfer_mode(struct sdhci *host, struct mci_cmd *cmd,
+ struct mci_data *data, bool dma, u32 *command,
+ u32 *xfer);
+int sdhci_transfer_data(struct sdhci *sdhci, struct mci_data *data);
#endif /* __MCI_SDHCI_H */
diff --git a/drivers/mci/tegra-sdmmc.c b/drivers/mci/tegra-sdmmc.c
index 4c47918..1cc75dc 100644
--- a/drivers/mci/tegra-sdmmc.c
+++ b/drivers/mci/tegra-sdmmc.c
@@ -74,9 +74,24 @@ struct tegra_sdmmc_host {
struct clk *clk;
struct reset_control *reset;
int gpio_cd, gpio_pwr;
+ struct sdhci sdhci;
};
#define to_tegra_sdmmc_host(mci) container_of(mci, struct tegra_sdmmc_host, mci)
+static u32 tegra_sdmmc_read32(struct sdhci *sdhci, int reg)
+{
+ struct tegra_sdmmc_host *host = container_of(sdhci, struct tegra_sdmmc_host, sdhci);
+
+ return readl(host->regs + reg);
+}
+
+static void tegra_sdmmc_write32(struct sdhci *sdhci, int reg, u32 val)
+{
+ struct tegra_sdmmc_host *host = container_of(sdhci, struct tegra_sdmmc_host, sdhci);
+
+ writel(val, host->regs + reg);
+}
+
static int tegra_sdmmc_wait_inhibit(struct tegra_sdmmc_host *host,
struct mci_cmd *cmd, struct mci_data *data,
unsigned int timeout)
@@ -91,7 +106,7 @@ static int tegra_sdmmc_wait_inhibit(struct tegra_sdmmc_host *host,
val |= TEGRA_SDMMC_PRESENT_STATE_CMD_INHIBIT_DAT;
wait_on_timeout(timeout * MSECOND,
- !(readl(host->regs + TEGRA_SDMMC_PRESENT_STATE) & val));
+ !(sdhci_read32(&host->sdhci, TEGRA_SDMMC_PRESENT_STATE) & val));
return 0;
}
@@ -101,7 +116,7 @@ static int tegra_sdmmc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
{
struct tegra_sdmmc_host *host = to_tegra_sdmmc_host(mci);
unsigned int num_bytes = 0;
- u32 val = 0;
+ u32 val = 0, command, xfer;
int ret;
ret = tegra_sdmmc_wait_inhibit(host, cmd, data, 10);
@@ -115,102 +130,66 @@ static int tegra_sdmmc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
if (data->flags & MMC_DATA_WRITE) {
dma_sync_single_for_device((unsigned long)data->src,
num_bytes, DMA_TO_DEVICE);
- writel((u32)data->src, host->regs + SDHCI_DMA_ADDRESS);
+ sdhci_write32(&host->sdhci, SDHCI_DMA_ADDRESS, (u32)data->src);
} else {
dma_sync_single_for_device((unsigned long)data->dest,
num_bytes, DMA_FROM_DEVICE);
- writel((u32)data->dest, host->regs + SDHCI_DMA_ADDRESS);
+ sdhci_write32(&host->sdhci, SDHCI_DMA_ADDRESS, (u32)data->dest);
}
- writel((7 << 12) | data->blocks << 16 | data->blocksize,
- host->regs + SDHCI_BLOCK_SIZE__BLOCK_COUNT);
+ sdhci_write32(&host->sdhci, SDHCI_BLOCK_SIZE__BLOCK_COUNT,
+ (7 << 12) | data->blocks << 16 | data->blocksize);
}
- writel(cmd->cmdarg, host->regs + SDHCI_ARGUMENT);
+ sdhci_write32(&host->sdhci, SDHCI_ARGUMENT, cmd->cmdarg);
if ((cmd->resp_type & MMC_RSP_136) && (cmd->resp_type & MMC_RSP_BUSY))
return -1;
- if (data) {
- if (data->blocks > 1)
- val |= TRANSFER_MODE_MSBSEL;
-
- if (data->flags & MMC_DATA_READ)
- val |= TRANSFER_MODE_DTDSEL;
-
- val |= TRANSFER_MODE_DMAEN | TRANSFER_MODE_BCEN;
- }
-
- if (!(cmd->resp_type & MMC_RSP_PRESENT))
- val |= COMMAND_RSPTYP_NONE;
- else if (cmd->resp_type & MMC_RSP_136)
- val |= COMMAND_RSPTYP_136;
- else if (cmd->resp_type & MMC_RSP_BUSY)
- val |= COMMAND_RSPTYP_48_BUSY;
- else
- val |= COMMAND_RSPTYP_48;
-
- if (cmd->resp_type & MMC_RSP_CRC)
- val |= COMMAND_CCCEN;
- if (cmd->resp_type & MMC_RSP_OPCODE)
- val |= COMMAND_CICEN;
+ sdhci_set_cmd_xfer_mode(&host->sdhci, cmd, data, true, &command, &xfer);
- if (data)
- val |= COMMAND_DPSEL;
-
- writel(COMMAND_CMD(cmd->cmdidx) | val,
- host->regs + SDHCI_TRANSFER_MODE__COMMAND);
+ sdhci_write32(&host->sdhci, SDHCI_TRANSFER_MODE__COMMAND,
+ command << 16 | xfer);
ret = wait_on_timeout(100 * MSECOND,
- (val = readl(host->regs + SDHCI_INT_STATUS))
- & IRQSTAT_CC);
+ (val = sdhci_read32(&host->sdhci, SDHCI_INT_STATUS))
+ & SDHCI_INT_CMD_COMPLETE);
if (ret) {
- writel(val, host->regs + SDHCI_INT_STATUS);
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, val);
return ret;
}
- if ((val & IRQSTAT_CC) && !data)
- writel(val, host->regs + SDHCI_INT_STATUS);
+ if ((val & SDHCI_INT_CMD_COMPLETE) && !data)
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, val);
if (val & TEGRA_SDMMC_INTERRUPT_STATUS_CMD_TIMEOUT) {
/* Timeout Error */
dev_dbg(mci->hw_dev, "timeout: %08x cmd %d\n", val, cmd->cmdidx);
- writel(val, host->regs + SDHCI_INT_STATUS);
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, val);
return -ETIMEDOUT;
} else if (val & TEGRA_SDMMC_INTERRUPT_STATUS_ERR_INTERRUPT) {
/* Error Interrupt */
dev_dbg(mci->hw_dev, "error: %08x cmd %d\n", val, cmd->cmdidx);
- writel(val, host->regs + SDHCI_INT_STATUS);
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, val);
return -EIO;
}
if (cmd->resp_type & MMC_RSP_PRESENT) {
- if (cmd->resp_type & MMC_RSP_136) {
- u32 cmdrsp[4];
-
- cmdrsp[3] = readl(host->regs + SDHCI_RESPONSE_3);
- cmdrsp[2] = readl(host->regs + SDHCI_RESPONSE_2);
- cmdrsp[1] = readl(host->regs + SDHCI_RESPONSE_1);
- cmdrsp[0] = readl(host->regs + SDHCI_RESPONSE_0);
- cmd->response[0] = (cmdrsp[3] << 8) | (cmdrsp[2] >> 24);
- cmd->response[1] = (cmdrsp[2] << 8) | (cmdrsp[1] >> 24);
- cmd->response[2] = (cmdrsp[1] << 8) | (cmdrsp[0] >> 24);
- cmd->response[3] = (cmdrsp[0] << 8);
- } else if (cmd->resp_type & MMC_RSP_BUSY) {
+ sdhci_read_response(&host->sdhci, cmd);
+
+ if (cmd->resp_type & MMC_RSP_BUSY) {
ret = wait_on_timeout(100 * MSECOND,
- readl(host->regs + TEGRA_SDMMC_PRESENT_STATE)
+ sdhci_read32(&host->sdhci, TEGRA_SDMMC_PRESENT_STATE)
& (1 << 20));
if (ret) {
dev_err(mci->hw_dev, "card is still busy\n");
- writel(val, host->regs + SDHCI_INT_STATUS);
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, val);
return ret;
}
- cmd->response[0] = readl(host->regs + SDHCI_RESPONSE_0);
- } else {
- cmd->response[0] = readl(host->regs + SDHCI_RESPONSE_0);
+ cmd->response[0] = sdhci_read32(&host->sdhci, SDHCI_RESPONSE_0);
}
}
@@ -218,15 +197,15 @@ static int tegra_sdmmc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
uint64_t start = get_time_ns();
while (1) {
- val = readl(host->regs + SDHCI_INT_STATUS);
+ val = sdhci_read32(&host->sdhci, SDHCI_INT_STATUS);
if (val & TEGRA_SDMMC_INTERRUPT_STATUS_ERR_INTERRUPT) {
/* Error Interrupt */
- writel(val, host->regs + SDHCI_INT_STATUS);
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, val);
dev_err(mci->hw_dev,
"error during transfer: 0x%08x\n", val);
return -EIO;
- } else if (val & IRQSTAT_DINT) {
+ } else if (val & SDHCI_INT_DMA) {
/*
* DMA Interrupt, restart the transfer where
* it was interrupted.
@@ -234,27 +213,26 @@ static int tegra_sdmmc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
u32 address = readl(host->regs +
SDHCI_DMA_ADDRESS);
- writel(IRQSTAT_DINT,
- host->regs + SDHCI_INT_STATUS);
- writel(address, host->regs + SDHCI_DMA_ADDRESS);
- } else if (val & IRQSTAT_TC) {
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, SDHCI_INT_DMA);
+ sdhci_write32(&host->sdhci, SDHCI_DMA_ADDRESS, address);
+ } else if (val & SDHCI_INT_XFER_COMPLETE) {
/* Transfer Complete */;
break;
} else if (is_timeout(start, 2 * SECOND)) {
- writel(val, host->regs + SDHCI_INT_STATUS);
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, val);
dev_err(mci->hw_dev, "MMC Timeout\n"
" Interrupt status 0x%08x\n"
" Interrupt status enable 0x%08x\n"
" Interrupt signal enable 0x%08x\n"
" Present status 0x%08x\n",
val,
- readl(host->regs + SDHCI_INT_ENABLE),
- readl(host->regs + SDHCI_SIGNAL_ENABLE),
- readl(host->regs + SDHCI_PRESENT_STATE));
+ sdhci_read32(&host->sdhci, SDHCI_INT_ENABLE),
+ sdhci_read32(&host->sdhci, SDHCI_SIGNAL_ENABLE),
+ sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE));
return -ETIMEDOUT;
}
}
- writel(val, host->regs + SDHCI_INT_STATUS);
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, val);
if (data->flags & MMC_DATA_WRITE)
dma_sync_single_for_cpu((unsigned long)data->src,
@@ -277,25 +255,25 @@ static void tegra_sdmmc_set_clock(struct tegra_sdmmc_host *host, u32 clock)
}
/* clear clock related bits */
- val = readl(host->regs + TEGRA_SDMMC_CLK_CNTL);
+ val = sdhci_read32(&host->sdhci, TEGRA_SDMMC_CLK_CNTL);
val &= 0xffff0000;
- writel(val, host->regs + TEGRA_SDMMC_CLK_CNTL);
+ sdhci_write32(&host->sdhci, TEGRA_SDMMC_CLK_CNTL, val);
/* set new frequency */
val |= prediv << 8;
val |= TEGRA_SDMMC_CLK_CNTL_INTERNAL_CLOCK_EN;
- writel(val, host->regs + TEGRA_SDMMC_CLK_CNTL);
+ sdhci_write32(&host->sdhci, TEGRA_SDMMC_CLK_CNTL, val);
clk_set_rate(host->clk, adjusted_clock);
/* wait for controller to settle */
wait_on_timeout(10 * MSECOND,
- !(readl(host->regs + TEGRA_SDMMC_CLK_CNTL) &
+ !(sdhci_read32(&host->sdhci, TEGRA_SDMMC_CLK_CNTL) &
TEGRA_SDMMC_CLK_INTERNAL_CLOCK_STABLE));
/* enable card clock */
val |= TEGRA_SDMMC_CLK_CNTL_SD_CLOCK_EN;
- writel(val, host->regs + TEGRA_SDMMC_CLK_CNTL);
+ sdhci_write32(&host->sdhci, TEGRA_SDMMC_CLK_CNTL, val);
}
static void tegra_sdmmc_set_ios(struct mci_host *mci, struct mci_ios *ios)
@@ -308,7 +286,7 @@ static void tegra_sdmmc_set_ios(struct mci_host *mci, struct mci_ios *ios)
tegra_sdmmc_set_clock(host, ios->clock);
/* set bus width */
- val = readl(host->regs + TEGRA_SDMMC_PWR_CNTL);
+ val = sdhci_read32(&host->sdhci, TEGRA_SDMMC_PWR_CNTL);
val &= ~(0x21);
if (ios->bus_width == MMC_BUS_WIDTH_8)
@@ -316,7 +294,7 @@ static void tegra_sdmmc_set_ios(struct mci_host *mci, struct mci_ios *ios)
else if (ios->bus_width == MMC_BUS_WIDTH_4)
val |= (1 << 1);
- writel(val, host->regs + TEGRA_SDMMC_PWR_CNTL);
+ sdhci_write32(&host->sdhci, TEGRA_SDMMC_PWR_CNTL, val);
}
static int tegra_sdmmc_init(struct mci_host *mci, struct device_d *dev)
@@ -327,8 +305,8 @@ static int tegra_sdmmc_init(struct mci_host *mci, struct device_d *dev)
int ret;
/* reset controller */
- writel(TEGRA_SDMMC_CLK_CNTL_SW_RESET_FOR_ALL,
- regs + TEGRA_SDMMC_CLK_CNTL);
+ sdhci_write32(&host->sdhci, TEGRA_SDMMC_CLK_CNTL,
+ TEGRA_SDMMC_CLK_CNTL_SW_RESET_FOR_ALL);
ret = wait_on_timeout(100 * MSECOND,
!(readl(regs + TEGRA_SDMMC_CLK_CNTL) &
@@ -342,7 +320,7 @@ static int tegra_sdmmc_init(struct mci_host *mci, struct device_d *dev)
val = readl(regs + TEGRA_SDMMC_PWR_CNTL);
val &= ~(0xff << 8);
val |= TEGRA_SDMMC_PWR_CNTL_33_V | TEGRA_SDMMC_PWR_CNTL_SD_BUS;
- writel(val, regs + TEGRA_SDMMC_PWR_CNTL);
+ sdhci_write32(&host->sdhci, TEGRA_SDMMC_PWR_CNTL, val);
/* sdmmc1 and sdmmc3 on T30 need a bit of padctrl init */
if (of_device_is_compatible(mci->hw_dev->device_node,
@@ -351,21 +329,21 @@ static int tegra_sdmmc_init(struct mci_host *mci, struct device_d *dev)
val = readl(regs + TEGRA_SDMMC_SDMEMCOMPPADCTRL);
val &= 0xfffffff0;
val |= 0x7 << TEGRA_SDMMC_SDMEMCOMPPADCTRL_VREF_SEL_SHIFT;
- writel(val, regs + TEGRA_SDMMC_SDMEMCOMPPADCTRL);
+ sdhci_write32(&host->sdhci, TEGRA_SDMMC_SDMEMCOMPPADCTRL, val);
val = readl(regs + TEGRA_SDMMC_AUTO_CAL_CONFIG);
val &= 0xffff0000;
val |= (0x62 << TEGRA_SDMMC_AUTO_CAL_CONFIG_PU_OFFSET_SHIFT) |
(0x70 << TEGRA_SDMMC_AUTO_CAL_CONFIG_PD_OFFSET_SHIFT) |
TEGRA_SDMMC_AUTO_CAL_CONFIG_ENABLE;
- writel(val, regs + TEGRA_SDMMC_AUTO_CAL_CONFIG);
+ sdhci_write32(&host->sdhci, TEGRA_SDMMC_AUTO_CAL_CONFIG, val);
}
/* setup signaling */
- writel(0xffffffff, regs + TEGRA_SDMMC_INT_STAT_EN);
- writel(0xffffffff, regs + TEGRA_SDMMC_INT_SIG_EN);
+ sdhci_write32(&host->sdhci, TEGRA_SDMMC_INT_STAT_EN, 0xffffffff);
+ sdhci_write32(&host->sdhci, TEGRA_SDMMC_INT_SIG_EN, 0xffffffff);
- writel(0xe << 16, regs + TEGRA_SDMMC_CLK_CNTL);
+ sdhci_write32(&host->sdhci, TEGRA_SDMMC_CLK_CNTL, 0xe << 16);
val = readl(regs + TEGRA_SDMMC_INT_STAT_EN);
val &= ~(0xffff);
@@ -374,12 +352,12 @@ static int tegra_sdmmc_init(struct mci_host *mci, struct device_d *dev)
TEGRA_SDMMC_INT_STAT_EN_DMA_INTERRUPT |
TEGRA_SDMMC_INT_STAT_EN_BUFFER_WRITE_READY |
TEGRA_SDMMC_INT_STAT_EN_BUFFER_READ_READY);
- writel(val, regs + TEGRA_SDMMC_INT_STAT_EN);
+ sdhci_write32(&host->sdhci, TEGRA_SDMMC_INT_STAT_EN, val);
val = readl(regs + TEGRA_SDMMC_INT_SIG_EN);
val &= ~(0xffff);
val |= TEGRA_SDMMC_INT_SIG_EN_XFER_COMPLETE;
- writel(val, regs + TEGRA_SDMMC_INT_SIG_EN);
+ sdhci_write32(&host->sdhci, TEGRA_SDMMC_INT_SIG_EN, val);
tegra_sdmmc_set_clock(host, 400000);
@@ -398,7 +376,7 @@ static int tegra_sdmmc_card_present(struct mci_host *mci)
return gpio_get_value(host->gpio_cd) ? 0 : 1;
}
- return !(readl(host->regs + SDHCI_PRESENT_STATE) & PRSSTAT_WPSPL);
+ return !(sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & SDHCI_WRITE_PROTECT);
}
static int tegra_sdmmc_detect(struct device_d *dev)
@@ -442,6 +420,9 @@ static int tegra_sdmmc_probe(struct device_d *dev)
}
host->regs = IOMEM(iores->start);
+ host->sdhci.read32 = tegra_sdmmc_read32;
+ host->sdhci.write32 = tegra_sdmmc_write32;
+
mci->hw_dev = dev;
mci->f_max = 48000000;
mci->f_min = 375000;
diff --git a/drivers/mfd/da9053.c b/drivers/mfd/da9053.c
index f4bfb68..1f32869 100644
--- a/drivers/mfd/da9053.c
+++ b/drivers/mfd/da9053.c
@@ -235,7 +235,7 @@ static void da9053_detect_reset_source(struct da9053_priv *da9053)
else
return;
- reset_source_set_device(da9053->dev, ltype);
+ reset_source_set_device(da9053->dev, type);
ret = da9053_reg_write(da9053, DA9053_FAULTLOG_REG, val);
if (ret < 0)
diff --git a/drivers/mfd/da9063.c b/drivers/mfd/da9063.c
index 0862a7e..e48c38a 100644
--- a/drivers/mfd/da9063.c
+++ b/drivers/mfd/da9063.c
@@ -401,13 +401,15 @@ static int da9063_probe(struct device_d *dev)
restart_handler_register(&priv->restart);
- priv->gpio.base = -1;
- priv->gpio.ngpio = 5;
- priv->gpio.ops = &da9063_gpio_ops;
- priv->gpio.dev = dev;
- ret = gpiochip_add(&priv->gpio);
- if (ret)
- goto on_error;
+ if (IS_ENABLED(CONFIG_GPIOLIB)) {
+ priv->gpio.base = -1;
+ priv->gpio.ngpio = 5;
+ priv->gpio.ops = &da9063_gpio_ops;
+ priv->gpio.dev = dev;
+ ret = gpiochip_add(&priv->gpio);
+ if (ret)
+ goto on_error;
+ }
if (IS_ENABLED(CONFIG_OFDEVICE) && dev->device_node)
return of_platform_populate(dev->device_node, NULL, dev);
diff --git a/drivers/mfd/stpmic1.c b/drivers/mfd/stpmic1.c
index eae6fe3..ab13ded 100644
--- a/drivers/mfd/stpmic1.c
+++ b/drivers/mfd/stpmic1.c
@@ -12,8 +12,7 @@
#include <of.h>
#include <regmap.h>
#include <xfuncs.h>
-
-#define VERSION_SR 0x6
+#include <linux/mfd/stpmic1.h>
struct stpmic1 {
struct device_d *dev;
diff --git a/drivers/mfd/superio.c b/drivers/mfd/superio.c
index 12d74b4..ab94a4f 100644
--- a/drivers/mfd/superio.c
+++ b/drivers/mfd/superio.c
@@ -24,7 +24,7 @@ struct device_d *superio_func_add(struct superio_chip *siochip, const char *name
return dev;
}
-EXPORT_SYMBOL(superio_func_add)
+EXPORT_SYMBOL(superio_func_add);
static int superio_reg_read(void *ctx, unsigned int reg, unsigned int *val)
{
@@ -95,4 +95,4 @@ void superio_chip_add(struct superio_chip *siochip)
pr_warn("registering %s regmap cdev failed: %s\n",
chipname, strerror(-ret));
}
-EXPORT_SYMBOL(superio_chip_add)
+EXPORT_SYMBOL(superio_chip_add);
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 0f736f8..87674a2 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -25,6 +25,7 @@ config DEV_MEM
config UBOOTVAR
bool "U-Boot environment storage"
+ depends on OFTREE
help
This driver exposes U-Boot environment variable storage as a
single mmap-able device, hiding various low-level details
@@ -35,4 +36,10 @@ config UBOOTVAR
While it can be used standalone, it is best when coupled
with corresponding filesystem driver.
+config ACPI_TEST
+ bool "ACPI Test driver"
+ depends on ACPI
+ help
+ This is a simple Test driver to test the ACPI bus.
+
endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index bc1c01e..4d92465 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_SRAM) += sram.o
obj-$(CONFIG_STATE_DRV) += state.o
obj-$(CONFIG_DEV_MEM) += mem.o
obj-$(CONFIG_UBOOTVAR) += ubootvar.o
+obj-$(CONFIG_ACPI_TEST) += acpi-test.o
diff --git a/drivers/misc/acpi-test.c b/drivers/misc/acpi-test.c
new file mode 100644
index 0000000..970b435
--- /dev/null
+++ b/drivers/misc/acpi-test.c
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Ahmad Fatoum
+ */
+
+#include <common.h>
+#include <init.h>
+#include <acpi.h>
+
+static const char *profiles[] = {
+ "Unspecified",
+ "Desktop",
+ "Mobile",
+ "Workstation",
+ "Enterprise Server",
+ "SOHO Server",
+ "Applicance PC",
+ "Performance Server",
+ "Tablet",
+};
+
+static int acpi_test_probe(struct device_d *dev)
+{
+ const char *profile = "reserved";
+ u8 *sdt;
+ u8 profileno;
+
+ dev_dbg(dev, "driver initializing...\n");
+
+ sdt = (u8 __force *)dev_request_mem_region_by_name(dev, "SDT");
+ if (IS_ERR(sdt)) {
+ dev_err(dev, "no SDT resource available: %s\n", strerrorp(sdt));
+ return PTR_ERR(sdt);
+ }
+
+ dev_dbg(dev, "SDT is at 0x%p\n", sdt);
+
+ profileno = sdt[45];
+
+ if (profileno < ARRAY_SIZE(profiles))
+ profile = profiles[profileno];
+
+ dev_info(dev, "PM profile is for '%s'\n", profile);
+
+ return 0;
+}
+
+static void acpi_test_remove(struct device_d *dev)
+{
+ dev_info(dev, "FADT driver removed\n");
+}
+
+static struct acpi_driver acpi_test_driver = {
+ .signature = "FACP",
+ .driver = {
+ .name = "acpi-test",
+ .probe = acpi_test_probe,
+ .remove = acpi_test_remove,
+ }
+};
+device_acpi_driver(acpi_test_driver);
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 6b7d019..00f0f75 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -407,7 +407,7 @@ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
}
/* Mark block bad in BBT */
- if (chip->bbt) {
+ if (IS_ENABLED(CONFIG_NAND_BBT) && chip->bbt) {
res = nand_markbad_bbt(mtd, ofs);
if (!ret)
ret = res;
@@ -458,7 +458,7 @@ static int nand_block_markgood_lowlevel(struct mtd_info *mtd, loff_t ofs)
}
/* Mark block good in BBT */
- if (chip->bbt) {
+ if (IS_ENABLED(CONFIG_NAND_BBT) && chip->bbt) {
ret = nand_markgood_bbt(mtd, ofs);
if (ret)
return ret;
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index b251035..038d707 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -646,6 +646,8 @@ static const struct spi_device_id spi_nor_ids[] = {
{ "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) },
{ "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) },
{ "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) },
+ { "en25qh64", INFO(0x1c7017, 0, 64 * 1024, 128,
+ SECT_4K | SPI_NOR_DUAL_READ) },
{ "en25qh128", INFO(0x1c7018, 0, 64 * 1024, 256, 0) },
{ "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) },
{ "en25s64", INFO(0x1c3817, 0, 64 * 1024, 128, 0) },
@@ -677,6 +679,8 @@ static const struct spi_device_id spi_nor_ids[] = {
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "is25lp016d", INFO(0x9d6015, 0, 64 * 1024, 32,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ { "is25lp01g", INFO(0x9d601b, 0, 64 * 1024, 2048,
+ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "is25lp080d", INFO(0x9d6014, 0, 64 * 1024, 16,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "is25lp032", INFO(0x9d6016, 0, 64 * 1024, 64,
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 62e522a..5823320 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -90,8 +90,9 @@ endif
config DRIVER_NET_DESIGNWARE_EQOS
bool "Designware Designware Ethernet QoS support"
depends on HAS_DMA
+ depends on COMMON_CLK
+ depends on OFTREE
select PHYLIB
- select OFTREE
help
This option enables support for the Synopsys
Designware Ethernet Quality-of-Service (GMAC4).
diff --git a/drivers/net/designware_eqos.c b/drivers/net/designware_eqos.c
index a49239e..da67adf 100644
--- a/drivers/net/designware_eqos.c
+++ b/drivers/net/designware_eqos.c
@@ -204,7 +204,7 @@ static int eqos_mdio_read(struct mii_bus *bus, int addr, int reg)
ret = eqos_mdio_wait_idle(eqos);
if (ret) {
- eqos_err(eqos, "MDIO not idle at entry\n");
+ dev_err(&bus->dev, "MDIO not idle at entry\n");
return ret;
}
@@ -222,7 +222,7 @@ static int eqos_mdio_read(struct mii_bus *bus, int addr, int reg)
ret = eqos_mdio_wait_idle(eqos);
if (ret) {
- eqos_err(eqos, "MDIO read didn't complete\n");
+ dev_err(&bus->dev, "MDIO read didn't complete\n");
return ret;
}
@@ -237,7 +237,7 @@ static int eqos_mdio_write(struct mii_bus *bus, int addr, int reg, u16 val)
ret = eqos_mdio_wait_idle(eqos);
if (ret) {
- eqos_err(eqos, "MDIO not idle at entry\n");
+ dev_err(&bus->dev, "MDIO not idle at entry\n");
return ret;
}
@@ -256,7 +256,7 @@ static int eqos_mdio_write(struct mii_bus *bus, int addr, int reg, u16 val)
ret = eqos_mdio_wait_idle(eqos);
if (ret) {
- eqos_err(eqos, "MDIO read didn't complete\n");
+ dev_err(&bus->dev, "MDIO read didn't complete\n");
return ret;
}
@@ -365,7 +365,7 @@ static int phy_resume(struct phy_device *phydev)
return 0;
}
-int eqos_start(struct eth_device *edev)
+static int eqos_start(struct eth_device *edev)
{
struct eqos *eqos = edev->priv;
u32 val, tx_fifo_sz, rx_fifo_sz, tqs, rqs, pbl;
@@ -611,7 +611,7 @@ int eqos_start(struct eth_device *edev)
return 0;
}
-void eqos_stop(struct eth_device *edev)
+static void eqos_stop(struct eth_device *edev)
{
struct eqos *eqos = edev->priv;
int i;
@@ -841,10 +841,10 @@ int eqos_probe(struct device_d *dev, const struct eqos_ops *ops, void *priv)
dev->priv = edev->priv = eqos;
edev->parent = dev;
- edev->open = ops->start;
+ edev->open = eqos_start;
edev->send = eqos_send;
edev->recv = eqos_recv;
- edev->halt = ops->stop;
+ edev->halt = eqos_stop;
edev->get_ethaddr = ops->get_ethaddr;
edev->set_ethaddr = ops->set_ethaddr;
@@ -869,6 +869,8 @@ void eqos_remove(struct device_d *dev)
{
struct eqos *eqos = dev->priv;
+ eth_unregister(&eqos->netdev);
+
mdiobus_unregister(&eqos->miibus);
dma_free(phys_to_virt(eqos->rx_descs[0].des0));
diff --git a/drivers/net/designware_eqos.h b/drivers/net/designware_eqos.h
index 969a524..f794195 100644
--- a/drivers/net/designware_eqos.h
+++ b/drivers/net/designware_eqos.h
@@ -11,8 +11,6 @@ struct eth_device;
struct eqos_ops {
int (*init)(struct device_d *dev, struct eqos *priv);
- int (*start)(struct eth_device *edev);
- void (*stop)(struct eth_device *edev);
int (*get_ethaddr)(struct eth_device *dev, unsigned char *mac);
int (*set_ethaddr)(struct eth_device *edev, const unsigned char *mac);
void (*adjust_link)(struct eth_device *edev);
@@ -73,8 +71,6 @@ int eqos_reset(struct eqos *priv);
int eqos_get_ethaddr(struct eth_device *edev, unsigned char *mac);
int eqos_set_ethaddr(struct eth_device *edev, const unsigned char *mac);
-int eqos_start(struct eth_device *edev);
-void eqos_stop(struct eth_device *edev);
void eqos_adjust_link(struct eth_device *edev);
#define eqos_dbg(eqos, ...) dev_dbg(&eqos->netdev.dev, __VA_ARGS__)
diff --git a/drivers/net/designware_stm32.c b/drivers/net/designware_stm32.c
index 5b087ad..4c682a5 100644
--- a/drivers/net/designware_stm32.c
+++ b/drivers/net/designware_stm32.c
@@ -164,16 +164,6 @@ static int eqos_init_stm32(struct device_d *dev, struct eqos *eqos)
dev_dbg(dev, "No phy clock provided. Continuing without.\n");
}
- return 0;
-
-}
-
-static int eqos_start_stm32(struct eth_device *edev)
-{
- struct eqos *eqos = edev->priv;
- struct eqos_stm32 *priv = to_stm32(eqos);
- int ret;
-
ret = clk_bulk_enable(priv->num_clks, priv->clks);
if (ret < 0) {
eqos_err(eqos, "clk_bulk_enable() failed: %s\n",
@@ -181,34 +171,13 @@ static int eqos_start_stm32(struct eth_device *edev)
return ret;
}
- udelay(10);
-
- ret = eqos_start(edev);
- if (ret)
- goto err_stop_clks;
-
return 0;
-
-err_stop_clks:
- clk_bulk_disable(priv->num_clks, priv->clks);
-
- return ret;
-}
-
-static void eqos_stop_stm32(struct eth_device *edev)
-{
- struct eqos_stm32 *priv = to_stm32(edev->priv);
-
- clk_bulk_disable(priv->num_clks, priv->clks);
}
-// todo split!
static struct eqos_ops stm32_ops = {
.init = eqos_init_stm32,
.get_ethaddr = eqos_get_ethaddr,
.set_ethaddr = eqos_set_ethaddr,
- .start = eqos_start_stm32,
- .stop = eqos_stop_stm32,
.adjust_link = eqos_adjust_link,
.get_csr_clk_rate = eqos_get_csr_clk_rate_stm32,
@@ -228,6 +197,7 @@ static void eqos_remove_stm32(struct device_d *dev)
eqos_remove(dev);
+ clk_bulk_disable(priv->num_clks, priv->clks);
clk_bulk_put(priv->num_clks, priv->clks);
}
diff --git a/drivers/net/designware_tegra186.c b/drivers/net/designware_tegra186.c
index 58484d4..20521db 100644
--- a/drivers/net/designware_tegra186.c
+++ b/drivers/net/designware_tegra186.c
@@ -230,29 +230,16 @@ static int eqos_init_tegra186(struct device_d *dev, struct eqos *eqos)
priv->clks = xmemdup(tegra186_clks, sizeof(tegra186_clks));
priv->num_clks = ARRAY_SIZE(tegra186_clks);
- return 0;
-
-release_res:
- reset_control_put(priv->rst);
- return ret;
-}
-
-static int eqos_start_tegra186(struct eth_device *edev)
-{
- struct eqos *eqos = edev->priv;
- struct eqos_tegra186 *priv = to_tegra186(eqos);
- int ret;
-
ret = clk_bulk_enable(priv->num_clks, priv->clks);
if (ret < 0) {
eqos_err(eqos, "clk_bulk_enable() failed: %s\n", strerror(-ret));
- return ret;
+ goto release_res;
}
ret = eqos_clks_set_rate_tegra186(priv);
if (ret < 0) {
eqos_err(eqos, "clks_set_rate() failed: %s\n", strerror(-ret));
- goto err;
+ goto err_stop_clks;
}
eqos_reset_tegra186(priv, false);
@@ -261,30 +248,14 @@ static int eqos_start_tegra186(struct eth_device *edev)
goto err_stop_clks;
}
- udelay(10);
-
- ret = eqos_start(edev);
- if (ret)
- goto err_stop_resets;
-
return 0;
-err_stop_resets:
- eqos_reset_tegra186(priv, true);
err_stop_clks:
clk_bulk_disable(priv->num_clks, priv->clks);
-err:
- return ret;
-}
-
-
-static void eqos_stop_tegra186(struct eth_device *edev)
-{
- struct eqos_tegra186 *priv = to_tegra186(edev->priv);
-
- eqos_reset_tegra186(priv, true);
+release_res:
+ reset_control_put(priv->rst);
- clk_bulk_disable(priv->num_clks, priv->clks);
+ return ret;
}
static void eqos_adjust_link_tegra186(struct eth_device *edev)
@@ -306,8 +277,6 @@ static const struct eqos_ops tegra186_ops = {
.init = eqos_init_tegra186,
.get_ethaddr = eqos_get_ethaddr,
.set_ethaddr = eqos_set_ethaddr_tegra186,
- .start = eqos_start_tegra186,
- .stop = eqos_stop_tegra186,
.adjust_link = eqos_adjust_link_tegra186,
.get_csr_clk_rate = eqos_get_csr_clk_rate_tegra186,
@@ -327,6 +296,10 @@ static void eqos_remove_tegra186(struct device_d *dev)
eqos_remove(dev);
+ eqos_reset_tegra186(priv, true);
+
+ clk_bulk_disable(priv->num_clks, priv->clks);
+
clk_bulk_put(priv->num_clks, priv->clks);
gpio_free(priv->phy_reset_gpio);
diff --git a/drivers/net/fsl-fman.c b/drivers/net/fsl-fman.c
index 4e6bb2e..1aae58e 100644
--- a/drivers/net/fsl-fman.c
+++ b/drivers/net/fsl-fman.c
@@ -104,11 +104,11 @@ struct fm_eth {
struct device_d *dev;
struct fm_port_global_pram *rx_pram; /* Rx parameter table */
struct fm_port_global_pram *tx_pram; /* Tx parameter table */
- void *rx_bd_ring; /* Rx BD ring base */
- void *cur_rxbd; /* current Rx BD */
+ struct fm_port_bd *rx_bd_ring; /* Rx BD ring base */
+ int cur_rxbd_idx; /* current Rx BD index */
void *rx_buf; /* Rx buffer base */
- void *tx_bd_ring; /* Tx BD ring base */
- void *cur_txbd; /* current Tx BD */
+ struct fm_port_bd *tx_bd_ring; /* Tx BD ring base */
+ int cur_txbd_idx; /* current Tx BD index */
struct memac *regs;
};
@@ -628,12 +628,13 @@ static int fm_eth_rx_port_parameter_init(struct fm_eth *fm_eth)
/* save them to fm_eth */
fm_eth->rx_bd_ring = rx_bd_ring_base;
- fm_eth->cur_rxbd = rx_bd_ring_base;
+ fm_eth->cur_rxbd_idx = 0;
fm_eth->rx_buf = rx_buf_pool;
/* init Rx BDs ring */
- rxbd = rx_bd_ring_base;
for (i = 0; i < RX_BD_RING_SIZE; i++) {
+ rxbd = &fm_eth->rx_bd_ring[i];
+
muram_writew(&rxbd->status, RxBD_EMPTY);
muram_writew(&rxbd->len, 0);
buf_hi = upper_32_bits(virt_to_phys(rx_buf_pool +
@@ -644,7 +645,6 @@ static int fm_eth_rx_port_parameter_init(struct fm_eth *fm_eth)
MAX_RXBUF_LEN, DMA_FROM_DEVICE);
muram_writew(&rxbd->buf_ptr_hi, (u16)buf_hi);
out_be32(&rxbd->buf_ptr_lo, buf_lo);
- rxbd++;
}
/* set the Rx queue descriptor */
@@ -702,16 +702,16 @@ static int fm_eth_tx_port_parameter_init(struct fm_eth *fm_eth)
* TX_BD_RING_SIZE);
/* save it to fm_eth */
fm_eth->tx_bd_ring = tx_bd_ring_base;
- fm_eth->cur_txbd = tx_bd_ring_base;
+ fm_eth->cur_txbd_idx = 0;
/* init Tx BDs ring */
- txbd = tx_bd_ring_base;
for (i = 0; i < TX_BD_RING_SIZE; i++) {
+ txbd = &fm_eth->tx_bd_ring[i];
+
muram_writew(&txbd->status, TxBD_LAST);
muram_writew(&txbd->len, 0);
muram_writew(&txbd->buf_ptr_hi, 0);
out_be32(&txbd->buf_ptr_lo, 0);
- txbd++;
}
/* set the Tx queue decriptor */
@@ -834,13 +834,12 @@ static int fm_eth_send(struct eth_device *edev, void *buf, int len)
{
struct fm_eth *fm_eth = to_fm_eth(edev);
struct fm_port_global_pram *pram;
- struct fm_port_bd *txbd, *txbd_base;
- u16 offset_in;
- int i;
+ struct fm_port_bd *txbd;
+ int i, ret;
dma_addr_t dma;
pram = fm_eth->tx_pram;
- txbd = fm_eth->cur_txbd;
+ txbd = &fm_eth->tx_bd_ring[fm_eth->cur_txbd_idx];
/* find one empty TxBD */
for (i = 0; muram_readw(&txbd->status) & TxBD_READY; i++) {
@@ -862,41 +861,35 @@ static int fm_eth_send(struct eth_device *edev, void *buf, int len)
muram_writew(&txbd->len, len);
muram_writew(&txbd->status, TxBD_READY | TxBD_LAST);
+ /* advance the TxBD */
+ fm_eth->cur_txbd_idx = (fm_eth->cur_txbd_idx + 1) % TX_BD_RING_SIZE;
+
/* update TxQD, let RISC to send the packet */
- offset_in = muram_readw(&pram->txqd.offset_in);
- offset_in += sizeof(struct fm_port_bd);
- if (offset_in >= muram_readw(&pram->txqd.bd_ring_size))
- offset_in = 0;
- muram_writew(&pram->txqd.offset_in, offset_in);
+ muram_writew(&pram->txqd.offset_in,
+ fm_eth->cur_txbd_idx * sizeof(struct fm_port_bd));
/* wait for buffer to be transmitted */
+ ret = 0;
for (i = 0; muram_readw(&txbd->status) & TxBD_READY; i++) {
udelay(10);
if (i > 0x10000) {
dev_err(&edev->dev, "Tx error, txbd->status = 0x%x\n",
muram_readw(&txbd->status));
- return -EIO;
+ ret = -EIO;
+ break;
}
}
dma_unmap_single(fm_eth->dev, dma, len, DMA_TO_DEVICE);
- /* advance the TxBD */
- txbd++;
- txbd_base = fm_eth->tx_bd_ring;
- if (txbd >= (txbd_base + TX_BD_RING_SIZE))
- txbd = txbd_base;
- /* update current txbd */
- fm_eth->cur_txbd = (void *)txbd;
-
- return 0;
+ return ret;
}
static int fm_eth_recv(struct eth_device *edev)
{
struct fm_eth *fm_eth = to_fm_eth(edev);
struct fm_port_global_pram *pram;
- struct fm_port_bd *rxbd, *rxbd_base;
+ struct fm_port_bd *rxbd;
u16 status, len;
u32 buf_lo, buf_hi;
u8 *data;
@@ -904,10 +897,14 @@ static int fm_eth_recv(struct eth_device *edev)
int ret = 1;
pram = fm_eth->rx_pram;
- rxbd = fm_eth->cur_rxbd;
- status = muram_readw(&rxbd->status);
- while (!(status & RxBD_EMPTY)) {
+ while (1) {
+ rxbd = &fm_eth->rx_bd_ring[fm_eth->cur_rxbd_idx];
+
+ status = muram_readw(&rxbd->status);
+ if (status & RxBD_EMPTY)
+ break;
+
if (!(status & RxBD_ERROR)) {
buf_hi = muram_readw(&rxbd->buf_ptr_hi);
buf_lo = in_be32(&rxbd->buf_ptr_lo);
@@ -933,12 +930,7 @@ static int fm_eth_recv(struct eth_device *edev)
muram_writew(&rxbd->len, 0);
/* advance RxBD */
- rxbd++;
- rxbd_base = fm_eth->rx_bd_ring;
- if (rxbd >= (rxbd_base + RX_BD_RING_SIZE))
- rxbd = rxbd_base;
- /* read next status */
- status = muram_readw(&rxbd->status);
+ fm_eth->cur_rxbd_idx = (fm_eth->cur_rxbd_idx + 1) % RX_BD_RING_SIZE;
/* update RxQD */
offset_out = muram_readw(&pram->rxqd.offset_out);
@@ -947,7 +939,6 @@ static int fm_eth_recv(struct eth_device *edev)
offset_out = 0;
muram_writew(&pram->rxqd.offset_out, offset_out);
}
- fm_eth->cur_rxbd = rxbd;
return ret;
}
@@ -1175,6 +1166,8 @@ static int fsl_fman_memac_probe(struct device_d *dev)
/* alloc the FMan ethernet private struct */
fm_eth = xzalloc(sizeof(*fm_eth));
+ dev->priv = fm_eth;
+
fm_eth->dev = dev;
ret = fsl_fman_memac_port_bind(fm_eth, FMAN_PORT_TYPE_TX);
@@ -1216,6 +1209,13 @@ static int fsl_fman_memac_probe(struct device_d *dev)
return 0;
}
+static void fsl_fman_memac_remove(struct device_d *dev)
+{
+ struct fm_eth *fm_eth = dev->priv;
+
+ fm_eth_halt(&fm_eth->edev);
+}
+
static int fsl_fman_muram_probe(struct device_d *dev)
{
struct resource *iores;
@@ -1274,6 +1274,7 @@ static struct of_device_id fsl_fman_memac_dt_ids[] = {
static struct driver_d fman_memac_driver = {
.name = "fsl-fman-memac",
.probe = fsl_fman_memac_probe,
+ .remove = fsl_fman_memac_remove,
.of_compatible = DRV_OF_COMPAT(fsl_fman_memac_dt_ids),
};
@@ -1303,6 +1304,7 @@ static int fsl_fman_probe(struct device_d *dev)
return PTR_ERR(iores);
reg = IOMEM(iores->start);
+ dev->priv = reg;
ret = of_platform_populate(dev->device_node, NULL, dev);
if (ret)
@@ -1320,6 +1322,13 @@ static int fsl_fman_probe(struct device_d *dev)
return 0;
}
+static void fsl_fman_remove(struct device_d *dev)
+{
+ struct ccsr_fman *reg = dev->priv;
+
+ setbits_be32(&reg->fm_fpm.fmrstc, FMFP_RSTC_RFM);
+}
+
static struct of_device_id fsl_fman_dt_ids[] = {
{
.compatible = "fsl,fman",
@@ -1330,6 +1339,45 @@ static struct of_device_id fsl_fman_dt_ids[] = {
static struct driver_d fman_driver = {
.name = "fsl-fman",
.probe = fsl_fman_probe,
+ .remove = fsl_fman_remove,
.of_compatible = DRV_OF_COMPAT(fsl_fman_dt_ids),
};
device_platform_driver(fman_driver);
+
+static int fman_of_fixup(struct device_node *root, void *context)
+{
+ struct device_node *fman, *fman_bb;
+ struct device_node *child, *child_bb;
+
+ fman_bb = of_find_compatible_node(NULL, NULL, "fsl,fman");
+ fman = of_find_compatible_node(root, NULL, "fsl,fman");
+
+ /*
+ * The dts files in the Linux tree have all network interfaces
+ * enabled. Disable the ones that are disabled under barebox
+ * as well.
+ */
+ for_each_child_of_node(fman, child) {
+ if (!of_device_is_compatible(child, "fsl,fman-memac"))
+ continue;
+
+ child_bb = of_get_child_by_name(fman_bb, child->name);
+ if (!child_bb)
+ continue;
+
+ if (of_device_is_available(child_bb))
+ of_device_enable(child);
+ else
+ of_device_disable(child);
+ }
+
+ return 0;
+}
+
+static int fman_register_of_fixup(void)
+{
+ of_register_fixup(fman_of_fixup, NULL);
+
+ return 0;
+}
+late_initcall(fman_register_of_fixup);
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index d2c2b6f..257679f 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -20,7 +20,7 @@ int nvme_submit_sync_cmd(struct nvme_ctrl *ctrl,
return __nvme_submit_sync_cmd(ctrl, cmd, NULL, buffer, bufflen, 0,
NVME_QID_ADMIN);
}
-EXPORT_SYMBOL_GPL(nvme_sec_submit);
+EXPORT_SYMBOL_GPL(nvme_submit_sync_cmd);
static int nvme_identify_ctrl(struct nvme_ctrl *dev, struct nvme_id_ctrl **id)
{
diff --git a/drivers/nvmem/bsec.c b/drivers/nvmem/bsec.c
index 8235d46..d772d0b 100644
--- a/drivers/nvmem/bsec.c
+++ b/drivers/nvmem/bsec.c
@@ -57,7 +57,7 @@ static int bsec_smc(struct bsec_priv *priv, u8 op, enum bsec_field field,
return -ENXIO;
}
-static int st32_bsec_read_shadow(void *ctx, unsigned reg, unsigned *val)
+static int stm32_bsec_read_shadow(void *ctx, unsigned reg, unsigned *val)
{
return bsec_smc(ctx, BSEC_SMC_READ_SHADOW, reg, 0, val);
}
@@ -69,7 +69,7 @@ static int stm32_bsec_reg_write_shadow(void *ctx, unsigned reg, unsigned val)
static struct regmap_bus stm32_bsec_regmap_bus = {
.reg_write = stm32_bsec_reg_write_shadow,
- .reg_read = st32_bsec_read_shadow,
+ .reg_read = stm32_bsec_read_shadow,
};
static int stm32_bsec_write(struct device_d *dev, int offset,
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 4e12522..007c5fd 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -74,7 +74,7 @@ static u64 of_bus_default_map(__be32 *addr, const __be32 *range,
s = of_read_number(range + na + pna, ns);
da = of_read_number(addr, na);
- pr_debug("OF: default map, cp=%llx, s=%llx, da=%llx\n",
+ pr_vdebug("OF: default map, cp=%llx, s=%llx, da=%llx\n",
(unsigned long long)cp, (unsigned long long)s,
(unsigned long long)da);
@@ -164,7 +164,7 @@ static u64 of_bus_pci_map(__be32 *addr, const __be32 *range, int na, int ns,
s = of_read_number(range + na + pna, ns);
da = of_read_number(addr + 1, na - 1);
- pr_debug("OF: PCI map, cp=%llx, s=%llx, da=%llx\n",
+ pr_vdebug("OF: PCI map, cp=%llx, s=%llx, da=%llx\n",
(unsigned long long)cp, (unsigned long long)s,
(unsigned long long)da);
@@ -314,18 +314,18 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
ranges = of_get_property(parent, rprop, &rlen);
#if !defined(CONFIG_PPC)
if (ranges == NULL) {
- pr_debug("OF: no ranges; cannot translate\n");
+ pr_vdebug("OF: no ranges; cannot translate\n");
return 1;
}
#endif /* !defined(CONFIG_PPC) */
if (ranges == NULL || rlen == 0) {
offset = of_read_number(addr, na);
memset(addr, 0, pna * 4);
- pr_debug("OF: empty ranges; 1:1 translation\n");
+ pr_vdebug("OF: empty ranges; 1:1 translation\n");
goto finish;
}
- pr_debug("OF: walking ranges...\n");
+ pr_vdebug("OF: walking ranges...\n");
/* Now walk through the ranges */
rlen /= 4;
@@ -336,14 +336,14 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
break;
}
if (offset == OF_BAD_ADDR) {
- pr_debug("OF: not found !\n");
+ pr_vdebug("OF: not found !\n");
return 1;
}
memcpy(addr, ranges + na, 4 * pna);
finish:
of_dump_addr("OF: parent translation for:", addr, pna);
- pr_debug("OF: with offset: %llx\n", (unsigned long long)offset);
+ pr_vdebug("OF: with offset: %llx\n", (unsigned long long)offset);
/* Translate it into parent bus space */
return pbus->translate(addr, offset, pna);
@@ -368,7 +368,7 @@ static u64 __of_translate_address(struct device_node *dev,
int na, ns, pna, pns;
u64 result = OF_BAD_ADDR;
- pr_debug("OF: ** translation for device %s **\n", dev->full_name);
+ pr_vdebug("OF: ** translation for device %s **\n", dev->full_name);
/* Get parent & match bus type */
parent = of_get_parent(dev);
@@ -379,13 +379,13 @@ static u64 __of_translate_address(struct device_node *dev,
/* Count address cells & copy address locally */
bus->count_cells(dev, &na, &ns);
if (!OF_CHECK_COUNTS(na, ns)) {
- pr_debug("prom_parse: Bad cell count for %s\n",
+ pr_vdebug("prom_parse: Bad cell count for %s\n",
dev->full_name);
return OF_BAD_ADDR;
}
memcpy(addr, in_addr, na * 4);
- pr_debug("OF: bus is %s (na=%d, ns=%d) on %s\n",
+ pr_vdebug("OF: bus is %s (na=%d, ns=%d) on %s\n",
bus->name, na, ns, parent->full_name);
of_dump_addr("OF: translating address:", addr, na);
@@ -397,7 +397,7 @@ static u64 __of_translate_address(struct device_node *dev,
/* If root, we have finished */
if (parent == NULL) {
- pr_debug("OF: reached root node\n");
+ pr_vdebug("OF: reached root node\n");
result = of_read_number(addr, na);
break;
}
@@ -411,7 +411,7 @@ static u64 __of_translate_address(struct device_node *dev,
break;
}
- pr_debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
+ pr_vdebug("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
pbus->name, pna, pns, parent->full_name);
/* Apply bus translation */
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 98ef5fc..80ceeab 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -887,54 +887,6 @@ int of_property_read_string(struct device_node *np, const char *propname,
EXPORT_SYMBOL_GPL(of_property_read_string);
/**
- * of_property_read_string_index - Find and read a string from a multiple
- * strings property.
- * @np: device node from which the property value is to be read.
- * @propname: name of the property to be searched.
- * @index: index of the string in the list of strings
- * @out_string: pointer to null terminated return string, modified only if
- * return value is 0.
- *
- * Search for a property in a device tree node and retrieve a null
- * terminated string value (pointer to data, not a copy) in the list of strings
- * contained in that property.
- * Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if
- * property does not have a value, and -EILSEQ if the string is not
- * null-terminated within the length of the property data.
- *
- * The out_string pointer is modified only if a valid string can be decoded.
- */
-int of_property_read_string_index(struct device_node *np, const char *propname,
- int index, const char **output)
-{
- struct property *prop = of_find_property(np, propname, NULL);
- int i = 0;
- size_t l = 0, total = 0;
- const char *p;
- const void *value;
-
- if (!prop)
- return -EINVAL;
- value = of_property_get_value(prop);
- if (!value)
- return -ENODATA;
- if (strnlen(value, prop->length) >= prop->length)
- return -EILSEQ;
-
- p = value;
-
- for (i = 0; total < prop->length; total += l, p += l) {
- l = strlen(p) + 1;
- if (i++ == index) {
- *output = p;
- return 0;
- }
- }
- return -ENODATA;
-}
-EXPORT_SYMBOL_GPL(of_property_read_string_index);
-
-/**
* of_property_match_string() - Find string in a list and return index
* @np: pointer to node containing string list property
* @propname: string list property name
@@ -972,43 +924,6 @@ int of_property_match_string(struct device_node *np, const char *propname,
}
EXPORT_SYMBOL_GPL(of_property_match_string);
-/**
- * of_property_count_strings - Find and return the number of strings from a
- * multiple strings property.
- * @np: device node from which the property value is to be read.
- * @propname: name of the property to be searched.
- *
- * Search for a property in a device tree node and retrieve the number of null
- * terminated string contain in it. Returns the number of strings on
- * success, -EINVAL if the property does not exist, -ENODATA if property
- * does not have a value, and -EILSEQ if the string is not null-terminated
- * within the length of the property data.
- */
-int of_property_count_strings(struct device_node *np, const char *propname)
-{
- struct property *prop = of_find_property(np, propname, NULL);
- int i = 0;
- size_t l = 0, total = 0;
- const char *p;
- const void *value;
-
- if (!prop)
- return -EINVAL;
- value = of_property_get_value(prop);
- if (!value)
- return -ENODATA;
- if (strnlen(value, prop->length) >= prop->length)
- return -EILSEQ;
-
- p = value;
-
- for (i = 0; total < prop->length; total += l, p += l, i++)
- l = strlen(p) + 1;
-
- return i;
-}
-EXPORT_SYMBOL_GPL(of_property_count_strings);
-
const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
u32 *pu)
{
@@ -1777,6 +1692,43 @@ struct device_node *of_get_child_by_name(const struct device_node *node,
}
EXPORT_SYMBOL(of_get_child_by_name);
+/**
+ * of_property_read_string_helper() - Utility helper for parsing string properties
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_strs: output array of string pointers.
+ * @sz: number of array elements to read.
+ * @skip: Number of strings to skip over at beginning of list.
+ *
+ * Don't call this function directly. It is a utility helper for the
+ * of_property_read_string*() family of functions.
+ */
+int of_property_read_string_helper(const struct device_node *np,
+ const char *propname, const char **out_strs,
+ size_t sz, int skip)
+{
+ const struct property *prop = of_find_property(np, propname, NULL);
+ int l = 0, i = 0;
+ const char *p, *end;
+
+ if (!prop)
+ return -EINVAL;
+ if (!prop->value)
+ return -ENODATA;
+ p = prop->value;
+ end = p + prop->length;
+
+ for (i = 0; p < end && (!out_strs || i < skip + sz); i++, p += l) {
+ l = strnlen(p, end - p) + 1;
+ if (p + l > end)
+ return -EILSEQ;
+ if (out_strs && i >= skip)
+ *out_strs++ = p;
+ }
+ i -= skip;
+ return i <= 0 ? -ENODATA : i;
+}
+
static void __of_print_nodes(struct device_node *node, int indent, const char *prefix)
{
struct device_node *n;
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 44a89d0..025c418 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -47,6 +47,13 @@ config PCI_IMX6
select OF_PCI
select PCI
+config PCI_LAYERSCAPE
+ bool "Freescale Layerscape PCIe controller"
+ depends on ARCH_LAYERSCAPE
+ select PCIE_DW
+ select OF_PCI
+ select PCI
+
endmenu
endif
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 562304c..3ca6708 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o pci-mvebu-phy.o
obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
obj-$(CONFIG_PCIE_DW) += pcie-designware.o pcie-designware-host.o
obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
+obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index ac15623..251be4f 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -23,6 +23,32 @@ pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev)
return NULL;
}
+/**
+ * pci_match_id - See if a pci device matches a given pci_id table
+ * @ids: array of PCI device id structures to search in
+ * @dev: the PCI device structure to match against.
+ *
+ * Used by a driver to check whether a PCI device present in the
+ * system is in its list of supported devices. Returns the matching
+ * pci_device_id structure or %NULL if there is no match.
+ *
+ * Deprecated, don't use this as it will not catch any dynamic ids
+ * that a driver might want to check for.
+ */
+const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
+ struct pci_dev *dev)
+{
+ if (ids) {
+ while (ids->vendor || ids->subvendor || ids->class_mask) {
+ if (pci_match_one_device(ids, dev))
+ return ids;
+ ids++;
+ }
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(pci_match_id);
+
static int pci_match(struct device_d *dev, struct driver_d *drv)
{
struct pci_dev *pdev = to_pci_dev(dev);
diff --git a/drivers/pci/pci-imx6.c b/drivers/pci/pci-imx6.c
index 85307ba..05df9c0 100644
--- a/drivers/pci/pci-imx6.c
+++ b/drivers/pci/pci-imx6.c
@@ -97,8 +97,6 @@ struct imx6_pcie {
#define PCIE_PL_PFLR (PL_OFFSET + 0x08)
#define PCIE_PL_PFLR_LINK_STATE_MASK (0x3f << 16)
#define PCIE_PL_PFLR_FORCE_LINK (1 << 15)
-#define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28)
-#define PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING (1 << 29)
#define PCIE_PHY_DEBUG_R1_XMLH_LINK_UP (1 << 4)
#define PCIE_PHY_CTRL (PL_OFFSET + 0x114)
@@ -112,7 +110,6 @@ struct imx6_pcie {
#define PCIE_PHY_STAT_ACK_LOC 16
#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C
-#define PORT_LOGIC_SPEED_CHANGE (0x1 << 17)
/* PHY registers (not memory-mapped) */
#define PCIE_PHY_RX_ASIC_OUT 0x100D
@@ -636,8 +633,8 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
err_reset_phy:
dev_dbg(dev, "PHY DEBUG_R0=0x%08x DEBUG_R1=0x%08x\n",
- dw_pcie_readl_dbi(pci, PCIE_PHY_DEBUG_R0),
- dw_pcie_readl_dbi(pci, PCIE_PHY_DEBUG_R1));
+ dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG0),
+ dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG1));
imx6_pcie_reset_phy(imx6_pcie);
return ret;
@@ -659,8 +656,8 @@ static int imx6_pcie_host_init(struct pcie_port *pp)
static int imx6_pcie_link_up(struct dw_pcie *pci)
{
- return dw_pcie_readl_dbi(pci, PCIE_PHY_DEBUG_R1) &
- PCIE_PHY_DEBUG_R1_XMLH_LINK_UP;
+ return dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG1) &
+ PCIE_PORT_DEBUG1_LINK_UP;
}
static const struct dw_pcie_ops dw_pcie_ops = {
diff --git a/drivers/pci/pci-layerscape.c b/drivers/pci/pci-layerscape.c
new file mode 100644
index 0000000..ccdc025
--- /dev/null
+++ b/drivers/pci/pci-layerscape.c
@@ -0,0 +1,484 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PCIe host controller driver for Freescale Layerscape SoCs
+ *
+ * Copyright (C) 2014 Freescale Semiconductor.
+ *
+ * Author: Minghuan Lian <Minghuan.Lian@freescale.com>
+ */
+
+#include <common.h>
+#include <clock.h>
+#include <abort.h>
+#include <malloc.h>
+#include <io.h>
+#include <init.h>
+#include <gpio.h>
+#include <asm/mmu.h>
+#include <of_gpio.h>
+#include <of_device.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <of_address.h>
+#include <of_pci.h>
+#include <regmap.h>
+#include <mfd/syscon.h>
+#include <linux/pci.h>
+#include <linux/phy/phy.h>
+#include <linux/reset.h>
+#include <linux/sizes.h>
+
+#include "pcie-designware.h"
+
+/* PEX1/2 Misc Ports Status Register */
+#define SCFG_PEXMSCPORTSR(pex_idx) (0x94 + (pex_idx) * 4)
+#define LTSSM_STATE_SHIFT 20
+#define LTSSM_STATE_MASK 0x3f
+#define LTSSM_PCIE_L0 0x11 /* L0 state */
+
+/* PEX Internal Configuration Registers */
+#define PCIE_STRFMR1 0x71c /* Symbol Timer & Filter Mask Register1 */
+#define PCIE_ABSERR 0x8d0 /* Bridge Slave Error Response Register */
+#define PCIE_ABSERR_SETTING 0x9401 /* Forward error of non-posted request */
+
+#define PCIE_IATU_NUM 6
+
+#define PCIE_LUT_UDR(n) (0x800 + (n) * 8)
+#define PCIE_LUT_ENABLE (1 << 31)
+#define PCIE_LUT_LDR(n) (0x804 + (n) * 8)
+
+struct ls_pcie_drvdata {
+ u32 lut_offset;
+ u32 ltssm_shift;
+ u32 lut_dbg;
+ int pex_stream_id_start;
+ int pex_stream_id_end;
+ const struct dw_pcie_host_ops *ops;
+ const struct dw_pcie_ops *dw_pcie_ops;
+};
+
+struct ls_pcie {
+ struct dw_pcie pci;
+ void __iomem *lut;
+ struct regmap *scfg;
+ const char *compatible;
+ const struct ls_pcie_drvdata *drvdata;
+ int index;
+ int next_lut_index;
+};
+
+static struct ls_pcie *to_ls_pcie(struct dw_pcie *pci)
+{
+ return container_of(pci, struct ls_pcie, pci);
+}
+
+static u32 lut_readl(struct ls_pcie *pcie, unsigned int offset)
+{
+ return in_be32(pcie->lut + offset);
+}
+
+static void lut_writel(struct ls_pcie *pcie, unsigned int value,
+ unsigned int offset)
+{
+ out_be32(pcie->lut + offset, value);
+}
+
+static int ls_pcie_next_streamid(struct ls_pcie *pcie)
+{
+ static int next_stream_id;
+ int first = pcie->drvdata->pex_stream_id_start;
+ int last = pcie->drvdata->pex_stream_id_end;
+ int current = next_stream_id + first;
+
+ if (current > last)
+ return -EINVAL;
+
+ next_stream_id++;
+
+ return current;
+}
+
+#define PCIE_LUT_ENTRY_COUNT 32
+
+static int ls_pcie_next_lut_index(struct ls_pcie *pcie)
+{
+ if (pcie->next_lut_index < PCIE_LUT_ENTRY_COUNT)
+ return pcie->next_lut_index++;
+ else
+ return -ENOSPC; /* LUT is full */
+}
+
+static void ls_pcie_lut_set_mapping(struct ls_pcie *pcie, int index, u32 devid,
+ u32 stream_id)
+{
+ /* leave mask as all zeroes, want to match all bits */
+ lut_writel(pcie, devid << 16, PCIE_LUT_UDR(index));
+ lut_writel(pcie, stream_id | PCIE_LUT_ENABLE, PCIE_LUT_LDR(index));
+}
+
+static bool ls_pcie_is_bridge(struct ls_pcie *pcie)
+{
+ struct dw_pcie *pci = &pcie->pci;
+ u32 header_type;
+
+ header_type = ioread8(pci->dbi_base + PCI_HEADER_TYPE);
+ header_type &= 0x7f;
+
+ return header_type == PCI_HEADER_TYPE_BRIDGE;
+}
+
+/* Clear multi-function bit */
+static void ls_pcie_clear_multifunction(struct ls_pcie *pcie)
+{
+ struct dw_pcie *pci = &pcie->pci;
+
+ iowrite8(PCI_HEADER_TYPE_BRIDGE, pci->dbi_base + PCI_HEADER_TYPE);
+}
+
+/* Drop MSG TLP except for Vendor MSG */
+static void ls_pcie_drop_msg_tlp(struct ls_pcie *pcie)
+{
+ u32 val;
+ struct dw_pcie *pci = &pcie->pci;
+
+ val = ioread32(pci->dbi_base + PCIE_STRFMR1);
+ val &= 0xDFFFFFFF;
+ iowrite32(val, pci->dbi_base + PCIE_STRFMR1);
+}
+
+static void ls_pcie_disable_outbound_atus(struct ls_pcie *pcie)
+{
+ int i;
+
+ for (i = 0; i < PCIE_IATU_NUM; i++)
+ dw_pcie_disable_atu(&pcie->pci, i, DW_PCIE_REGION_OUTBOUND);
+}
+
+static int ls1021_pcie_link_up(struct dw_pcie *pci)
+{
+ u32 state;
+ struct ls_pcie *pcie = to_ls_pcie(pci);
+
+ if (!pcie->scfg)
+ return 0;
+
+ regmap_read(pcie->scfg, SCFG_PEXMSCPORTSR(pcie->index), &state);
+ state = (state >> LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK;
+
+ if (state < LTSSM_PCIE_L0)
+ return 0;
+
+ return 1;
+}
+
+static int ls_pcie_link_up(struct dw_pcie *pci)
+{
+ struct ls_pcie *pcie = to_ls_pcie(pci);
+ u32 state;
+
+ state = (ioread32(pcie->lut + pcie->drvdata->lut_dbg) >>
+ pcie->drvdata->ltssm_shift) &
+ LTSSM_STATE_MASK;
+
+ if (state < LTSSM_PCIE_L0)
+ return 0;
+
+ return 1;
+}
+
+/* Forward error response of outbound non-posted requests */
+static void ls_pcie_fix_error_response(struct ls_pcie *pcie)
+{
+ struct dw_pcie *pci = &pcie->pci;
+
+ iowrite32(PCIE_ABSERR_SETTING, pci->dbi_base + PCIE_ABSERR);
+}
+
+static int ls_pcie_host_init(struct pcie_port *pp)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct ls_pcie *pcie = to_ls_pcie(pci);
+
+ /*
+ * Disable outbound windows configured by the bootloader to avoid
+ * one transaction hitting multiple outbound windows.
+ * dw_pcie_setup_rc() will reconfigure the outbound windows.
+ */
+ ls_pcie_disable_outbound_atus(pcie);
+ ls_pcie_fix_error_response(pcie);
+
+ dw_pcie_dbi_ro_wr_en(pci);
+ ls_pcie_clear_multifunction(pcie);
+ dw_pcie_dbi_ro_wr_dis(pci);
+
+ ls_pcie_drop_msg_tlp(pcie);
+
+ dw_pcie_setup_rc(pp);
+
+ return 0;
+}
+
+static int ls1021_pcie_host_init(struct pcie_port *pp)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct ls_pcie *pcie = to_ls_pcie(pci);
+ struct device_d *dev = pci->dev;
+ u32 index[2];
+ int ret;
+
+ pcie->scfg = syscon_regmap_lookup_by_phandle(dev->device_node,
+ "fsl,pcie-scfg");
+ if (IS_ERR(pcie->scfg)) {
+ ret = PTR_ERR(pcie->scfg);
+ dev_err(dev, "No syscfg phandle specified\n");
+ pcie->scfg = NULL;
+ return ret;
+ }
+
+ if (of_property_read_u32_array(dev->device_node,
+ "fsl,pcie-scfg", index, 2)) {
+ pcie->scfg = NULL;
+ return -EINVAL;
+ }
+ pcie->index = index[1];
+
+ return ls_pcie_host_init(pp);
+}
+
+static const struct dw_pcie_host_ops ls1021_pcie_host_ops = {
+ .host_init = ls1021_pcie_host_init,
+};
+
+static const struct dw_pcie_host_ops ls_pcie_host_ops = {
+ .host_init = ls_pcie_host_init,
+};
+
+static const struct dw_pcie_ops dw_ls1021_pcie_ops = {
+ .link_up = ls1021_pcie_link_up,
+};
+
+static const struct dw_pcie_ops dw_ls_pcie_ops = {
+ .link_up = ls_pcie_link_up,
+};
+
+static const struct ls_pcie_drvdata ls1021_drvdata = {
+ .ops = &ls1021_pcie_host_ops,
+ .dw_pcie_ops = &dw_ls1021_pcie_ops,
+};
+
+static const struct ls_pcie_drvdata ls1043_drvdata = {
+ .lut_offset = 0x10000,
+ .ltssm_shift = 24,
+ .lut_dbg = 0x7fc,
+ .pex_stream_id_start = 11,
+ .pex_stream_id_end = 26,
+ .ops = &ls_pcie_host_ops,
+ .dw_pcie_ops = &dw_ls_pcie_ops,
+};
+
+static const struct ls_pcie_drvdata ls1046_drvdata = {
+ .lut_offset = 0x80000,
+ .ltssm_shift = 24,
+ .lut_dbg = 0x407fc,
+ .pex_stream_id_start = 11,
+ .pex_stream_id_end = 26,
+ .ops = &ls_pcie_host_ops,
+ .dw_pcie_ops = &dw_ls_pcie_ops,
+};
+
+static const struct ls_pcie_drvdata ls2080_drvdata = {
+ .lut_offset = 0x80000,
+ .ltssm_shift = 0,
+ .lut_dbg = 0x7fc,
+ .pex_stream_id_start = 7,
+ .pex_stream_id_end = 22,
+ .ops = &ls_pcie_host_ops,
+ .dw_pcie_ops = &dw_ls_pcie_ops,
+};
+
+static const struct ls_pcie_drvdata ls2088_drvdata = {
+ .lut_offset = 0x80000,
+ .ltssm_shift = 0,
+ .lut_dbg = 0x407fc,
+ .pex_stream_id_start = 7,
+ .pex_stream_id_end = 18,
+ .ops = &ls_pcie_host_ops,
+ .dw_pcie_ops = &dw_ls_pcie_ops,
+};
+
+static const struct of_device_id ls_pcie_of_match[] = {
+ { .compatible = "fsl,ls1012a-pcie", .data = &ls1046_drvdata },
+ { .compatible = "fsl,ls1021a-pcie", .data = &ls1021_drvdata },
+ { .compatible = "fsl,ls1043a-pcie", .data = &ls1043_drvdata },
+ { .compatible = "fsl,ls1046a-pcie", .data = &ls1046_drvdata },
+ { .compatible = "fsl,ls2080a-pcie", .data = &ls2080_drvdata },
+ { .compatible = "fsl,ls2085a-pcie", .data = &ls2080_drvdata },
+ { .compatible = "fsl,ls2088a-pcie", .data = &ls2088_drvdata },
+ { .compatible = "fsl,ls1088a-pcie", .data = &ls2088_drvdata },
+ { },
+};
+
+static int __init ls_add_pcie_port(struct ls_pcie *pcie)
+{
+ struct dw_pcie *pci = &pcie->pci;
+ struct pcie_port *pp = &pci->pp;
+ struct device_d *dev = pci->dev;
+ int ret;
+
+ pp->ops = pcie->drvdata->ops;
+
+ ret = dw_pcie_host_init(pp);
+ if (ret) {
+ dev_err(dev, "failed to initialize host\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ls_pcie_of_fixup(struct device_node *root, void *ctx)
+{
+ struct ls_pcie *pcie = ctx;
+ struct device_d *dev = pcie->pci.dev;
+ struct device_node *np;
+ char *name;
+ u32 *arr, phandle;
+ int nluts;
+ int ret, i;
+ u32 devid, stream_id;
+
+ name = of_get_reproducible_name(dev->device_node);
+
+ np = root;
+ do {
+ np = of_find_node_by_reproducible_name(np, name);
+ if (!np)
+ return -ENODEV;
+ } while (!of_device_is_compatible(np, pcie->compatible));
+
+ nluts = pcie->next_lut_index;
+
+ ret = of_property_read_u32(np, "msi-parent", &phandle);
+ if (ret) {
+ dev_err(pcie->pci.dev, "Unable to get \"msi-parent\" phandle\n");
+ return ret;
+ }
+
+ arr = xmalloc(nluts * sizeof(u32) * 4);
+
+ for (i = 0; i < nluts; i++) {
+ u32 udr = lut_readl(pcie, PCIE_LUT_UDR(i));
+ u32 ldr = lut_readl(pcie, PCIE_LUT_LDR(i));
+
+ if (!(ldr & PCIE_LUT_ENABLE))
+ break;
+
+ devid = udr >> 16;
+ stream_id = ldr & 0x7fff;
+
+ arr[i * 4] = devid;
+ arr[i * 4 + 1] = phandle;
+ arr[i * 4 + 2] = stream_id;
+ arr[i * 4 + 3] = 1;
+ }
+
+ /*
+ * An msi-map is a property to be added to the pci controller
+ * node. It is a table, where each entry consists of 4 fields
+ * e.g.:
+ *
+ * msi-map = <[devid] [phandle-to-msi-ctrl] [stream-id] [count]
+ * [devid] [phandle-to-msi-ctrl] [stream-id] [count]>;
+ */
+
+ ret = of_property_write_u32_array(np, "msi-map", arr, nluts * 4);
+ if (ret)
+ goto out;
+
+ of_device_enable(np);
+
+ ret = 0;
+
+out:
+ free(arr);
+ return ret;
+}
+
+static int __init ls_pcie_probe(struct device_d *dev)
+{
+ struct dw_pcie *pci;
+ struct ls_pcie *pcie;
+ struct resource *dbi_base;
+ const struct of_device_id *match;
+ int ret;
+
+ pcie = xzalloc(sizeof(*pcie));
+ if (!pcie)
+ return -ENOMEM;
+
+ pci = &pcie->pci;
+
+ match = of_match_device(dev->driver->of_compatible, dev);
+ if (!match)
+ return -ENODEV;
+
+ pcie->drvdata = match->data;
+ pcie->compatible = match->compatible;
+
+ pci->dev = dev;
+ pci->ops = pcie->drvdata->dw_pcie_ops;
+
+ dbi_base = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(dbi_base))
+ return PTR_ERR(dbi_base);
+
+ pci->dbi_base = IOMEM(dbi_base->start);
+
+ pcie->lut = pci->dbi_base + pcie->drvdata->lut_offset;
+
+ if (!ls_pcie_is_bridge(pcie))
+ return -ENODEV;
+
+ dev->priv = pcie;
+
+ ret = ls_add_pcie_port(pcie);
+ if (ret < 0)
+ return ret;
+
+ of_register_fixup(ls_pcie_of_fixup, pcie);
+
+ return 0;
+}
+
+static struct driver_d ls_pcie_driver = {
+ .name = "layerscape-pcie",
+ .of_compatible = DRV_OF_COMPAT(ls_pcie_of_match),
+ .probe = ls_pcie_probe,
+};
+device_platform_driver(ls_pcie_driver);
+
+static void ls_pcie_fixup(struct pci_dev *pcidev)
+{
+ struct pci_bus *bus = pcidev->bus, *p;
+ struct pci_controller *host = bus->host;
+ struct pcie_port *pp = container_of(host, struct pcie_port, pci);
+ struct dw_pcie *dwpcie = container_of(pp, struct dw_pcie, pp);
+ struct ls_pcie *lspcie = container_of(dwpcie, struct ls_pcie, pci);
+ int stream_id, index;
+ int base_bus_num = 0;
+
+ stream_id = ls_pcie_next_streamid(lspcie);
+ index = ls_pcie_next_lut_index(lspcie);
+
+ p = pcidev->bus;
+ while (p) {
+ base_bus_num = p->number;
+ p = p->parent_bus;
+ }
+
+ ls_pcie_lut_set_mapping(lspcie, index,
+ (pcidev->bus->number - base_bus_num) << 8 | pcidev->devfn,
+ stream_id);
+}
+
+DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ls_pcie_fixup);
diff --git a/drivers/pci/pcie-designware-host.c b/drivers/pci/pcie-designware-host.c
index 7a95b2a..b2d46d3 100644
--- a/drivers/pci/pcie-designware-host.c
+++ b/drivers/pci/pcie-designware-host.c
@@ -340,17 +340,6 @@ static const struct pci_ops dw_pcie_ops = {
.write = dw_pcie_wr_conf,
};
-static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
-{
- u32 val;
-
- val = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT);
- if (val == 0xffffffff)
- return 1;
-
- return 0;
-}
-
void dw_pcie_setup_rc(struct pcie_port *pp)
{
u32 val;
@@ -381,11 +370,6 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
* we should not program the ATU here.
*/
if (!pp->ops->rd_other_conf) {
- /* get iATU unroll support */
- pci->iatu_unroll_enabled = dw_pcie_iatu_unroll_enabled(pci);
- dev_dbg(pci->dev, "iATU unroll: %s\n",
- pci->iatu_unroll_enabled ? "enabled" : "disabled");
-
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,
PCIE_ATU_TYPE_MEM, pp->mem_mod_base,
pp->mem_bus_addr, pp->mem_size);
diff --git a/drivers/pci/pcie-designware.c b/drivers/pci/pcie-designware.c
index c6d1955..e2007db 100644
--- a/drivers/pci/pcie-designware.c
+++ b/drivers/pci/pcie-designware.c
@@ -29,7 +29,7 @@
int dw_pcie_read(void __iomem *addr, int size, u32 *val)
{
- if ((uintptr_t)addr & (size - 1)) {
+ if (!IS_ALIGNED((uintptr_t)addr, size)) {
*val = 0;
return PCIBIOS_BAD_REGISTER_NUMBER;
}
@@ -50,7 +50,7 @@ int dw_pcie_read(void __iomem *addr, int size, u32 *val)
int dw_pcie_write(void __iomem *addr, int size, u32 val)
{
- if ((uintptr_t)addr & (size - 1))
+ if (!IS_ALIGNED((uintptr_t)addr, size))
return PCIBIOS_BAD_REGISTER_NUMBER;
if (size == 4)
@@ -65,42 +65,69 @@ int dw_pcie_write(void __iomem *addr, int size, u32 val)
return PCIBIOS_SUCCESSFUL;
}
-u32 __dw_pcie_readl_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg,
- size_t size)
+u32 dw_pcie_read_dbi(struct dw_pcie *pci, u32 reg, size_t size)
{
int ret;
u32 val;
- if (pci->ops->readl_dbi)
- return pci->ops->readl_dbi(pci, base, reg, size);
+ if (pci->ops->read_dbi)
+ return pci->ops->read_dbi(pci, pci->dbi_base, reg, size);
- ret = dw_pcie_read(base + reg, size, &val);
+ ret = dw_pcie_read(pci->dbi_base + reg, size, &val);
if (ret)
dev_err(pci->dev, "Read DBI address failed\n");
return val;
}
-void __dw_pcie_writel_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg,
- size_t size, u32 val)
+void dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
{
int ret;
- if (pci->ops->writel_dbi) {
- pci->ops->writel_dbi(pci, base, reg, size, val);
+ if (pci->ops->write_dbi) {
+ pci->ops->write_dbi(pci, pci->dbi_base, reg, size, val);
return;
}
- ret = dw_pcie_write(base + reg, size, val);
+ ret = dw_pcie_write(pci->dbi_base + reg, size, val);
if (ret)
dev_err(pci->dev, "Write DBI address failed\n");
}
+u32 dw_pcie_read_atu(struct dw_pcie *pci, u32 reg, size_t size)
+{
+ int ret;
+ u32 val;
+
+ if (pci->ops->read_dbi)
+ return pci->ops->read_dbi(pci, pci->atu_base, reg, size);
+
+ ret = dw_pcie_read(pci->atu_base + reg, size, &val);
+ if (ret)
+ dev_err(pci->dev, "Read ATU address failed\n");
+
+ return val;
+}
+
+void dw_pcie_write_atu(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
+{
+ int ret;
+
+ if (pci->ops->write_dbi) {
+ pci->ops->write_dbi(pci, pci->atu_base, reg, size, val);
+ return;
+ }
+
+ ret = dw_pcie_write(pci->atu_base + reg, size, val);
+ if (ret)
+ dev_err(pci->dev, "Write ATU address failed\n");
+}
+
static u32 dw_pcie_readl_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg)
{
u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
- return dw_pcie_readl_dbi(pci, offset + reg);
+ return dw_pcie_readl_atu(pci, offset + reg);
}
static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index,
@@ -108,7 +135,7 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index,
{
u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
- dw_pcie_writel_dbi(pci, offset + reg, val);
+ dw_pcie_writel_atu(pci, offset + reg, val);
}
static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index,
@@ -188,6 +215,26 @@ void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
dev_err(pci->dev, "Outbound iATU is not being enabled\n");
}
+void dw_pcie_disable_atu(struct dw_pcie *pci, int index,
+ enum dw_pcie_region_type type)
+{
+ int region;
+
+ switch (type) {
+ case DW_PCIE_REGION_INBOUND:
+ region = PCIE_ATU_REGION_INBOUND;
+ break;
+ case DW_PCIE_REGION_OUTBOUND:
+ region = PCIE_ATU_REGION_OUTBOUND;
+ break;
+ default:
+ return;
+ }
+
+ dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, region | index);
+ dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, (u32)~PCIE_ATU_ENABLE);
+}
+
int dw_pcie_wait_for_link(struct dw_pcie *pci)
{
int retries;
@@ -213,9 +260,20 @@ int dw_pcie_link_up(struct dw_pcie *pci)
if (pci->ops->link_up)
return pci->ops->link_up(pci);
- val = readl(pci->dbi_base + PCIE_PHY_DEBUG_R1);
- return ((val & PCIE_PHY_DEBUG_R1_LINK_UP) &&
- !(val & PCIE_PHY_DEBUG_R1_LINK_IN_TRAINING));
+ val = readl(pci->dbi_base + PCIE_PORT_DEBUG1);
+ return ((val & PCIE_PORT_DEBUG1_LINK_UP) &&
+ (!(val & PCIE_PORT_DEBUG1_LINK_IN_TRAINING)));
+}
+
+static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
+{
+ u32 val;
+
+ val = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT);
+ if (val == 0xffffffff)
+ return 1;
+
+ return 0;
}
void dw_pcie_setup(struct dw_pcie *pci)
@@ -226,9 +284,21 @@ void dw_pcie_setup(struct dw_pcie *pci)
struct device_d *dev = pci->dev;
struct device_node *np = dev->device_node;
+ if (pci->version >= 0x480A || (!pci->version &&
+ dw_pcie_iatu_unroll_enabled(pci))) {
+ pci->iatu_unroll_enabled = true;
+ if (!pci->atu_base)
+ pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
+ }
+ dev_dbg(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ?
+ "enabled" : "disabled");
+
+
ret = of_property_read_u32(np, "num-lanes", &lanes);
- if (ret)
- lanes = 0;
+ if (ret) {
+ dev_dbg(pci->dev, "property num-lanes isn't found\n");
+ return;
+ }
/* Set the number of lanes */
val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL);
diff --git a/drivers/pci/pcie-designware.h b/drivers/pci/pcie-designware.h
index 058a0ac..de20654 100644
--- a/drivers/pci/pcie-designware.h
+++ b/drivers/pci/pcie-designware.h
@@ -11,6 +11,8 @@
#ifndef _PCIE_DESIGNWARE_H
#define _PCIE_DESIGNWARE_H
+#include <linux/bitfield.h>
+
/* Parameters for the waiting for link up routine */
#define LINK_WAIT_MAX_RETRIES 10
#define LINK_WAIT_USLEEP_MAX 100000
@@ -19,19 +21,30 @@
#define LINK_WAIT_MAX_IATU_RETRIES 5
#define LINK_WAIT_IATU_MAX 10000
-/* Synopsis specific PCIE configuration registers */
+/* Synopsys-specific PCIe configuration registers */
#define PCIE_PORT_LINK_CONTROL 0x710
-#define PORT_LINK_MODE_MASK (0x3f << 16)
-#define PORT_LINK_MODE_1_LANES (0x1 << 16)
-#define PORT_LINK_MODE_2_LANES (0x3 << 16)
-#define PORT_LINK_MODE_4_LANES (0x7 << 16)
+#define PORT_LINK_MODE_MASK GENMASK(21, 16)
+#define PORT_LINK_MODE(n) FIELD_PREP(PORT_LINK_MODE_MASK, n)
+#define PORT_LINK_MODE_1_LANES PORT_LINK_MODE(0x1)
+#define PORT_LINK_MODE_2_LANES PORT_LINK_MODE(0x3)
+#define PORT_LINK_MODE_4_LANES PORT_LINK_MODE(0x7)
+#define PORT_LINK_MODE_8_LANES PORT_LINK_MODE(0xf)
+
+#define PCIE_PORT_DEBUG0 0x728
+#define PORT_LOGIC_LTSSM_STATE_MASK 0x1f
+#define PORT_LOGIC_LTSSM_STATE_L0 0x11
+#define PCIE_PORT_DEBUG1 0x72C
+#define PCIE_PORT_DEBUG1_LINK_UP BIT(4)
+#define PCIE_PORT_DEBUG1_LINK_IN_TRAINING BIT(29)
#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C
-#define PORT_LOGIC_SPEED_CHANGE (0x1 << 17)
-#define PORT_LOGIC_LINK_WIDTH_MASK (0x1f << 8)
-#define PORT_LOGIC_LINK_WIDTH_1_LANES (0x1 << 8)
-#define PORT_LOGIC_LINK_WIDTH_2_LANES (0x2 << 8)
-#define PORT_LOGIC_LINK_WIDTH_4_LANES (0x4 << 8)
+#define PORT_LOGIC_SPEED_CHANGE BIT(17)
+#define PORT_LOGIC_LINK_WIDTH_MASK GENMASK(12, 8)
+#define PORT_LOGIC_LINK_WIDTH(n) FIELD_PREP(PORT_LOGIC_LINK_WIDTH_MASK, n)
+#define PORT_LOGIC_LINK_WIDTH_1_LANES PORT_LOGIC_LINK_WIDTH(0x1)
+#define PORT_LOGIC_LINK_WIDTH_2_LANES PORT_LOGIC_LINK_WIDTH(0x2)
+#define PORT_LOGIC_LINK_WIDTH_4_LANES PORT_LOGIC_LINK_WIDTH(0x4)
+#define PORT_LOGIC_LINK_WIDTH_8_LANES PORT_LOGIC_LINK_WIDTH(0x8)
#define PCIE_MSI_ADDR_LO 0x820
#define PCIE_MSI_ADDR_HI 0x824
@@ -40,61 +53,86 @@
#define PCIE_MSI_INTR0_STATUS 0x830
#define PCIE_ATU_VIEWPORT 0x900
-#define PCIE_ATU_REGION_INBOUND (0x1 << 31)
-#define PCIE_ATU_REGION_OUTBOUND (0x0 << 31)
-#define PCIE_ATU_REGION_INDEX2 (0x2 << 0)
-#define PCIE_ATU_REGION_INDEX1 (0x1 << 0)
-#define PCIE_ATU_REGION_INDEX0 (0x0 << 0)
+#define PCIE_ATU_REGION_INBOUND BIT(31)
+#define PCIE_ATU_REGION_OUTBOUND 0
+#define PCIE_ATU_REGION_INDEX2 0x2
+#define PCIE_ATU_REGION_INDEX1 0x1
+#define PCIE_ATU_REGION_INDEX0 0x0
#define PCIE_ATU_CR1 0x904
-#define PCIE_ATU_TYPE_MEM (0x0 << 0)
-#define PCIE_ATU_TYPE_IO (0x2 << 0)
-#define PCIE_ATU_TYPE_CFG0 (0x4 << 0)
-#define PCIE_ATU_TYPE_CFG1 (0x5 << 0)
+#define PCIE_ATU_TYPE_MEM 0x0
+#define PCIE_ATU_TYPE_IO 0x2
+#define PCIE_ATU_TYPE_CFG0 0x4
+#define PCIE_ATU_TYPE_CFG1 0x5
#define PCIE_ATU_CR2 0x908
-#define PCIE_ATU_ENABLE (0x1 << 31)
-#define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30)
+#define PCIE_ATU_ENABLE BIT(31)
+#define PCIE_ATU_BAR_MODE_ENABLE BIT(30)
#define PCIE_ATU_LOWER_BASE 0x90C
#define PCIE_ATU_UPPER_BASE 0x910
#define PCIE_ATU_LIMIT 0x914
#define PCIE_ATU_LOWER_TARGET 0x918
-#define PCIE_ATU_BUS(x) (((x) & 0xff) << 24)
-#define PCIE_ATU_DEV(x) (((x) & 0x1f) << 19)
-#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16)
+#define PCIE_ATU_BUS(x) FIELD_PREP(GENMASK(31, 24), x)
+#define PCIE_ATU_DEV(x) FIELD_PREP(GENMASK(23, 19), x)
+#define PCIE_ATU_FUNC(x) FIELD_PREP(GENMASK(18, 16), x)
#define PCIE_ATU_UPPER_TARGET 0x91C
+#define PCIE_MISC_CONTROL_1_OFF 0x8BC
+#define PCIE_DBI_RO_WR_EN BIT(0)
+
+#define PCIE_PL_CHK_REG_CONTROL_STATUS 0xB20
+#define PCIE_PL_CHK_REG_CHK_REG_START BIT(0)
+#define PCIE_PL_CHK_REG_CHK_REG_CONTINUOUS BIT(1)
+#define PCIE_PL_CHK_REG_CHK_REG_COMPARISON_ERROR BIT(16)
+#define PCIE_PL_CHK_REG_CHK_REG_LOGIC_ERROR BIT(17)
+#define PCIE_PL_CHK_REG_CHK_REG_COMPLETE BIT(18)
+
+#define PCIE_PL_CHK_REG_ERR_ADDR 0xB28
+
/*
* iATU Unroll-specific register definitions
* From 4.80 core version the address translation will be made by unroll
*/
#define PCIE_ATU_UNR_REGION_CTRL1 0x00
#define PCIE_ATU_UNR_REGION_CTRL2 0x04
-#define PCIE_ATU_UNR_LOWER_BASE 0x08
-#define PCIE_ATU_UNR_UPPER_BASE 0x0C
+#define PCIE_ATU_UNR_LOWER_BASE 0x08
+#define PCIE_ATU_UNR_UPPER_BASE 0x0C
#define PCIE_ATU_UNR_LIMIT 0x10
#define PCIE_ATU_UNR_LOWER_TARGET 0x14
#define PCIE_ATU_UNR_UPPER_TARGET 0x18
+/*
+ * The default address offset between dbi_base and atu_base. Root controller
+ * drivers are not required to initialize atu_base if the offset matches this
+ * default; the driver core automatically derives atu_base from dbi_base using
+ * this offset, if atu_base not set.
+ */
+#define DEFAULT_DBI_ATU_OFFSET (0x3 << 20)
+
/* Register address builder */
-#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) ((0x3 << 20) | (region << 9))
+#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) \
+ ((region) << 9)
-/* PCIe Port Logic registers */
-#define PLR_OFFSET 0x700
-#define PCIE_PHY_DEBUG_R1 (PLR_OFFSET + 0x2c)
-#define PCIE_PHY_DEBUG_R1_LINK_UP (0x1 << 4)
-#define PCIE_PHY_DEBUG_R1_LINK_IN_TRAINING (0x1 << 29)
+#define PCIE_GET_ATU_INB_UNR_REG_OFFSET(region) \
+ (((region) << 9) | BIT(8))
-#define PCIE_MISC_CONTROL_1_OFF 0x8BC
-#define PCIE_DBI_RO_WR_EN (0x1 << 0)
+#define MAX_MSI_IRQS 256
+#define MAX_MSI_IRQS_PER_CTRL 32
+#define MAX_MSI_CTRLS (MAX_MSI_IRQS / MAX_MSI_IRQS_PER_CTRL)
+#define MSI_REG_CTRL_BLOCK_SIZE 12
+#define MSI_DEF_NUM_VECTORS 32
-/* PCIe Port Logic registers */
-#define PLR_OFFSET 0x700
-#define PCIE_PHY_DEBUG_R1 (PLR_OFFSET + 0x2c)
-#define PCIE_PHY_DEBUG_R1_LINK_UP (0x1 << 4)
-#define PCIE_PHY_DEBUG_R1_LINK_IN_TRAINING (0x1 << 29)
+/* Maximum number of inbound/outbound iATUs */
+#define MAX_IATU_IN 256
+#define MAX_IATU_OUT 256
struct pcie_port;
struct dw_pcie;
+enum dw_pcie_region_type {
+ DW_PCIE_REGION_UNKNOWN,
+ DW_PCIE_REGION_INBOUND,
+ DW_PCIE_REGION_OUTBOUND,
+};
+
struct dw_pcie_host_ops {
int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
@@ -134,20 +172,23 @@ struct pcie_port {
};
struct dw_pcie_ops {
- u32 (*readl_dbi)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
- size_t size);
- void (*writel_dbi)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
- size_t size, u32 val);
+ u32 (*read_dbi)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
+ size_t size);
+ void (*write_dbi)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
+ size_t size, u32 val);
int (*link_up)(struct dw_pcie *pcie);
};
struct dw_pcie {
struct device_d *dev;
void __iomem *dbi_base;
+ /* Used when iatu_unroll_enabled is true */
+ void __iomem *atu_base;
u32 num_viewport;
u8 iatu_unroll_enabled;
struct pcie_port pp;
const struct dw_pcie_ops *ops;
+ unsigned int version;
};
#define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp)
@@ -156,26 +197,37 @@ int dw_pcie_read(void __iomem *addr, int size, u32 *val);
int dw_pcie_write(void __iomem *addr, int size, u32 val);
void dw_pcie_setup_rc(struct pcie_port *pp);
int dw_pcie_host_init(struct pcie_port *pp);
-
-u32 __dw_pcie_readl_dbi(struct dw_pcie *pci, void __iomem *addr, u32 reg,
- size_t size);
-void __dw_pcie_writel_dbi(struct dw_pcie *pci, void __iomem *addr, u32 reg,
- size_t size, u32 val);
+u32 dw_pcie_read_dbi(struct dw_pcie *pci, u32 reg, size_t size);
+void dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val);
+u32 dw_pcie_read_atu(struct dw_pcie *pci, u32 reg, size_t size);
+void dw_pcie_write_atu(struct dw_pcie *pci, u32 reg, size_t size, u32 val);
int dw_pcie_link_up(struct dw_pcie *pci);
int dw_pcie_wait_for_link(struct dw_pcie *pci);
void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
int type, u64 cpu_addr, u64 pci_addr,
u32 size);
+void dw_pcie_disable_atu(struct dw_pcie *pci, int index,
+ enum dw_pcie_region_type type);
void dw_pcie_setup(struct dw_pcie *pci);
static inline void dw_pcie_writel_dbi(struct dw_pcie *pci, u32 reg, u32 val)
{
- __dw_pcie_writel_dbi(pci, pci->dbi_base, reg, 0x4, val);
+ dw_pcie_write_dbi(pci, reg, 0x4, val);
}
static inline u32 dw_pcie_readl_dbi(struct dw_pcie *pci, u32 reg)
{
- return __dw_pcie_readl_dbi(pci, pci->dbi_base, reg, 0x4);
+ return dw_pcie_read_dbi(pci, reg, 0x4);
+}
+
+static inline void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val)
+{
+ dw_pcie_write_atu(pci, reg, 0x4, val);
+}
+
+static inline u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 reg)
+{
+ return dw_pcie_read_atu(pci, reg, 0x4);
}
static inline void dw_pcie_dbi_ro_wr_en(struct dw_pcie *pci)
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 95c6708..fd75ea6 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -17,16 +17,6 @@ config PINCTRL_AT91
help
The pinmux controller found on AT91 SoCs.
-config PINCTRL_AT91PIO4
- bool "AT91 PIO4 pinctrl driver"
- depends on OFDEVICE
- depends on ARCH_AT91
- select GPIOLIB
- select OF_GPIO
- help
- Say Y here to enable the at91 pinctrl/gpio driver for Atmel PIO4
- controller available on sama5d2 SoC.
-
config PINCTRL_BCM283X
bool "GPIO and pinmux support for BCM283X"
depends on ARCH_BCM283X
@@ -55,6 +45,16 @@ comment "OFDEVICE is not enabled."
comment "Without device tree support PINCTRL won't do anything"
endif
+config PINCTRL_AT91PIO4
+ bool "AT91 PIO4 pinctrl driver"
+ depends on ARCH_AT91
+ depends on OFDEVICE
+ select GPIOLIB
+ select OF_GPIO
+ help
+ Say Y here to enable the at91 pinctrl/gpio driver for Atmel PIO4
+ controller available on sama5d2 SoC.
+
config PINCTRL_MXS
bool "MXS pinctrl"
depends on ARCH_MXS
diff --git a/drivers/pinctrl/pinctrl-tegra30.c b/drivers/pinctrl/pinctrl-tegra30.c
index ffb04ee..278ea8c 100644
--- a/drivers/pinctrl/pinctrl-tegra30.c
+++ b/drivers/pinctrl/pinctrl-tegra30.c
@@ -388,7 +388,7 @@ static const struct tegra_drive_pingroup tegra30_drive_groups[] = {
DRV_PG(vi1, 0x8c8, -1, -1, -1, 14, 5, 19, 5, 24, 4, 28, 4),
};
-static const struct pinctrl_tegra30_drvdata tegra30_drvdata = {
+__maybe_unused static const struct pinctrl_tegra30_drvdata tegra30_drvdata = {
.pingrps = tegra30_pin_groups,
.num_pingrps = ARRAY_SIZE(tegra30_pin_groups),
.drvgrps = tegra30_drive_groups,
@@ -632,7 +632,7 @@ static const struct tegra_drive_pingroup tegra124_drive_groups[] = {
DRV_PG(ao4, 0x9c8, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2),
};
-static const struct pinctrl_tegra30_drvdata tegra124_drvdata = {
+__maybe_unused static const struct pinctrl_tegra30_drvdata tegra124_drvdata = {
.pingrps = tegra124_pin_groups,
.num_pingrps = ARRAY_SIZE(tegra124_pin_groups),
.drvgrps = tegra124_drive_groups,
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 8139b64..a193fad 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -21,6 +21,16 @@ config IMX_REMOTEPROC
It's safe to say N here.
+config STM32_REMOTEPROC
+ tristate "STM32 remoteproc support"
+ depends on ARCH_STM32MP
+ select MFD_SYSCON
+ help
+ Say y here to support STM32 MCU processors via the
+ remote processor framework.
+
+ It's safe to say N here.
+
endif # REMOTEPROC
endmenu
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 1072969..43658df 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -5,3 +5,4 @@
obj-$(CONFIG_REMOTEPROC) += remoteproc_core.o remoteproc_elf_loader.o
obj-$(CONFIG_IMX_REMOTEPROC) += imx_rproc.o
+obj-$(CONFIG_STM32_REMOTEPROC) += stm32_rproc.o
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 7cac47e..8a28c1b 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -107,14 +107,36 @@ static int rproc_firmware_finish(struct firmware_handler *fh)
return ret;
}
+static int rproc_register_dev(struct rproc *rproc, const char *alias)
+{
+ if (alias) {
+ rproc->dev.id = DEVICE_ID_SINGLE;
+ dev_set_name(&rproc->dev, alias);
+ } else {
+ rproc->dev.id = DEVICE_ID_DYNAMIC;
+ dev_set_name(&rproc->dev, "remoteproc");
+ }
+
+ return register_device(&rproc->dev);
+}
+
int rproc_add(struct rproc *rproc)
{
struct device_d *dev = &rproc->dev;
struct firmware_handler *fh;
+ const char *alias = NULL;
int ret;
+ if (dev->device_node)
+ alias = of_alias_get(dev->device_node);
+
+ ret = rproc_register_dev(rproc, alias);
+ if (ret)
+ return ret;
+
fh = &rproc->fh;
- fh->id = xstrdup(rproc->name);
+ fh->id = xstrdup(dev_name(dev));
+ fh->model = xstrdup(rproc->name);
fh->open = rproc_firmware_start;
fh->write = rproc_firmware_write_buf;
fh->close = rproc_firmware_finish;
@@ -153,11 +175,6 @@ struct rproc *rproc_alloc(struct device_d *dev, const char *name,
rproc->dev.parent = dev;
rproc->dev.priv = rproc;
- /* Assign a unique device index and name */
- rproc->index = 1;
-
- dev_set_name(&rproc->dev, "remoteproc%d", rproc->index);
-
/* Default to ELF loader if no load function is specified */
if (!rproc->ops->load)
rproc->ops->load = rproc_elf_load_segments;
diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
new file mode 100644
index 0000000..bfd4d59
--- /dev/null
+++ b/drivers/remoteproc/stm32_rproc.c
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Authors: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
+ * Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
+ * Copyright (C) 2019 Ahmad Fatoum, Pengutronix
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <init.h>
+#include <io.h>
+#include <mach/smc.h>
+#include <mfd/syscon.h>
+#include <of_address.h>
+#include <regmap.h>
+#include <linux/remoteproc.h>
+#include <linux/reset.h>
+
+#include "remoteproc_internal.h"
+
+#define HOLD_BOOT 0
+#define RELEASE_BOOT 1
+
+struct stm32_syscon {
+ struct regmap *map;
+ u32 reg;
+ u32 mask;
+};
+
+struct stm32_rproc {
+ struct reset_control *rst;
+ struct stm32_syscon hold_boot;
+ bool secured_soc;
+};
+
+static void *stm32_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+{
+ __be32 in_addr = cpu_to_be32(da);
+ struct device_d *dev = &rproc->dev;
+ u64 paddr;
+
+ paddr = of_translate_dma_address(dev->parent->device_node, &in_addr);
+ if (paddr == OF_BAD_ADDR)
+ return NULL;
+
+ return phys_to_virt(paddr);
+}
+
+static int stm32_rproc_set_hold_boot(struct rproc *rproc, bool hold)
+{
+ struct stm32_rproc *ddata = rproc->priv;
+ struct stm32_syscon *hold_boot = &ddata->hold_boot;
+ struct arm_smccc_res smc_res;
+ int val, err;
+
+ val = hold ? HOLD_BOOT : RELEASE_BOOT;
+
+ if (IS_ENABLED(CONFIG_ARM_SMCC) && ddata->secured_soc) {
+ arm_smccc_smc(STM32_SMC_RCC, STM32_SMC_REG_WRITE,
+ hold_boot->reg, val, 0, 0, 0, 0, &smc_res);
+ err = smc_res.a0;
+ } else {
+ err = regmap_update_bits(hold_boot->map, hold_boot->reg,
+ hold_boot->mask, val);
+ }
+
+ if (err)
+ dev_err(&rproc->dev, "failed to set hold boot\n");
+
+ return err;
+}
+
+static int stm32_rproc_start(struct rproc *rproc)
+{
+ int err;
+
+ err = stm32_rproc_set_hold_boot(rproc, false);
+ if (err)
+ return err;
+
+ return stm32_rproc_set_hold_boot(rproc, true);
+}
+
+static int stm32_rproc_stop(struct rproc *rproc)
+{
+ struct stm32_rproc *ddata = rproc->priv;
+ int err;
+
+ err = stm32_rproc_set_hold_boot(rproc, true);
+ if (err)
+ return err;
+
+ err = reset_control_assert(ddata->rst);
+ if (err) {
+ dev_err(&rproc->dev, "failed to assert the reset\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static struct rproc_ops st_rproc_ops = {
+ .start = stm32_rproc_start,
+ .stop = stm32_rproc_stop,
+ .da_to_va = stm32_rproc_da_to_va,
+};
+
+static int stm32_rproc_get_syscon(struct device_node *np, const char *prop,
+ struct stm32_syscon *syscon)
+{
+ int err = 0;
+
+ syscon->map = syscon_regmap_lookup_by_phandle(np, prop);
+ if (IS_ERR(syscon->map)) {
+ err = PTR_ERR(syscon->map);
+ syscon->map = NULL;
+ goto out;
+ }
+
+ err = of_property_read_u32_index(np, prop, 1, &syscon->reg);
+ if (err)
+ goto out;
+
+ err = of_property_read_u32_index(np, prop, 2, &syscon->mask);
+
+out:
+ return err;
+}
+
+static int stm32_rproc_parse_dt(struct device_d *dev, struct stm32_rproc *ddata)
+{
+ struct device_node *np = dev->device_node;
+ struct stm32_syscon tz;
+ unsigned int tzen;
+ int err;
+
+ ddata->rst = reset_control_get(dev, NULL);
+ if (IS_ERR(ddata->rst)) {
+ dev_err(dev, "failed to get mcu reset\n");
+ return PTR_ERR(ddata->rst);
+ }
+
+ /*
+ * if platform is secured the hold boot bit must be written by
+ * smc call and read normally.
+ * if not secure the hold boot bit could be read/write normally
+ */
+ err = stm32_rproc_get_syscon(np, "st,syscfg-tz", &tz);
+ if (err) {
+ dev_err(dev, "failed to get tz syscfg\n");
+ return err;
+ }
+
+ err = regmap_read(tz.map, tz.reg, &tzen);
+ if (err) {
+ dev_err(dev, "failed to read tzen\n");
+ return err;
+ }
+ ddata->secured_soc = tzen & tz.mask;
+
+ err = stm32_rproc_get_syscon(np, "st,syscfg-holdboot",
+ &ddata->hold_boot);
+ if (err) {
+ dev_err(dev, "failed to get hold boot\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int stm32_rproc_probe(struct device_d *dev)
+{
+ struct rproc *rproc;
+ int ret;
+
+ rproc = rproc_alloc(dev, dev_name(dev), &st_rproc_ops,
+ sizeof(struct stm32_rproc));
+ if (!rproc)
+ return -ENOMEM;
+
+ ret = stm32_rproc_parse_dt(dev, rproc->priv);
+ if (ret)
+ return ret;
+
+ return rproc_add(rproc);
+}
+
+static const struct of_device_id stm32_rproc_of_match[] = {
+ { .compatible = "st,stm32mp1-m4" },
+ { /* sentinel */ },
+};
+
+static struct driver_d stm32_rproc_driver = {
+ .name = "stm32-rproc",
+ .probe = stm32_rproc_probe,
+ .of_compatible = DRV_OF_COMPAT(stm32_rproc_of_match),
+};
+device_platform_driver(stm32_rproc_driver);
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 7a411d4..bd02fe2 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -97,6 +97,14 @@ config DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS
help
Say Y here if you are using OMAP extensions to NS16550
+config DRIVER_SERIAL_NS16550_PCI
+ depends on DRIVER_SERIAL_NS16550
+ depends on PCI
+ default y
+ bool "NS16550 PCI serial driver"
+ help
+ Enable this to get support for NS16550 UARTs connected over PCI
+
config DRIVER_SERIAL_PL010
depends on ARCH_EP93XX
default y
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 6f9e3b7..8a2abbb 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_DRIVER_SERIAL_LINUX_CONSOLE) += linux_console.o
obj-$(CONFIG_DRIVER_SERIAL_MPC5XXX) += serial_mpc5xxx.o
obj-$(CONFIG_DRIVER_SERIAL_CLPS711X) += serial_clps711x.o
obj-$(CONFIG_DRIVER_SERIAL_NS16550) += serial_ns16550.o
+obj-$(CONFIG_DRIVER_SERIAL_NS16550_PCI) += serial_ns16550_pci.o
obj-$(CONFIG_DRIVER_SERIAL_PL010) += serial_pl010.o
obj-$(CONFIG_DRIVER_SERIAL_S3C) += serial_s3c.o
obj-$(CONFIG_DRIVER_SERIAL_STM32) += serial_stm32.o
diff --git a/drivers/serial/serial_ns16550_pci.c b/drivers/serial/serial_ns16550_pci.c
new file mode 100644
index 0000000..d4b5bd8
--- /dev/null
+++ b/drivers/serial/serial_ns16550_pci.c
@@ -0,0 +1,5311 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Probe module for 8250/16550-type PCI serial ports.
+ *
+ * Based on Linux drivers/tty/serial/8250_pci.c
+ * Itself based on Linux drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ * Copyright (C) 2001 Russell King, All Rights Reserved.
+ * Copyright (C) 2019 Ahmad Fatoum, Pengutronix
+ */
+
+#include <common.h>
+#include <init.h>
+#include <linux/pci.h>
+#include <driver.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+
+#include <platform_data/serial-ns16550.h>
+#include "serial_ns16550.h"
+
+#define PCI_NUM_BAR_RESOURCES 6
+
+#define FL_BASE_MASK 0x0007
+#define FL_BASE0 0x0000
+#define FL_BASE1 0x0001
+#define FL_BASE2 0x0002
+#define FL_BASE3 0x0003
+#define FL_BASE4 0x0004
+#define FL_GET_BASE(x) (x & FL_BASE_MASK)
+
+/* Use successive BARs (PCI base address registers),
+ else use offset into some specified BAR */
+#define FL_BASE_BARS 0x0008
+
+/* do not assign an irq; no-op, we use no irqs */
+#define FL_NOIRQ 0x0080
+
+/* Use the Base address register size to cap number of ports */
+#define FL_REGION_SZ_CAP 0x0100
+
+
+struct uart_8250_port {
+ struct NS16550_plat *pdata;
+ struct resource resource;
+
+};
+
+struct pciserial_board {
+ unsigned int flags;
+ unsigned int num_ports;
+ unsigned int base_baud;
+ unsigned int uart_offset;
+ unsigned int reg_shift;
+ unsigned int first_offset;
+};
+
+struct serial_private;
+
+/*
+ * init function returns:
+ * > 0 - number of ports
+ * = 0 - use board->num_ports
+ * < 0 - error
+ */
+struct pci_serial_quirk {
+ u32 vendor;
+ u32 device;
+ u32 subvendor;
+ u32 subdevice;
+ int (*probe)(struct pci_dev *dev);
+ int (*init)(struct pci_dev *dev);
+ int (*setup)(struct serial_private *,
+ const struct pciserial_board *,
+ struct uart_8250_port *, int);
+ void (*exit)(struct pci_dev *dev);
+};
+
+#define PCI_NUM_BAR_RESOURCES 6
+
+struct serial_private {
+ struct pci_dev *dev;
+ unsigned int nr;
+ struct pci_serial_quirk *quirk;
+ const struct pciserial_board *board;
+ void *private_data; /* for use by quirks */
+};
+
+static int pci_default_setup(struct serial_private*,
+ const struct pciserial_board*, struct uart_8250_port *, int);
+
+static void moan_device(const char *str, struct pci_dev *dev)
+{
+ dev_err(&dev->dev,
+ "%s: %s\n"
+ "Please send the output of lspci -vv, this\n"
+ "message (0x%04x,0x%04x,0x%04x,0x%04x), the\n"
+ "manufacturer and name of serial board or\n"
+ "modem board to <linux-serial@vger.kernel.org>.\n",
+ dev_name(&dev->dev), str, dev->vendor, dev->device,
+ dev->subsystem_vendor, dev->subsystem_device);
+}
+
+static int
+setup_port(struct serial_private *priv, struct uart_8250_port *port,
+ int bar, int offset, int regshift)
+{
+ struct pci_dev *dev = priv->dev;
+
+ if (bar >= PCI_NUM_BAR_RESOURCES)
+ return -EINVAL;
+
+ port->resource.flags = IORESOURCE_MEM_8BIT;
+
+ if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) {
+ if (!pci_iomap(dev, bar))
+ return -ENOMEM;
+
+ port->resource.flags |= IORESOURCE_MEM;
+ } else {
+ port->resource.flags |= IORESOURCE_IO;
+ }
+
+ port->resource.start = pci_resource_start(dev, bar) + offset;
+ port->resource.end = port->resource.start + pci_resource_len(dev, bar) - 1;
+
+ port->pdata->shift = regshift;
+
+ return 0;
+}
+
+/*
+ * ADDI-DATA GmbH communication cards <info@addi-data.com>
+ */
+static int addidata_apci7800_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ unsigned int bar = 0, offset = board->first_offset;
+ bar = FL_GET_BASE(board->flags);
+
+ if (idx < 2) {
+ offset += idx * board->uart_offset;
+ } else if ((idx >= 2) && (idx < 4)) {
+ bar += 1;
+ offset += ((idx - 2) * board->uart_offset);
+ } else if ((idx >= 4) && (idx < 6)) {
+ bar += 2;
+ offset += ((idx - 4) * board->uart_offset);
+ } else if (idx >= 6) {
+ bar += 3;
+ offset += ((idx - 6) * board->uart_offset);
+ }
+
+ return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+/*
+ * AFAVLAB uses a different mixture of BARs and offsets
+ * Not that ugly ;) -- HW
+ */
+static int
+afavlab_setup(struct serial_private *priv, const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ unsigned int bar, offset = board->first_offset;
+
+ bar = FL_GET_BASE(board->flags);
+ if (idx < 4)
+ bar += idx;
+ else {
+ bar = 4;
+ offset += (idx - 4) * board->uart_offset;
+ }
+
+ return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+/*
+ * HP's Remote Management Console. The Diva chip came in several
+ * different versions. N-class, L2000 and A500 have two Diva chips, each
+ * with 3 UARTs (the third UART on the second chip is unused). Superdome
+ * and Keystone have one Diva chip with 3 UARTs. Some later machines have
+ * one Diva chip, but it has been expanded to 5 UARTs.
+ */
+static int pci_hp_diva_init(struct pci_dev *dev)
+{
+ int rc = 0;
+
+ switch (dev->subsystem_device) {
+ case PCI_DEVICE_ID_HP_DIVA_TOSCA1:
+ case PCI_DEVICE_ID_HP_DIVA_HALFDOME:
+ case PCI_DEVICE_ID_HP_DIVA_KEYSTONE:
+ case PCI_DEVICE_ID_HP_DIVA_EVEREST:
+ rc = 3;
+ break;
+ case PCI_DEVICE_ID_HP_DIVA_TOSCA2:
+ rc = 2;
+ break;
+ case PCI_DEVICE_ID_HP_DIVA_MAESTRO:
+ rc = 4;
+ break;
+ case PCI_DEVICE_ID_HP_DIVA_POWERBAR:
+ case PCI_DEVICE_ID_HP_DIVA_HURRICANE:
+ rc = 1;
+ break;
+ }
+
+ return rc;
+}
+
+/*
+ * HP's Diva chip puts the 4th/5th serial port further out, and
+ * some serial ports are supposed to be hidden on certain models.
+ */
+static int
+pci_hp_diva_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ unsigned int offset = board->first_offset;
+ unsigned int bar = FL_GET_BASE(board->flags);
+
+ switch (priv->dev->subsystem_device) {
+ case PCI_DEVICE_ID_HP_DIVA_MAESTRO:
+ if (idx == 3)
+ idx++;
+ break;
+ case PCI_DEVICE_ID_HP_DIVA_EVEREST:
+ if (idx > 0)
+ idx++;
+ if (idx > 2)
+ idx++;
+ break;
+ }
+ if (idx > 2)
+ offset = 0x18;
+
+ offset += idx * board->uart_offset;
+
+ return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+/*
+ * Added for EKF Intel i960 serial boards
+ */
+static int pci_inteli960ni_init(struct pci_dev *dev)
+{
+ u32 oldval;
+
+ if (!(dev->subsystem_device & 0x1000))
+ return -ENODEV;
+
+ /* is firmware started? */
+ pci_read_config_dword(dev, 0x44, &oldval);
+ if (oldval == 0x00001000L) { /* RESET value */
+ dev_dbg(&dev->dev, "Local i960 firmware missing\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+/*
+ * Some PCI serial cards using the PLX 9050 PCI interface chip require
+ * that the card interrupt be explicitly enabled or disabled. This
+ * seems to be mainly needed on card using the PLX which also use I/O
+ * mapped memory.
+ */
+static int pci_plx9050_init(struct pci_dev *dev)
+{
+ void __iomem *p;
+
+ if ((pci_resource_flags(dev, 0) & IORESOURCE_MEM) == 0) {
+ moan_device("no memory in bar 0", dev);
+ return 0;
+ }
+
+ /*
+ * disable interrupts
+ */
+ p = pci_iomap(dev, 0);
+ if (p == NULL)
+ return -ENOMEM;
+
+ writel(0, p + 0x4c);
+
+ /*
+ * Read the register back to ensure that it took effect.
+ */
+ readl(p + 0x4c);
+
+ return 0;
+}
+
+#define NI8420_INT_ENABLE_REG 0x38
+#define NI8420_INT_ENABLE_BIT 0x2000
+
+/* MITE registers */
+#define MITE_IOWBSR1 0xc4
+#define MITE_IOWCR1 0xf4
+#define MITE_LCIMR1 0x08
+#define MITE_LCIMR2 0x10
+
+#define MITE_LCIMR2_CLR_CPU_IE (1 << 30)
+
+/* SBS Technologies Inc. PMC-OCTPRO and P-OCTAL cards */
+static int
+sbs_setup(struct serial_private *priv, const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ unsigned int bar, offset = board->first_offset;
+
+ bar = 0;
+
+ if (idx < 4) {
+ /* first four channels map to 0, 0x100, 0x200, 0x300 */
+ offset += idx * board->uart_offset;
+ } else if (idx < 8) {
+ /* last four channels map to 0x1000, 0x1100, 0x1200, 0x1300 */
+ offset += idx * board->uart_offset + 0xC00;
+ } else /* we have only 8 ports on PMC-OCTALPRO */
+ return 1;
+
+ return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+/*
+* This does initialization for PMC OCTALPRO cards:
+* maps the device memory, resets the UARTs (needed, bc
+* if the module is removed and inserted again, the card
+* is in the sleep mode) and enables global interrupt.
+*/
+
+/* global control register offset for SBS PMC-OctalPro */
+#define OCT_REG_CR_OFF 0x500
+
+static int sbs_init(struct pci_dev *dev)
+{
+ u8 __iomem *p;
+
+ p = pci_iomap(dev, 0);
+
+ if (p == NULL)
+ return -ENOMEM;
+ /* Set bit-4 Control Register (UART RESET) in to reset the uarts */
+ writeb(0x10, p + OCT_REG_CR_OFF);
+ udelay(50);
+ writeb(0x0, p + OCT_REG_CR_OFF);
+
+ /* Clear especially bit-2 (INTENABLE) of Control Register */
+ writeb(0, p + OCT_REG_CR_OFF);
+
+ return 0;
+}
+
+/*
+ * SIIG serial cards have an PCI interface chip which also controls
+ * the UART clocking frequency. Each UART can be clocked independently
+ * (except cards equipped with 4 UARTs) and initial clocking settings
+ * are stored in the EEPROM chip. It can cause problems because this
+ * version of serial driver doesn't support differently clocked UART's
+ * on single PCI card. To prevent this, initialization functions set
+ * high frequency clocking for all UART's on given card. It is safe (I
+ * hope) because it doesn't touch EEPROM settings to prevent conflicts
+ * with other OSes (like M$ DOS).
+ *
+ * SIIG support added by Andrey Panin <pazke@donpac.ru>, 10/1999
+ *
+ * There is two family of SIIG serial cards with different PCI
+ * interface chip and different configuration methods:
+ * - 10x cards have control registers in IO and/or memory space;
+ * - 20x cards have control registers in standard PCI configuration space.
+ *
+ * Note: all 10x cards have PCI device ids 0x10..
+ * all 20x cards have PCI device ids 0x20..
+ *
+ * There are also Quartet Serial cards which use Oxford Semiconductor
+ * 16954 quad UART PCI chip clocked by 18.432 MHz quartz.
+ *
+ * Note: some SIIG cards are probed by the parport_serial object.
+ */
+
+#define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc)
+#define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8)
+
+static int pci_siig10x_init(struct pci_dev *dev)
+{
+ u16 data;
+ void __iomem *p;
+
+ switch (dev->device & 0xfff8) {
+ case PCI_DEVICE_ID_SIIG_1S_10x: /* 1S */
+ data = 0xffdf;
+ break;
+ case PCI_DEVICE_ID_SIIG_2S_10x: /* 2S, 2S1P */
+ data = 0xf7ff;
+ break;
+ default: /* 1S1P, 4S */
+ data = 0xfffb;
+ break;
+ }
+
+ p = pci_iomap(dev, 0);
+ if (p == NULL)
+ return -ENOMEM;
+
+ writew(readw(p + 0x28) & data, p + 0x28);
+ readw(p + 0x28);
+
+
+ return 0;
+}
+
+#define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc)
+#define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc)
+
+static int pci_siig20x_init(struct pci_dev *dev)
+{
+ u8 data;
+
+ /* Change clock frequency for the first UART. */
+ pci_read_config_byte(dev, 0x6f, &data);
+ pci_write_config_byte(dev, 0x6f, data & 0xef);
+
+ /* If this card has 2 UART, we have to do the same with second UART. */
+ if (((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S_20x) ||
+ ((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S1P_20x)) {
+ pci_read_config_byte(dev, 0x73, &data);
+ pci_write_config_byte(dev, 0x73, data & 0xef);
+ }
+ return 0;
+}
+
+static int pci_siig_init(struct pci_dev *dev)
+{
+ unsigned int type = dev->device & 0xff00;
+
+ if (type == 0x1000)
+ return pci_siig10x_init(dev);
+ else if (type == 0x2000)
+ return pci_siig20x_init(dev);
+
+ moan_device("Unknown SIIG card", dev);
+ return -ENODEV;
+}
+
+static int pci_siig_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ unsigned int bar = FL_GET_BASE(board->flags) + idx, offset = 0;
+
+ if (idx > 3) {
+ bar = 4;
+ offset = (idx - 4) * 8;
+ }
+
+ return setup_port(priv, port, bar, offset, 0);
+}
+
+/*
+ * Timedia has an explosion of boards, and to avoid the PCI table from
+ * growing *huge*, we use this function to collapse some 70 entries
+ * in the PCI table into one, for sanity's and compactness's sake.
+ */
+static const unsigned short timedia_single_port[] = {
+ 0x4025, 0x4027, 0x4028, 0x5025, 0x5027, 0
+};
+
+static const unsigned short timedia_dual_port[] = {
+ 0x0002, 0x4036, 0x4037, 0x4038, 0x4078, 0x4079, 0x4085,
+ 0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079,
+ 0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079,
+ 0x9137, 0x9138, 0x9237, 0x9238, 0xA079, 0xB079, 0xC079,
+ 0xD079, 0
+};
+
+static const unsigned short timedia_quad_port[] = {
+ 0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157,
+ 0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159,
+ 0x9256, 0x9257, 0xA056, 0xA157, 0xA158, 0xA159, 0xB056,
+ 0xB157, 0
+};
+
+static const unsigned short timedia_eight_port[] = {
+ 0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166,
+ 0x9167, 0x9168, 0xA066, 0xA167, 0xA168, 0
+};
+
+static const struct timedia_struct {
+ int num;
+ const unsigned short *ids;
+} timedia_data[] = {
+ { 1, timedia_single_port },
+ { 2, timedia_dual_port },
+ { 4, timedia_quad_port },
+ { 8, timedia_eight_port }
+};
+
+/*
+ * There are nearly 70 different Timedia/SUNIX PCI serial devices. Instead of
+ * listing them individually, this driver merely grabs them all with
+ * PCI_ANY_ID. Some of these devices, however, also feature a parallel port,
+ * and should be left free to be claimed by parport_serial instead.
+ */
+static int pci_timedia_probe(struct pci_dev *dev)
+{
+ /*
+ * Check the third digit of the subdevice ID
+ * (0,2,3,5,6: serial only -- 7,8,9: serial + parallel)
+ */
+ if ((dev->subsystem_device & 0x00f0) >= 0x70) {
+ dev_info(&dev->dev,
+ "ignoring Timedia subdevice %04x for parport_serial\n",
+ dev->subsystem_device);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int pci_timedia_init(struct pci_dev *dev)
+{
+ const unsigned short *ids;
+ int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(timedia_data); i++) {
+ ids = timedia_data[i].ids;
+ for (j = 0; ids[j]; j++)
+ if (dev->subsystem_device == ids[j])
+ return timedia_data[i].num;
+ }
+ return 0;
+}
+
+/*
+ * Timedia/SUNIX uses a mixture of BARs and offsets
+ * Ugh, this is ugly as all hell --- TYT
+ */
+static int
+pci_timedia_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ unsigned int bar = 0, offset = board->first_offset;
+
+ switch (idx) {
+ case 0:
+ bar = 0;
+ break;
+ case 1:
+ offset = board->uart_offset;
+ bar = 0;
+ break;
+ case 2:
+ bar = 1;
+ break;
+ case 3:
+ offset = board->uart_offset;
+ /* FALLTHROUGH */
+ case 4: /* BAR 2 */
+ case 5: /* BAR 3 */
+ case 6: /* BAR 4 */
+ case 7: /* BAR 5 */
+ bar = idx - 2;
+ }
+
+ return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+/*
+ * Some Titan cards are also a little weird
+ */
+static int
+titan_400l_800l_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ unsigned int bar, offset = board->first_offset;
+
+ switch (idx) {
+ case 0:
+ bar = 1;
+ break;
+ case 1:
+ bar = 2;
+ break;
+ default:
+ bar = 4;
+ offset = (idx - 2) * board->uart_offset;
+ }
+
+ return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+static int pci_xircom_init(struct pci_dev *dev)
+{
+ mdelay(100);
+ return 0;
+}
+
+static int pci_ni8420_init(struct pci_dev *dev)
+{
+ void __iomem *p;
+ unsigned int bar = 0;
+
+ if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) {
+ moan_device("no memory in bar", dev);
+ return 0;
+ }
+
+ p = pci_iomap(dev, bar);
+ if (p == NULL)
+ return -ENOMEM;
+
+ /* Disable the CPU Interrupt */
+ writel(readl(p + NI8420_INT_ENABLE_REG) & ~(NI8420_INT_ENABLE_BIT),
+ p + NI8420_INT_ENABLE_REG);
+
+ return 0;
+}
+
+static int pci_ni8430_init(struct pci_dev *dev)
+{
+ return -ENOSYS;
+}
+
+/* UART Port Control Register */
+#define NI16550_PCR_OFFSET 0x0f
+#define NI16550_PCR_RS422 0x00
+#define NI16550_PCR_ECHO_RS485 0x01
+#define NI16550_PCR_DTR_RS485 0x02
+#define NI16550_PCR_AUTO_RS485 0x03
+#define NI16550_PCR_WIRE_MODE_MASK 0x03
+#define NI16550_PCR_TXVR_ENABLE_BIT BIT(3)
+#define NI16550_PCR_RS485_TERMINATION_BIT BIT(6)
+#define NI16550_ACR_DTR_AUTO_DTR (0x2 << 3)
+#define NI16550_ACR_DTR_MANUAL_DTR (0x0 << 3)
+
+static int
+pci_ni8430_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ struct pci_dev *dev = priv->dev;
+ void __iomem *p;
+ unsigned int bar, offset = board->first_offset;
+
+ if (idx >= board->num_ports)
+ return 1;
+
+ bar = FL_GET_BASE(board->flags);
+ offset += idx * board->uart_offset;
+
+ p = pci_iomap(dev, bar);
+ if (!p)
+ return -ENOMEM;
+
+ /* enable the transceiver */
+ writeb(readb(p + offset + NI16550_PCR_OFFSET) | NI16550_PCR_TXVR_ENABLE_BIT,
+ p + offset + NI16550_PCR_OFFSET);
+
+ return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+static int pci_ni8431_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *uart, int idx)
+{
+ return -ENOSYS;
+}
+
+static int pci_netmos_9900_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ unsigned int bar;
+
+ if ((priv->dev->device != PCI_DEVICE_ID_NETMOS_9865) &&
+ (priv->dev->subsystem_device & 0xff00) == 0x3000) {
+ /* netmos apparently orders BARs by datasheet layout, so serial
+ * ports get BARs 0 and 3 (or 1 and 4 for memmapped)
+ */
+ bar = 3 * idx;
+
+ return setup_port(priv, port, bar, 0, board->reg_shift);
+ } else {
+ return pci_default_setup(priv, board, port, idx);
+ }
+}
+
+/* the 99xx series comes with a range of device IDs and a variety
+ * of capabilities:
+ *
+ * 9900 has varying capabilities and can cascade to sub-controllers
+ * (cascading should be purely internal)
+ * 9904 is hardwired with 4 serial ports
+ * 9912 and 9922 are hardwired with 2 serial ports
+ */
+static int pci_netmos_9900_numports(struct pci_dev *dev)
+{
+ unsigned int c = dev->class;
+ unsigned int pi;
+ unsigned short sub_serports;
+
+ pi = c & 0xff;
+
+ if (pi == 2)
+ return 1;
+
+ if ((pi == 0) && (dev->device == PCI_DEVICE_ID_NETMOS_9900)) {
+ /* two possibilities: 0x30ps encodes number of parallel and
+ * serial ports, or 0x1000 indicates *something*. This is not
+ * immediately obvious, since the 2s1p+4s configuration seems
+ * to offer all functionality on functions 0..2, while still
+ * advertising the same function 3 as the 4s+2s1p config.
+ */
+ sub_serports = dev->subsystem_device & 0xf;
+ if (sub_serports > 0)
+ return sub_serports;
+
+ dev_err(&dev->dev,
+ "NetMos/Mostech serial driver ignoring port on ambiguous config.\n");
+ return 0;
+ }
+
+ moan_device("unknown NetMos/Mostech program interface", dev);
+ return 0;
+}
+
+static int pci_netmos_init(struct pci_dev *dev)
+{
+ /* subdevice 0x00PS means <P> parallel, <S> serial */
+ unsigned int num_serial = dev->subsystem_device & 0xf;
+
+ if ((dev->device == PCI_DEVICE_ID_NETMOS_9901) ||
+ (dev->device == PCI_DEVICE_ID_NETMOS_9865))
+ return 0;
+
+ if (dev->subsystem_vendor == PCI_VENDOR_ID_IBM &&
+ dev->subsystem_device == 0x0299)
+ return 0;
+
+ switch (dev->device) { /* FALLTHROUGH on all */
+ case PCI_DEVICE_ID_NETMOS_9904:
+ case PCI_DEVICE_ID_NETMOS_9912:
+ case PCI_DEVICE_ID_NETMOS_9922:
+ case PCI_DEVICE_ID_NETMOS_9900:
+ num_serial = pci_netmos_9900_numports(dev);
+ break;
+
+ default:
+ break;
+ }
+
+ if (num_serial == 0) {
+ moan_device("unknown NetMos/Mostech device", dev);
+ return -ENODEV;
+ }
+
+ return num_serial;
+}
+
+/*
+ * These chips are available with optionally one parallel port and up to
+ * two serial ports. Unfortunately they all have the same product id.
+ *
+ * Basic configuration is done over a region of 32 I/O ports. The base
+ * ioport is called INTA or INTC, depending on docs/other drivers.
+ *
+ * The region of the 32 I/O ports is configured in POSIO0R...
+ */
+
+/* registers */
+#define ITE_887x_MISCR 0x9c
+#define ITE_887x_INTCBAR 0x78
+#define ITE_887x_UARTBAR 0x7c
+#define ITE_887x_PS0BAR 0x10
+#define ITE_887x_POSIO0 0x60
+
+/* I/O space size */
+#define ITE_887x_IOSIZE 32
+/* I/O space size (bits 26-24; 8 bytes = 011b) */
+#define ITE_887x_POSIO_IOSIZE_8 (3 << 24)
+/* I/O space size (bits 26-24; 32 bytes = 101b) */
+#define ITE_887x_POSIO_IOSIZE_32 (5 << 24)
+/* Decoding speed (1 = slow, 2 = medium, 3 = fast) */
+#define ITE_887x_POSIO_SPEED (3 << 29)
+/* enable IO_Space bit */
+#define ITE_887x_POSIO_ENABLE (1 << 31)
+
+static int pci_ite887x_init(struct pci_dev *dev)
+{
+ struct serial_private *priv;
+ /* inta_addr are the configuration addresses of the ITE */
+ static const short inta_addr[] = { 0x2a0, 0x2c0, 0x220, 0x240, 0x1e0,
+ 0x200, 0x280, 0 };
+ int ret, i, type;
+ struct resource *iobase = NULL;
+ u32 miscr, uartbar, ioport;
+
+ /* search for the base-ioport */
+ i = 0;
+ while (inta_addr[i] && iobase == NULL) {
+ iobase = request_ioport_region("ite887x",
+ inta_addr[i],
+ inta_addr[i] + ITE_887x_IOSIZE - 1);
+ if (!IS_ERR(iobase)) {
+ /* write POSIO0R - speed | size | ioport */
+ pci_write_config_dword(dev, ITE_887x_POSIO0,
+ ITE_887x_POSIO_ENABLE | ITE_887x_POSIO_SPEED |
+ ITE_887x_POSIO_IOSIZE_32 | inta_addr[i]);
+ /* write INTCBAR - ioport */
+ pci_write_config_dword(dev, ITE_887x_INTCBAR,
+ inta_addr[i]);
+ ret = inb(inta_addr[i]);
+ if (ret != 0xff) {
+ /* ioport connected */
+ break;
+ }
+ release_region(iobase);
+ iobase = NULL;
+ }
+ i++;
+ }
+
+ if (!inta_addr[i]) {
+ dev_err(&dev->dev, "ite887x: could not find iobase\n");
+ return -ENODEV;
+ }
+
+ /* start of undocumented type checking (see parport_pc.c) */
+ type = inb(iobase->start + 0x18) & 0x0f;
+
+ switch (type) {
+ case 0x2: /* ITE8871 (1P) */
+ case 0xa: /* ITE8875 (1P) */
+ ret = 0;
+ break;
+ case 0xe: /* ITE8872 (2S1P) */
+ ret = 2;
+ break;
+ case 0x6: /* ITE8873 (1S) */
+ ret = 1;
+ break;
+ case 0x8: /* ITE8874 (2S) */
+ ret = 2;
+ break;
+ default:
+ moan_device("Unknown ITE887x", dev);
+ ret = -ENODEV;
+ }
+
+ /* configure all serial ports */
+ for (i = 0; i < ret; i++) {
+ /* read the I/O port from the device */
+ pci_read_config_dword(dev, ITE_887x_PS0BAR + (0x4 * (i + 1)),
+ &ioport);
+ ioport &= 0x0000FF00; /* the actual base address */
+ pci_write_config_dword(dev, ITE_887x_POSIO0 + (0x4 * (i + 1)),
+ ITE_887x_POSIO_ENABLE | ITE_887x_POSIO_SPEED |
+ ITE_887x_POSIO_IOSIZE_8 | ioport);
+
+ /* write the ioport to the UARTBAR */
+ pci_read_config_dword(dev, ITE_887x_UARTBAR, &uartbar);
+ uartbar &= ~(0xffff << (16 * i)); /* clear half the reg */
+ uartbar |= (ioport << (16 * i)); /* set the ioport */
+ pci_write_config_dword(dev, ITE_887x_UARTBAR, uartbar);
+
+ /* get current config */
+ pci_read_config_dword(dev, ITE_887x_MISCR, &miscr);
+ /* disable interrupts (UARTx_Routing[3:0]) */
+ miscr &= ~(0xf << (12 - 4 * i));
+ /* activate the UART (UARTx_En) */
+ miscr |= 1 << (23 - i);
+ /* write new config with activated UART */
+ pci_write_config_dword(dev, ITE_887x_MISCR, miscr);
+ }
+
+ if (ret <= 0) {
+ /* the device has no UARTs if we get here */
+ release_region(iobase);
+ }
+
+ priv = dev->dev.priv;
+ priv->private_data = iobase;
+
+ return ret;
+}
+
+static void pci_ite887x_exit(struct pci_dev *dev)
+{
+ struct serial_private *priv;
+ u32 ioport;
+ /* the ioport is bit 0-15 in POSIO0R */
+ pci_read_config_dword(dev, ITE_887x_POSIO0, &ioport);
+ ioport &= 0xffff;
+
+ priv = dev->dev.priv;
+ if (priv->private_data)
+ release_region(priv->private_data);
+}
+
+/*
+ * EndRun Technologies.
+ * Determine the number of ports available on the device.
+ */
+#define PCI_VENDOR_ID_ENDRUN 0x7401
+#define PCI_DEVICE_ID_ENDRUN_1588 0xe100
+
+static int pci_endrun_init(struct pci_dev *dev)
+{
+ u8 __iomem *p;
+ unsigned long deviceID;
+ unsigned int number_uarts = 0;
+
+ /* EndRun device is all 0xexxx */
+ if (dev->vendor == PCI_VENDOR_ID_ENDRUN &&
+ (dev->device & 0xf000) != 0xe000)
+ return 0;
+
+ p = pci_iomap(dev, 0);
+ if (p == NULL)
+ return -ENOMEM;
+
+ deviceID = ioread32(p);
+ /* EndRun device */
+ if (deviceID == 0x07000200) {
+ number_uarts = ioread8(p + 4);
+ dev_dbg(&dev->dev,
+ "%d ports detected on EndRun PCI Express device\n",
+ number_uarts);
+ }
+
+ return number_uarts;
+}
+
+/*
+ * Oxford Semiconductor Inc.
+ * Check that device is part of the Tornado range of devices, then determine
+ * the number of ports available on the device.
+ */
+static int pci_oxsemi_tornado_init(struct pci_dev *dev)
+{
+ u8 __iomem *p;
+ unsigned long deviceID;
+ unsigned int number_uarts = 0;
+
+ /* OxSemi Tornado devices are all 0xCxxx */
+ if (dev->vendor == PCI_VENDOR_ID_OXSEMI &&
+ (dev->device & 0xF000) != 0xC000)
+ return 0;
+
+ p = pci_iomap(dev, 0);
+ if (p == NULL)
+ return -ENOMEM;
+
+ deviceID = ioread32(p);
+ /* Tornado device */
+ if (deviceID == 0x07000200) {
+ number_uarts = ioread8(p + 4);
+ dev_dbg(&dev->dev,
+ "%d ports detected on Oxford PCI Express device\n",
+ number_uarts);
+ }
+
+ return number_uarts;
+}
+
+static int pci_asix_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return -ENOSYS;
+}
+
+/* Quatech devices have their own extra interface features */
+
+struct quatech_feature {
+ u16 devid;
+ bool amcc;
+};
+
+#define QPCR_TEST_FOR1 0x3F
+#define QPCR_TEST_GET1 0x00
+#define QPCR_TEST_FOR2 0x40
+#define QPCR_TEST_GET2 0x40
+#define QPCR_TEST_FOR3 0x80
+#define QPCR_TEST_GET3 0x40
+#define QPCR_TEST_FOR4 0xC0
+#define QPCR_TEST_GET4 0x80
+
+#define QOPR_CLOCK_X1 0x0000
+#define QOPR_CLOCK_X2 0x0001
+#define QOPR_CLOCK_X4 0x0002
+#define QOPR_CLOCK_X8 0x0003
+#define QOPR_CLOCK_RATE_MASK 0x0003
+
+
+static struct quatech_feature quatech_cards[] = {
+ { PCI_DEVICE_ID_QUATECH_QSC100, 1 },
+ { PCI_DEVICE_ID_QUATECH_DSC100, 1 },
+ { PCI_DEVICE_ID_QUATECH_DSC100E, 0 },
+ { PCI_DEVICE_ID_QUATECH_DSC200, 1 },
+ { PCI_DEVICE_ID_QUATECH_DSC200E, 0 },
+ { PCI_DEVICE_ID_QUATECH_ESC100D, 1 },
+ { PCI_DEVICE_ID_QUATECH_ESC100M, 1 },
+ { PCI_DEVICE_ID_QUATECH_QSCP100, 1 },
+ { PCI_DEVICE_ID_QUATECH_DSCP100, 1 },
+ { PCI_DEVICE_ID_QUATECH_QSCP200, 1 },
+ { PCI_DEVICE_ID_QUATECH_DSCP200, 1 },
+ { PCI_DEVICE_ID_QUATECH_ESCLP100, 0 },
+ { PCI_DEVICE_ID_QUATECH_QSCLP100, 0 },
+ { PCI_DEVICE_ID_QUATECH_DSCLP100, 0 },
+ { PCI_DEVICE_ID_QUATECH_SSCLP100, 0 },
+ { PCI_DEVICE_ID_QUATECH_QSCLP200, 0 },
+ { PCI_DEVICE_ID_QUATECH_DSCLP200, 0 },
+ { PCI_DEVICE_ID_QUATECH_SSCLP200, 0 },
+ { PCI_DEVICE_ID_QUATECH_SPPXP_100, 0 },
+ { 0, }
+};
+
+static int pci_quatech_amcc(u16 devid)
+{
+ struct quatech_feature *qf = &quatech_cards[0];
+ while (qf->devid) {
+ if (qf->devid == devid)
+ return qf->amcc;
+ qf++;
+ }
+ pr_err("quatech: unknown port type '0x%04X'.\n", devid);
+ return 0;
+};
+
+static int pci_quatech_rqopr(struct uart_8250_port *port)
+{
+ unsigned long base = port->resource.start;
+ u8 LCR, val;
+
+ LCR = inb(base + lcr);
+ outb(0xBF, base + lcr);
+ val = inb(base + scr);
+ outb(LCR, base + lcr);
+ return val;
+}
+
+static void pci_quatech_wqopr(struct uart_8250_port *port, u8 qopr)
+{
+ unsigned long base = port->resource.start;
+ u8 LCR;
+
+ LCR = inb(base + lcr);
+ outb(0xBF, base + lcr);
+ inb(base + scr);
+ outb(qopr, base + scr);
+ outb(LCR, base + lcr);
+}
+
+static int pci_quatech_rqmcr(struct uart_8250_port *port)
+{
+ unsigned long base = port->resource.start;
+ u8 LCR, val, qmcr;
+
+ LCR = inb(base + lcr);
+ outb(0xBF, base + lcr);
+ val = inb(base + scr);
+ outb(val | 0x10, base + scr);
+ qmcr = inb(base + mcr);
+ outb(val, base + scr);
+ outb(LCR, base + lcr);
+
+ return qmcr;
+}
+
+static void pci_quatech_wqmcr(struct uart_8250_port *port, u8 qmcr)
+{
+ unsigned long base = port->resource.start;
+ u8 LCR, val;
+
+ LCR = inb(base + lcr);
+ outb(0xBF, base + lcr);
+ val = inb(base + scr);
+ outb(val | 0x10, base + scr);
+ outb(qmcr, base + mcr);
+ outb(val, base + scr);
+ outb(LCR, base + lcr);
+}
+
+static int pci_quatech_has_qmcr(struct uart_8250_port *port)
+{
+ unsigned long base = port->resource.start;
+ u8 LCR, val;
+
+ LCR = inb(base + lcr);
+ outb(0xBF, base + lcr);
+ val = inb(base + scr);
+ if (val & 0x20) {
+ outb(0x80, lcr);
+ if (!(inb(scr) & 0x20)) {
+ outb(LCR, base + lcr);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int pci_quatech_test(struct uart_8250_port *port)
+{
+ u8 reg, qopr;
+
+ qopr = pci_quatech_rqopr(port);
+ pci_quatech_wqopr(port, qopr & QPCR_TEST_FOR1);
+ reg = pci_quatech_rqopr(port) & 0xC0;
+ if (reg != QPCR_TEST_GET1)
+ return -EINVAL;
+ pci_quatech_wqopr(port, (qopr & QPCR_TEST_FOR1)|QPCR_TEST_FOR2);
+ reg = pci_quatech_rqopr(port) & 0xC0;
+ if (reg != QPCR_TEST_GET2)
+ return -EINVAL;
+ pci_quatech_wqopr(port, (qopr & QPCR_TEST_FOR1)|QPCR_TEST_FOR3);
+ reg = pci_quatech_rqopr(port) & 0xC0;
+ if (reg != QPCR_TEST_GET3)
+ return -EINVAL;
+ pci_quatech_wqopr(port, (qopr & QPCR_TEST_FOR1)|QPCR_TEST_FOR4);
+ reg = pci_quatech_rqopr(port) & 0xC0;
+ if (reg != QPCR_TEST_GET4)
+ return -EINVAL;
+
+ pci_quatech_wqopr(port, qopr);
+ return 0;
+}
+
+static int pci_quatech_clock(struct uart_8250_port *port)
+{
+ u8 qopr, reg, set;
+ unsigned long clock;
+
+ if (pci_quatech_test(port) < 0)
+ return 1843200;
+
+ qopr = pci_quatech_rqopr(port);
+
+ pci_quatech_wqopr(port, qopr & ~QOPR_CLOCK_X8);
+ reg = pci_quatech_rqopr(port);
+ if (reg & QOPR_CLOCK_X8) {
+ clock = 1843200;
+ goto out;
+ }
+ pci_quatech_wqopr(port, qopr | QOPR_CLOCK_X8);
+ reg = pci_quatech_rqopr(port);
+ if (!(reg & QOPR_CLOCK_X8)) {
+ clock = 1843200;
+ goto out;
+ }
+ reg &= QOPR_CLOCK_X8;
+ if (reg == QOPR_CLOCK_X2) {
+ clock = 3685400;
+ set = QOPR_CLOCK_X2;
+ } else if (reg == QOPR_CLOCK_X4) {
+ clock = 7372800;
+ set = QOPR_CLOCK_X4;
+ } else if (reg == QOPR_CLOCK_X8) {
+ clock = 14745600;
+ set = QOPR_CLOCK_X8;
+ } else {
+ clock = 1843200;
+ set = QOPR_CLOCK_X1;
+ }
+ qopr &= ~QOPR_CLOCK_RATE_MASK;
+ qopr |= set;
+
+out:
+ pci_quatech_wqopr(port, qopr);
+ return clock;
+}
+
+static int pci_quatech_rs422(struct uart_8250_port *port)
+{
+ u8 qmcr;
+ int rs422 = 0;
+
+ if (!pci_quatech_has_qmcr(port))
+ return 0;
+ qmcr = pci_quatech_rqmcr(port);
+ pci_quatech_wqmcr(port, 0xFF);
+ if (pci_quatech_rqmcr(port))
+ rs422 = 1;
+ pci_quatech_wqmcr(port, qmcr);
+ return rs422;
+}
+
+static int pci_quatech_init(struct pci_dev *dev)
+{
+ if (pci_quatech_amcc(dev->device)) {
+ unsigned long base = pci_resource_start(dev, 0);
+ if (base) {
+ u32 tmp;
+
+ outl(inl(base + 0x38) | 0x00002000, base + 0x38);
+ tmp = inl(base + 0x3c);
+ outl(tmp | 0x01000000, base + 0x3c);
+ outl(tmp &= ~0x01000000, base + 0x3c);
+ }
+ }
+ return 0;
+}
+
+static int pci_quatech_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ /* Needed by pci_quatech calls below */
+ port->resource.start = pci_resource_start(priv->dev, FL_GET_BASE(board->flags));
+ /* Set up the clocking */
+ port->pdata->clock = pci_quatech_clock(port);
+ /* For now just warn about RS422 */
+ if (pci_quatech_rs422(port))
+ pr_warn("quatech: software control of RS422 features not currently supported.\n");
+ return pci_default_setup(priv, board, port, idx);
+}
+
+static int pci_default_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ unsigned int bar, offset = board->first_offset, maxnr;
+
+ bar = FL_GET_BASE(board->flags);
+ if (board->flags & FL_BASE_BARS)
+ bar += idx;
+ else
+ offset += idx * board->uart_offset;
+
+ maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >>
+ (board->reg_shift + 3);
+
+ if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
+ return 1;
+
+ return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+static int pci_pericom_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return -ENOSYS;
+}
+
+static int pci_pericom_setup_four_at_eight(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return -ENOSYS;
+}
+
+static int
+ce4100_serial_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return -ENOSYS;
+}
+
+static int
+pci_omegapci_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return setup_port(priv, port, 2, idx * 8, 0);
+}
+
+static int
+pci_brcm_trumanage_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return -ENOSYS;
+}
+
+/* RTS will control by MCR if this bit is 0 */
+#define FINTEK_RTS_CONTROL_BY_HW BIT(4)
+/* only worked with FINTEK_RTS_CONTROL_BY_HW on */
+#define FINTEK_RTS_INVERT BIT(5)
+
+static int pci_fintek_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ struct pci_dev *pdev = priv->dev;
+ u8 config_base;
+ u16 iobase;
+
+ config_base = 0x40 + 0x08 * idx;
+
+ /* Get the io address from configuration space */
+ pci_read_config_word(pdev, config_base + 4, &iobase);
+
+ dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%x", __func__, idx, iobase);
+
+ port->resource.flags = IORESOURCE_IO;
+ port->resource.start = iobase;
+ port->resource.end = iobase + 8 - 1;
+
+ return 0;
+}
+
+static int pci_fintek_init(struct pci_dev *dev)
+{
+ unsigned long iobase;
+ u32 max_port, i;
+ resource_size_t bar_data[3];
+ u8 config_base;
+
+ if (!(pci_resource_flags(dev, 5) & IORESOURCE_IO) ||
+ !(pci_resource_flags(dev, 4) & IORESOURCE_IO) ||
+ !(pci_resource_flags(dev, 3) & IORESOURCE_IO))
+ return -ENODEV;
+
+ switch (dev->device) {
+ case 0x1104: /* 4 ports */
+ case 0x1108: /* 8 ports */
+ max_port = dev->device & 0xff;
+ break;
+ case 0x1112: /* 12 ports */
+ max_port = 12;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Get the io address dispatch from the BIOS */
+ bar_data[0] = pci_resource_start(dev, 5);
+ bar_data[1] = pci_resource_start(dev, 4);
+ bar_data[2] = pci_resource_start(dev, 3);
+
+ for (i = 0; i < max_port; ++i) {
+ /* UART0 configuration offset start from 0x40 */
+ config_base = 0x40 + 0x08 * i;
+
+ /* Calculate Real IO Port */
+ iobase = (bar_data[i / 4] & 0xffffffe0) + (i % 4) * 8;
+
+ /* Enable UART I/O port */
+ pci_write_config_byte(dev, config_base + 0x00, 0x01);
+
+ /* Select 128-byte FIFO and 8x FIFO threshold */
+ pci_write_config_byte(dev, config_base + 0x01, 0x33);
+
+ /* LSB UART */
+ pci_write_config_byte(dev, config_base + 0x04,
+ (u8)(iobase & 0xff));
+
+ /* MSB UART */
+ pci_write_config_byte(dev, config_base + 0x05,
+ (u8)((iobase & 0xff00) >> 8));
+
+ /* First init without port data
+ * force init to RS232 Mode
+ */
+ pci_write_config_byte(dev, config_base + 0x07, 0x01);
+ }
+
+ return max_port;
+}
+
+static int pci_fintek_f815xxa_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return -ENOSYS;
+}
+
+static int pci_fintek_f815xxa_init(struct pci_dev *dev)
+{
+ u32 max_port, i;
+ int config_base;
+
+ if (!(pci_resource_flags(dev, 0) & IORESOURCE_MEM))
+ return -ENODEV;
+
+ switch (dev->device) {
+ case 0x1204: /* 4 ports */
+ case 0x1208: /* 8 ports */
+ max_port = dev->device & 0xff;
+ break;
+ case 0x1212: /* 12 ports */
+ max_port = 12;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Set to mmio decode */
+ pci_write_config_byte(dev, 0x209, 0x40);
+
+ for (i = 0; i < max_port; ++i) {
+ /* UART0 configuration offset start from 0x2A0 */
+ config_base = 0x2A0 + 0x08 * i;
+
+ /* Select 128-byte FIFO and 8x FIFO threshold */
+ pci_write_config_byte(dev, config_base + 0x01, 0x33);
+
+ /* Enable UART I/O port */
+ pci_write_config_byte(dev, config_base + 0, 0x01);
+ }
+
+ return max_port;
+}
+
+static int skip_tx_en_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return -ENOSYS;
+}
+
+static int kt_serial_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return -ENOSYS;
+}
+
+static int
+pci_wch_ch353_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return -ENOSYS;
+}
+
+static int
+pci_wch_ch355_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return -ENOSYS;
+}
+
+static int
+pci_wch_ch38x_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return -ENOSYS;
+}
+
+static int
+pci_sunix_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return -ENOSYS;
+}
+
+static int
+pci_moxa_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ unsigned int bar = FL_GET_BASE(board->flags);
+ int offset;
+
+ if (board->num_ports == 4 && idx == 3)
+ offset = 7 * board->uart_offset;
+ else
+ offset = idx * board->uart_offset;
+
+ return setup_port(priv, port, bar, offset, 0);
+}
+
+#define PCI_VENDOR_ID_SBSMODULARIO 0x124B
+#define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B
+#define PCI_DEVICE_ID_OCTPRO 0x0001
+#define PCI_SUBDEVICE_ID_OCTPRO232 0x0108
+#define PCI_SUBDEVICE_ID_OCTPRO422 0x0208
+#define PCI_SUBDEVICE_ID_POCTAL232 0x0308
+#define PCI_SUBDEVICE_ID_POCTAL422 0x0408
+#define PCI_SUBDEVICE_ID_SIIG_DUAL_00 0x2500
+#define PCI_SUBDEVICE_ID_SIIG_DUAL_30 0x2530
+#define PCI_VENDOR_ID_ADVANTECH 0x13fe
+#define PCI_DEVICE_ID_INTEL_CE4100_UART 0x2e66
+#define PCI_DEVICE_ID_ADVANTECH_PCI3620 0x3620
+#define PCI_DEVICE_ID_ADVANTECH_PCI3618 0x3618
+#define PCI_DEVICE_ID_ADVANTECH_PCIf618 0xf618
+#define PCI_DEVICE_ID_TITAN_200I 0x8028
+#define PCI_DEVICE_ID_TITAN_400I 0x8048
+#define PCI_DEVICE_ID_TITAN_800I 0x8088
+#define PCI_DEVICE_ID_TITAN_800EH 0xA007
+#define PCI_DEVICE_ID_TITAN_800EHB 0xA008
+#define PCI_DEVICE_ID_TITAN_400EH 0xA009
+#define PCI_DEVICE_ID_TITAN_100E 0xA010
+#define PCI_DEVICE_ID_TITAN_200E 0xA012
+#define PCI_DEVICE_ID_TITAN_400E 0xA013
+#define PCI_DEVICE_ID_TITAN_800E 0xA014
+#define PCI_DEVICE_ID_TITAN_200EI 0xA016
+#define PCI_DEVICE_ID_TITAN_200EISI 0xA017
+#define PCI_DEVICE_ID_TITAN_200V3 0xA306
+#define PCI_DEVICE_ID_TITAN_400V3 0xA310
+#define PCI_DEVICE_ID_TITAN_410V3 0xA312
+#define PCI_DEVICE_ID_TITAN_800V3 0xA314
+#define PCI_DEVICE_ID_TITAN_800V3B 0xA315
+#define PCI_DEVICE_ID_OXSEMI_16PCI958 0x9538
+#define PCIE_DEVICE_ID_NEO_2_OX_IBM 0x00F6
+#define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001
+#define PCI_DEVICE_ID_INTEL_PATSBURG_KT 0x1d3d
+#define PCI_VENDOR_ID_WCH 0x4348
+#define PCI_DEVICE_ID_WCH_CH352_2S 0x3253
+#define PCI_DEVICE_ID_WCH_CH353_4S 0x3453
+#define PCI_DEVICE_ID_WCH_CH353_2S1PF 0x5046
+#define PCI_DEVICE_ID_WCH_CH353_1S1P 0x5053
+#define PCI_DEVICE_ID_WCH_CH353_2S1P 0x7053
+#define PCI_DEVICE_ID_WCH_CH355_4S 0x7173
+#define PCI_VENDOR_ID_AGESTAR 0x5372
+#define PCI_DEVICE_ID_AGESTAR_9375 0x6872
+#define PCI_VENDOR_ID_ASIX 0x9710
+#define PCI_DEVICE_ID_BROADCOM_TRUMANAGE 0x160a
+#define PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800 0x818e
+
+#define PCIE_VENDOR_ID_WCH 0x1c00
+#define PCIE_DEVICE_ID_WCH_CH382_2S1P 0x3250
+#define PCIE_DEVICE_ID_WCH_CH384_4S 0x3470
+#define PCIE_DEVICE_ID_WCH_CH382_2S 0x3253
+
+#define PCI_VENDOR_ID_PERICOM 0x12D8
+#define PCI_DEVICE_ID_PERICOM_PI7C9X7951 0x7951
+#define PCI_DEVICE_ID_PERICOM_PI7C9X7952 0x7952
+#define PCI_DEVICE_ID_PERICOM_PI7C9X7954 0x7954
+#define PCI_DEVICE_ID_PERICOM_PI7C9X7958 0x7958
+
+#define PCI_VENDOR_ID_ACCESIO 0x494f
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SDB 0x1051
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2S 0x1053
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB 0x105C
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S 0x105E
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM232_2DB 0x1091
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_2 0x1093
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB 0x1099
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4 0x109B
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SMDB 0x10D1
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2SM 0x10D3
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB 0x10DA
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM 0x10DC
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_1 0x1108
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_2 0x1110
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_2 0x1111
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4 0x1118
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4 0x1119
+#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2S 0x1152
+#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S 0x115A
+#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_2 0x1190
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_2 0x1191
+#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4 0x1198
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4 0x1199
+#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2SM 0x11D0
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4 0x105A
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4 0x105B
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM422_8 0x106A
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM485_8 0x106B
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4 0x1098
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM232_8 0x10A9
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM 0x10D9
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_8SM 0x10E9
+#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM 0x11D8
+
+#define PCIE_DEVICE_ID_NI_PXIE8430_2328 0x74C2
+#define PCIE_DEVICE_ID_NI_PXIE8430_23216 0x74C1
+#define PCI_DEVICE_ID_NI_PXI8431_4852 0x7081
+#define PCI_DEVICE_ID_NI_PXI8431_4854 0x70DE
+#define PCI_DEVICE_ID_NI_PXI8431_4858 0x70E3
+#define PCI_DEVICE_ID_NI_PXI8433_4852 0x70E9
+#define PCI_DEVICE_ID_NI_PXI8433_4854 0x70ED
+#define PCIE_DEVICE_ID_NI_PXIE8431_4858 0x74C4
+#define PCIE_DEVICE_ID_NI_PXIE8431_48516 0x74C3
+
+#define PCI_DEVICE_ID_MOXA_CP102E 0x1024
+#define PCI_DEVICE_ID_MOXA_CP102EL 0x1025
+#define PCI_DEVICE_ID_MOXA_CP104EL_A 0x1045
+#define PCI_DEVICE_ID_MOXA_CP114EL 0x1144
+#define PCI_DEVICE_ID_MOXA_CP116E_A_A 0x1160
+#define PCI_DEVICE_ID_MOXA_CP116E_A_B 0x1161
+#define PCI_DEVICE_ID_MOXA_CP118EL_A 0x1182
+#define PCI_DEVICE_ID_MOXA_CP118E_A_I 0x1183
+#define PCI_DEVICE_ID_MOXA_CP132EL 0x1322
+#define PCI_DEVICE_ID_MOXA_CP134EL_A 0x1342
+#define PCI_DEVICE_ID_MOXA_CP138E_A 0x1381
+#define PCI_DEVICE_ID_MOXA_CP168EL_A 0x1683
+
+/* Unknown vendors/cards - this should not be in linux/pci_ids.h */
+#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584
+#define PCI_SUBDEVICE_ID_UNKNOWN_0x1588 0x1588
+
+/*
+ * Master list of serial port init/setup/exit quirks.
+ * This does not describe the general nature of the port.
+ * (ie, baud base, number and location of ports, etc)
+ *
+ * This list is ordered alphabetically by vendor then device.
+ * Specific entries must come before more generic entries.
+ */
+static struct pci_serial_quirk pci_serial_quirks[] = {
+ /*
+ * ADDI-DATA GmbH communication cards <info@addi-data.com>
+ */
+ {
+ .vendor = PCI_VENDOR_ID_AMCC,
+ .device = PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = addidata_apci7800_setup,
+ },
+ /*
+ * AFAVLAB cards - these may be called via parport_serial
+ * It is not clear whether this applies to all products.
+ */
+ {
+ .vendor = PCI_VENDOR_ID_AFAVLAB,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = afavlab_setup,
+ },
+ /*
+ * HP Diva
+ */
+ {
+ .vendor = PCI_VENDOR_ID_HP,
+ .device = PCI_DEVICE_ID_HP_DIVA,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_hp_diva_init,
+ .setup = pci_hp_diva_setup,
+ },
+ /*
+ * Intel
+ */
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_80960_RP,
+ .subvendor = 0xe4bf,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_inteli960ni_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_8257X_SOL,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = skip_tx_en_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82573L_SOL,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = skip_tx_en_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82573E_SOL,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = skip_tx_en_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_CE4100_UART,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = ce4100_serial_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_PATSBURG_KT,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = kt_serial_setup,
+ },
+ /*
+ * ITE
+ */
+ {
+ .vendor = PCI_VENDOR_ID_ITE,
+ .device = PCI_DEVICE_ID_ITE_8872,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ite887x_init,
+ .setup = pci_default_setup,
+ .exit = pci_ite887x_exit,
+ },
+ /*
+ * National Instruments
+ */
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PCI23216,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8420_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PCI2328,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8420_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PCI2324,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8420_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PCI2322,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8420_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PCI2324I,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8420_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PCI2322I,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8420_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PXI8420_23216,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8420_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PXI8420_2328,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8420_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PXI8420_2324,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8420_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PXI8420_2322,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8420_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PXI8422_2324,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8420_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PXI8422_2322,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8420_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8430_init,
+ .setup = pci_ni8430_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCIE_DEVICE_ID_NI_PXIE8430_2328,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8430_init,
+ .setup = pci_ni8430_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCIE_DEVICE_ID_NI_PXIE8430_23216,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8430_init,
+ .setup = pci_ni8430_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PXI8431_4852,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8430_init,
+ .setup = pci_ni8431_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PXI8431_4854,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8430_init,
+ .setup = pci_ni8431_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PXI8431_4858,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8430_init,
+ .setup = pci_ni8431_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PXI8433_4852,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8430_init,
+ .setup = pci_ni8431_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PXI8433_4854,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8430_init,
+ .setup = pci_ni8431_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCIE_DEVICE_ID_NI_PXIE8431_4858,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8430_init,
+ .setup = pci_ni8431_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCIE_DEVICE_ID_NI_PXIE8431_48516,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8430_init,
+ .setup = pci_ni8431_setup,
+ },
+ /* Quatech */
+ {
+ .vendor = PCI_VENDOR_ID_QUATECH,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_quatech_init,
+ .setup = pci_quatech_setup,
+ },
+ /*
+ * Panacom
+ */
+ {
+ .vendor = PCI_VENDOR_ID_PANACOM,
+ .device = PCI_DEVICE_ID_PANACOM_QUADMODEM,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_plx9050_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_PANACOM,
+ .device = PCI_DEVICE_ID_PANACOM_DUALMODEM,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_plx9050_init,
+ .setup = pci_default_setup,
+ },
+ /*
+ * Pericom (Only 7954 - It have a offset jump for port 4)
+ */
+ {
+ .vendor = PCI_VENDOR_ID_PERICOM,
+ .device = PCI_DEVICE_ID_PERICOM_PI7C9X7954,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ /*
+ * PLX
+ */
+ {
+ .vendor = PCI_VENDOR_ID_PLX,
+ .device = PCI_DEVICE_ID_PLX_9050,
+ .subvendor = PCI_SUBVENDOR_ID_EXSYS,
+ .subdevice = PCI_SUBDEVICE_ID_EXSYS_4055,
+ .init = pci_plx9050_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_PLX,
+ .device = PCI_DEVICE_ID_PLX_9050,
+ .subvendor = PCI_SUBVENDOR_ID_KEYSPAN,
+ .subdevice = PCI_SUBDEVICE_ID_KEYSPAN_SX2,
+ .init = pci_plx9050_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_PLX,
+ .device = PCI_DEVICE_ID_PLX_ROMULUS,
+ .subvendor = PCI_VENDOR_ID_PLX,
+ .subdevice = PCI_DEVICE_ID_PLX_ROMULUS,
+ .init = pci_plx9050_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup,
+ }, /*
+ * SBS Technologies, Inc., PMC-OCTALPRO 232
+ */
+ {
+ .vendor = PCI_VENDOR_ID_SBSMODULARIO,
+ .device = PCI_DEVICE_ID_OCTPRO,
+ .subvendor = PCI_SUBVENDOR_ID_SBSMODULARIO,
+ .subdevice = PCI_SUBDEVICE_ID_OCTPRO232,
+ .init = sbs_init,
+ .setup = sbs_setup,
+ },
+ /*
+ * SBS Technologies, Inc., PMC-OCTALPRO 422
+ */
+ {
+ .vendor = PCI_VENDOR_ID_SBSMODULARIO,
+ .device = PCI_DEVICE_ID_OCTPRO,
+ .subvendor = PCI_SUBVENDOR_ID_SBSMODULARIO,
+ .subdevice = PCI_SUBDEVICE_ID_OCTPRO422,
+ .init = sbs_init,
+ .setup = sbs_setup,
+ },
+ /*
+ * SBS Technologies, Inc., P-Octal 232
+ */
+ {
+ .vendor = PCI_VENDOR_ID_SBSMODULARIO,
+ .device = PCI_DEVICE_ID_OCTPRO,
+ .subvendor = PCI_SUBVENDOR_ID_SBSMODULARIO,
+ .subdevice = PCI_SUBDEVICE_ID_POCTAL232,
+ .init = sbs_init,
+ .setup = sbs_setup,
+ },
+ /*
+ * SBS Technologies, Inc., P-Octal 422
+ */
+ {
+ .vendor = PCI_VENDOR_ID_SBSMODULARIO,
+ .device = PCI_DEVICE_ID_OCTPRO,
+ .subvendor = PCI_SUBVENDOR_ID_SBSMODULARIO,
+ .subdevice = PCI_SUBDEVICE_ID_POCTAL422,
+ .init = sbs_init,
+ .setup = sbs_setup,
+ },
+ /*
+ * SIIG cards - these may be called via parport_serial
+ */
+ {
+ .vendor = PCI_VENDOR_ID_SIIG,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_siig_init,
+ .setup = pci_siig_setup,
+ },
+ /*
+ * Titan cards
+ */
+ {
+ .vendor = PCI_VENDOR_ID_TITAN,
+ .device = PCI_DEVICE_ID_TITAN_400L,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = titan_400l_800l_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_TITAN,
+ .device = PCI_DEVICE_ID_TITAN_800L,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = titan_400l_800l_setup,
+ },
+ /*
+ * Timedia cards
+ */
+ {
+ .vendor = PCI_VENDOR_ID_TIMEDIA,
+ .device = PCI_DEVICE_ID_TIMEDIA_1889,
+ .subvendor = PCI_VENDOR_ID_TIMEDIA,
+ .subdevice = PCI_ANY_ID,
+ .probe = pci_timedia_probe,
+ .init = pci_timedia_init,
+ .setup = pci_timedia_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_TIMEDIA,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_timedia_setup,
+ },
+ /*
+ * Sunix PCI serial boards
+ */
+ {
+ .vendor = PCI_VENDOR_ID_SUNIX,
+ .device = PCI_DEVICE_ID_SUNIX_1999,
+ .subvendor = PCI_VENDOR_ID_SUNIX,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_sunix_setup,
+ },
+ /*
+ * Xircom cards
+ */
+ {
+ .vendor = PCI_VENDOR_ID_XIRCOM,
+ .device = PCI_DEVICE_ID_XIRCOM_X3201_MDM,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_xircom_init,
+ .setup = pci_default_setup,
+ },
+ /*
+ * Netmos cards - these may be called via parport_serial
+ */
+ {
+ .vendor = PCI_VENDOR_ID_NETMOS,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_netmos_init,
+ .setup = pci_netmos_9900_setup,
+ },
+ /*
+ * EndRun Technologies
+ */
+ {
+ .vendor = PCI_VENDOR_ID_ENDRUN,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_endrun_init,
+ .setup = pci_default_setup,
+ },
+ /*
+ * For Oxford Semiconductor Tornado based devices
+ */
+ {
+ .vendor = PCI_VENDOR_ID_OXSEMI,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_oxsemi_tornado_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_MAINPINE,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_oxsemi_tornado_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_DIGI,
+ .device = PCIE_DEVICE_ID_NEO_2_OX_IBM,
+ .subvendor = PCI_SUBVENDOR_ID_IBM,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_oxsemi_tornado_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = 0x8811,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = 0x8812,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = 0x8813,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = 0x8814,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = 0x10DB,
+ .device = 0x8027,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = 0x10DB,
+ .device = 0x8028,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = 0x10DB,
+ .device = 0x8029,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = 0x10DB,
+ .device = 0x800C,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = 0x10DB,
+ .device = 0x800D,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_default_setup,
+ },
+ /*
+ * Cronyx Omega PCI (PLX-chip based)
+ */
+ {
+ .vendor = PCI_VENDOR_ID_PLX,
+ .device = PCI_DEVICE_ID_PLX_CRONYX_OMEGA,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_omegapci_setup,
+ },
+ /* WCH CH353 1S1P card (16550 clone) */
+ {
+ .vendor = PCI_VENDOR_ID_WCH,
+ .device = PCI_DEVICE_ID_WCH_CH353_1S1P,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch353_setup,
+ },
+ /* WCH CH353 2S1P card (16550 clone) */
+ {
+ .vendor = PCI_VENDOR_ID_WCH,
+ .device = PCI_DEVICE_ID_WCH_CH353_2S1P,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch353_setup,
+ },
+ /* WCH CH353 4S card (16550 clone) */
+ {
+ .vendor = PCI_VENDOR_ID_WCH,
+ .device = PCI_DEVICE_ID_WCH_CH353_4S,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch353_setup,
+ },
+ /* WCH CH353 2S1PF card (16550 clone) */
+ {
+ .vendor = PCI_VENDOR_ID_WCH,
+ .device = PCI_DEVICE_ID_WCH_CH353_2S1PF,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch353_setup,
+ },
+ /* WCH CH352 2S card (16550 clone) */
+ {
+ .vendor = PCI_VENDOR_ID_WCH,
+ .device = PCI_DEVICE_ID_WCH_CH352_2S,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch353_setup,
+ },
+ /* WCH CH355 4S card (16550 clone) */
+ {
+ .vendor = PCI_VENDOR_ID_WCH,
+ .device = PCI_DEVICE_ID_WCH_CH355_4S,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch355_setup,
+ },
+ /* WCH CH382 2S card (16850 clone) */
+ {
+ .vendor = PCIE_VENDOR_ID_WCH,
+ .device = PCIE_DEVICE_ID_WCH_CH382_2S,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch38x_setup,
+ },
+ /* WCH CH382 2S1P card (16850 clone) */
+ {
+ .vendor = PCIE_VENDOR_ID_WCH,
+ .device = PCIE_DEVICE_ID_WCH_CH382_2S1P,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch38x_setup,
+ },
+ /* WCH CH384 4S card (16850 clone) */
+ {
+ .vendor = PCIE_VENDOR_ID_WCH,
+ .device = PCIE_DEVICE_ID_WCH_CH384_4S,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch38x_setup,
+ },
+ /*
+ * ASIX devices with FIFO bug
+ */
+ {
+ .vendor = PCI_VENDOR_ID_ASIX,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_asix_setup,
+ },
+ /*
+ * Broadcom TruManage (NetXtreme)
+ */
+ {
+ .vendor = PCI_VENDOR_ID_BROADCOM,
+ .device = PCI_DEVICE_ID_BROADCOM_TRUMANAGE,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_brcm_trumanage_setup,
+ },
+ {
+ .vendor = 0x1c29,
+ .device = 0x1104,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_fintek_setup,
+ .init = pci_fintek_init,
+ },
+ {
+ .vendor = 0x1c29,
+ .device = 0x1108,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_fintek_setup,
+ .init = pci_fintek_init,
+ },
+ {
+ .vendor = 0x1c29,
+ .device = 0x1112,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_fintek_setup,
+ .init = pci_fintek_init,
+ },
+ /*
+ * MOXA
+ */
+ {
+ .vendor = PCI_VENDOR_ID_MOXA,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_moxa_setup,
+ },
+ {
+ .vendor = 0x1c29,
+ .device = 0x1204,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_fintek_f815xxa_setup,
+ .init = pci_fintek_f815xxa_init,
+ },
+ {
+ .vendor = 0x1c29,
+ .device = 0x1208,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_fintek_f815xxa_setup,
+ .init = pci_fintek_f815xxa_init,
+ },
+ {
+ .vendor = 0x1c29,
+ .device = 0x1212,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_fintek_f815xxa_setup,
+ .init = pci_fintek_f815xxa_init,
+ },
+
+ /*
+ * Default "match everything" terminator entry
+ */
+ {
+ .vendor = PCI_ANY_ID,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_default_setup,
+ }
+};
+
+static inline int quirk_id_matches(u32 quirk_id, u32 dev_id)
+{
+ return quirk_id == PCI_ANY_ID || quirk_id == dev_id;
+}
+
+static struct pci_serial_quirk *find_quirk(struct pci_dev *dev)
+{
+ struct pci_serial_quirk *quirk;
+
+ for (quirk = pci_serial_quirks; ; quirk++)
+ if (quirk_id_matches(quirk->vendor, dev->vendor) &&
+ quirk_id_matches(quirk->device, dev->device) &&
+ quirk_id_matches(quirk->subvendor, dev->subsystem_vendor) &&
+ quirk_id_matches(quirk->subdevice, dev->subsystem_device))
+ break;
+ return quirk;
+}
+
+/*
+ * This is the configuration table for all of the PCI serial boards
+ * which we support. It is directly indexed by the pci_board_num_t enum
+ * value, which is encoded in the pci_device_id PCI probe table's
+ * driver_data member.
+ *
+ * The makeup of these names are:
+ * pbn_bn{_bt}_n_baud{_offsetinhex}
+ *
+ * bn = PCI BAR number
+ * bt = Index using PCI BARs
+ * n = number of serial ports
+ * baud = baud rate
+ * offsetinhex = offset for each sequential port (in hex)
+ *
+ * This table is sorted by (in order): bn, bt, baud, offsetindex, n.
+ *
+ * Please note: in theory if n = 1, _bt infix should make no difference.
+ * ie, pbn_b0_1_115200 is the same as pbn_b0_bt_1_115200
+ */
+enum pci_board_num_t {
+ pbn_default = 0,
+
+ pbn_b0_1_115200,
+ pbn_b0_2_115200,
+ pbn_b0_4_115200,
+ pbn_b0_5_115200,
+ pbn_b0_8_115200,
+
+ pbn_b0_1_921600,
+ pbn_b0_2_921600,
+ pbn_b0_4_921600,
+
+ pbn_b0_2_1130000,
+
+ pbn_b0_4_1152000,
+
+ pbn_b0_4_1250000,
+
+ pbn_b0_2_1843200,
+ pbn_b0_4_1843200,
+
+ pbn_b0_1_4000000,
+
+ pbn_b0_bt_1_115200,
+ pbn_b0_bt_2_115200,
+ pbn_b0_bt_4_115200,
+ pbn_b0_bt_8_115200,
+
+ pbn_b0_bt_1_460800,
+ pbn_b0_bt_2_460800,
+ pbn_b0_bt_4_460800,
+
+ pbn_b0_bt_1_921600,
+ pbn_b0_bt_2_921600,
+ pbn_b0_bt_4_921600,
+ pbn_b0_bt_8_921600,
+
+ pbn_b1_1_115200,
+ pbn_b1_2_115200,
+ pbn_b1_4_115200,
+ pbn_b1_8_115200,
+ pbn_b1_16_115200,
+
+ pbn_b1_1_921600,
+ pbn_b1_2_921600,
+ pbn_b1_4_921600,
+ pbn_b1_8_921600,
+
+ pbn_b1_2_1250000,
+
+ pbn_b1_bt_1_115200,
+ pbn_b1_bt_2_115200,
+ pbn_b1_bt_4_115200,
+
+ pbn_b1_bt_2_921600,
+
+ pbn_b1_1_1382400,
+ pbn_b1_2_1382400,
+ pbn_b1_4_1382400,
+ pbn_b1_8_1382400,
+
+ pbn_b2_1_115200,
+ pbn_b2_2_115200,
+ pbn_b2_4_115200,
+ pbn_b2_8_115200,
+
+ pbn_b2_1_460800,
+ pbn_b2_4_460800,
+ pbn_b2_8_460800,
+ pbn_b2_16_460800,
+
+ pbn_b2_1_921600,
+ pbn_b2_4_921600,
+ pbn_b2_8_921600,
+
+ pbn_b2_8_1152000,
+
+ pbn_b2_bt_1_115200,
+ pbn_b2_bt_2_115200,
+ pbn_b2_bt_4_115200,
+
+ pbn_b2_bt_2_921600,
+ pbn_b2_bt_4_921600,
+
+ pbn_b3_2_115200,
+ pbn_b3_4_115200,
+ pbn_b3_8_115200,
+
+ pbn_b4_bt_2_921600,
+ pbn_b4_bt_4_921600,
+ pbn_b4_bt_8_921600,
+
+ /*
+ * Board-specific versions.
+ */
+ pbn_panacom,
+ pbn_panacom2,
+ pbn_panacom4,
+ pbn_plx_romulus,
+ pbn_endrun_2_4000000,
+ pbn_oxsemi,
+ pbn_oxsemi_1_4000000,
+ pbn_oxsemi_2_4000000,
+ pbn_oxsemi_4_4000000,
+ pbn_oxsemi_8_4000000,
+ pbn_intel_i960,
+ pbn_sgi_ioc3,
+ pbn_computone_4,
+ pbn_computone_6,
+ pbn_computone_8,
+ pbn_sbsxrsio,
+ pbn_pasemi_1682M,
+ pbn_ni8430_2,
+ pbn_ni8430_4,
+ pbn_ni8430_8,
+ pbn_ni8430_16,
+ pbn_ni8430_pxie_8,
+ pbn_ni8430_pxie_16,
+ pbn_ni8431_2,
+ pbn_ni8431_4,
+ pbn_ni8431_8,
+ pbn_ni8431_pxie_8,
+ pbn_ni8431_pxie_16,
+ pbn_ADDIDATA_PCIe_1_3906250,
+ pbn_ADDIDATA_PCIe_2_3906250,
+ pbn_ADDIDATA_PCIe_4_3906250,
+ pbn_ADDIDATA_PCIe_8_3906250,
+ pbn_ce4100_1_115200,
+ pbn_omegapci,
+ pbn_NETMOS9900_2s_115200,
+ pbn_brcm_trumanage,
+ pbn_fintek_4,
+ pbn_fintek_8,
+ pbn_fintek_12,
+ pbn_fintek_F81504A,
+ pbn_fintek_F81508A,
+ pbn_fintek_F81512A,
+ pbn_wch382_2,
+ pbn_wch384_4,
+ pbn_pericom_PI7C9X7951,
+ pbn_pericom_PI7C9X7952,
+ pbn_pericom_PI7C9X7954,
+ pbn_pericom_PI7C9X7958,
+ pbn_sunix_pci_1s,
+ pbn_sunix_pci_2s,
+ pbn_sunix_pci_4s,
+ pbn_sunix_pci_8s,
+ pbn_sunix_pci_16s,
+ pbn_moxa8250_2p,
+ pbn_moxa8250_4p,
+ pbn_moxa8250_8p,
+};
+
+/*
+ * uart_offset - the space between channels
+ * reg_shift - describes how the UART registers are mapped
+ * to PCI memory by the card.
+ * For example IER register on SBS, Inc. PMC-OctPro is located at
+ * offset 0x10 from the UART base, while UART_IER is defined as 1
+ * in include/linux/serial_reg.h,
+ * see first lines of serial_in() and serial_out() in 8250.c
+*/
+
+static struct pciserial_board pci_boards[] = {
+ [pbn_default] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b0_1_115200] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b0_2_115200] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b0_4_115200] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b0_5_115200] = {
+ .flags = FL_BASE0,
+ .num_ports = 5,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b0_8_115200] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b0_1_921600] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b0_2_921600] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b0_4_921600] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+
+ [pbn_b0_2_1130000] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 1130000,
+ .uart_offset = 8,
+ },
+
+ [pbn_b0_4_1152000] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 1152000,
+ .uart_offset = 8,
+ },
+
+ [pbn_b0_4_1250000] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 1250000,
+ .uart_offset = 8,
+ },
+
+ [pbn_b0_2_1843200] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 1843200,
+ .uart_offset = 8,
+ },
+ [pbn_b0_4_1843200] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 1843200,
+ .uart_offset = 8,
+ },
+
+ [pbn_b0_1_4000000] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 4000000,
+ .uart_offset = 8,
+ },
+
+ [pbn_b0_bt_1_115200] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 1,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b0_bt_2_115200] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 2,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b0_bt_4_115200] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 4,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b0_bt_8_115200] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 8,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+
+ [pbn_b0_bt_1_460800] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 1,
+ .base_baud = 460800,
+ .uart_offset = 8,
+ },
+ [pbn_b0_bt_2_460800] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 2,
+ .base_baud = 460800,
+ .uart_offset = 8,
+ },
+ [pbn_b0_bt_4_460800] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 4,
+ .base_baud = 460800,
+ .uart_offset = 8,
+ },
+
+ [pbn_b0_bt_1_921600] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 1,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b0_bt_2_921600] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 2,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b0_bt_4_921600] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b0_bt_8_921600] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 8,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+
+ [pbn_b1_1_115200] = {
+ .flags = FL_BASE1,
+ .num_ports = 1,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b1_2_115200] = {
+ .flags = FL_BASE1,
+ .num_ports = 2,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b1_4_115200] = {
+ .flags = FL_BASE1,
+ .num_ports = 4,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b1_8_115200] = {
+ .flags = FL_BASE1,
+ .num_ports = 8,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b1_16_115200] = {
+ .flags = FL_BASE1,
+ .num_ports = 16,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+
+ [pbn_b1_1_921600] = {
+ .flags = FL_BASE1,
+ .num_ports = 1,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b1_2_921600] = {
+ .flags = FL_BASE1,
+ .num_ports = 2,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b1_4_921600] = {
+ .flags = FL_BASE1,
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b1_8_921600] = {
+ .flags = FL_BASE1,
+ .num_ports = 8,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b1_2_1250000] = {
+ .flags = FL_BASE1,
+ .num_ports = 2,
+ .base_baud = 1250000,
+ .uart_offset = 8,
+ },
+
+ [pbn_b1_bt_1_115200] = {
+ .flags = FL_BASE1|FL_BASE_BARS,
+ .num_ports = 1,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b1_bt_2_115200] = {
+ .flags = FL_BASE1|FL_BASE_BARS,
+ .num_ports = 2,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b1_bt_4_115200] = {
+ .flags = FL_BASE1|FL_BASE_BARS,
+ .num_ports = 4,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+
+ [pbn_b1_bt_2_921600] = {
+ .flags = FL_BASE1|FL_BASE_BARS,
+ .num_ports = 2,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+
+ [pbn_b1_1_1382400] = {
+ .flags = FL_BASE1,
+ .num_ports = 1,
+ .base_baud = 1382400,
+ .uart_offset = 8,
+ },
+ [pbn_b1_2_1382400] = {
+ .flags = FL_BASE1,
+ .num_ports = 2,
+ .base_baud = 1382400,
+ .uart_offset = 8,
+ },
+ [pbn_b1_4_1382400] = {
+ .flags = FL_BASE1,
+ .num_ports = 4,
+ .base_baud = 1382400,
+ .uart_offset = 8,
+ },
+ [pbn_b1_8_1382400] = {
+ .flags = FL_BASE1,
+ .num_ports = 8,
+ .base_baud = 1382400,
+ .uart_offset = 8,
+ },
+
+ [pbn_b2_1_115200] = {
+ .flags = FL_BASE2,
+ .num_ports = 1,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b2_2_115200] = {
+ .flags = FL_BASE2,
+ .num_ports = 2,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b2_4_115200] = {
+ .flags = FL_BASE2,
+ .num_ports = 4,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b2_8_115200] = {
+ .flags = FL_BASE2,
+ .num_ports = 8,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+
+ [pbn_b2_1_460800] = {
+ .flags = FL_BASE2,
+ .num_ports = 1,
+ .base_baud = 460800,
+ .uart_offset = 8,
+ },
+ [pbn_b2_4_460800] = {
+ .flags = FL_BASE2,
+ .num_ports = 4,
+ .base_baud = 460800,
+ .uart_offset = 8,
+ },
+ [pbn_b2_8_460800] = {
+ .flags = FL_BASE2,
+ .num_ports = 8,
+ .base_baud = 460800,
+ .uart_offset = 8,
+ },
+ [pbn_b2_16_460800] = {
+ .flags = FL_BASE2,
+ .num_ports = 16,
+ .base_baud = 460800,
+ .uart_offset = 8,
+ },
+
+ [pbn_b2_1_921600] = {
+ .flags = FL_BASE2,
+ .num_ports = 1,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b2_4_921600] = {
+ .flags = FL_BASE2,
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b2_8_921600] = {
+ .flags = FL_BASE2,
+ .num_ports = 8,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+
+ [pbn_b2_8_1152000] = {
+ .flags = FL_BASE2,
+ .num_ports = 8,
+ .base_baud = 1152000,
+ .uart_offset = 8,
+ },
+
+ [pbn_b2_bt_1_115200] = {
+ .flags = FL_BASE2|FL_BASE_BARS,
+ .num_ports = 1,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b2_bt_2_115200] = {
+ .flags = FL_BASE2|FL_BASE_BARS,
+ .num_ports = 2,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b2_bt_4_115200] = {
+ .flags = FL_BASE2|FL_BASE_BARS,
+ .num_ports = 4,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+
+ [pbn_b2_bt_2_921600] = {
+ .flags = FL_BASE2|FL_BASE_BARS,
+ .num_ports = 2,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b2_bt_4_921600] = {
+ .flags = FL_BASE2|FL_BASE_BARS,
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+
+ [pbn_b3_2_115200] = {
+ .flags = FL_BASE3,
+ .num_ports = 2,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b3_4_115200] = {
+ .flags = FL_BASE3,
+ .num_ports = 4,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b3_8_115200] = {
+ .flags = FL_BASE3,
+ .num_ports = 8,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+
+ [pbn_b4_bt_2_921600] = {
+ .flags = FL_BASE4,
+ .num_ports = 2,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b4_bt_4_921600] = {
+ .flags = FL_BASE4,
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b4_bt_8_921600] = {
+ .flags = FL_BASE4,
+ .num_ports = 8,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+
+ /*
+ * Entries following this are board-specific.
+ */
+
+ /*
+ * Panacom - IOMEM
+ */
+ [pbn_panacom] = {
+ .flags = FL_BASE2,
+ .num_ports = 2,
+ .base_baud = 921600,
+ .uart_offset = 0x400,
+ .reg_shift = 7,
+ },
+ [pbn_panacom2] = {
+ .flags = FL_BASE2|FL_BASE_BARS,
+ .num_ports = 2,
+ .base_baud = 921600,
+ .uart_offset = 0x400,
+ .reg_shift = 7,
+ },
+ [pbn_panacom4] = {
+ .flags = FL_BASE2|FL_BASE_BARS,
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 0x400,
+ .reg_shift = 7,
+ },
+
+ /* I think this entry is broken - the first_offset looks wrong --rmk */
+ [pbn_plx_romulus] = {
+ .flags = FL_BASE2,
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 8 << 2,
+ .reg_shift = 2,
+ .first_offset = 0x03,
+ },
+
+ /*
+ * EndRun Technologies
+ * Uses the size of PCI Base region 0 to
+ * signal now many ports are available
+ * 2 port 952 Uart support
+ */
+ [pbn_endrun_2_4000000] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 4000000,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+
+ /*
+ * This board uses the size of PCI Base region 0 to
+ * signal now many ports are available
+ */
+ [pbn_oxsemi] = {
+ .flags = FL_BASE0|FL_REGION_SZ_CAP,
+ .num_ports = 32,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_oxsemi_1_4000000] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 4000000,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+ [pbn_oxsemi_2_4000000] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 4000000,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+ [pbn_oxsemi_4_4000000] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 4000000,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+ [pbn_oxsemi_8_4000000] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 4000000,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+
+
+ /*
+ * EKF addition for i960 Boards form EKF with serial port.
+ * Max 256 ports.
+ */
+ [pbn_intel_i960] = {
+ .flags = FL_BASE0,
+ .num_ports = 32,
+ .base_baud = 921600,
+ .uart_offset = 8 << 2,
+ .reg_shift = 2,
+ .first_offset = 0x10000,
+ },
+ [pbn_sgi_ioc3] = {
+ .flags = FL_BASE0|FL_NOIRQ,
+ .num_ports = 1,
+ .base_baud = 458333,
+ .uart_offset = 8,
+ .reg_shift = 0,
+ .first_offset = 0x20178,
+ },
+
+ /*
+ * Computone - uses IOMEM.
+ */
+ [pbn_computone_4] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 0x40,
+ .reg_shift = 2,
+ .first_offset = 0x200,
+ },
+ [pbn_computone_6] = {
+ .flags = FL_BASE0,
+ .num_ports = 6,
+ .base_baud = 921600,
+ .uart_offset = 0x40,
+ .reg_shift = 2,
+ .first_offset = 0x200,
+ },
+ [pbn_computone_8] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 921600,
+ .uart_offset = 0x40,
+ .reg_shift = 2,
+ .first_offset = 0x200,
+ },
+ [pbn_sbsxrsio] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 460800,
+ .uart_offset = 256,
+ .reg_shift = 4,
+ },
+ /*
+ * PA Semi PWRficient PA6T-1682M on-chip UART
+ */
+ [pbn_pasemi_1682M] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 8333333,
+ },
+ /*
+ * National Instruments 843x
+ */
+ [pbn_ni8430_16] = {
+ .flags = FL_BASE0,
+ .num_ports = 16,
+ .base_baud = 3686400,
+ .uart_offset = 0x10,
+ .first_offset = 0x800,
+ },
+ [pbn_ni8430_8] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 3686400,
+ .uart_offset = 0x10,
+ .first_offset = 0x800,
+ },
+ [pbn_ni8430_4] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 3686400,
+ .uart_offset = 0x10,
+ .first_offset = 0x800,
+ },
+ [pbn_ni8430_2] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 3686400,
+ .uart_offset = 0x10,
+ .first_offset = 0x800,
+ },
+ [pbn_ni8430_pxie_16] = {
+ .flags = FL_BASE0,
+ .num_ports = 16,
+ .base_baud = 3125000,
+ .uart_offset = 0x10,
+ .first_offset = 0x800,
+ },
+ [pbn_ni8430_pxie_8] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 3125000,
+ .uart_offset = 0x10,
+ .first_offset = 0x800,
+ },
+ [pbn_ni8431_8] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 3686400,
+ .uart_offset = 0x10,
+ .first_offset = 0x800,
+ },
+ [pbn_ni8431_4] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 3686400,
+ .uart_offset = 0x10,
+ .first_offset = 0x800,
+ },
+ [pbn_ni8431_2] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 3686400,
+ .uart_offset = 0x10,
+ .first_offset = 0x800,
+ },
+ [pbn_ni8431_pxie_16] = {
+ .flags = FL_BASE0,
+ .num_ports = 16,
+ .base_baud = 3125000,
+ .uart_offset = 0x10,
+ .first_offset = 0x800,
+ },
+ [pbn_ni8431_pxie_8] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 3125000,
+ .uart_offset = 0x10,
+ .first_offset = 0x800,
+ },
+ /*
+ * ADDI-DATA GmbH PCI-Express communication cards <info@addi-data.com>
+ */
+ [pbn_ADDIDATA_PCIe_1_3906250] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 3906250,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+ [pbn_ADDIDATA_PCIe_2_3906250] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 3906250,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+ [pbn_ADDIDATA_PCIe_4_3906250] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 3906250,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+ [pbn_ADDIDATA_PCIe_8_3906250] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 3906250,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+ [pbn_ce4100_1_115200] = {
+ .flags = FL_BASE_BARS,
+ .num_ports = 2,
+ .base_baud = 921600,
+ .reg_shift = 2,
+ },
+ [pbn_omegapci] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 115200,
+ .uart_offset = 0x200,
+ },
+ [pbn_NETMOS9900_2s_115200] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 115200,
+ },
+ [pbn_brcm_trumanage] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .reg_shift = 2,
+ .base_baud = 115200,
+ },
+ [pbn_fintek_4] = {
+ .num_ports = 4,
+ .uart_offset = 8,
+ .base_baud = 115200,
+ .first_offset = 0x40,
+ },
+ [pbn_fintek_8] = {
+ .num_ports = 8,
+ .uart_offset = 8,
+ .base_baud = 115200,
+ .first_offset = 0x40,
+ },
+ [pbn_fintek_12] = {
+ .num_ports = 12,
+ .uart_offset = 8,
+ .base_baud = 115200,
+ .first_offset = 0x40,
+ },
+ [pbn_fintek_F81504A] = {
+ .num_ports = 4,
+ .uart_offset = 8,
+ .base_baud = 115200,
+ },
+ [pbn_fintek_F81508A] = {
+ .num_ports = 8,
+ .uart_offset = 8,
+ .base_baud = 115200,
+ },
+ [pbn_fintek_F81512A] = {
+ .num_ports = 12,
+ .uart_offset = 8,
+ .base_baud = 115200,
+ },
+ [pbn_wch382_2] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ .first_offset = 0xC0,
+ },
+ [pbn_wch384_4] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ .first_offset = 0xC0,
+ },
+ /*
+ * Pericom PI7C9X795[1248] Uno/Dual/Quad/Octal UART
+ */
+ [pbn_pericom_PI7C9X7951] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 921600,
+ .uart_offset = 0x8,
+ },
+ [pbn_pericom_PI7C9X7952] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 921600,
+ .uart_offset = 0x8,
+ },
+ [pbn_pericom_PI7C9X7954] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 0x8,
+ },
+ [pbn_pericom_PI7C9X7958] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 921600,
+ .uart_offset = 0x8,
+ },
+ [pbn_sunix_pci_1s] = {
+ .num_ports = 1,
+ .base_baud = 921600,
+ .uart_offset = 0x8,
+ },
+ [pbn_sunix_pci_2s] = {
+ .num_ports = 2,
+ .base_baud = 921600,
+ .uart_offset = 0x8,
+ },
+ [pbn_sunix_pci_4s] = {
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 0x8,
+ },
+ [pbn_sunix_pci_8s] = {
+ .num_ports = 8,
+ .base_baud = 921600,
+ .uart_offset = 0x8,
+ },
+ [pbn_sunix_pci_16s] = {
+ .num_ports = 16,
+ .base_baud = 921600,
+ .uart_offset = 0x8,
+ },
+ [pbn_moxa8250_2p] = {
+ .flags = FL_BASE1,
+ .num_ports = 2,
+ .base_baud = 921600,
+ .uart_offset = 0x200,
+ },
+ [pbn_moxa8250_4p] = {
+ .flags = FL_BASE1,
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 0x200,
+ },
+ [pbn_moxa8250_8p] = {
+ .flags = FL_BASE1,
+ .num_ports = 8,
+ .base_baud = 921600,
+ .uart_offset = 0x200,
+ },
+};
+
+static const struct pci_device_id blacklist[] = {
+ /* softmodems */
+ { PCI_VDEVICE(AL, 0x5457), }, /* ALi Corporation M5457 AC'97 Modem */
+ { PCI_VDEVICE(MOTOROLA, 0x3052), }, /* Motorola Si3052-based modem */
+ { PCI_DEVICE(0x1543, 0x3052), }, /* Si3052-based modem, default IDs */
+
+ /* multi-io cards handled by parport_serial */
+ { PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */
+ { PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */
+ { PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */
+
+ /* Intel platforms with MID UART */
+ { PCI_VDEVICE(INTEL, 0x081b), },
+ { PCI_VDEVICE(INTEL, 0x081c), },
+ { PCI_VDEVICE(INTEL, 0x081d), },
+ { PCI_VDEVICE(INTEL, 0x1191), },
+ { PCI_VDEVICE(INTEL, 0x18d8), },
+ { PCI_VDEVICE(INTEL, 0x19d8), },
+
+ /* Intel platforms with DesignWare UART */
+ { PCI_VDEVICE(INTEL, 0x0936), },
+ { PCI_VDEVICE(INTEL, 0x0f0a), },
+ { PCI_VDEVICE(INTEL, 0x0f0c), },
+ { PCI_VDEVICE(INTEL, 0x228a), },
+ { PCI_VDEVICE(INTEL, 0x228c), },
+ { PCI_VDEVICE(INTEL, 0x9ce3), },
+ { PCI_VDEVICE(INTEL, 0x9ce4), },
+
+ /* Exar devices */
+ { PCI_VDEVICE(EXAR, PCI_ANY_ID), },
+ { PCI_VDEVICE(COMMTECH, PCI_ANY_ID), },
+
+ /* End of the black list */
+ { }
+};
+
+static int serial_pci_is_class_communication(struct pci_dev *dev)
+{
+ /*
+ * If it is not a communications device or the programming
+ * interface is greater than 6, give up.
+ */
+ if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
+ ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MULTISERIAL) &&
+ ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
+ (dev->class & 0xff) > 6)
+ return -ENODEV;
+
+ return 0;
+}
+
+/*
+ * Given a complete unknown PCI device, try to use some heuristics to
+ * guess what the configuration might be, based on the pitiful PCI
+ * serial specs. Returns 0 on success, -ENODEV on failure.
+ */
+static int
+serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
+{
+ int num_iomem, num_port, first_port = -1, i;
+ int rc;
+
+ rc = serial_pci_is_class_communication(dev);
+ if (rc)
+ return rc;
+
+ /*
+ * Should we try to make guesses for multiport serial devices later?
+ */
+ if ((dev->class >> 8) == PCI_CLASS_COMMUNICATION_MULTISERIAL)
+ return -ENODEV;
+
+ num_iomem = num_port = 0;
+ for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
+ if (pci_resource_flags(dev, i) & IORESOURCE_IO) {
+ num_port++;
+ if (first_port == -1)
+ first_port = i;
+ }
+ if (pci_resource_flags(dev, i) & IORESOURCE_MEM)
+ num_iomem++;
+ }
+
+ /*
+ * If there is 1 or 0 iomem regions, and exactly one port,
+ * use it. We guess the number of ports based on the IO
+ * region size.
+ */
+ if (num_iomem <= 1 && num_port == 1) {
+ board->flags = first_port;
+ board->num_ports = pci_resource_len(dev, first_port) / 8;
+ return 0;
+ }
+
+ /*
+ * Now guess if we've got a board which indexes by BARs.
+ * Each IO BAR should be 8 bytes, and they should follow
+ * consecutively.
+ */
+ first_port = -1;
+ num_port = 0;
+ for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
+ if (pci_resource_flags(dev, i) & IORESOURCE_IO &&
+ pci_resource_len(dev, i) == 8 &&
+ (first_port == -1 || (first_port + num_port) == i)) {
+ num_port++;
+ if (first_port == -1)
+ first_port = i;
+ }
+ }
+
+ if (num_port > 1) {
+ board->flags = first_port | FL_BASE_BARS;
+ board->num_ports = num_port;
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+static inline int
+serial_pci_matches(const struct pciserial_board *board,
+ const struct pciserial_board *guessed)
+{
+ return
+ board->num_ports == guessed->num_ports &&
+ board->base_baud == guessed->base_baud &&
+ board->uart_offset == guessed->uart_offset &&
+ board->reg_shift == guessed->reg_shift &&
+ board->first_offset == guessed->first_offset;
+}
+
+static struct serial_private *
+pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
+{
+ struct uart_8250_port uart;
+ struct serial_private *priv;
+ struct pci_serial_quirk *quirk;
+ int rc, nr_ports, i;
+
+ nr_ports = board->num_ports;
+
+ /*
+ * Find an init and setup quirks.
+ */
+ quirk = find_quirk(dev);
+
+ /*
+ * Run the new-style initialization function.
+ * The initialization function returns:
+ * <0 - error
+ * 0 - use board->num_ports
+ * >0 - number of ports
+ */
+ if (quirk->init) {
+ rc = quirk->init(dev);
+ if (rc < 0) {
+ priv = ERR_PTR(rc);
+ goto err_out;
+ }
+ if (rc)
+ nr_ports = rc;
+ }
+
+ priv = xzalloc(sizeof(struct serial_private) +
+ sizeof(unsigned int) * nr_ports);
+
+ priv->dev = dev;
+ priv->quirk = quirk;
+
+ memset(&uart, 0, sizeof(uart));
+ uart.pdata = xzalloc(sizeof(*uart.pdata));
+ uart.pdata->clock = board->base_baud * 16;
+
+ if (rc < 0) {
+ kfree(priv);
+ priv = ERR_PTR(rc);
+ goto err_deinit;
+ }
+
+ for (i = 0; i < nr_ports; i++) {
+ struct device_d *ns16550_dev;
+ struct resource *res;
+
+ rc = quirk->setup(priv, board, &uart, i);
+ if (rc == -ENOSYS) {
+ priv = ERR_PTR(-ENOSYS);
+ goto err_deinit;
+ }
+
+ if (rc)
+ break;
+
+ res = &uart.resource;
+
+ dev_dbg(&dev->dev, "setup PCI %s console @ 0x%llx-0x%llx\n",
+ res->flags & IORESOURCE_MEM ? "MMIO" : "IO port",
+ res->start, res->end);
+
+ ns16550_dev = device_alloc("ns16550_serial", DEVICE_ID_DYNAMIC);
+ ns16550_dev->platform_data = uart.pdata;
+ ns16550_dev->parent = &dev->dev;
+ device_add_resource(ns16550_dev, NULL,
+ res->start, res->end - res->start + 1,
+ res->flags);
+
+ rc = platform_device_register(ns16550_dev);
+ if (rc < 0) {
+ dev_err(&dev->dev, "couldn't register PCI %s console @0x%llx: %s\n",
+ res->flags & IORESOURCE_MEM ? "MMIO" : "IO port",
+ res->start, strerror(-rc));
+
+ break;
+ }
+ }
+ priv->nr = i;
+ priv->board = board;
+ return priv;
+
+err_deinit:
+ if (quirk->exit)
+ quirk->exit(dev);
+err_out:
+ return priv;
+}
+
+/*
+ * Probe one serial board. Unfortunately, there is no rhyme nor reason
+ * to the arrangement of serial ports on a PCI card.
+ */
+static int
+pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
+{
+ struct pci_serial_quirk *quirk;
+ struct serial_private *priv;
+ const struct pciserial_board *board;
+ const struct pci_device_id *exclude;
+ struct pciserial_board tmp;
+ int rc;
+
+ quirk = find_quirk(dev);
+ if (quirk->probe) {
+ rc = quirk->probe(dev);
+ if (rc)
+ return rc;
+ }
+
+ if (ent->driver_data >= ARRAY_SIZE(pci_boards)) {
+ dev_err(&dev->dev, "invalid driver_data: %ld\n",
+ ent->driver_data);
+ return -EINVAL;
+ }
+
+ board = &pci_boards[ent->driver_data];
+
+ exclude = pci_match_id(blacklist, dev);
+ if (exclude)
+ return -ENODEV;
+
+ rc = pci_enable_device(dev);
+ if (rc)
+ return rc;
+
+ if (ent->driver_data == pbn_default) {
+ /*
+ * Use a copy of the pci_board entry for this;
+ * avoid changing entries in the table.
+ */
+ memcpy(&tmp, board, sizeof(struct pciserial_board));
+ board = &tmp;
+
+ /*
+ * We matched one of our class entries. Try to
+ * determine the parameters of this board.
+ */
+ rc = serial_pci_guess_board(dev, &tmp);
+ if (rc)
+ return rc;
+ } else {
+ /*
+ * We matched an explicit entry. If we are able to
+ * detect this boards settings with our heuristic,
+ * then we no longer need this entry.
+ */
+ memcpy(&tmp, &pci_boards[pbn_default],
+ sizeof(struct pciserial_board));
+ rc = serial_pci_guess_board(dev, &tmp);
+ if (rc == 0 && serial_pci_matches(board, &tmp))
+ moan_device("Redundant entry in serial pci_table.",
+ dev);
+ }
+
+ priv = pciserial_init_ports(dev, board);
+ if (IS_ERR(priv)) {
+ if (PTR_ERR(priv) == -ENOSYS) {
+ dev_err(&dev->dev,
+ "serial port requires not-yet-supported quirky behavior.\n"
+ "Consider porting it over from the Linux 8250_pci driver\n");
+ }
+
+ return PTR_ERR(priv);
+ }
+
+ dev->dev.priv = priv;
+ return 0;
+}
+
+static const struct pci_device_id serial_pci_tbl[] = {
+ /* Advantech use PCI_DEVICE_ID_ADVANTECH_PCI3620 (0x3620) as 'PCI_SUBVENDOR_ID' */
+ { PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620,
+ PCI_DEVICE_ID_ADVANTECH_PCI3620, 0x0001, 0, 0,
+ pbn_b2_8_921600 },
+ /* Advantech also use 0x3618 and 0xf618 */
+ { PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3618,
+ PCI_DEVICE_ID_ADVANTECH_PCI3618, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCIf618,
+ PCI_DEVICE_ID_ADVANTECH_PCI3618, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
+ pbn_b1_8_1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
+ pbn_b1_4_1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
+ pbn_b1_2_1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
+ pbn_b1_8_1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
+ pbn_b1_4_1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
+ pbn_b1_2_1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, 0, 0,
+ pbn_b1_8_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, 0, 0,
+ pbn_b1_8_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, 0, 0,
+ pbn_b1_4_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, 0, 0,
+ pbn_b1_4_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, 0, 0,
+ pbn_b1_2_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, 0, 0,
+ pbn_b1_8_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, 0, 0,
+ pbn_b1_8_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, 0, 0,
+ pbn_b1_4_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_20MHZ, 0, 0,
+ pbn_b1_2_1250000 },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_2, 0, 0,
+ pbn_b0_2_1843200 },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_4, 0, 0,
+ pbn_b0_4_1843200 },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+ PCI_VENDOR_ID_AFAVLAB,
+ PCI_SUBDEVICE_ID_AFAVLAB_P061, 0, 0,
+ pbn_b0_4_1152000 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_1_115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_4_115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_4_115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_8_115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_7803,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_8_460800 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM8,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_8_115200 },
+
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_115200 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_921600 },
+ /*
+ * VScom SPCOM800, from sl@s.pl
+ */
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_8_921600 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_4_921600 },
+ /* Unknown card - subdevice 0x1584 */
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_VENDOR_ID_PLX,
+ PCI_SUBDEVICE_ID_UNKNOWN_0x1584, 0, 0,
+ pbn_b2_4_115200 },
+ /* Unknown card - subdevice 0x1588 */
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_VENDOR_ID_PLX,
+ PCI_SUBDEVICE_ID_UNKNOWN_0x1588, 0, 0,
+ pbn_b2_8_115200 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_KEYSPAN,
+ PCI_SUBDEVICE_ID_KEYSPAN_SX2, 0, 0,
+ pbn_panacom },
+ { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_panacom4 },
+ { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_panacom2 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+ PCI_VENDOR_ID_ESDGMBH,
+ PCI_DEVICE_ID_ESDGMBH_CPCIASIO4, 0, 0,
+ pbn_b2_4_115200 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+ PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0,
+ pbn_b2_4_460800 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+ PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0,
+ pbn_b2_8_460800 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+ PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0,
+ pbn_b2_16_460800 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+ PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0,
+ pbn_b2_16_460800 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_CHASE_PCIRAS,
+ PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0,
+ pbn_b2_4_460800 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_CHASE_PCIRAS,
+ PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0,
+ pbn_b2_8_460800 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_EXSYS,
+ PCI_SUBDEVICE_ID_EXSYS_4055, 0, 0,
+ pbn_b2_4_115200 },
+ /*
+ * Megawolf Romulus PCI Serial Card, from Mike Hudson
+ * (Exoray@isys.ca)
+ */
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS,
+ 0x10b5, 0x106a, 0, 0,
+ pbn_plx_romulus },
+ /*
+ * EndRun Technologies. PCI express device range.
+ * EndRun PTP/1588 has 2 Native UARTs.
+ */
+ { PCI_VENDOR_ID_ENDRUN, PCI_DEVICE_ID_ENDRUN_1588,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_endrun_2_4000000 },
+ /*
+ * Quatech cards. These actually have configurable clocks but for
+ * now we just use the default.
+ *
+ * 100 series are RS232, 200 series RS422,
+ */
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_4_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_2_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100E,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_2_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_2_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC200E,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_2_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_4_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_8_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_8_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCP100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_4_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCP100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_2_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCP200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_4_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCP200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_2_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCLP100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_4_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCLP100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_2_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SSCLP100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_1_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCLP200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_4_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCLP200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_2_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SSCLP200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_1_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESCLP100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_8_115200 },
+
+ { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954,
+ PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4,
+ 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+ PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL,
+ 0, 0,
+ pbn_b0_4_1152000 },
+ { PCI_VENDOR_ID_OXSEMI, 0x9505,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_921600 },
+
+ /*
+ * The below card is a little controversial since it is the
+ * subject of a PCI vendor/device ID clash. (See
+ * www.ussg.iu.edu/hypermail/linux/kernel/0303.1/0516.html).
+ * For now just used the hex ID 0x950a.
+ */
+ { PCI_VENDOR_ID_OXSEMI, 0x950a,
+ PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_00,
+ 0, 0, pbn_b0_2_115200 },
+ { PCI_VENDOR_ID_OXSEMI, 0x950a,
+ PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_30,
+ 0, 0, pbn_b0_2_115200 },
+ { PCI_VENDOR_ID_OXSEMI, 0x950a,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_2_1130000 },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_C950,
+ PCI_VENDOR_ID_OXSEMI, PCI_SUBDEVICE_ID_OXSEMI_C950, 0, 0,
+ pbn_b0_1_921600 },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_115200 },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_921600 },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI958,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_8_1152000 },
+
+ /*
+ * Oxford Semiconductor Inc. Tornado PCI express device range.
+ */
+ { PCI_VENDOR_ID_OXSEMI, 0xc101, /* OXPCIe952 1 Legacy UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc105, /* OXPCIe952 1 Legacy UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc11b, /* OXPCIe952 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc11f, /* OXPCIe952 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc120, /* OXPCIe952 1 Legacy UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc124, /* OXPCIe952 1 Legacy UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc138, /* OXPCIe952 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc13d, /* OXPCIe952 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc140, /* OXPCIe952 1 Legacy UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc141, /* OXPCIe952 1 Legacy UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc144, /* OXPCIe952 1 Legacy UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc145, /* OXPCIe952 1 Legacy UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc158, /* OXPCIe952 2 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_2_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc15d, /* OXPCIe952 2 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_2_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc208, /* OXPCIe954 4 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_4_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc20d, /* OXPCIe954 4 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_4_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc308, /* OXPCIe958 8 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_8_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc30d, /* OXPCIe958 8 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_8_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc40b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc40f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc41b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc41f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc42b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc42f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc43b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc43f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc44b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc44f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc45b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc45f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc46b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc46f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc47b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc47f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc48b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc48f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc49b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc49f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc4ab, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc4af, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc4bb, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc4bf, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc4cb, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc4cf, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ /*
+ * Mainpine Inc. IQ Express "Rev3" utilizing OxSemi Tornado
+ */
+ { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 1 Port V.34 Super-G3 Fax */
+ PCI_VENDOR_ID_MAINPINE, 0x4001, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 2 Port V.34 Super-G3 Fax */
+ PCI_VENDOR_ID_MAINPINE, 0x4002, 0, 0,
+ pbn_oxsemi_2_4000000 },
+ { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 4 Port V.34 Super-G3 Fax */
+ PCI_VENDOR_ID_MAINPINE, 0x4004, 0, 0,
+ pbn_oxsemi_4_4000000 },
+ { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 8 Port V.34 Super-G3 Fax */
+ PCI_VENDOR_ID_MAINPINE, 0x4008, 0, 0,
+ pbn_oxsemi_8_4000000 },
+
+ /*
+ * Digi/IBM PCIe 2-port Async EIA-232 Adapter utilizing OxSemi Tornado
+ */
+ { PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_2_OX_IBM,
+ PCI_SUBVENDOR_ID_IBM, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_2_4000000 },
+
+ /*
+ * SBS Technologies, Inc. P-Octal and PMC-OCTPRO cards,
+ * from skokodyn@yahoo.com
+ */
+ { PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
+ PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_OCTPRO232, 0, 0,
+ pbn_sbsxrsio },
+ { PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
+ PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_OCTPRO422, 0, 0,
+ pbn_sbsxrsio },
+ { PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
+ PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_POCTAL232, 0, 0,
+ pbn_sbsxrsio },
+ { PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
+ PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_POCTAL422, 0, 0,
+ pbn_sbsxrsio },
+
+ /*
+ * Digitan DS560-558, from jimd@esoft.com
+ */
+ { PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_1_115200 },
+
+ /*
+ * Titan Electronic cards
+ * The 400L and 800L have a custom setup quirk.
+ */
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_2_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100L,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_1_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200L,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_bt_2_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400L,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800L,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_8_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200I,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b4_bt_2_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400I,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b4_bt_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800I,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b4_bt_8_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400EH,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EH,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EHB,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100E,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200E,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_2_4000000 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400E,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_4_4000000 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800E,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_8_4000000 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EI,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_2_4000000 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_2_4000000 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200V3,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400V3,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_410V3,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800V3,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800V3B,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_1_460800 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_1_460800 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_1_460800 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_4_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_4_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_4_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_4_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_4_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_4_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_8_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_8_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_8_921600 },
+
+ /*
+ * Computone devices submitted by Doug McNash dmcnash@computone.com
+ */
+ { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+ PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4,
+ 0, 0, pbn_computone_4 },
+ { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+ PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8,
+ 0, 0, pbn_computone_8 },
+ { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+ PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6,
+ 0, 0, pbn_computone_6 },
+
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi },
+ { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
+ PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_1_921600 },
+
+ /*
+ * Sunix PCI serial boards
+ */
+ { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
+ PCI_VENDOR_ID_SUNIX, 0x0001, 0, 0,
+ pbn_sunix_pci_1s },
+ { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
+ PCI_VENDOR_ID_SUNIX, 0x0002, 0, 0,
+ pbn_sunix_pci_2s },
+ { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
+ PCI_VENDOR_ID_SUNIX, 0x0004, 0, 0,
+ pbn_sunix_pci_4s },
+ { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
+ PCI_VENDOR_ID_SUNIX, 0x0084, 0, 0,
+ pbn_sunix_pci_4s },
+ { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
+ PCI_VENDOR_ID_SUNIX, 0x0008, 0, 0,
+ pbn_sunix_pci_8s },
+ { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
+ PCI_VENDOR_ID_SUNIX, 0x0088, 0, 0,
+ pbn_sunix_pci_8s },
+ { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
+ PCI_VENDOR_ID_SUNIX, 0x0010, 0, 0,
+ pbn_sunix_pci_16s },
+
+ /*
+ * AFAVLAB serial card, from Harald Welte <laforge@gnumonks.org>
+ */
+ { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P028,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_8_115200 },
+ { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P030,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_8_115200 },
+
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_115200 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_115200 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_115200 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATTRO_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_115200 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATTRO_B,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_115200 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_4_460800 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_B,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_4_460800 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_460800 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_460800 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_460800 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_1_115200 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_1_460800 },
+
+ /*
+ * Korenix Jetcard F0/F1 cards (JC1204, JC1208, JC1404, JC1408).
+ * Cards are identified by their subsystem vendor IDs, which
+ * (in hex) match the model number.
+ *
+ * Note that JC140x are RS422/485 cards which require ox950
+ * ACR = 0x10, and as such are not currently fully supported.
+ */
+ { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+ 0x1204, 0x0004, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+ 0x1208, 0x0004, 0, 0,
+ pbn_b0_4_921600 },
+/* { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+ 0x1402, 0x0002, 0, 0,
+ pbn_b0_2_921600 }, */
+/* { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+ 0x1404, 0x0004, 0, 0,
+ pbn_b0_4_921600 }, */
+ { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF1,
+ 0x1208, 0x0004, 0, 0,
+ pbn_b0_4_921600 },
+
+ { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2,
+ 0x1204, 0x0004, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2,
+ 0x1208, 0x0004, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF3,
+ 0x1208, 0x0004, 0, 0,
+ pbn_b0_4_921600 },
+ /*
+ * Dell Remote Access Card 4 - Tim_T_Murphy@Dell.com
+ */
+ { PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_RAC4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_1_1382400 },
+
+ /*
+ * Dell Remote Access Card III - Tim_T_Murphy@Dell.com
+ */
+ { PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_RACIII,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_1_1382400 },
+
+ /*
+ * RAStel 2 port modem, gerg@moreton.com.au
+ */
+ { PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_115200 },
+
+ /*
+ * EKF addition for i960 Boards form EKF with serial port
+ */
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80960_RP,
+ 0xE4BF, PCI_ANY_ID, 0, 0,
+ pbn_intel_i960 },
+
+ /*
+ * Xircom Cardbus/Ethernet combos
+ */
+ { PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_115200 },
+ /*
+ * Xircom RBM56G cardbus modem - Dirk Arnold (temp entry)
+ */
+ { PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_RBM56G,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_115200 },
+
+ /*
+ * Untested PCI modems, sent in from various folks...
+ */
+
+ /*
+ * Elsa Model 56K PCI Modem, from Andreas Rath <arh@01019freenet.de>
+ */
+ { PCI_VENDOR_ID_ROCKWELL, 0x1004,
+ 0x1048, 0x1500, 0, 0,
+ pbn_b1_1_115200 },
+
+ { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
+ 0xFF00, 0, 0, 0,
+ pbn_sgi_ioc3 },
+
+ /*
+ * HP Diva card
+ */
+ { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA,
+ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_RMP3, 0, 0,
+ pbn_b1_1_115200 },
+ { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_5_115200 },
+ { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_AUX,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_1_115200 },
+
+ { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b3_2_115200 },
+ { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b3_4_115200 },
+ { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b3_8_115200 },
+ /*
+ * Pericom PI7C9X795[1248] Uno/Dual/Quad/Octal UART
+ */
+ { PCI_VENDOR_ID_PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7951,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0,
+ 0, pbn_pericom_PI7C9X7951 },
+ { PCI_VENDOR_ID_PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7952,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0,
+ 0, pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7954,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0,
+ 0, pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7958,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0,
+ 0, pbn_pericom_PI7C9X7958 },
+ /*
+ * ACCES I/O Products quad
+ */
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SDB,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2S,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_2DB,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SMDB,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2SM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_1,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7951 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2S,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2SM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM422_8,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7958 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM485_8,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7958 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_8,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7958 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_8SM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7958 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ /*
+ * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke)
+ */
+ { PCI_VENDOR_ID_TOPIC, PCI_DEVICE_ID_TOPIC_TP560,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_115200 },
+ /*
+ * ITE
+ */
+ { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8872,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0,
+ pbn_b1_bt_1_115200 },
+
+ /*
+ * IntaShield IS-200
+ */
+ { PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* 135a.0811 */
+ pbn_b2_2_115200 },
+ /*
+ * IntaShield IS-400
+ */
+ { PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS400,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* 135a.0dc0 */
+ pbn_b2_4_115200 },
+ /*
+ * BrainBoxes UC-260
+ */
+ { PCI_VENDOR_ID_INTASHIELD, 0x0D21,
+ PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00,
+ pbn_b2_4_115200 },
+ { PCI_VENDOR_ID_INTASHIELD, 0x0E34,
+ PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00,
+ pbn_b2_4_115200 },
+ /*
+ * Perle PCI-RAS cards
+ */
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+ PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS4,
+ 0, 0, pbn_b2_4_921600 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+ PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS8,
+ 0, 0, pbn_b2_8_921600 },
+
+ /*
+ * Mainpine series cards: Fairly standard layout but fools
+ * parts of the autodetect in some cases and uses otherwise
+ * unmatched communications subclasses in the PCI Express case
+ */
+
+ { /* RockForceDUO */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0200,
+ 0, 0, pbn_b0_2_115200 },
+ { /* RockForceQUATRO */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0300,
+ 0, 0, pbn_b0_4_115200 },
+ { /* RockForceDUO+ */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0400,
+ 0, 0, pbn_b0_2_115200 },
+ { /* RockForceQUATRO+ */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0500,
+ 0, 0, pbn_b0_4_115200 },
+ { /* RockForce+ */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0600,
+ 0, 0, pbn_b0_2_115200 },
+ { /* RockForce+ */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0700,
+ 0, 0, pbn_b0_4_115200 },
+ { /* RockForceOCTO+ */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0800,
+ 0, 0, pbn_b0_8_115200 },
+ { /* RockForceDUO+ */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0C00,
+ 0, 0, pbn_b0_2_115200 },
+ { /* RockForceQUARTRO+ */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0D00,
+ 0, 0, pbn_b0_4_115200 },
+ { /* RockForceOCTO+ */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x1D00,
+ 0, 0, pbn_b0_8_115200 },
+ { /* RockForceD1 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x2000,
+ 0, 0, pbn_b0_1_115200 },
+ { /* RockForceF1 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x2100,
+ 0, 0, pbn_b0_1_115200 },
+ { /* RockForceD2 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x2200,
+ 0, 0, pbn_b0_2_115200 },
+ { /* RockForceF2 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x2300,
+ 0, 0, pbn_b0_2_115200 },
+ { /* RockForceD4 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x2400,
+ 0, 0, pbn_b0_4_115200 },
+ { /* RockForceF4 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x2500,
+ 0, 0, pbn_b0_4_115200 },
+ { /* RockForceD8 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x2600,
+ 0, 0, pbn_b0_8_115200 },
+ { /* RockForceF8 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x2700,
+ 0, 0, pbn_b0_8_115200 },
+ { /* IQ Express D1 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x3000,
+ 0, 0, pbn_b0_1_115200 },
+ { /* IQ Express F1 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x3100,
+ 0, 0, pbn_b0_1_115200 },
+ { /* IQ Express D2 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x3200,
+ 0, 0, pbn_b0_2_115200 },
+ { /* IQ Express F2 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x3300,
+ 0, 0, pbn_b0_2_115200 },
+ { /* IQ Express D4 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x3400,
+ 0, 0, pbn_b0_4_115200 },
+ { /* IQ Express F4 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x3500,
+ 0, 0, pbn_b0_4_115200 },
+ { /* IQ Express D8 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x3C00,
+ 0, 0, pbn_b0_8_115200 },
+ { /* IQ Express F8 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x3D00,
+ 0, 0, pbn_b0_8_115200 },
+
+
+ /*
+ * PA Semi PA6T-1682M on-chip UART
+ */
+ { PCI_VENDOR_ID_PASEMI, 0xa004,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pasemi_1682M },
+
+ /*
+ * National Instruments
+ */
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI23216,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_16_115200 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2328,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_8_115200 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2324,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_bt_4_115200 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2322,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_bt_2_115200 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2324I,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_bt_4_115200 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2322I,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_bt_2_115200 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_23216,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_16_115200 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2328,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_8_115200 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2324,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_bt_4_115200 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2322,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_bt_2_115200 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8422_2324,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_bt_4_115200 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8422_2322,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_bt_2_115200 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2322,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_2 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2322,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_2 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2324,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_4 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2324,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_4 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2328,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_8 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2328,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_8 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_23216,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_16 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_23216,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_16 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8432_2322,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_2 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8432_2322,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_2 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8432_2324,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_4 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8432_2324,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_4 },
+ { PCI_VENDOR_ID_NI, PCIE_DEVICE_ID_NI_PXIE8430_2328,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_pxie_8 },
+ { PCI_VENDOR_ID_NI, PCIE_DEVICE_ID_NI_PXIE8430_23216,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_pxie_16 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8431_4852,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8431_2 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8431_4854,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8431_4 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8431_4858,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8431_8 },
+ { PCI_VENDOR_ID_NI, PCIE_DEVICE_ID_NI_PXIE8431_4858,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8431_pxie_8 },
+ { PCI_VENDOR_ID_NI, PCIE_DEVICE_ID_NI_PXIE8431_48516,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8431_pxie_16 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8433_4852,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8431_2 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8433_4854,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8431_4 },
+
+ /*
+ * MOXA
+ */
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102E,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_moxa8250_2p },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102EL,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_moxa8250_2p },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104EL_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_moxa8250_4p },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP114EL,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_moxa8250_4p },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_moxa8250_8p },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_B,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_moxa8250_8p },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118EL_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_moxa8250_8p },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118E_A_I,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_moxa8250_8p },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132EL,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_moxa8250_2p },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP134EL_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_moxa8250_4p },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP138E_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_moxa8250_8p },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP168EL_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_moxa8250_8p },
+
+ /*
+ * ADDI-DATA GmbH communication cards <info@addi-data.com>
+ */
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7500,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_4_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7420,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_2_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7300,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_1_115200 },
+
+ { PCI_VENDOR_ID_AMCC,
+ PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b1_8_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7500_2,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_4_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7420_2,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_2_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7300_2,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_1_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7500_3,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_4_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7420_3,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_2_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7300_3,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_1_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7800_3,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_8_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCIe7500,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_ADDIDATA_PCIe_4_3906250 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCIe7420,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_ADDIDATA_PCIe_2_3906250 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCIe7300,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_ADDIDATA_PCIe_1_3906250 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCIe7800,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_ADDIDATA_PCIe_8_3906250 },
+
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,
+ PCI_VENDOR_ID_IBM, 0x0299,
+ 0, 0, pbn_b0_bt_2_115200 },
+
+ /*
+ * other NetMos 9835 devices are most likely handled by the
+ * parport_serial driver, check drivers/parport/parport_serial.c
+ * before adding them here.
+ */
+
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901,
+ 0xA000, 0x1000,
+ 0, 0, pbn_b0_1_115200 },
+
+ /* the 9901 is a rebranded 9912 */
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9912,
+ 0xA000, 0x1000,
+ 0, 0, pbn_b0_1_115200 },
+
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9922,
+ 0xA000, 0x1000,
+ 0, 0, pbn_b0_1_115200 },
+
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9904,
+ 0xA000, 0x1000,
+ 0, 0, pbn_b0_1_115200 },
+
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
+ 0xA000, 0x1000,
+ 0, 0, pbn_b0_1_115200 },
+
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
+ 0xA000, 0x3002,
+ 0, 0, pbn_NETMOS9900_2s_115200 },
+
+ /*
+ * Best Connectivity and Rosewill PCI Multi I/O cards
+ */
+
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
+ 0xA000, 0x1000,
+ 0, 0, pbn_b0_1_115200 },
+
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
+ 0xA000, 0x3002,
+ 0, 0, pbn_b0_bt_2_115200 },
+
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
+ 0xA000, 0x3004,
+ 0, 0, pbn_b0_bt_4_115200 },
+ /* Intel CE4100 */
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CE4100_UART,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ce4100_1_115200 },
+
+ /*
+ * Cronyx Omega PCI
+ */
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_CRONYX_OMEGA,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_omegapci },
+
+ /*
+ * Broadcom TruManage
+ */
+ { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BROADCOM_TRUMANAGE,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_brcm_trumanage },
+
+ /*
+ * AgeStar as-prs2-009
+ */
+ { PCI_VENDOR_ID_AGESTAR, PCI_DEVICE_ID_AGESTAR_9375,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, pbn_b0_bt_2_115200 },
+
+ /*
+ * WCH CH353 series devices: The 2S1P is handled by parport_serial
+ * so not listed here.
+ */
+ { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH353_4S,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, pbn_b0_bt_4_115200 },
+
+ { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH353_2S1PF,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, pbn_b0_bt_2_115200 },
+
+ { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH355_4S,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, pbn_b0_bt_4_115200 },
+
+ { PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH382_2S,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, pbn_wch382_2 },
+
+ { PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH384_4S,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, pbn_wch384_4 },
+
+ /* Fintek PCI serial cards */
+ { PCI_DEVICE(0x1c29, 0x1104), .driver_data = pbn_fintek_4 },
+ { PCI_DEVICE(0x1c29, 0x1108), .driver_data = pbn_fintek_8 },
+ { PCI_DEVICE(0x1c29, 0x1112), .driver_data = pbn_fintek_12 },
+ { PCI_DEVICE(0x1c29, 0x1204), .driver_data = pbn_fintek_F81504A },
+ { PCI_DEVICE(0x1c29, 0x1208), .driver_data = pbn_fintek_F81508A },
+ { PCI_DEVICE(0x1c29, 0x1212), .driver_data = pbn_fintek_F81512A },
+
+ /* MKS Tenta SCOM-080x serial cards */
+ { PCI_DEVICE(0x1601, 0x0800), .driver_data = pbn_b0_4_1250000 },
+ { PCI_DEVICE(0x1601, 0xa801), .driver_data = pbn_b0_4_1250000 },
+
+ /* Amazon PCI serial device */
+ { PCI_DEVICE(0x1d0f, 0x8250), .driver_data = pbn_b0_1_115200 },
+
+ /*
+ * These entries match devices with class COMMUNICATION_SERIAL,
+ * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
+ */
+ { PCI_ANY_ID, PCI_ANY_ID,
+ PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_COMMUNICATION_SERIAL << 8,
+ 0xffff00, pbn_default },
+ { PCI_ANY_ID, PCI_ANY_ID,
+ PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_COMMUNICATION_MODEM << 8,
+ 0xffff00, pbn_default },
+ { PCI_ANY_ID, PCI_ANY_ID,
+ PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_COMMUNICATION_MULTISERIAL << 8,
+ 0xffff00, pbn_default },
+ { 0, }
+};
+
+static struct pci_driver serial_pci_driver = {
+ .name = "ns16550_serial_pci",
+ .probe = pciserial_init_one,
+ .id_table = serial_pci_tbl,
+};
+
+static int __init serial_pci_register(void)
+{
+ return pci_driver_register(&serial_pci_driver);
+}
+console_initcall(serial_pci_register);
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index d9311d4..bd615b4 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -283,7 +283,7 @@ int spi_register_controller(struct spi_controller *ctrl)
return status;
}
-EXPORT_SYMBOL(spi_register_ctrl);
+EXPORT_SYMBOL(spi_register_controller);
struct spi_controller *spi_get_controller(int bus)
{
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index 09da121..aa04897 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -1,7 +1,9 @@
config USB_DWC3
tristate "DesignWare USB3 DRD Core Support"
depends on USB && HAS_DMA
+ depends on OFDEVICE
select USB_XHCI
+ select USB_OTGDEV
help
Say Y or M here if your system has a Dual Role SuperSpeed
USB controller based on the DesignWare USB3 IP Core.
@@ -29,6 +31,7 @@ config USB_DWC3_GADGET
config USB_DWC3_DUAL_ROLE
bool "Dual Role mode"
+ depends on USB_GADGET
help
This is the default mode of working of DWC3 controller where
both host and gadget features are enabled.
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index d3f9d9e..04b700d 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -348,12 +348,9 @@ static void dwc3_frame_length_adjustment(struct dwc3 *dwc)
reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
dft = reg & DWC3_GFLADJ_30MHZ_MASK;
- if (!WARN(dft == dwc->fladj,
- "request value same as default, ignoring\n")) {
- reg &= ~DWC3_GFLADJ_30MHZ_MASK;
- reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj;
- dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
- }
+ reg &= ~DWC3_GFLADJ_30MHZ_MASK;
+ reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj;
+ dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
}
static void dwc3_core_num_eps(struct dwc3 *dwc)
@@ -914,7 +911,6 @@ static int dwc3_core_get_phy(struct dwc3 *dwc)
if (IS_ERR(dwc->usb2_generic_phy)) {
ret = PTR_ERR(dwc->usb2_generic_phy);
if (ret == -ENOSYS || ret == -ENODEV) {
- dev_err(dev, "no usb2 phy configured\n");
dwc->usb2_generic_phy = NULL;
} else if (ret == -EPROBE_DEFER) {
return ret;
@@ -928,7 +924,6 @@ static int dwc3_core_get_phy(struct dwc3 *dwc)
if (IS_ERR(dwc->usb3_generic_phy)) {
ret = PTR_ERR(dwc->usb3_generic_phy);
if (ret == -ENOSYS || ret == -ENODEV) {
- dev_err(dev, "no usb2 phy configured\n");
dwc->usb3_generic_phy = NULL;
} else if (ret == -EPROBE_DEFER) {
return ret;
@@ -941,12 +936,13 @@ static int dwc3_core_get_phy(struct dwc3 *dwc)
return 0;
}
-static int dwc3_core_init_mode(struct dwc3 *dwc)
+static int dwc3_set_mode(void *ctx, enum usb_dr_mode mode)
{
+ struct dwc3 *dwc = ctx;
struct device_d *dev = dwc->dev;
int ret;
- switch (dwc->dr_mode) {
+ switch (mode) {
case USB_DR_MODE_PERIPHERAL:
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
@@ -968,13 +964,20 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
}
break;
default:
- dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
return -EINVAL;
}
return 0;
}
+static int dwc3_core_init_mode(struct dwc3 *dwc)
+{
+ if (dwc->dr_mode == USB_DR_MODE_OTG)
+ return usb_register_otg_device(dwc->dev, dwc3_set_mode, dwc);
+ else
+ return dwc3_set_mode(dwc, dwc->dr_mode);
+}
+
static void dwc3_get_properties(struct dwc3 *dwc)
{
struct device_d *dev = dwc->dev;
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index df0a188..f2f7a31 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -1336,7 +1336,6 @@ struct dwc3_gadget_ep_cmd_params {
/* prototypes */
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode);
-void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
/* check whether we are on the DWC_usb3 core */
static inline bool dwc3_is_usb3(struct dwc3 *dwc)
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
index 82a202c..35c4b8c 100644
--- a/drivers/usb/gadget/f_fastboot.c
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -861,7 +861,7 @@ static int check_ubi(struct f_fastboot *f_fb, struct file_list_entry *fentry,
if (filetype == filetype_ubi) {
fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO,
- "This is an UBI image...");
+ "This is a UBI image...");
return 1;
} else {
fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL,
diff --git a/drivers/usb/imx/Kconfig b/drivers/usb/imx/Kconfig
index 05f17fb..34f35e0 100644
--- a/drivers/usb/imx/Kconfig
+++ b/drivers/usb/imx/Kconfig
@@ -2,6 +2,7 @@
config USB_IMX_CHIPIDEA
bool "i.MX USB support (read help)"
depends on ARCH_IMX
+ select USB_OTGDEV
help
The Freescale i.MX SoCs have a variant of the chipidea ci13xxx for
USB support. Traditionally in barebox this is supported through the
diff --git a/drivers/usb/imx/chipidea-imx.c b/drivers/usb/imx/chipidea-imx.c
index 6c60c38..3cf5d26 100644
--- a/drivers/usb/imx/chipidea-imx.c
+++ b/drivers/usb/imx/chipidea-imx.c
@@ -36,12 +36,11 @@ struct imx_chipidea {
void __iomem *base;
struct ehci_data data;
unsigned long flags;
- uint32_t mode;
+ enum usb_dr_mode mode;
int portno;
struct device_d *usbmisc;
enum usb_phy_interface phymode;
struct param_d *param_mode;
- int role_registered;
struct regulator *vbus;
struct phy *phy;
struct usb_phy *usbphy;
@@ -103,7 +102,6 @@ static int imx_chipidea_port_post_init(void *drvdata)
static int imx_chipidea_probe_dt(struct imx_chipidea *ci)
{
struct of_phandle_args out_args;
- enum usb_dr_mode mode;
if (of_parse_phandle_with_args(ci->dev->device_node, "fsl,usbmisc",
"#index-cells", 0, &out_args))
@@ -116,29 +114,17 @@ static int imx_chipidea_probe_dt(struct imx_chipidea *ci)
ci->portno = out_args.args[0];
ci->flags = MXC_EHCI_MODE_UTMI_8BIT;
- mode = of_usb_get_dr_mode(ci->dev->device_node, NULL);
+ ci->mode = of_usb_get_dr_mode(ci->dev->device_node, NULL);
- switch (mode) {
- case USB_DR_MODE_HOST:
- default:
- ci->mode = IMX_USB_MODE_HOST;
- break;
- case USB_DR_MODE_PERIPHERAL:
- ci->mode = IMX_USB_MODE_DEVICE;
- break;
- case USB_DR_MODE_OTG:
- ci->mode = IMX_USB_MODE_OTG;
- break;
- case USB_DR_MODE_UNKNOWN:
+ if (ci->mode == USB_DR_MODE_UNKNOWN) {
/*
* No dr_mode specified. This means it can either be OTG
* for port 0 or host mode for the other host-only ports.
*/
if (ci->portno == 0)
- ci->mode = IMX_USB_MODE_OTG;
+ ci->mode = USB_DR_MODE_OTG;
else
- ci->mode = IMX_USB_MODE_HOST;
- break;
+ ci->mode = USB_DR_MODE_HOST;
}
ci->phymode = of_usb_get_phy_mode(ci->dev->device_node, NULL);
@@ -184,18 +170,15 @@ static int ci_ehci_detect(struct device_d *dev)
return ehci_detect(ci->ehci);
}
-static int ci_register_role(struct imx_chipidea *ci)
+static int ci_set_mode(void *ctx, enum usb_dr_mode mode)
{
+ struct imx_chipidea *ci = ctx;
int ret;
- if (ci->role_registered != IMX_USB_MODE_OTG)
- return -EBUSY;
-
- if (ci->mode == IMX_USB_MODE_HOST) {
+ if (mode == USB_DR_MODE_HOST) {
if (IS_ENABLED(CONFIG_USB_EHCI)) {
struct ehci_host *ehci;
- ci->role_registered = IMX_USB_MODE_HOST;
ret = regulator_enable(ci->vbus);
if (ret)
return ret;
@@ -215,10 +198,9 @@ static int ci_register_role(struct imx_chipidea *ci)
}
}
- if (ci->mode == IMX_USB_MODE_DEVICE) {
+ if (mode == USB_DR_MODE_PERIPHERAL) {
if (IS_ENABLED(CONFIG_USB_GADGET_DRIVER_ARC)) {
struct fsl_udc *udc;
- ci->role_registered = IMX_USB_MODE_DEVICE;
udc = ci_udc_register(ci->dev, ci->base);
if (IS_ERR(udc))
@@ -234,48 +216,6 @@ static int ci_register_role(struct imx_chipidea *ci)
return 0;
}
-static int ci_set_mode(struct param_d *param, void *priv)
-{
- struct imx_chipidea *ci = priv;
-
- if (ci->role_registered != IMX_USB_MODE_OTG) {
- if (ci->role_registered == ci->mode)
- return 0;
- else
- return -EBUSY;
- }
-
- return ci_register_role(ci);
-}
-
-static const char *ci_mode_names[] = {
- "host", "peripheral", "otg"
-};
-
-static struct device_d imx_otg_device = {
- .name = "otg",
- .id = DEVICE_ID_SINGLE,
-};
-
-static int ci_register_otg_device(struct imx_chipidea *ci)
-{
- int ret;
-
- if (imx_otg_device.parent)
- return -EBUSY;
-
- imx_otg_device.parent = ci->dev;
-
- ret = register_device(&imx_otg_device);
- if (ret)
- return ret;
-
- ci->param_mode = dev_add_param_enum(&imx_otg_device, "mode",
- ci_set_mode, NULL, &ci->mode,
- ci_mode_names, ARRAY_SIZE(ci_mode_names), ci);
- return 0;
-}
-
static int imx_chipidea_probe(struct device_d *dev)
{
struct resource *iores;
@@ -288,7 +228,6 @@ static int imx_chipidea_probe(struct device_d *dev)
ci = xzalloc(sizeof(*ci));
ci->dev = dev;
dev->priv = ci;
- ci->role_registered = IMX_USB_MODE_OTG;
if (IS_ENABLED(CONFIG_OFDEVICE) && dev->device_node) {
ret = imx_chipidea_probe_dt(ci);
@@ -361,10 +300,10 @@ static int imx_chipidea_probe(struct device_d *dev)
ci->data.hcor = base + 0x140;
ci->data.flags = EHCI_HAS_TT;
- if (ci->mode == IMX_USB_MODE_OTG)
- ret = ci_register_otg_device(ci);
+ if (ci->mode == USB_DR_MODE_OTG)
+ ret = usb_register_otg_device(ci->dev, ci_set_mode, ci);
else
- ret = ci_register_role(ci);
+ ret = ci_set_mode(ci, ci->mode);
return ret;
};
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index 7d6c9da..270606f 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -6,6 +6,7 @@ comment "USB Miscellaneous drivers"
config USB_HUB_USB251XB
bool "USB251XB Hub Controller Configuration Driver"
depends on I2C
+ depends on OFDEVICE
select NLS
help
This option enables support for configuration via SMBus of the
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index b795f30..127d6d1 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -6,6 +6,7 @@ if USB_MUSB
config USB_MUSB_DSPS
tristate
select OFDEVICE
+ select USB_OTGDEV
config USB_MUSB_AM335X
tristate "AM335x USB support"
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 5fe3bcb..3b76b6c 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -303,50 +303,20 @@ static int get_musb_port_mode(struct device_d *dev)
}
}
-static int dsps_set_mode(struct param_d *param, void *priv)
+static int dsps_set_mode(void *ctx, enum usb_dr_mode mode)
{
- struct dsps_glue *glue = priv;
+ struct dsps_glue *glue = ctx;
- if (glue->pdata.mode != MUSB_PORT_MODE_DUAL_ROLE)
- return -EBUSY;
-
- switch (glue->otgmode) {
- case 0:
- default:
- return -EINVAL;
- case 1:
+ if (mode == USB_DR_MODE_HOST)
glue->pdata.mode = MUSB_PORT_MODE_HOST;
- break;
- case 2:
+ else if (mode == USB_DR_MODE_PERIPHERAL)
glue->pdata.mode = MUSB_PORT_MODE_GADGET;
- break;
- }
+ else
+ return -EINVAL;
return musb_init_controller(&glue->musb, &glue->pdata);
}
-static const char *dsps_mode_names[] = {
- "otg", "host", "peripheral"
-};
-
-static int dsps_register_otg_device(struct dsps_glue *glue)
-{
- int ret;
-
- dev_set_name(&glue->otg_dev, "otg");
- glue->otg_dev.id = DEVICE_ID_DYNAMIC,
- glue->otg_dev.parent = glue->dev;
-
- ret = register_device(&glue->otg_dev);
- if (ret)
- return ret;
-
- dev_add_param_enum(&glue->otg_dev, "mode",
- dsps_set_mode, NULL, &glue->otgmode,
- dsps_mode_names, ARRAY_SIZE(dsps_mode_names), glue);
- return 0;
-}
-
static int dsps_probe(struct device_d *dev)
{
struct resource *iores;
@@ -405,7 +375,7 @@ static int dsps_probe(struct device_d *dev)
config->multipoint = of_property_read_bool(dn, "mentor,multipoint");
if (pdata->mode == MUSB_PORT_MODE_DUAL_ROLE) {
- ret = dsps_register_otg_device(glue);
+ ret = usb_register_otg_device(dev, dsps_set_mode, glue);
if (ret)
return ret;
return 0;
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
index 2c9fb46..2c09445 100644
--- a/drivers/usb/otg/Kconfig
+++ b/drivers/usb/otg/Kconfig
@@ -6,3 +6,7 @@ config USB_ULPI
config USB_TWL4030
depends on MFD_TWL4030
bool "TWL4030 Transceiver support"
+
+config USB_OTGDEV
+ bool
+
diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile
index 465a7f0..49c2491 100644
--- a/drivers/usb/otg/Makefile
+++ b/drivers/usb/otg/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_USB_ULPI) += ulpi.o
obj-$(CONFIG_USB_TWL4030) += twl4030.o
-
+obj-$(CONFIG_USB_OTGDEV) += otgdev.o
diff --git a/drivers/usb/otg/otgdev.c b/drivers/usb/otg/otgdev.c
new file mode 100644
index 0000000..7017796
--- /dev/null
+++ b/drivers/usb/otg/otgdev.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <common.h>
+#include <driver.h>
+#include <usb/usb.h>
+
+static int (*set_mode_callback)(void *ctx, enum usb_dr_mode mode);
+static unsigned int otg_mode;
+
+static int otg_set_mode(struct param_d *param, void *ctx)
+{
+ static int cur_mode = USB_DR_MODE_OTG;
+ int ret;
+
+ if (otg_mode == USB_DR_MODE_UNKNOWN)
+ return -EINVAL;
+
+ if (otg_mode == cur_mode)
+ return 0;
+
+ if (cur_mode != USB_DR_MODE_OTG)
+ return -EBUSY;
+
+ ret = set_mode_callback(ctx, otg_mode);
+ if (ret)
+ return ret;
+
+ cur_mode = otg_mode;
+
+ return 0;
+}
+
+static const char *otg_mode_names[] = {
+ [USB_DR_MODE_UNKNOWN] = "unknown",
+ [USB_DR_MODE_HOST] = "host",
+ [USB_DR_MODE_PERIPHERAL] = "peripheral",
+ [USB_DR_MODE_OTG] = "otg",
+};
+
+static struct device_d otg_device = {
+ .name = "otg",
+ .id = DEVICE_ID_SINGLE,
+};
+
+int usb_register_otg_device(struct device_d *parent,
+ int (*set_mode)(void *ctx, enum usb_dr_mode mode), void *ctx)
+{
+ int ret;
+ struct param_d *param_mode;
+
+ if (otg_device.parent)
+ return -EBUSY;
+
+ otg_device.parent = parent;
+ set_mode_callback = set_mode;
+ otg_mode = USB_DR_MODE_OTG;
+
+ ret = register_device(&otg_device);
+ if (ret)
+ return ret;
+
+ param_mode = dev_add_param_enum(&otg_device, "mode",
+ otg_set_mode, NULL, &otg_mode,
+ otg_mode_names, ARRAY_SIZE(otg_mode_names), ctx);
+ if (IS_ERR(param_mode))
+ return PTR_ERR(param_mode);
+
+ return 0;
+}
diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c
index 4d252e5..c7a5cb9 100644
--- a/drivers/watchdog/stm32_iwdg.c
+++ b/drivers/watchdog/stm32_iwdg.c
@@ -132,7 +132,7 @@ static int stm32_iwdg_set_timeout(struct watchdog *wdd, unsigned int timeout)
int ret;
if (!timeout)
- return -EINVAL; /* can't disable */
+ return -ENOSYS; /* can't disable */
if (timeout > wdd->timeout_max)
return -EINVAL;
@@ -256,6 +256,7 @@ static int stm32_iwdg_probe(struct device_d *dev)
wdd->set_timeout = stm32_iwdg_set_timeout;
wdd->timeout_max = (RLR_MAX + 1) * data->max_prescaler * 1000;
wdd->timeout_max /= wd->rate * 1000;
+ wdd->running = WDOG_HW_RUNNING_UNSUPPORTED; /* ONF bit not present in IP */
ret = watchdog_register(wdd);
if (ret) {
diff --git a/drivers/watchdog/stpmic1_wdt.c b/drivers/watchdog/stpmic1_wdt.c
index 9b7a586..40273ff 100644
--- a/drivers/watchdog/stpmic1_wdt.c
+++ b/drivers/watchdog/stpmic1_wdt.c
@@ -14,22 +14,15 @@
#include <restart.h>
#include <reset_source.h>
-#define RESTART_SR 0x05
-#define MAIN_CR 0x10
-#define WCHDG_CR 0x1B
-#define WCHDG_TIMER_CR 0x1C
+#include <linux/mfd/stpmic1.h>
-/* Restart Status Register (RESTART_SR) */
+/* Restart Status Register (RREQ_STATE_SR) */
#define R_RST BIT(0)
#define R_SWOFF BIT(1)
#define R_WDG BIT(2)
#define R_PKEYLKP BIT(3)
#define R_VINOK_FA BIT(4)
-/* Main PMIC Control Register (MAIN_CR) */
-#define SWOFF BIT(0)
-#define RREQ_EN BIT(1)
-
/* Watchdog Control Register (WCHDG_CR) */
#define WDT_START BIT(0)
#define WDT_PING BIT(1)
@@ -106,8 +99,9 @@ static void __noreturn stpmic1_restart_handler(struct restart_handler *rst)
{
struct stpmic1_wdt *wdt = container_of(rst, struct stpmic1_wdt, restart);
- regmap_write_bits(wdt->regmap, MAIN_CR,
- SWOFF | RREQ_EN, SWOFF | RREQ_EN);
+ regmap_write_bits(wdt->regmap, SWOFF_PWRCTRL_CR,
+ SOFTWARE_SWITCH_OFF_ENABLED | RESTART_REQUEST_ENABLED,
+ SOFTWARE_SWITCH_OFF_ENABLED | RESTART_REQUEST_ENABLED);
mdelay(1000);
hang();
@@ -119,8 +113,9 @@ static void __noreturn stpmic1_poweroff(struct poweroff_handler *handler)
shutdown_barebox();
- regmap_write_bits(wdt->regmap, MAIN_CR,
- SWOFF | RREQ_EN, SWOFF);
+ regmap_write_bits(wdt->regmap, SWOFF_PWRCTRL_CR,
+ SOFTWARE_SWITCH_OFF_ENABLED | RESTART_REQUEST_ENABLED,
+ SOFTWARE_SWITCH_OFF_ENABLED);
mdelay(1000);
hang();
@@ -142,7 +137,7 @@ static int stpmic1_set_reset_reason(struct regmap *map)
int ret;
int i, instance = 0;
- ret = regmap_read(map, RESTART_SR, &reg);
+ ret = regmap_read(map, RREQ_STATE_SR, &reg);
if (ret)
return ret;
@@ -156,7 +151,7 @@ static int stpmic1_set_reset_reason(struct regmap *map)
reset_source_set_prinst(type, 400, instance);
- pr_info("STPMIC1 reset reason %s (RESTART_SR: 0x%08x)\n",
+ pr_info("STPMIC1 reset reason %s (RREQ_STATE_SR: 0x%08x)\n",
reset_source_name(), reg);
return 0;
@@ -180,7 +175,8 @@ static int stpmic1_wdt_probe(struct device_d *dev)
wdd->timeout_max = PMIC_WDT_MAX_TIMEOUT;
/* have the watchdog reset, not power-off the system */
- regmap_write_bits(wdt->regmap, MAIN_CR, RREQ_EN, RREQ_EN);
+ regmap_write_bits(wdt->regmap, SWOFF_PWRCTRL_CR,
+ RESTART_REQUEST_ENABLED, RESTART_REQUEST_ENABLED);
ret = watchdog_register(wdd);
if (ret) {
diff --git a/drivers/watchdog/wd_core.c b/drivers/watchdog/wd_core.c
index fcead11..b6e2a37 100644
--- a/drivers/watchdog/wd_core.c
+++ b/drivers/watchdog/wd_core.c
@@ -152,12 +152,6 @@ static unsigned int dev_get_watchdog_priority(struct device_d *dev)
return priority;
}
-const char *running_names[] = {
- [WDOG_HW_RUNNING_UNSUPPORTED] = "unknown",
- [WDOG_HW_RUNNING] = "1",
- [WDOG_HW_NOT_RUNNING] = "0",
-};
-
int watchdog_register(struct watchdog *wd)
{
struct param_d *p;
@@ -176,8 +170,7 @@ int watchdog_register(struct watchdog *wd)
if (ret)
return ret;
- p = dev_add_param_enum_ro(&wd->dev, "running", &wd->running,
- running_names, ARRAY_SIZE(running_names));
+ p = dev_add_param_tristate_ro(&wd->dev, "running", &wd->running);
if (IS_ERR(p))
return PTR_ERR(p);
diff --git a/dts/scripts/cronjob b/dts/scripts/cronjob
index ccdbc06..b7511e4 100755
--- a/dts/scripts/cronjob
+++ b/dts/scripts/cronjob
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
set -e
diff --git a/dts/scripts/index-filter.sh b/dts/scripts/index-filter.sh
index 9610855..c301fce 100755
--- a/dts/scripts/index-filter.sh
+++ b/dts/scripts/index-filter.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
set -e
set -o pipefail
diff --git a/dts/scripts/merge-new-release.sh b/dts/scripts/merge-new-release.sh
index a2763c6..554b97b 100755
--- a/dts/scripts/merge-new-release.sh
+++ b/dts/scripts/merge-new-release.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
case $1 in
v*-dts) ;;
diff --git a/dts/src/arm/imx6-logicpd-baseboard.dtsi b/dts/src/arm/imx6-logicpd-baseboard.dtsi
index 2a6ce87..9e027b9 100644
--- a/dts/src/arm/imx6-logicpd-baseboard.dtsi
+++ b/dts/src/arm/imx6-logicpd-baseboard.dtsi
@@ -328,6 +328,10 @@
pinctrl-0 = <&pinctrl_pwm3>;
};
+&snvs_pwrkey {
+ status = "okay";
+};
+
&ssi2 {
status = "okay";
};
diff --git a/dts/src/arm/imx6qdl-sabreauto.dtsi b/dts/src/arm/imx6qdl-sabreauto.dtsi
index f3404dd..cf62846 100644
--- a/dts/src/arm/imx6qdl-sabreauto.dtsi
+++ b/dts/src/arm/imx6qdl-sabreauto.dtsi
@@ -230,6 +230,8 @@
accelerometer@1c {
compatible = "fsl,mma8451";
reg = <0x1c>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_mma8451_int>;
interrupt-parent = <&gpio6>;
interrupts = <31 IRQ_TYPE_LEVEL_LOW>;
};
@@ -628,6 +630,12 @@
>;
};
+ pinctrl_mma8451_int: mma8451intgrp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_BCLK__GPIO6_IO31 0xb0b1
+ >;
+ };
+
pinctrl_pwm3: pwm1grp {
fsl,pins = <
MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1
diff --git a/dts/src/arm/stm32mp157c-ev1.dts b/dts/src/arm/stm32mp157c-ev1.dts
index 89d29b5..91fc0a3 100644
--- a/dts/src/arm/stm32mp157c-ev1.dts
+++ b/dts/src/arm/stm32mp157c-ev1.dts
@@ -183,14 +183,12 @@
ov5640: camera@3c {
compatible = "ovti,ov5640";
- pinctrl-names = "default";
- pinctrl-0 = <&ov5640_pins>;
reg = <0x3c>;
clocks = <&clk_ext_camera>;
clock-names = "xclk";
DOVDD-supply = <&v2v8>;
- powerdown-gpios = <&stmfx_pinctrl 18 GPIO_ACTIVE_HIGH>;
- reset-gpios = <&stmfx_pinctrl 19 GPIO_ACTIVE_LOW>;
+ powerdown-gpios = <&stmfx_pinctrl 18 (GPIO_ACTIVE_HIGH | GPIO_PUSH_PULL)>;
+ reset-gpios = <&stmfx_pinctrl 19 (GPIO_ACTIVE_LOW | GPIO_PUSH_PULL)>;
rotation = <180>;
status = "okay";
@@ -223,15 +221,8 @@
joystick_pins: joystick {
pins = "gpio0", "gpio1", "gpio2", "gpio3", "gpio4";
- drive-push-pull;
bias-pull-down;
};
-
- ov5640_pins: camera {
- pins = "agpio2", "agpio3"; /* stmfx pins 18 & 19 */
- drive-push-pull;
- output-low;
- };
};
};
};
diff --git a/dts/src/arm/stm32mp157c.dtsi b/dts/src/arm/stm32mp157c.dtsi
index 9b11654..f98e037 100644
--- a/dts/src/arm/stm32mp157c.dtsi
+++ b/dts/src/arm/stm32mp157c.dtsi
@@ -932,7 +932,7 @@
interrupt-names = "int0", "int1";
clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>;
clock-names = "hclk", "cclk";
- bosch,mram-cfg = <0x1400 0 0 32 0 0 2 2>;
+ bosch,mram-cfg = <0x0 0 0 32 0 0 2 2>;
status = "disabled";
};
@@ -945,7 +945,7 @@
interrupt-names = "int0", "int1";
clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>;
clock-names = "hclk", "cclk";
- bosch,mram-cfg = <0x0 0 0 32 0 0 2 2>;
+ bosch,mram-cfg = <0x1400 0 0 32 0 0 2 2>;
status = "disabled";
};
diff --git a/dts/src/arm/sun8i-a83t-tbs-a711.dts b/dts/src/arm/sun8i-a83t-tbs-a711.dts
index 568b90e..3bec3e0 100644
--- a/dts/src/arm/sun8i-a83t-tbs-a711.dts
+++ b/dts/src/arm/sun8i-a83t-tbs-a711.dts
@@ -192,6 +192,7 @@
vqmmc-supply = <&reg_dldo1>;
non-removable;
wakeup-source;
+ keep-power-in-suspend;
status = "okay";
brcmf: wifi@1 {
diff --git a/dts/src/arm64/freescale/fsl-ls1028a-qds.dts b/dts/src/arm64/freescale/fsl-ls1028a-qds.dts
index d98346d..078a501 100644
--- a/dts/src/arm64/freescale/fsl-ls1028a-qds.dts
+++ b/dts/src/arm64/freescale/fsl-ls1028a-qds.dts
@@ -127,7 +127,7 @@
status = "okay";
i2c-mux@77 {
- compatible = "nxp,pca9847";
+ compatible = "nxp,pca9547";
reg = <0x77>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/dts/src/arm64/freescale/imx8mm.dtsi b/dts/src/arm64/freescale/imx8mm.dtsi
index 58b8cd0..23c8fad 100644
--- a/dts/src/arm64/freescale/imx8mm.dtsi
+++ b/dts/src/arm64/freescale/imx8mm.dtsi
@@ -394,7 +394,7 @@
};
sdma2: dma-controller@302c0000 {
- compatible = "fsl,imx8mm-sdma", "fsl,imx7d-sdma";
+ compatible = "fsl,imx8mm-sdma", "fsl,imx8mq-sdma";
reg = <0x302c0000 0x10000>;
interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MM_CLK_SDMA2_ROOT>,
@@ -405,7 +405,7 @@
};
sdma3: dma-controller@302b0000 {
- compatible = "fsl,imx8mm-sdma", "fsl,imx7d-sdma";
+ compatible = "fsl,imx8mm-sdma", "fsl,imx8mq-sdma";
reg = <0x302b0000 0x10000>;
interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MM_CLK_SDMA3_ROOT>,
@@ -737,7 +737,7 @@
};
sdma1: dma-controller@30bd0000 {
- compatible = "fsl,imx8mm-sdma", "fsl,imx7d-sdma";
+ compatible = "fsl,imx8mm-sdma", "fsl,imx8mq-sdma";
reg = <0x30bd0000 0x10000>;
interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MM_CLK_SDMA1_ROOT>,
diff --git a/dts/src/arm64/freescale/imx8mn.dtsi b/dts/src/arm64/freescale/imx8mn.dtsi
index 98496f5..43c4db3 100644
--- a/dts/src/arm64/freescale/imx8mn.dtsi
+++ b/dts/src/arm64/freescale/imx8mn.dtsi
@@ -288,7 +288,7 @@
};
sdma3: dma-controller@302b0000 {
- compatible = "fsl,imx8mn-sdma", "fsl,imx7d-sdma";
+ compatible = "fsl,imx8mn-sdma", "fsl,imx8mq-sdma";
reg = <0x302b0000 0x10000>;
interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MN_CLK_SDMA3_ROOT>,
@@ -299,7 +299,7 @@
};
sdma2: dma-controller@302c0000 {
- compatible = "fsl,imx8mn-sdma", "fsl,imx7d-sdma";
+ compatible = "fsl,imx8mn-sdma", "fsl,imx8mq-sdma";
reg = <0x302c0000 0x10000>;
interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MN_CLK_SDMA2_ROOT>,
@@ -612,7 +612,7 @@
};
sdma1: dma-controller@30bd0000 {
- compatible = "fsl,imx8mn-sdma", "fsl,imx7d-sdma";
+ compatible = "fsl,imx8mn-sdma", "fsl,imx8mq-sdma";
reg = <0x30bd0000 0x10000>;
interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MN_CLK_SDMA1_ROOT>,
diff --git a/dts/src/arm64/freescale/imx8mq-zii-ultra.dtsi b/dts/src/arm64/freescale/imx8mq-zii-ultra.dtsi
index 087b5b6..32ce149 100644
--- a/dts/src/arm64/freescale/imx8mq-zii-ultra.dtsi
+++ b/dts/src/arm64/freescale/imx8mq-zii-ultra.dtsi
@@ -88,7 +88,7 @@
regulator-name = "0V9_ARM";
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <1000000>;
- gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>;
+ gpios = <&gpio3 16 GPIO_ACTIVE_HIGH>;
states = <1000000 0x1
900000 0x0>;
regulator-always-on;
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index 15c0174..f4b7722 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -46,35 +46,6 @@ void pstore_set_kmsg_bytes(int bytes)
static int pstore_ready;
-static void pstore_console_write(const char *s, unsigned c)
-{
- const char *e = s + c;
-
- while (s < e) {
- struct pstore_record record = {
- .type = PSTORE_TYPE_CONSOLE,
- .psi = psinfo,
- };
-
- if (c > psinfo->bufsize)
- c = psinfo->bufsize;
-
- record.buf = (char *)s;
- record.size = c;
- psinfo->write_buf(PSTORE_TYPE_CONSOLE, 0, &record.id, 0,
- record.buf, 0, record.size, psinfo);
- s += c;
- c = e - s;
- }
-}
-
-static int pstore_console_puts(struct console_device *cdev, const char *s,
- size_t nbytes)
-{
- pstore_console_write(s, nbytes);
- return nbytes;
-}
-
void pstore_log(const char *str)
{
uint64_t id;
@@ -102,6 +73,9 @@ static void pstore_console_capture_log(void)
uint64_t id;
struct log_entry *log, *tmp;
+ if (IS_ENABLED(CONFIG_CONSOLE_NONE))
+ return;
+
list_for_each_entry_safe(log, tmp, &barebox_logbuf, list) {
psinfo->write_buf(PSTORE_TYPE_CONSOLE, 0, &id, 0,
log->msg, 0, strlen(log->msg), psinfo);
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index 86049f9..958f46b 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -623,10 +623,10 @@ static int ramoops_probe(struct device_d *dev)
if (!IS_ENABLED(CONFIG_OFTREE)) {
scnprintf(kernelargs, sizeof(kernelargs),
- "ramoops.record_size=0x%x "
- "ramoops.console_size=0x%x "
- "ramoops.ftrace_size=0x%x "
- "ramoops.pmsg_size=0x%x "
+ "ramoops.record_size=0x%zx "
+ "ramoops.console_size=0x%zx "
+ "ramoops.ftrace_size=0x%zx "
+ "ramoops.pmsg_size=0x%zx "
"ramoops.mem_address=0x%llx "
"ramoops.mem_size=0x%lx "
"ramoops.ecc=%d",
@@ -646,7 +646,6 @@ static int ramoops_probe(struct device_d *dev)
return 0;
fail_buf:
-fail_clear:
kfree(cxt->mprz);
fail_init_mprz:
kfree(cxt->fprz);
diff --git a/images/.gitignore b/images/.gitignore
index 949f534..b673c98 100644
--- a/images/.gitignore
+++ b/images/.gitignore
@@ -27,3 +27,4 @@ barebox.sha.bin
barebox.sum
*.pimximg
*.psimximg
+*.zynqimg
diff --git a/images/Makefile.imx b/images/Makefile.imx
index 6572474..24d3536 100644
--- a/images/Makefile.imx
+++ b/images/Makefile.imx
@@ -23,27 +23,22 @@ endef
# %.imximg - convert into i.MX image
# ----------------------------------------------------------------
-$(obj)/%.imximg: $(obj)/% FORCE
- $(call if_changed,imx_image,$(CFG_$(@F)),)
-
-$(obj)/%.pimximg: $(obj)/% FORCE
- $(call if_changed,imx_image,$(CFG_$(patsubst %.pimximg,%.imximg,$(@F))),\
- -p $($(patsubst $(obj)/%.pblb,PBL_MEMORY_SIZE_%,$<)))
-
-$(obj)/%.psimximg: $(obj)/% FORCE
- $(call if_changed,imx_image,$(CFG_$(patsubst %.psimximg,%.imximg,$(@F))),-s \
- -p $($(patsubst $(obj)/%.pblb,PBL_MEMORY_SIZE_%,$<)))
-
-$(obj)/%.simximg: $(obj)/% FORCE
- $(call if_changed,imx_image,$(CFG_$(patsubst %.simximg,%.imximg,$(@F))),-s)
-
-$(obj)/%.usimximg: $(obj)/% FORCE
- $(call if_changed,imx_image,$(CFG_$(patsubst %.usimximg,%.imximg,$(@F))),-s -u)
+.SECONDEXPANSION:
+define imx_image_rule
+$(eval
+$$(obj)/%.$(strip $(1)): $$(obj)/% $$$$(CFG_%.imximg) FORCE
+ $$(call if_changed,imx_image,$$(CFG_$$(patsubst %.$(strip $(1)),%.imximg,$$(@F))),$(strip $(2)))
+)
+endef
-$(obj)/%.esimximg $(obj)/%.esimximg.dek: $(obj)/% FORCE
- $(call if_changed,imx_image,$(CFG_$(patsubst %.esimximg,%.imximg,$(@F))),-s -e)
+$(call imx_image_rule,imximg)
+$(call imx_image_rule,pimximg, -p $$($$(patsubst $$(obj)/%.pblb,PBL_MEMORY_SIZE_%,$$<)))
+$(call imx_image_rule,psimximg, -p $$($$(patsubst $$(obj)/%.pblb,PBL_MEMORY_SIZE_%,$$<)) -s)
+$(call imx_image_rule,simximg, -s)
+$(call imx_image_rule,usimximg, -u -s)
+$(call imx_image_rule,esimximg, -e -s)
+$(call imx_image_rule,esimximg.dek, -e -s)
-.SECONDEXPANSION:
$(obj)/%.img.dek: $(obj)/$$(FILE_$$(@F))
$(Q)if [ -z $(FILE_$(@F)) ]; then echo "FILE_$(@F) empty!"; false; fi
$(call if_changed,shipped)
diff --git a/include/acpi.h b/include/acpi.h
new file mode 100644
index 0000000..2d5fd30
--- /dev/null
+++ b/include/acpi.h
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Ahmad Fatoum
+ */
+
+#ifndef __ACPI_H_
+#define __ACPI_H_
+
+#include <linux/types.h>
+#include <driver.h>
+
+typedef char acpi_sig_t[4];
+
+struct __packed acpi_rsdp { /* root system description pointer */
+ char signature[8];
+ u8 checksum;
+ u8 oem_id[6];
+ u8 revision;
+ u32 rsdt_addr;
+};
+
+struct __packed acpi2_rsdp { /* root system description */
+ struct acpi_rsdp acpi1;
+ u32 length;
+ u64 xsdt_addr;
+ u8 extended_checksum;
+ u8 reserved[3];
+};
+
+struct __packed acpi_sdt { /* system description table header */
+ acpi_sig_t signature;
+ u32 len;
+ u8 revision;
+ u8 checksum;
+ char oem_id[6];
+ char oem_table_id[8];
+ u32 oem_revision;
+ u32 creator_id;
+ u32 creator_revision;
+};
+
+struct __packed acpi_rsdt { /* system description table header */
+ struct acpi_sdt sdt;
+ struct acpi_sdt * __aligned(8) entries[];
+};
+
+struct acpi_driver {
+ struct driver_d driver;
+ acpi_sig_t signature;
+};
+
+extern struct bus_type acpi_bus;
+
+static inline struct acpi_driver *to_acpi_driver(struct driver_d *drv)
+{
+ return container_of(drv, struct acpi_driver, driver);
+}
+
+#define device_acpi_driver(drv) \
+ register_driver_macro(device, acpi, drv)
+
+static inline int acpi_driver_register(struct acpi_driver *acpidrv)
+{
+ acpidrv->driver.bus = &acpi_bus;
+ return register_driver(&acpidrv->driver);
+}
+
+static inline int acpi_sigcmp(const acpi_sig_t sig_a, const acpi_sig_t sig_b)
+{
+ return memcmp(sig_a, sig_b, sizeof(acpi_sig_t));
+}
+
+#endif
diff --git a/include/common.h b/include/common.h
index 6563068..c6eb504 100644
--- a/include/common.h
+++ b/include/common.h
@@ -68,7 +68,12 @@ long get_ram_size (volatile long *, long);
/* common/console.c */
int ctrlc(void);
int arch_ctrlc(void);
+
+#ifdef CONFIG_CONSOLE_FULL
void ctrlc_handled(void);
+#else
+static inline void ctrlc_handled(void) { }
+#endif
#ifdef CONFIG_ARCH_HAS_STACK_DUMP
void dump_stack(void);
diff --git a/include/console.h b/include/console.h
index 7afe59e..537ac97 100644
--- a/include/console.h
+++ b/include/console.h
@@ -207,7 +207,12 @@ static inline void pbl_set_putc(void (*putcf)(void *ctx, int c), void *ctx) {}
bool console_allow_color(void);
+#ifdef CONFIG_CONSOLE_FULL
void console_ctrlc_allow(void);
void console_ctrlc_forbid(void);
+#else
+static inline void console_ctrlc_allow(void) { }
+static inline void console_ctrlc_forbid(void) { }
+#endif
#endif
diff --git a/include/driver.h b/include/driver.h
index 300603f..ad59ce9 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -155,12 +155,12 @@ int unregister_device(struct device_d *);
/* Iterate over a devices children
*/
#define device_for_each_child(dev, child) \
- list_for_each_entry(child, &dev->children, sibling)
+ list_for_each_entry(child, &(dev)->children, sibling)
/* Iterate over a devices children - Safe against removal version
*/
#define device_for_each_child_safe(dev, tmpdev, child) \
- list_for_each_entry_safe(child, tmpdev, &dev->children, sibling)
+ list_for_each_entry_safe(child, tmpdev, &(dev)->children, sibling)
/* Iterate through the devices of a given type. if last is NULL, the
* first device of this type is returned. Put this pointer in as
diff --git a/include/efi.h b/include/efi.h
index 166803a..43c0593 100644
--- a/include/efi.h
+++ b/include/efi.h
@@ -91,21 +91,23 @@ typedef struct {
*/
/* Memory types: */
-#define EFI_RESERVED_TYPE 0
-#define EFI_LOADER_CODE 1
-#define EFI_LOADER_DATA 2
-#define EFI_BOOT_SERVICES_CODE 3
-#define EFI_BOOT_SERVICES_DATA 4
-#define EFI_RUNTIME_SERVICES_CODE 5
-#define EFI_RUNTIME_SERVICES_DATA 6
-#define EFI_CONVENTIONAL_MEMORY 7
-#define EFI_UNUSABLE_MEMORY 8
-#define EFI_ACPI_RECLAIM_MEMORY 9
-#define EFI_ACPI_MEMORY_NVS 10
-#define EFI_MEMORY_MAPPED_IO 11
-#define EFI_MEMORY_MAPPED_IO_PORT_SPACE 12
-#define EFI_PAL_CODE 13
-#define EFI_MAX_MEMORY_TYPE 14
+enum efi_memory_type {
+ EFI_RESERVED_TYPE,
+ EFI_LOADER_CODE,
+ EFI_LOADER_DATA,
+ EFI_BOOT_SERVICES_CODE,
+ EFI_BOOT_SERVICES_DATA,
+ EFI_RUNTIME_SERVICES_CODE,
+ EFI_RUNTIME_SERVICES_DATA,
+ EFI_CONVENTIONAL_MEMORY,
+ EFI_UNUSABLE_MEMORY,
+ EFI_ACPI_RECLAIM_MEMORY,
+ EFI_ACPI_MEMORY_NVS,
+ EFI_MEMORY_MAPPED_IO,
+ EFI_MEMORY_MAPPED_IO_PORT_SPACE,
+ EFI_PAL_CODE,
+ EFI_MAX_MEMORY_TYPE
+};
/* Attribute values: */
#define EFI_MEMORY_UC ((u64)0x0000000000000001ULL) /* uncached */
@@ -124,10 +126,12 @@ typedef struct {
/*
* Allocation types for calls to boottime->allocate_pages.
*/
-#define EFI_ALLOCATE_ANY_PAGES 0
-#define EFI_ALLOCATE_MAX_ADDRESS 1
-#define EFI_ALLOCATE_ADDRESS 2
-#define EFI_MAX_ALLOCATE_TYPE 3
+enum efi_allocate_type {
+ EFI_ALLOCATE_ANY_PAGES,
+ EFI_ALLOCATE_MAX_ADDRESS,
+ EFI_ALLOCATE_ADDRESS,
+ EFI_MAX_ALLOCATE_TYPE
+};
typedef int (*efi_freemem_callback_t) (u64 start, u64 end, void *arg);
diff --git a/include/efi/efi-device.h b/include/efi/efi-device.h
index 5eaf1f2..5ec59a8 100644
--- a/include/efi/efi-device.h
+++ b/include/efi/efi-device.h
@@ -45,4 +45,16 @@ int efi_connect_all(void);
void efi_register_devices(void);
struct efi_device *efi_get_bootsource(void);
+static inline bool efi_device_has_guid(struct efi_device *efidev, efi_guid_t guid)
+{
+ int i;
+
+ for (i = 0; i < efidev->num_guids; i++) {
+ if (!efi_guidcmp(efidev->guids[i], guid))
+ return true;
+ }
+
+ return false;
+}
+
#endif /* __EFI_EFI_DEVICE_H */
diff --git a/include/envfs.h b/include/envfs.h
index 27c4b42..c8fc375 100644
--- a/include/envfs.h
+++ b/include/envfs.h
@@ -93,8 +93,13 @@ struct envfs_super {
#endif
#define ENV_FLAG_NO_OVERWRITE (1 << 0)
+#define PAD4(x) ((x + 3) & ~3)
int envfs_load(const char *filename, const char *dirname, unsigned flags);
int envfs_save(const char *filename, const char *dirname, unsigned flags);
+int envfs_check_super(struct envfs_super *super, size_t *size);
+int envfs_check_data(struct envfs_super *super, const void *buf, size_t size);
+int envfs_load_data(struct envfs_super *super, void *buf, size_t size,
+ const char *dir, unsigned flags);
int envfs_load_from_buf(void *buf, int len, const char *dir, unsigned flags);
/* defaults to /dev/env0 */
diff --git a/include/filetype.h b/include/filetype.h
index 90a03de..db95fda 100644
--- a/include/filetype.h
+++ b/include/filetype.h
@@ -49,6 +49,7 @@ enum filetype {
filetype_layerscape_qspi_image,
filetype_ubootvar,
filetype_stm32_image_v1,
+ filetype_zynq_image,
filetype_max,
};
diff --git a/include/gpio.h b/include/gpio.h
index 4d5f2c2..0c0c033 100644
--- a/include/gpio.h
+++ b/include/gpio.h
@@ -114,6 +114,11 @@ static inline int gpio_request(unsigned gpio, const char *label)
return 0;
}
+static inline int gpio_find_by_name(const char *name)
+{
+ return -ENOSYS;
+}
+
static inline int gpio_find_by_label(const char *label)
{
return -ENOSYS;
@@ -141,6 +146,7 @@ static inline void gpio_free_array(const struct gpio *array, size_t num)
}
#else
int gpio_request(unsigned gpio, const char *label);
+int gpio_find_by_name(const char *name);
int gpio_find_by_label(const char *label);
void gpio_free(unsigned gpio);
int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index d812521..1fbb3dc 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -15,6 +15,7 @@ struct pci_device_id {
__u32 vendor, device; /* Vendor and device ID or PCI_ANY_ID*/
__u32 subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */
__u32 class, class_mask; /* (class,subclass,prog-if) triplet */
+ unsigned long driver_data; /* Data private to the driver */
};
#define SPI_NAME_SIZE 32
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 105f381..1c6f442 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -116,7 +116,7 @@
#define FSR_READY BIT(7)
/* Configuration Register bits. */
-#define CR_QUAD_EN_SPAN BIT(2) /* Spansion Quad I/O */
+#define CR_QUAD_EN_SPAN BIT(1) /* Spansion Quad I/O */
/* Supported SPI protocols */
#define SNOR_PROTO_INST_MASK GENMASK(23, 16)
diff --git a/include/linux/pci.h b/include/linux/pci.h
index d92d70b..c742570 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -115,6 +115,17 @@ struct pci_dev {
};
#define to_pci_dev(d) container_of(d, struct pci_dev, dev)
+#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start)
+#define pci_resource_end(dev, bar) ((dev)->resource[(bar)].end)
+#define pci_resource_flags(dev, bar) ((dev)->resource[(bar)].flags)
+#define pci_resource_len(dev,bar) \
+ ((pci_resource_start((dev), (bar)) == 0 && \
+ pci_resource_end((dev), (bar)) == \
+ pci_resource_start((dev), (bar))) ? 0 : \
+ \
+ (pci_resource_end((dev), (bar)) - \
+ pci_resource_start((dev), (bar)) + 1))
+
enum {
PCI_BUS_RESOURCE_IO = 0,
PCI_BUS_RESOURCE_MEM = 1,
@@ -211,6 +222,20 @@ struct pci_driver {
.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
/**
+ * PCI_DEVICE_SUB - macro used to describe a specific PCI device with subsystem
+ * @vend: the 16 bit PCI Vendor ID
+ * @dev: the 16 bit PCI Device ID
+ * @subvend: the 16 bit PCI Subvendor ID
+ * @subdev: the 16 bit PCI Subdevice ID
+ *
+ * This macro is used to create a struct pci_device_id that matches a
+ * specific device with subsystem information.
+ */
+#define PCI_DEVICE_SUB(vend, dev, subvend, subdev) \
+ .vendor = (vend), .device = (dev), \
+ .subvendor = (subvend), .subdevice = (subdev)
+
+/**
* PCI_DEVICE_CLASS - macro used to describe a specific pci device class
* @dev_class: the class, subclass, prog-if triple for this device
* @dev_class_mask: the class mask for this device
@@ -350,4 +375,13 @@ enum pci_fixup_pass {
void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
+#ifdef CONFIG_PCI
+const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
+ struct pci_dev *dev);
+#else
+static inline const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
+ struct pci_dev *dev)
+{ return NULL; }
+#endif
+
#endif /* LINUX_PCI_H */
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index feee9ee..c6264d1 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -38,7 +38,6 @@ struct rproc {
void *priv;
struct rproc_ops *ops;
struct device_d dev;
- int index;
void *fw_buf;
size_t fw_buf_ofs;
diff --git a/include/of.h b/include/of.h
index 98ddf79..f63a3ef 100644
--- a/include/of.h
+++ b/include/of.h
@@ -197,14 +197,12 @@ extern int of_property_read_u64(const struct device_node *np,
extern int of_property_read_string(struct device_node *np,
const char *propname,
const char **out_string);
-extern int of_property_read_string_index(struct device_node *np,
- const char *propname,
- int index, const char **output);
extern int of_property_match_string(struct device_node *np,
const char *propname,
const char *string);
-extern int of_property_count_strings(struct device_node *np,
- const char *propname);
+extern int of_property_read_string_helper(const struct device_node *np,
+ const char *propname,
+ const char **out_strs, size_t sz, int index);
extern const __be32 *of_prop_next_u32(struct property *prop,
const __be32 *cur, u32 *pu);
@@ -444,20 +442,15 @@ static inline int of_property_read_string(struct device_node *np,
return -ENOSYS;
}
-static inline int of_property_read_string_index(struct device_node *np,
- const char *propname, int index, const char **output)
-{
- return -ENOSYS;
-}
-
static inline int of_property_match_string(struct device_node *np,
const char *propname, const char *string)
{
return -ENOSYS;
}
-static inline int of_property_count_strings(struct device_node *np,
- const char *propname)
+static inline int of_property_read_string_helper(const struct device_node *np,
+ const char *propname,
+ const char **out_strs, size_t sz, int index)
{
return -ENOSYS;
}
@@ -753,6 +746,70 @@ static inline struct device_node *of_find_matching_node(
child = of_get_next_available_child(parent, child))
/**
+ * of_property_read_string_array() - Read an array of strings from a multiple
+ * strings property.
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_strs: output array of string pointers.
+ * @sz: number of array elements to read.
+ *
+ * Search for a property in a device tree node and retrieve a list of
+ * terminated string values (pointer to data, not a copy) in that property.
+ *
+ * If @out_strs is NULL, the number of strings in the property is returned.
+ */
+static inline int of_property_read_string_array(const struct device_node *np,
+ const char *propname, const char **out_strs,
+ size_t sz)
+{
+ return of_property_read_string_helper(np, propname, out_strs, sz, 0);
+}
+
+/**
+ * of_property_count_strings() - Find and return the number of strings from a
+ * multiple strings property.
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ *
+ * Search for a property in a device tree node and retrieve the number of null
+ * terminated string contain in it. Returns the number of strings on
+ * success, -EINVAL if the property does not exist, -ENODATA if property
+ * does not have a value, and -EILSEQ if the string is not null-terminated
+ * within the length of the property data.
+ */
+static inline int of_property_count_strings(const struct device_node *np,
+ const char *propname)
+{
+ return of_property_read_string_helper(np, propname, NULL, 0, 0);
+}
+
+/**
+ * of_property_read_string_index() - Find and read a string from a multiple
+ * strings property.
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @index: index of the string in the list of strings
+ * @out_string: pointer to null terminated return string, modified only if
+ * return value is 0.
+ *
+ * Search for a property in a device tree node and retrieve a null
+ * terminated string value (pointer to data, not a copy) in the list of strings
+ * contained in that property.
+ * Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if
+ * property does not have a value, and -EILSEQ if the string is not
+ * null-terminated within the length of the property data.
+ *
+ * The out_string pointer is modified only if a valid string can be decoded.
+ */
+static inline int of_property_read_string_index(const struct device_node *np,
+ const char *propname,
+ int index, const char **output)
+{
+ int rc = of_property_read_string_helper(np, propname, output, 1, index);
+ return rc < 0 ? rc : 0;
+}
+
+/**
* of_property_read_bool - Findfrom a property
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
diff --git a/include/param.h b/include/param.h
index 4ac502e..d75f50e 100644
--- a/include/param.h
+++ b/include/param.h
@@ -63,6 +63,16 @@ struct param_d *dev_add_param_enum(struct device_d *dev, const char *name,
int (*get)(struct param_d *p, void *priv),
int *value, const char * const *names, int max, void *priv);
+enum param_tristate { PARAM_TRISTATE_UNKNOWN, PARAM_TRISTATE_TRUE, PARAM_TRISTATE_FALSE };
+
+struct param_d *dev_add_param_tristate(struct device_d *dev, const char *name,
+ int (*set)(struct param_d *p, void *priv),
+ int (*get)(struct param_d *p, void *priv),
+ int *value, void *priv);
+
+struct param_d *dev_add_param_tristate_ro(struct device_d *dev, const char *name,
+ int *value);
+
struct param_d *dev_add_param_bitmask(struct device_d *dev, const char *name,
int (*set)(struct param_d *p, void *priv),
int (*get)(struct param_d *p, void *priv),
@@ -144,6 +154,20 @@ static inline struct param_d *dev_add_param_bitmask(struct device_d *dev, const
return ERR_PTR(-ENOSYS);
}
+static inline struct param_d *dev_add_param_tristate(struct device_d *dev, const char *name,
+ int (*set)(struct param_d *p, void *priv),
+ int (*get)(struct param_d *p, void *priv),
+ int *value, void *priv)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
+static inline struct param_d *dev_add_param_tristate_ro(struct device_d *dev, const char *name,
+ int *value)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
static inline struct param_d *dev_add_param_ip(struct device_d *dev, const char *name,
int (*set)(struct param_d *p, void *priv),
int (*get)(struct param_d *p, void *priv),
diff --git a/include/reset_source.h b/include/reset_source.h
index 3ccd529..305dde0 100644
--- a/include/reset_source.h
+++ b/include/reset_source.h
@@ -60,6 +60,11 @@ static inline struct device_d *reset_source_get_device(void)
return NULL;
}
+static inline void reset_source_set_device(struct device_d *dev,
+ enum reset_src_type st)
+{
+}
+
static inline void reset_source_set_prinst(enum reset_src_type type,
unsigned int priority, int instance)
{
diff --git a/include/soc/fsl/fsl_fman.h b/include/soc/fsl/fsl_fman.h
index 96d6129..fd69fde 100644
--- a/include/soc/fsl/fsl_fman.h
+++ b/include/soc/fsl/fsl_fman.h
@@ -348,6 +348,9 @@ struct fm_fpm {
/* FPM Flush Control Register */
#define FMFP_FLC_DISP_LIM_NONE 0x00000000 /* no dispatch limitation */
+/* FMan Reset Command Register */
+#define FMFP_RSTC_RFM 0x80000000 /* FMan Soft Reset Command */
+
/* FMFP_EE - FPM event and enable register */
#define FMFPEE_DECC 0x80000000 /* double ECC err on FPM ram */
#define FMFPEE_STL 0x40000000 /* stall of task ... */
diff --git a/include/usb/chipidea-imx.h b/include/usb/chipidea-imx.h
index 973aee6..5ea5fcc 100644
--- a/include/usb/chipidea-imx.h
+++ b/include/usb/chipidea-imx.h
@@ -37,16 +37,10 @@
#define MXC_EHCI_DISABLE_OVERCURRENT (1 << 14)
-enum imx_usb_mode {
- IMX_USB_MODE_HOST,
- IMX_USB_MODE_DEVICE,
- IMX_USB_MODE_OTG,
-};
-
struct imxusb_platformdata {
unsigned long flags;
enum usb_phy_interface phymode;
- enum imx_usb_mode mode;
+ enum usb_dr_mode mode;
};
int imx_usbmisc_port_init(struct device_d *dev, int port, unsigned flags);
diff --git a/include/usb/usb.h b/include/usb/usb.h
index 0045608..d39de71 100644
--- a/include/usb/usb.h
+++ b/include/usb/usb.h
@@ -444,6 +444,9 @@ enum usb_phy_interface of_usb_get_phy_mode(struct device_node *np,
enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np,
const char *propname);
+int usb_register_otg_device(struct device_d *parent,
+ int (*set_mode)(void *ctx, enum usb_dr_mode mode), void *ctx);
+
extern struct list_head usb_device_list;
#endif /*_USB_H_ */
diff --git a/include/watchdog.h b/include/watchdog.h
index 5790205..9741570 100644
--- a/include/watchdog.h
+++ b/include/watchdog.h
@@ -15,9 +15,12 @@
#include <poller.h>
#include <driver.h>
+#include <param.h>
enum wdog_hw_runnning {
- WDOG_HW_RUNNING_UNSUPPORTED, WDOG_HW_RUNNING, WDOG_HW_NOT_RUNNING
+ WDOG_HW_RUNNING_UNSUPPORTED = PARAM_TRISTATE_UNKNOWN,
+ WDOG_HW_RUNNING = PARAM_TRISTATE_TRUE,
+ WDOG_HW_NOT_RUNNING = PARAM_TRISTATE_FALSE
};
struct watchdog {
diff --git a/lib/Kconfig b/lib/Kconfig
index 6216fdd..9a80780 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -105,6 +105,11 @@ config LIBFDT
config RATP
select CRC_ITU_T
+ select COMPILE_MEMORY
+ select COMMAND_SUPPORT
+ select POLLER
+ depends on CONSOLE_FULL
+ depends on !SHELL_NONE
bool "RATP protocol support"
help
Reliable Asynchronous Transfer Protocol (RATP) is a protocol for reliably
diff --git a/lib/gui/picopng.c b/lib/gui/picopng.c
index ad44efa..80f03be 100644
--- a/lib/gui/picopng.c
+++ b/lib/gui/picopng.c
@@ -32,7 +32,7 @@ typedef struct png_alloc_node {
png_alloc_node_t *png_alloc_head = NULL;
png_alloc_node_t *png_alloc_tail = NULL;
-png_alloc_node_t *png_alloc_find_node(void *addr)
+static png_alloc_node_t *png_alloc_find_node(void *addr)
{
png_alloc_node_t *node;
for (node = png_alloc_head; node; node = node->next)
@@ -41,7 +41,7 @@ png_alloc_node_t *png_alloc_find_node(void *addr)
return node;
}
-void png_alloc_add_node(void *addr, size_t size)
+static void png_alloc_add_node(void *addr, size_t size)
{
png_alloc_node_t *node;
if (png_alloc_find_node(addr))
@@ -58,7 +58,7 @@ void png_alloc_add_node(void *addr, size_t size)
png_alloc_head = node;
}
-void png_alloc_remove_node(png_alloc_node_t *node)
+static void png_alloc_remove_node(png_alloc_node_t *node)
{
if (node->prev)
node->prev->next = node->next;
@@ -72,14 +72,14 @@ void png_alloc_remove_node(png_alloc_node_t *node)
free(node);
}
-void *png_alloc_malloc(size_t size)
+static void *png_alloc_malloc(size_t size)
{
void *addr = malloc(size);
png_alloc_add_node(addr, size);
return addr;
}
-void *png_alloc_realloc(void *addr, size_t size)
+static void *png_alloc_realloc(void *addr, size_t size)
{
void *new_addr;
if (!addr)
@@ -94,7 +94,7 @@ void *png_alloc_realloc(void *addr, size_t size)
return new_addr;
}
-void png_alloc_free(void *addr)
+static void png_alloc_free(void *addr)
{
png_alloc_node_t *node = png_alloc_find_node(addr);
if (!node)
@@ -114,7 +114,7 @@ void png_alloc_free_all()
/*************************************************************************************************/
-__maybe_unused void vector32_cleanup(vector32_t *p)
+__maybe_unused static void vector32_cleanup(vector32_t *p)
{
p->size = p->allocsize = 0;
if (p->data)
@@ -122,7 +122,7 @@ __maybe_unused void vector32_cleanup(vector32_t *p)
p->data = NULL;
}
-uint32_t vector32_resize(vector32_t *p, size_t size)
+static uint32_t vector32_resize(vector32_t *p, size_t size)
{ // returns 1 if success, 0 if failure ==> nothing done
if (size * sizeof (uint32_t) > p->allocsize) {
size_t newsize = size * sizeof (uint32_t) * 2;
@@ -138,7 +138,7 @@ uint32_t vector32_resize(vector32_t *p, size_t size)
return 1;
}
-uint32_t vector32_resizev(vector32_t *p, size_t size, uint32_t value)
+static uint32_t vector32_resizev(vector32_t *p, size_t size, uint32_t value)
{ // resize and give all new elements the value
size_t oldsize = p->size, i;
if (!vector32_resize(p, size))
@@ -148,13 +148,13 @@ uint32_t vector32_resizev(vector32_t *p, size_t size, uint32_t value)
return 1;
}
-void vector32_init(vector32_t *p)
+static void vector32_init(vector32_t *p)
{
p->data = NULL;
p->size = p->allocsize = 0;
}
-vector32_t *vector32_new(size_t size, uint32_t value)
+__maybe_unused static vector32_t *vector32_new(size_t size, uint32_t value)
{
vector32_t *p = png_alloc_malloc(sizeof (vector32_t));
vector32_init(p);
@@ -165,7 +165,7 @@ vector32_t *vector32_new(size_t size, uint32_t value)
/*************************************************************************************************/
-__maybe_unused void vector8_cleanup(vector8_t *p)
+__maybe_unused static void vector8_cleanup(vector8_t *p)
{
p->size = p->allocsize = 0;
if (p->data)
@@ -173,7 +173,7 @@ __maybe_unused void vector8_cleanup(vector8_t *p)
p->data = NULL;
}
-uint32_t vector8_resize(vector8_t *p, size_t size)
+static uint32_t vector8_resize(vector8_t *p, size_t size)
{ // returns 1 if success, 0 if failure ==> nothing done
// xxx: the use of sizeof uint32_t here seems like a bug (this descends from the lodepng vector
// compatibility functions which do the same). without this there is corruption in certain cases,
@@ -192,7 +192,7 @@ uint32_t vector8_resize(vector8_t *p, size_t size)
return 1;
}
-uint32_t vector8_resizev(vector8_t *p, size_t size, uint8_t value)
+static uint32_t vector8_resizev(vector8_t *p, size_t size, uint8_t value)
{ // resize and give all new elements the value
size_t oldsize = p->size, i;
if (!vector8_resize(p, size))
@@ -202,13 +202,13 @@ uint32_t vector8_resizev(vector8_t *p, size_t size, uint8_t value)
return 1;
}
-void vector8_init(vector8_t *p)
+static void vector8_init(vector8_t *p)
{
p->data = NULL;
p->size = p->allocsize = 0;
}
-vector8_t *vector8_new(size_t size, uint8_t value)
+static vector8_t *vector8_new(size_t size, uint8_t value)
{
vector8_t *p = png_alloc_malloc(sizeof (vector8_t));
vector8_init(p);
@@ -217,7 +217,7 @@ vector8_t *vector8_new(size_t size, uint8_t value)
return p;
}
-vector8_t *vector8_copy(vector8_t *p)
+static vector8_t *vector8_copy(vector8_t *p)
{
vector8_t *q = vector8_new(p->size, 0);
uint32_t n;
@@ -227,7 +227,7 @@ vector8_t *vector8_copy(vector8_t *p)
}
/*************************************************************************************************/
-int Zlib_decompress(vector8_t *out, const vector8_t *in) // returns error value
+static int Zlib_decompress(vector8_t *out, const vector8_t *in) // returns error value
{
return picopng_zlib_decompress(out->data, out->size, in->data, in->size);
}
@@ -244,14 +244,14 @@ int Zlib_decompress(vector8_t *out, const vector8_t *in) // returns error value
int PNG_error;
-uint32_t PNG_readBitFromReversedStream(size_t *bitp, const uint8_t *bits)
+static uint32_t PNG_readBitFromReversedStream(size_t *bitp, const uint8_t *bits)
{
uint32_t result = (bits[*bitp >> 3] >> (7 - (*bitp & 0x7))) & 1;
(*bitp)++;
return result;
}
-uint32_t PNG_readBitsFromReversedStream(size_t *bitp, const uint8_t *bits, uint32_t nbits)
+static uint32_t PNG_readBitsFromReversedStream(size_t *bitp, const uint8_t *bits, uint32_t nbits)
{
uint32_t i, result = 0;
for (i = nbits - 1; i < nbits; i--)
@@ -259,18 +259,18 @@ uint32_t PNG_readBitsFromReversedStream(size_t *bitp, const uint8_t *bits, uint3
return result;
}
-void PNG_setBitOfReversedStream(size_t *bitp, uint8_t *bits, uint32_t bit)
+static void PNG_setBitOfReversedStream(size_t *bitp, uint8_t *bits, uint32_t bit)
{
bits[*bitp >> 3] |= (bit << (7 - (*bitp & 0x7)));
(*bitp)++;
}
-uint32_t PNG_read32bitInt(const uint8_t *buffer)
+static uint32_t PNG_read32bitInt(const uint8_t *buffer)
{
return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
}
-int PNG_checkColorValidity(uint32_t colorType, uint32_t bd) // return type is a LodePNG error code
+static int PNG_checkColorValidity(uint32_t colorType, uint32_t bd) // return type is a LodePNG error code
{
if ((colorType == 2 || colorType == 4 || colorType == 6)) {
if (!(bd == 8 || bd == 16))
@@ -291,7 +291,7 @@ int PNG_checkColorValidity(uint32_t colorType, uint32_t bd) // return type is a
return 31; // nonexistent color type
}
-uint32_t PNG_getBpp(const PNG_info_t *info)
+static uint32_t PNG_getBpp(const PNG_info_t *info)
{
uint32_t bitDepth, colorType;
bitDepth = info->bitDepth;
@@ -304,7 +304,7 @@ uint32_t PNG_getBpp(const PNG_info_t *info)
return bitDepth;
}
-void PNG_readPngHeader(PNG_info_t *info, const uint8_t *in, size_t inlength)
+static void PNG_readPngHeader(PNG_info_t *info, const uint8_t *in, size_t inlength)
{ // read the information from the header and store it in the Info
if (inlength < 29) {
PNG_error = 27; // error: the data length is smaller than the length of the header
@@ -340,7 +340,7 @@ void PNG_readPngHeader(PNG_info_t *info, const uint8_t *in, size_t inlength)
PNG_error = PNG_checkColorValidity(info->colorType, info->bitDepth);
}
-int PNG_paethPredictor(int a, int b, int c) // Paeth predicter, used by PNG filter type 4
+static int PNG_paethPredictor(int a, int b, int c) // Paeth predicter, used by PNG filter type 4
{
int p, pa, pb, pc;
p = a + b - c;
@@ -350,7 +350,7 @@ int PNG_paethPredictor(int a, int b, int c) // Paeth predicter, used by PNG filt
return (pa <= pb && pa <= pc) ? a : (pb <= pc ? b : c);
}
-void PNG_unFilterScanline(uint8_t *recon, const uint8_t *scanline, const uint8_t *precon,
+static void PNG_unFilterScanline(uint8_t *recon, const uint8_t *scanline, const uint8_t *precon,
size_t bytewidth, uint32_t filterType, size_t length)
{
size_t i;
@@ -406,7 +406,7 @@ void PNG_unFilterScanline(uint8_t *recon, const uint8_t *scanline, const uint8_t
}
}
-void PNG_adam7Pass(uint8_t *out, uint8_t *linen, uint8_t *lineo, const uint8_t *in, uint32_t w,
+static void PNG_adam7Pass(uint8_t *out, uint8_t *linen, uint8_t *lineo, const uint8_t *in, uint32_t w,
size_t passleft, size_t passtop, size_t spacex, size_t spacey, size_t passw, size_t passh,
uint32_t bpp)
{
@@ -446,7 +446,7 @@ void PNG_adam7Pass(uint8_t *out, uint8_t *linen, uint8_t *lineo, const uint8_t *
}
}
-int PNG_convert(const PNG_info_t *info, vector8_t *out, const uint8_t *in)
+static int PNG_convert(const PNG_info_t *info, vector8_t *out, const uint8_t *in)
{ // converts from any color type to 32-bit. return value = LodePNG error code
size_t i, c;
uint32_t bitDepth, colorType;
@@ -530,7 +530,7 @@ int PNG_convert(const PNG_info_t *info, vector8_t *out, const uint8_t *in)
return 0;
}
-PNG_info_t *PNG_info_new(void)
+static PNG_info_t *PNG_info_new(void)
{
PNG_info_t *info = png_alloc_malloc(sizeof (PNG_info_t));
uint32_t i;
diff --git a/lib/parameter.c b/lib/parameter.c
index fdbb2e7..2269563 100644
--- a/lib/parameter.c
+++ b/lib/parameter.c
@@ -588,6 +588,28 @@ struct param_d *dev_add_param_enum(struct device_d *dev, const char *name,
return &pe->param;
}
+static const char *const tristate_names[] = {
+ [PARAM_TRISTATE_UNKNOWN] = "unknown",
+ [PARAM_TRISTATE_TRUE] = "1",
+ [PARAM_TRISTATE_FALSE] = "0",
+};
+
+struct param_d *dev_add_param_tristate(struct device_d *dev, const char *name,
+ int (*set)(struct param_d *p, void *priv),
+ int (*get)(struct param_d *p, void *priv),
+ int *value, void *priv)
+{
+ return dev_add_param_enum(dev, name, set, get, value, tristate_names,
+ ARRAY_SIZE(tristate_names), priv);
+}
+
+struct param_d *dev_add_param_tristate_ro(struct device_d *dev, const char *name,
+ int *value)
+{
+ return dev_add_param_enum_ro(dev, name, value, tristate_names,
+ ARRAY_SIZE(tristate_names));
+}
+
struct param_bitmask {
struct param_d param;
unsigned long *value;
diff --git a/lib/zstd/decompress.c b/lib/zstd/decompress.c
index 8203b81..19bf712 100644
--- a/lib/zstd/decompress.c
+++ b/lib/zstd/decompress.c
@@ -123,7 +123,7 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx *dctx)
return 0;
}
-ZSTD_DCtx *ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
+static ZSTD_DCtx *ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
{
ZSTD_DCtx *dctx;
@@ -391,7 +391,7 @@ typedef struct {
/*! ZSTD_getcBlockSize() :
* Provides the size of compressed block from block header `src` */
-size_t ZSTD_getcBlockSize(const void *src, size_t srcSize, blockProperties_t *bpPtr)
+static size_t ZSTD_getcBlockSize(const void *src, size_t srcSize, blockProperties_t *bpPtr)
{
if (srcSize < ZSTD_blockHeaderSize)
return ERROR(srcSize_wrong);
@@ -429,7 +429,7 @@ static size_t ZSTD_setRleBlock(void *dst, size_t dstCapacity, const void *src, s
/*! ZSTD_decodeLiteralsBlock() :
@return : nb of bytes read from src (< srcSize ) */
-size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx *dctx, const void *src, size_t srcSize) /* note : srcSize < BLOCKSIZE */
+static size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx *dctx, const void *src, size_t srcSize) /* note : srcSize < BLOCKSIZE */
{
if (srcSize < MIN_CBLOCK_SIZE)
return ERROR(corruption_detected);
@@ -791,7 +791,7 @@ static size_t ZSTD_buildSeqTable(FSE_DTable *DTableSpace, const FSE_DTable **DTa
}
}
-size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx *dctx, int *nbSeqPtr, const void *src, size_t srcSize)
+static size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx *dctx, int *nbSeqPtr, const void *src, size_t srcSize)
{
const BYTE *const istart = (const BYTE *const)src;
const BYTE *const iend = istart + srcSize;
@@ -1494,7 +1494,7 @@ size_t ZSTD_insertBlock(ZSTD_DCtx *dctx, const void *blockStart, size_t blockSiz
return blockSize;
}
-size_t ZSTD_generateNxBytes(void *dst, size_t dstCapacity, BYTE byte, size_t length)
+static size_t ZSTD_generateNxBytes(void *dst, size_t dstCapacity, BYTE byte, size_t length)
{
if (length > dstCapacity)
return ERROR(dstSize_tooSmall);
diff --git a/scripts/bareboxenv.c b/scripts/bareboxenv.c
index c512a10..d1cf33a 100644
--- a/scripts/bareboxenv.c
+++ b/scripts/bareboxenv.c
@@ -104,6 +104,7 @@ static char *concat_subpath_file(const char *path, const char *f)
#include "../include/envfs.h"
#include "../crypto/crc32.c"
#include "../lib/make_directory.c"
+#include "../common/envfs-core.c"
#include "../common/environment.c"
static void usage(char *prgname)
diff --git a/scripts/canon-a1100-image b/scripts/canon-a1100-image
index 6c08d74..17fd473 100755
--- a/scripts/canon-a1100-image
+++ b/scripts/canon-a1100-image
@@ -1,4 +1,6 @@
-#!/bin/bash -e
+#!/usr/bin/env bash
+
+set -e
IFILE=$1
OFILE=$2
diff --git a/scripts/check_size b/scripts/check_size
index 8530435..76608ec 100755
--- a/scripts/check_size
+++ b/scripts/check_size
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
symbol="$1"
file="$2"
diff --git a/scripts/dfuboot.sh b/scripts/dfuboot.sh
index 524113b..9847579 100755
--- a/scripts/dfuboot.sh
+++ b/scripts/dfuboot.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
DEVICETREE=
KERNEL=
diff --git a/scripts/extract_symbol_offset b/scripts/extract_symbol_offset
index 78b8668..d0ea224 100755
--- a/scripts/extract_symbol_offset
+++ b/scripts/extract_symbol_offset
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
symbol="$1"
file="$2"
diff --git a/scripts/gen-dtb-s b/scripts/gen-dtb-s
index b2dd253..0649247 100755
--- a/scripts/gen-dtb-s
+++ b/scripts/gen-dtb-s
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
name=$1
dtb=$2
diff --git a/scripts/genenv b/scripts/genenv
index 5ebe699..454f232 100755
--- a/scripts/genenv
+++ b/scripts/genenv
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
# Generate the default environment file from a list of directories
# usage: genenv <basedir> <objdir> <target> <dir>...
diff --git a/scripts/imx/imx.c b/scripts/imx/imx.c
index b3e8d62..b8d939a 100644
--- a/scripts/imx/imx.c
+++ b/scripts/imx/imx.c
@@ -673,13 +673,16 @@ static char *readcmd(struct config_data *data, FILE *f)
}
}
-int parse_config(struct config_data *data, const char *filename)
+int parse_config(struct config_data *data, const char *_filename)
{
FILE *f;
int lineno = 0;
char *line = NULL, *tmp;
char *argv[MAXARGS];
int nargs, i, ret = 0;
+ char *filename;
+
+ filename = strdup(_filename);
f = fopen(filename, "r");
if (!f) {
@@ -695,8 +698,17 @@ int parse_config(struct config_data *data, const char *filename)
lineno++;
tmp = strchr(line, '#');
- if (tmp)
- *tmp = 0;
+ if (tmp) {
+ char *endptr;
+ long linenum = strtol(tmp + 1, &endptr, 10);
+ if (strncmp(endptr, " \"", 2) == 0 && endptr[2]) {
+ free(filename);
+ lineno = linenum - 1;
+ filename = strdup(endptr + 2);
+ filename[strlen(filename) - 1] = '\0';
+ }
+ *tmp = '\0';
+ }
nargs = parse_line(line, argv);
if (!nargs)
@@ -708,8 +720,8 @@ int parse_config(struct config_data *data, const char *filename)
if (!strcmp(cmds[i].name, argv[0])) {
ret = cmds[i].parse(data, nargs, argv);
if (ret) {
- fprintf(stderr, "error in line %d: %s\n",
- lineno, strerror(-ret));
+ fprintf(stderr, "%s:%d: %s\n",
+ filename, lineno, strerror(-ret));
goto cleanup;
}
break;
@@ -724,5 +736,6 @@ int parse_config(struct config_data *data, const char *filename)
cleanup:
fclose(f);
+ free(filename);
return ret;
}
diff --git a/scripts/socfpga_get_sequencer b/scripts/socfpga_get_sequencer
index 36f6749..5405bfa 100755
--- a/scripts/socfpga_get_sequencer
+++ b/scripts/socfpga_get_sequencer
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
if [ "$#" -lt "2" ]
then
diff --git a/scripts/socfpga_import_preloader b/scripts/socfpga_import_preloader
index 6c748fa..23e3c38 100755
--- a/scripts/socfpga_import_preloader
+++ b/scripts/socfpga_import_preloader
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
if [ "$#" -lt "2" ]
then
diff --git a/scripts/socfpga_xml_to_config.sh b/scripts/socfpga_xml_to_config.sh
index 7e22ebb..3bb0dd2 100755
--- a/scripts/socfpga_xml_to_config.sh
+++ b/scripts/socfpga_xml_to_config.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
## TODO:
## - read in mpuclk and nocclk, must be calculated by hand at the moment