2580 lines
76 KiB
Diff
2580 lines
76 KiB
Diff
.../devicetree/bindings/mmc/ti-omap-hsmmc.txt | 26 +-
|
|
.../devicetree/bindings/reset/gpio-reset.txt | 35 +++
|
|
arch/arm/boot/dts/Makefile | 3 +-
|
|
arch/arm/boot/dts/am335x-bone.dts | 7 +
|
|
arch/arm/boot/dts/am335x-boneblack.dts | 285 ++++++++++++++++++++
|
|
arch/arm/boot/dts/am335x-evm.dts | 7 +
|
|
arch/arm/boot/dts/am335x-evmsk.dts | 7 +
|
|
arch/arm/boot/dts/am33xx.dtsi | 60 +++++
|
|
arch/arm/common/edma.c | 31 ++-
|
|
arch/arm/mach-davinci/da830.c | 8 +-
|
|
arch/arm/mach-davinci/da850.c | 8 +-
|
|
arch/arm/mach-davinci/devices-da8xx.c | 42 ++-
|
|
arch/arm/mach-davinci/devices-tnetv107x.c | 37 ++-
|
|
arch/arm/mach-davinci/dm355.c | 52 +++-
|
|
arch/arm/mach-davinci/dm365.c | 38 ++-
|
|
arch/arm/mach-davinci/dm644x.c | 52 +++-
|
|
arch/arm/mach-davinci/dm646x.c | 52 +++-
|
|
arch/arm/mach-davinci/include/mach/da8xx.h | 2 +-
|
|
arch/arm/mach-davinci/include/mach/tnetv107x.h | 2 +-
|
|
arch/arm/mach-davinci/serial.c | 19 +-
|
|
arch/arm/mach-davinci/tnetv107x.c | 8 +-
|
|
arch/arm/mach-omap2/Makefile | 3 +
|
|
arch/arm/mach-omap2/am33xx-cpsw.c | 94 +++++++
|
|
arch/arm/mach-omap2/control.h | 4 +
|
|
drivers/dma/edma.c | 299 ++++++++++++++++-----
|
|
drivers/mmc/host/omap_hsmmc.c | 178 +++++++++---
|
|
drivers/reset/Kconfig | 11 +
|
|
drivers/reset/Makefile | 1 +
|
|
drivers/reset/gpio-reset.c | 169 ++++++++++++
|
|
include/linux/dmaengine.h | 39 +++
|
|
include/linux/platform_data/mmc-omap.h | 3 +
|
|
sound/soc/soc-dmaengine-pcm.c | 22 ++
|
|
32 files changed, 1409 insertions(+), 195 deletions(-)
|
|
|
|
diff --git a/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt b/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
|
|
index ed271fc..8c8908a 100644
|
|
--- a/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
|
|
+++ b/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
|
|
@@ -20,8 +20,29 @@ ti,dual-volt: boolean, supports dual voltage cards
|
|
ti,non-removable: non-removable slot (like eMMC)
|
|
ti,needs-special-reset: Requires a special softreset sequence
|
|
ti,needs-special-hs-handling: HSMMC IP needs special setting for handling High Speed
|
|
+dmas: List of DMA specifiers with the controller specific format
|
|
+as described in the generic DMA client binding. A tx and rx
|
|
+specifier is required.
|
|
+dma-names: List of DMA request names. These strings correspond
|
|
+1:1 with the DMA specifiers listed in dmas. The string naming is
|
|
+to be "rx" and "tx" for RX and TX DMA requests, respectively.
|
|
+
|
|
+Examples:
|
|
+
|
|
+[hwmod populated DMA resources]
|
|
+
|
|
+ mmc1: mmc@0x4809c000 {
|
|
+ compatible = "ti,omap4-hsmmc";
|
|
+ reg = <0x4809c000 0x400>;
|
|
+ ti,hwmods = "mmc1";
|
|
+ ti,dual-volt;
|
|
+ bus-width = <4>;
|
|
+ vmmc-supply = <&vmmc>; /* phandle to regulator node */
|
|
+ ti,non-removable;
|
|
+ };
|
|
+
|
|
+[generic DMA request binding]
|
|
|
|
-Example:
|
|
mmc1: mmc@0x4809c000 {
|
|
compatible = "ti,omap4-hsmmc";
|
|
reg = <0x4809c000 0x400>;
|
|
@@ -30,4 +51,7 @@ Example:
|
|
bus-width = <4>;
|
|
vmmc-supply = <&vmmc>; /* phandle to regulator node */
|
|
ti,non-removable;
|
|
+ dmas = <&edma 24
|
|
+ &edma 25>;
|
|
+ dma-names = "tx", "rx";
|
|
};
|
|
diff --git a/Documentation/devicetree/bindings/reset/gpio-reset.txt b/Documentation/devicetree/bindings/reset/gpio-reset.txt
|
|
new file mode 100644
|
|
index 0000000..bca5348
|
|
--- /dev/null
|
|
+++ b/Documentation/devicetree/bindings/reset/gpio-reset.txt
|
|
@@ -0,0 +1,35 @@
|
|
+GPIO reset controller
|
|
+=====================
|
|
+
|
|
+A GPIO reset controller controls a single GPIO that is connected to the reset
|
|
+pin of a peripheral IC. Please also refer to reset.txt in this directory for
|
|
+common reset controller binding usage.
|
|
+
|
|
+Required properties:
|
|
+- compatible: Should be "gpio-reset"
|
|
+- reset-gpios: A gpio used as reset line. The gpio specifier for this property
|
|
+ depends on the gpio controller that provides the gpio.
|
|
+- #reset-cells: 0, see below
|
|
+
|
|
+Optional properties:
|
|
+- reset-delay-us: delay in microseconds. The gpio reset line will be asserted for
|
|
+ this duration to reset.
|
|
+- initially-in-reset: boolean. If not set, the initial state should be a
|
|
+ deasserted reset line. If this property exists, the
|
|
+ reset line should be kept in reset.
|
|
+
|
|
+example:
|
|
+
|
|
+sii902x_reset: gpio-reset {
|
|
+ compatible = "gpio-reset";
|
|
+ reset-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
|
|
+ reset-delay-us = <10000>;
|
|
+ initially-in-reset;
|
|
+ #reset-cells = <0>;
|
|
+};
|
|
+
|
|
+/* Device with nRESET pin connected to GPIO5_0 */
|
|
+sii902x@39 {
|
|
+ /* ... */
|
|
+ resets = <&sii902x_reset>; /* active-low GPIO5_0, 10 ms delay */
|
|
+};
|
|
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
|
|
index 641b3c9..1b60731 100644
|
|
--- a/arch/arm/boot/dts/Makefile
|
|
+++ b/arch/arm/boot/dts/Makefile
|
|
@@ -173,7 +173,8 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \
|
|
am335x-bone.dtb \
|
|
am3517-evm.dtb \
|
|
am3517_mt_ventoux.dtb \
|
|
- am43x-epos-evm.dtb
|
|
+ am43x-epos-evm.dtb \
|
|
+ am335x-boneblack.dtb
|
|
dtb-$(CONFIG_ARCH_ORION5X) += orion5x-lacie-ethernet-disk-mini-v2.dtb
|
|
dtb-$(CONFIG_ARCH_PRIMA2) += prima2-evb.dtb
|
|
dtb-$(CONFIG_ARCH_U8500) += snowball.dtb \
|
|
diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts
|
|
index 444b4ed..b8debea 100644
|
|
--- a/arch/arm/boot/dts/am335x-bone.dts
|
|
+++ b/arch/arm/boot/dts/am335x-bone.dts
|
|
@@ -203,6 +203,8 @@
|
|
};
|
|
|
|
ldo3_reg: regulator@5 {
|
|
+ regulator-min-microvolt = <1800000>;
|
|
+ regulator-max-microvolt = <3300000>;
|
|
regulator-always-on;
|
|
};
|
|
|
|
@@ -234,3 +236,8 @@
|
|
pinctrl-0 = <&davinci_mdio_default>;
|
|
pinctrl-1 = <&davinci_mdio_sleep>;
|
|
};
|
|
+
|
|
+&mmc1 {
|
|
+ status = "okay";
|
|
+ vmmc-supply = <&ldo3_reg>;
|
|
+};
|
|
diff --git a/arch/arm/boot/dts/am335x-boneblack.dts b/arch/arm/boot/dts/am335x-boneblack.dts
|
|
new file mode 100644
|
|
index 0000000..75a924d
|
|
--- /dev/null
|
|
+++ b/arch/arm/boot/dts/am335x-boneblack.dts
|
|
@@ -0,0 +1,285 @@
|
|
+/*
|
|
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License version 2 as
|
|
+ * published by the Free Software Foundation.
|
|
+ */
|
|
+/dts-v1/;
|
|
+
|
|
+#include "am33xx.dtsi"
|
|
+
|
|
+/ {
|
|
+ model = "TI AM335x BeagleBone";
|
|
+ compatible = "ti,am335x-bone", "ti,am33xx";
|
|
+
|
|
+ cpus {
|
|
+ cpu@0 {
|
|
+ cpu0-supply = <&dcdc2_reg>;
|
|
+
|
|
+ /*
|
|
+ * To consider voltage drop between PMIC and SoC,
|
|
+ * tolerance value is reduced to 2% from 4% and
|
|
+ * voltage value is increased as a precaution.
|
|
+ */
|
|
+ operating-points = <
|
|
+ /* kHz uV */
|
|
+ 1000000 1350000
|
|
+ 800000 1300000
|
|
+ 600000 1112000
|
|
+ 300000 969000
|
|
+ >;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ memory {
|
|
+ device_type = "memory";
|
|
+ reg = <0x80000000 0x20000000>; /* 512 MB */
|
|
+ };
|
|
+
|
|
+ am33xx_pinmux: pinmux@44e10800 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&clkout2_pin>;
|
|
+
|
|
+ user_leds_s0: user_leds_s0 {
|
|
+ pinctrl-single,pins = <
|
|
+ 0x54 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a5.gpio1_21 */
|
|
+ 0x58 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_a6.gpio1_22 */
|
|
+ 0x5c (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a7.gpio1_23 */
|
|
+ 0x60 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_a8.gpio1_24 */
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ i2c0_pins: pinmux_i2c0_pins {
|
|
+ pinctrl-single,pins = <
|
|
+ 0x188 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_sda.i2c0_sda */
|
|
+ 0x18c (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_scl.i2c0_scl */
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ uart0_pins: pinmux_uart0_pins {
|
|
+ pinctrl-single,pins = <
|
|
+ 0x170 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
|
|
+ 0x174 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ clkout2_pin: pinmux_clkout2_pin {
|
|
+ pinctrl-single,pins = <
|
|
+ 0x1b4 (PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr1.clkout2 */
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ cpsw_default: cpsw_default {
|
|
+ pinctrl-single,pins = <
|
|
+ /* Slave 1 */
|
|
+ 0x110 (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxerr.mii1_rxerr */
|
|
+ 0x114 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txen.mii1_txen */
|
|
+ 0x118 (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxdv.mii1_rxdv */
|
|
+ 0x11c (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd3.mii1_txd3 */
|
|
+ 0x120 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd2.mii1_txd2 */
|
|
+ 0x124 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd1.mii1_txd1 */
|
|
+ 0x128 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd0.mii1_txd0 */
|
|
+ 0x12c (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_txclk.mii1_txclk */
|
|
+ 0x130 (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxclk.mii1_rxclk */
|
|
+ 0x134 (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxd3.mii1_rxd3 */
|
|
+ 0x138 (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxd2.mii1_rxd2 */
|
|
+ 0x13c (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxd1.mii1_rxd1 */
|
|
+ 0x140 (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxd0.mii1_rxd0 */
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ cpsw_sleep: cpsw_sleep {
|
|
+ pinctrl-single,pins = <
|
|
+ /* Slave 1 reset value */
|
|
+ 0x110 (PIN_INPUT_PULLDOWN | MUX_MODE7)
|
|
+ 0x114 (PIN_INPUT_PULLDOWN | MUX_MODE7)
|
|
+ 0x118 (PIN_INPUT_PULLDOWN | MUX_MODE7)
|
|
+ 0x11c (PIN_INPUT_PULLDOWN | MUX_MODE7)
|
|
+ 0x120 (PIN_INPUT_PULLDOWN | MUX_MODE7)
|
|
+ 0x124 (PIN_INPUT_PULLDOWN | MUX_MODE7)
|
|
+ 0x128 (PIN_INPUT_PULLDOWN | MUX_MODE7)
|
|
+ 0x12c (PIN_INPUT_PULLDOWN | MUX_MODE7)
|
|
+ 0x130 (PIN_INPUT_PULLDOWN | MUX_MODE7)
|
|
+ 0x134 (PIN_INPUT_PULLDOWN | MUX_MODE7)
|
|
+ 0x138 (PIN_INPUT_PULLDOWN | MUX_MODE7)
|
|
+ 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE7)
|
|
+ 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE7)
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ davinci_mdio_default: davinci_mdio_default {
|
|
+ pinctrl-single,pins = <
|
|
+ /* MDIO */
|
|
+ 0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
|
|
+ 0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ davinci_mdio_sleep: davinci_mdio_sleep {
|
|
+ pinctrl-single,pins = <
|
|
+ /* MDIO reset value */
|
|
+ 0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7)
|
|
+ 0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7)
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ emmc_pins: pinmux_emmc_pins {
|
|
+ pinctrl-single,pins = <
|
|
+ 0x80 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
|
|
+ 0x84 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
|
|
+ 0x00 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
|
|
+ 0x04 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
|
|
+ 0x08 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
|
|
+ 0x0c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
|
|
+ 0x10 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad4.mmc1_dat4 */
|
|
+ 0x14 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad5.mmc1_dat5 */
|
|
+ 0x18 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad6.mmc1_dat6 */
|
|
+ 0x1c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad7.mmc1_dat7 */
|
|
+ /* eMMC_RSTn */
|
|
+ 0x50 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_a4.gpio1_20 */
|
|
+ >;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ ocp {
|
|
+ uart0: serial@44e09000 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&uart0_pins>;
|
|
+
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ i2c0: i2c@44e0b000 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&i2c0_pins>;
|
|
+
|
|
+ status = "okay";
|
|
+ clock-frequency = <400000>;
|
|
+
|
|
+ tps: tps@24 {
|
|
+ reg = <0x24>;
|
|
+ };
|
|
+
|
|
+ };
|
|
+ };
|
|
+
|
|
+ leds {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&user_leds_s0>;
|
|
+
|
|
+ compatible = "gpio-leds";
|
|
+
|
|
+ led@2 {
|
|
+ label = "beaglebone:blue:heartbeat";
|
|
+ gpios = <&gpio1 21 0>;
|
|
+ linux,default-trigger = "heartbeat";
|
|
+ default-state = "off";
|
|
+ };
|
|
+
|
|
+ led@3 {
|
|
+ label = "beaglebone:blue:mmc0";
|
|
+ gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>;
|
|
+ linux,default-trigger = "mmc0";
|
|
+ default-state = "off";
|
|
+ };
|
|
+
|
|
+ led@4 {
|
|
+ label = "beaglebone:blue:usr2";
|
|
+ gpios = <&gpio1 23 GPIO_ACTIVE_HIGH>;
|
|
+ default-state = "off";
|
|
+ };
|
|
+
|
|
+ led@5 {
|
|
+ label = "beaglebone:blue:usr3";
|
|
+ gpios = <&gpio1 24 GPIO_ACTIVE_HIGH>;
|
|
+ default-state = "off";
|
|
+ };
|
|
+ };
|
|
+
|
|
+ vmmcsd_fixed: fixedregulator@0 {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "vmmcsd_fixed";
|
|
+ regulator-min-microvolt = <3300000>;
|
|
+ regulator-max-microvolt = <3300000>;
|
|
+ };
|
|
+
|
|
+};
|
|
+
|
|
+/include/ "tps65217.dtsi"
|
|
+
|
|
+&tps {
|
|
+ regulators {
|
|
+ dcdc1_reg: regulator@0 {
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ dcdc2_reg: regulator@1 {
|
|
+ /* VDD_MPU voltage limits 0.95V - 1.26V with +/-4% tolerance */
|
|
+ regulator-name = "vdd_mpu";
|
|
+ regulator-min-microvolt = <925000>;
|
|
+ regulator-max-microvolt = <1325000>;
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ dcdc3_reg: regulator@2 {
|
|
+ /* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */
|
|
+ regulator-name = "vdd_core";
|
|
+ regulator-min-microvolt = <925000>;
|
|
+ regulator-max-microvolt = <1150000>;
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ ldo1_reg: regulator@3 {
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ ldo2_reg: regulator@4 {
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ ldo3_reg: regulator@5 {
|
|
+ regulator-min-microvolt = <1800000>;
|
|
+ regulator-max-microvolt = <1800000>; /* orig 3.3V*/
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ ldo4_reg: regulator@6 {
|
|
+ regulator-always-on;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&cpsw_emac0 {
|
|
+ phy_id = <&davinci_mdio>, <0>;
|
|
+};
|
|
+
|
|
+&cpsw_emac1 {
|
|
+ phy_id = <&davinci_mdio>, <1>;
|
|
+};
|
|
+
|
|
+&mac {
|
|
+ pinctrl-names = "default", "sleep";
|
|
+ pinctrl-0 = <&cpsw_default>;
|
|
+ pinctrl-1 = <&cpsw_sleep>;
|
|
+};
|
|
+
|
|
+&mmc1 {
|
|
+ status = "okay";
|
|
+ vmmc-supply = <&vmmcsd_fixed>;
|
|
+ ti,vcc-aux-disable-is-sleep;
|
|
+};
|
|
+
|
|
+&mmc2 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&emmc_pins>;
|
|
+ vmmc-supply = <&ldo3_reg>;
|
|
+ bus-width = <8>;
|
|
+ ti,non-removable;
|
|
+ status = "okay";
|
|
+ ti,vcc-aux-disable-is-sleep;
|
|
+
|
|
+ reset-gpio = <&gpio1 20 GPIO_ACTIVE_HIGH>;
|
|
+};
|
|
diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
|
|
index 3aee1a4..44e69d9 100644
|
|
--- a/arch/arm/boot/dts/am335x-evm.dts
|
|
+++ b/arch/arm/boot/dts/am335x-evm.dts
|
|
@@ -448,6 +448,8 @@
|
|
};
|
|
|
|
vmmc_reg: regulator@12 {
|
|
+ regulator-min-microvolt = <1800000>;
|
|
+ regulator-max-microvolt = <3300000>;
|
|
regulator-always-on;
|
|
};
|
|
};
|
|
@@ -488,3 +490,8 @@
|
|
ti,adc-channels = <4 5 6 7>;
|
|
};
|
|
};
|
|
+
|
|
+&mmc1 {
|
|
+ status = "okay";
|
|
+ vmmc-supply = <&vmmc_reg>;
|
|
+};
|
|
diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts
|
|
index 0c8ad17..4e355d6 100644
|
|
--- a/arch/arm/boot/dts/am335x-evmsk.dts
|
|
+++ b/arch/arm/boot/dts/am335x-evmsk.dts
|
|
@@ -376,6 +376,8 @@
|
|
};
|
|
|
|
vmmc_reg: regulator@12 {
|
|
+ regulator-min-microvolt = <1800000>;
|
|
+ regulator-max-microvolt = <3300000>;
|
|
regulator-always-on;
|
|
};
|
|
};
|
|
@@ -402,3 +404,8 @@
|
|
phy_id = <&davinci_mdio>, <1>;
|
|
phy-mode = "rgmii-txid";
|
|
};
|
|
+
|
|
+&mmc1 {
|
|
+ status = "okay";
|
|
+ vmmc-supply = <&vmmc_reg>;
|
|
+};
|
|
diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
|
|
index 38b446b..969c81b 100644
|
|
--- a/arch/arm/boot/dts/am33xx.dtsi
|
|
+++ b/arch/arm/boot/dts/am33xx.dtsi
|
|
@@ -96,6 +96,18 @@
|
|
reg = <0x48200000 0x1000>;
|
|
};
|
|
|
|
+ edma: edma@49000000 {
|
|
+ compatible = "ti,edma3";
|
|
+ ti,hwmods = "tpcc", "tptc0", "tptc1", "tptc2";
|
|
+ reg = <0x49000000 0x10000>,
|
|
+ <0x44e10f90 0x10>;
|
|
+ interrupts = <12 13 14>;
|
|
+ #dma-cells = <1>;
|
|
+ dma-channels = <64>;
|
|
+ ti,edma-regions = <4>;
|
|
+ ti,edma-slots = <256>;
|
|
+ };
|
|
+
|
|
gpio0: gpio@44e07000 {
|
|
compatible = "ti,omap4-gpio";
|
|
ti,hwmods = "gpio1";
|
|
@@ -224,6 +236,44 @@
|
|
status = "disabled";
|
|
};
|
|
|
|
+ mmc1: mmc@48060000 {
|
|
+ compatible = "ti,omap4-hsmmc";
|
|
+ ti,hwmods = "mmc1";
|
|
+ ti,dual-volt;
|
|
+ ti,needs-special-reset;
|
|
+ ti,needs-special-hs-handling;
|
|
+ dmas = <&edma 24
|
|
+ &edma 25>;
|
|
+ dma-names = "tx", "rx";
|
|
+ interrupts = <64>;
|
|
+ interrupt-parent = <&intc>;
|
|
+ reg = <0x48060000 0x1000>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ mmc2: mmc@481d8000 {
|
|
+ compatible = "ti,omap4-hsmmc";
|
|
+ ti,hwmods = "mmc2";
|
|
+ ti,needs-special-reset;
|
|
+ dmas = <&edma 2
|
|
+ &edma 3>;
|
|
+ dma-names = "tx", "rx";
|
|
+ interrupts = <28>;
|
|
+ interrupt-parent = <&intc>;
|
|
+ reg = <0x481d8000 0x1000>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ mmc3: mmc@47810000 {
|
|
+ compatible = "ti,omap4-hsmmc";
|
|
+ ti,hwmods = "mmc3";
|
|
+ ti,needs-special-reset;
|
|
+ interrupts = <29>;
|
|
+ interrupt-parent = <&intc>;
|
|
+ reg = <0x47810000 0x1000>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
wdt2: wdt@44e35000 {
|
|
compatible = "ti,omap3-wdt";
|
|
ti,hwmods = "wd_timer2";
|
|
@@ -319,6 +369,11 @@
|
|
interrupts = <65>;
|
|
ti,spi-num-cs = <2>;
|
|
ti,hwmods = "spi0";
|
|
+ dmas = <&edma 16
|
|
+ &edma 17
|
|
+ &edma 18
|
|
+ &edma 19>;
|
|
+ dma-names = "tx0", "rx0", "tx1", "rx1";
|
|
status = "disabled";
|
|
};
|
|
|
|
@@ -330,6 +385,11 @@
|
|
interrupts = <125>;
|
|
ti,spi-num-cs = <2>;
|
|
ti,hwmods = "spi1";
|
|
+ dmas = <&edma 42
|
|
+ &edma 43
|
|
+ &edma 44
|
|
+ &edma 45>;
|
|
+ dma-names = "tx0", "rx0", "tx1", "rx1";
|
|
status = "disabled";
|
|
};
|
|
|
|
diff --git a/arch/arm/common/edma.c b/arch/arm/common/edma.c
|
|
index 39ad030..18159d7 100644
|
|
--- a/arch/arm/common/edma.c
|
|
+++ b/arch/arm/common/edma.c
|
|
@@ -560,14 +560,29 @@ static int reserve_contiguous_slots(int ctlr, unsigned int id,
|
|
static int prepare_unused_channel_list(struct device *dev, void *data)
|
|
{
|
|
struct platform_device *pdev = to_platform_device(dev);
|
|
- int i, ctlr;
|
|
-
|
|
- for (i = 0; i < pdev->num_resources; i++) {
|
|
- if ((pdev->resource[i].flags & IORESOURCE_DMA) &&
|
|
- (int)pdev->resource[i].start >= 0) {
|
|
- ctlr = EDMA_CTLR(pdev->resource[i].start);
|
|
- clear_bit(EDMA_CHAN_SLOT(pdev->resource[i].start),
|
|
- edma_cc[ctlr]->edma_unused);
|
|
+ int i = 0, ctlr;
|
|
+ u32 dma_chan;
|
|
+ __be32 *dma_chan_p;
|
|
+ struct property *prop;
|
|
+
|
|
+ if (dev->of_node) {
|
|
+ of_property_for_each_u32(dev->of_node, "dmas", prop, \
|
|
+ dma_chan_p, dma_chan) {
|
|
+ if (i++ & 1) {
|
|
+ ctlr = EDMA_CTLR(dma_chan);
|
|
+ clear_bit(EDMA_CHAN_SLOT(dma_chan),
|
|
+ edma_cc[ctlr]->edma_unused);
|
|
+ }
|
|
+ }
|
|
+ } else {
|
|
+ for (; i < pdev->num_resources; i++) {
|
|
+ if ((pdev->resource[i].flags & IORESOURCE_DMA) &&
|
|
+ (int)pdev->resource[i].start >= 0) {
|
|
+ ctlr = EDMA_CTLR(pdev->resource[i].start);
|
|
+ clear_bit(EDMA_CHAN_SLOT(
|
|
+ pdev->resource[i].start),
|
|
+ edma_cc[ctlr]->edma_unused);
|
|
+ }
|
|
}
|
|
}
|
|
|
|
diff --git a/arch/arm/mach-davinci/da830.c b/arch/arm/mach-davinci/da830.c
|
|
index abbaf02..a3ffd52 100644
|
|
--- a/arch/arm/mach-davinci/da830.c
|
|
+++ b/arch/arm/mach-davinci/da830.c
|
|
@@ -395,9 +395,9 @@ static struct clk_lookup da830_clks[] = {
|
|
CLK(NULL, "tptc0", &tptc0_clk),
|
|
CLK(NULL, "tptc1", &tptc1_clk),
|
|
CLK("da830-mmc.0", NULL, &mmcsd_clk),
|
|
- CLK(NULL, "uart0", &uart0_clk),
|
|
- CLK(NULL, "uart1", &uart1_clk),
|
|
- CLK(NULL, "uart2", &uart2_clk),
|
|
+ CLK("serial8250.0", NULL, &uart0_clk),
|
|
+ CLK("serial8250.1", NULL, &uart1_clk),
|
|
+ CLK("serial8250.2", NULL, &uart2_clk),
|
|
CLK("spi_davinci.0", NULL, &spi0_clk),
|
|
CLK("spi_davinci.1", NULL, &spi1_clk),
|
|
CLK(NULL, "ecap0", &ecap0_clk),
|
|
@@ -1199,7 +1199,7 @@ static struct davinci_soc_info davinci_soc_info_da830 = {
|
|
.gpio_base = DA8XX_GPIO_BASE,
|
|
.gpio_num = 128,
|
|
.gpio_irq = IRQ_DA8XX_GPIO0,
|
|
- .serial_dev = &da8xx_serial_device,
|
|
+ .serial_dev = da8xx_serial_device,
|
|
.emac_pdata = &da8xx_emac_pdata,
|
|
};
|
|
|
|
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
|
|
index a0d4f60..d4274ab 100644
|
|
--- a/arch/arm/mach-davinci/da850.c
|
|
+++ b/arch/arm/mach-davinci/da850.c
|
|
@@ -451,9 +451,9 @@ static struct clk_lookup da850_clks[] = {
|
|
CLK(NULL, "tpcc1", &tpcc1_clk),
|
|
CLK(NULL, "tptc2", &tptc2_clk),
|
|
CLK("pruss_uio", "pruss", &pruss_clk),
|
|
- CLK(NULL, "uart0", &uart0_clk),
|
|
- CLK(NULL, "uart1", &uart1_clk),
|
|
- CLK(NULL, "uart2", &uart2_clk),
|
|
+ CLK("serial8250.0", NULL, &uart0_clk),
|
|
+ CLK("serial8250.1", NULL, &uart1_clk),
|
|
+ CLK("serial8250.2", NULL, &uart2_clk),
|
|
CLK(NULL, "aintc", &aintc_clk),
|
|
CLK(NULL, "gpio", &gpio_clk),
|
|
CLK("i2c_davinci.2", NULL, &i2c1_clk),
|
|
@@ -1301,7 +1301,7 @@ static struct davinci_soc_info davinci_soc_info_da850 = {
|
|
.gpio_base = DA8XX_GPIO_BASE,
|
|
.gpio_num = 144,
|
|
.gpio_irq = IRQ_DA8XX_GPIO0,
|
|
- .serial_dev = &da8xx_serial_device,
|
|
+ .serial_dev = da8xx_serial_device,
|
|
.emac_pdata = &da8xx_emac_pdata,
|
|
.sram_dma = DA8XX_SHARED_RAM_BASE,
|
|
.sram_len = SZ_128K,
|
|
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
|
|
index 71a46a3..280f67d 100644
|
|
--- a/arch/arm/mach-davinci/devices-da8xx.c
|
|
+++ b/arch/arm/mach-davinci/devices-da8xx.c
|
|
@@ -68,7 +68,7 @@
|
|
void __iomem *da8xx_syscfg0_base;
|
|
void __iomem *da8xx_syscfg1_base;
|
|
|
|
-static struct plat_serial8250_port da8xx_serial_pdata[] = {
|
|
+static struct plat_serial8250_port da8xx_serial0_pdata[] = {
|
|
{
|
|
.mapbase = DA8XX_UART0_BASE,
|
|
.irq = IRQ_DA8XX_UARTINT0,
|
|
@@ -78,6 +78,11 @@ static struct plat_serial8250_port da8xx_serial_pdata[] = {
|
|
.regshift = 2,
|
|
},
|
|
{
|
|
+ .flags = 0,
|
|
+ }
|
|
+};
|
|
+static struct plat_serial8250_port da8xx_serial1_pdata[] = {
|
|
+ {
|
|
.mapbase = DA8XX_UART1_BASE,
|
|
.irq = IRQ_DA8XX_UARTINT1,
|
|
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
|
|
@@ -86,6 +91,11 @@ static struct plat_serial8250_port da8xx_serial_pdata[] = {
|
|
.regshift = 2,
|
|
},
|
|
{
|
|
+ .flags = 0,
|
|
+ }
|
|
+};
|
|
+static struct plat_serial8250_port da8xx_serial2_pdata[] = {
|
|
+ {
|
|
.mapbase = DA8XX_UART2_BASE,
|
|
.irq = IRQ_DA8XX_UARTINT2,
|
|
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
|
|
@@ -95,15 +105,33 @@ static struct plat_serial8250_port da8xx_serial_pdata[] = {
|
|
},
|
|
{
|
|
.flags = 0,
|
|
- },
|
|
+ }
|
|
};
|
|
|
|
-struct platform_device da8xx_serial_device = {
|
|
- .name = "serial8250",
|
|
- .id = PLAT8250_DEV_PLATFORM,
|
|
- .dev = {
|
|
- .platform_data = da8xx_serial_pdata,
|
|
+struct platform_device da8xx_serial_device[] = {
|
|
+ {
|
|
+ .name = "serial8250",
|
|
+ .id = PLAT8250_DEV_PLATFORM,
|
|
+ .dev = {
|
|
+ .platform_data = da8xx_serial0_pdata,
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ .name = "serial8250",
|
|
+ .id = PLAT8250_DEV_PLATFORM1,
|
|
+ .dev = {
|
|
+ .platform_data = da8xx_serial1_pdata,
|
|
+ }
|
|
},
|
|
+ {
|
|
+ .name = "serial8250",
|
|
+ .id = PLAT8250_DEV_PLATFORM2,
|
|
+ .dev = {
|
|
+ .platform_data = da8xx_serial2_pdata,
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ }
|
|
};
|
|
|
|
static s8 da8xx_queue_tc_mapping[][2] = {
|
|
diff --git a/arch/arm/mach-davinci/devices-tnetv107x.c b/arch/arm/mach-davinci/devices-tnetv107x.c
|
|
index 128cb9a..fc4a0fe 100644
|
|
--- a/arch/arm/mach-davinci/devices-tnetv107x.c
|
|
+++ b/arch/arm/mach-davinci/devices-tnetv107x.c
|
|
@@ -126,7 +126,7 @@ static struct platform_device edma_device = {
|
|
.dev.platform_data = tnetv107x_edma_info,
|
|
};
|
|
|
|
-static struct plat_serial8250_port serial_data[] = {
|
|
+static struct plat_serial8250_port serial0_platform_data[] = {
|
|
{
|
|
.mapbase = TNETV107X_UART0_BASE,
|
|
.irq = IRQ_TNETV107X_UART0,
|
|
@@ -137,6 +137,11 @@ static struct plat_serial8250_port serial_data[] = {
|
|
.regshift = 2,
|
|
},
|
|
{
|
|
+ .flags = 0,
|
|
+ }
|
|
+};
|
|
+static struct plat_serial8250_port serial1_platform_data[] = {
|
|
+ {
|
|
.mapbase = TNETV107X_UART1_BASE,
|
|
.irq = IRQ_TNETV107X_UART1,
|
|
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
|
|
@@ -146,6 +151,11 @@ static struct plat_serial8250_port serial_data[] = {
|
|
.regshift = 2,
|
|
},
|
|
{
|
|
+ .flags = 0,
|
|
+ }
|
|
+};
|
|
+static struct plat_serial8250_port serial2_platform_data[] = {
|
|
+ {
|
|
.mapbase = TNETV107X_UART2_BASE,
|
|
.irq = IRQ_TNETV107X_UART2,
|
|
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
|
|
@@ -156,13 +166,28 @@ static struct plat_serial8250_port serial_data[] = {
|
|
},
|
|
{
|
|
.flags = 0,
|
|
- },
|
|
+ }
|
|
};
|
|
|
|
-struct platform_device tnetv107x_serial_device = {
|
|
- .name = "serial8250",
|
|
- .id = PLAT8250_DEV_PLATFORM,
|
|
- .dev.platform_data = serial_data,
|
|
+
|
|
+struct platform_device tnetv107x_serial_device[] = {
|
|
+ {
|
|
+ .name = "serial8250",
|
|
+ .id = PLAT8250_DEV_PLATFORM,
|
|
+ .dev.platform_data = serial0_platform_data,
|
|
+ },
|
|
+ {
|
|
+ .name = "serial8250",
|
|
+ .id = PLAT8250_DEV_PLATFORM1,
|
|
+ .dev.platform_data = serial1_platform_data,
|
|
+ },
|
|
+ {
|
|
+ .name = "serial8250",
|
|
+ .id = PLAT8250_DEV_PLATFORM2,
|
|
+ .dev.platform_data = serial2_platform_data,
|
|
+ },
|
|
+ {
|
|
+ }
|
|
};
|
|
|
|
static struct resource mmc0_resources[] = {
|
|
diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c
|
|
index 86100d1..1701a2d 100644
|
|
--- a/arch/arm/mach-davinci/dm355.c
|
|
+++ b/arch/arm/mach-davinci/dm355.c
|
|
@@ -357,9 +357,9 @@ static struct clk_lookup dm355_clks[] = {
|
|
CLK(NULL, "clkout3", &clkout3_clk),
|
|
CLK(NULL, "arm", &arm_clk),
|
|
CLK(NULL, "mjcp", &mjcp_clk),
|
|
- CLK(NULL, "uart0", &uart0_clk),
|
|
- CLK(NULL, "uart1", &uart1_clk),
|
|
- CLK(NULL, "uart2", &uart2_clk),
|
|
+ CLK("serial8250.0", NULL, &uart0_clk),
|
|
+ CLK("serial8250.1", NULL, &uart1_clk),
|
|
+ CLK("serial8250.2", NULL, &uart2_clk),
|
|
CLK("i2c_davinci.1", NULL, &i2c_clk),
|
|
CLK("davinci-mcbsp.0", NULL, &asp0_clk),
|
|
CLK("davinci-mcbsp.1", NULL, &asp1_clk),
|
|
@@ -922,7 +922,7 @@ static struct davinci_timer_info dm355_timer_info = {
|
|
.clocksource_id = T0_TOP,
|
|
};
|
|
|
|
-static struct plat_serial8250_port dm355_serial_platform_data[] = {
|
|
+static struct plat_serial8250_port dm355_serial0_platform_data[] = {
|
|
{
|
|
.mapbase = DAVINCI_UART0_BASE,
|
|
.irq = IRQ_UARTINT0,
|
|
@@ -932,6 +932,11 @@ static struct plat_serial8250_port dm355_serial_platform_data[] = {
|
|
.regshift = 2,
|
|
},
|
|
{
|
|
+ .flags = 0,
|
|
+ }
|
|
+};
|
|
+static struct plat_serial8250_port dm355_serial1_platform_data[] = {
|
|
+ {
|
|
.mapbase = DAVINCI_UART1_BASE,
|
|
.irq = IRQ_UARTINT1,
|
|
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
|
|
@@ -940,6 +945,11 @@ static struct plat_serial8250_port dm355_serial_platform_data[] = {
|
|
.regshift = 2,
|
|
},
|
|
{
|
|
+ .flags = 0,
|
|
+ }
|
|
+};
|
|
+static struct plat_serial8250_port dm355_serial2_platform_data[] = {
|
|
+ {
|
|
.mapbase = DM355_UART2_BASE,
|
|
.irq = IRQ_DM355_UARTINT2,
|
|
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
|
|
@@ -948,16 +958,34 @@ static struct plat_serial8250_port dm355_serial_platform_data[] = {
|
|
.regshift = 2,
|
|
},
|
|
{
|
|
- .flags = 0
|
|
- },
|
|
+ .flags = 0,
|
|
+ }
|
|
};
|
|
|
|
-static struct platform_device dm355_serial_device = {
|
|
- .name = "serial8250",
|
|
- .id = PLAT8250_DEV_PLATFORM,
|
|
- .dev = {
|
|
- .platform_data = dm355_serial_platform_data,
|
|
+static struct platform_device dm355_serial_device[] = {
|
|
+ {
|
|
+ .name = "serial8250",
|
|
+ .id = PLAT8250_DEV_PLATFORM,
|
|
+ .dev = {
|
|
+ .platform_data = dm355_serial0_platform_data,
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ .name = "serial8250",
|
|
+ .id = PLAT8250_DEV_PLATFORM1,
|
|
+ .dev = {
|
|
+ .platform_data = dm355_serial1_platform_data,
|
|
+ }
|
|
},
|
|
+ {
|
|
+ .name = "serial8250",
|
|
+ .id = PLAT8250_DEV_PLATFORM2,
|
|
+ .dev = {
|
|
+ .platform_data = dm355_serial2_platform_data,
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ }
|
|
};
|
|
|
|
static struct davinci_soc_info davinci_soc_info_dm355 = {
|
|
@@ -981,7 +1009,7 @@ static struct davinci_soc_info davinci_soc_info_dm355 = {
|
|
.gpio_base = DAVINCI_GPIO_BASE,
|
|
.gpio_num = 104,
|
|
.gpio_irq = IRQ_DM355_GPIOBNK0,
|
|
- .serial_dev = &dm355_serial_device,
|
|
+ .serial_dev = dm355_serial_device,
|
|
.sram_dma = 0x00010000,
|
|
.sram_len = SZ_32K,
|
|
};
|
|
diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c
|
|
index dad2802..5b3a1bc 100644
|
|
--- a/arch/arm/mach-davinci/dm365.c
|
|
+++ b/arch/arm/mach-davinci/dm365.c
|
|
@@ -455,8 +455,8 @@ static struct clk_lookup dm365_clks[] = {
|
|
CLK("vpss", "master", &vpss_master_clk),
|
|
CLK("vpss", "slave", &vpss_slave_clk),
|
|
CLK(NULL, "arm", &arm_clk),
|
|
- CLK(NULL, "uart0", &uart0_clk),
|
|
- CLK(NULL, "uart1", &uart1_clk),
|
|
+ CLK("serial8250.0", NULL, &uart0_clk),
|
|
+ CLK("serial8250.1", NULL, &uart1_clk),
|
|
CLK("i2c_davinci.1", NULL, &i2c_clk),
|
|
CLK("da830-mmc.0", NULL, &mmcsd0_clk),
|
|
CLK("da830-mmc.1", NULL, &mmcsd1_clk),
|
|
@@ -1041,7 +1041,7 @@ static struct davinci_timer_info dm365_timer_info = {
|
|
|
|
#define DM365_UART1_BASE (IO_PHYS + 0x106000)
|
|
|
|
-static struct plat_serial8250_port dm365_serial_platform_data[] = {
|
|
+static struct plat_serial8250_port dm365_serial0_platform_data[] = {
|
|
{
|
|
.mapbase = DAVINCI_UART0_BASE,
|
|
.irq = IRQ_UARTINT0,
|
|
@@ -1051,6 +1051,11 @@ static struct plat_serial8250_port dm365_serial_platform_data[] = {
|
|
.regshift = 2,
|
|
},
|
|
{
|
|
+ .flags = 0,
|
|
+ }
|
|
+};
|
|
+static struct plat_serial8250_port dm365_serial1_platform_data[] = {
|
|
+ {
|
|
.mapbase = DM365_UART1_BASE,
|
|
.irq = IRQ_UARTINT1,
|
|
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
|
|
@@ -1059,16 +1064,27 @@ static struct plat_serial8250_port dm365_serial_platform_data[] = {
|
|
.regshift = 2,
|
|
},
|
|
{
|
|
- .flags = 0
|
|
- },
|
|
+ .flags = 0,
|
|
+ }
|
|
};
|
|
|
|
-static struct platform_device dm365_serial_device = {
|
|
- .name = "serial8250",
|
|
- .id = PLAT8250_DEV_PLATFORM,
|
|
- .dev = {
|
|
- .platform_data = dm365_serial_platform_data,
|
|
+static struct platform_device dm365_serial_device[] = {
|
|
+ {
|
|
+ .name = "serial8250",
|
|
+ .id = PLAT8250_DEV_PLATFORM,
|
|
+ .dev = {
|
|
+ .platform_data = dm365_serial0_platform_data,
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ .name = "serial8250",
|
|
+ .id = PLAT8250_DEV_PLATFORM1,
|
|
+ .dev = {
|
|
+ .platform_data = dm365_serial1_platform_data,
|
|
+ }
|
|
},
|
|
+ {
|
|
+ }
|
|
};
|
|
|
|
static struct davinci_soc_info davinci_soc_info_dm365 = {
|
|
@@ -1093,7 +1109,7 @@ static struct davinci_soc_info davinci_soc_info_dm365 = {
|
|
.gpio_num = 104,
|
|
.gpio_irq = IRQ_DM365_GPIO0,
|
|
.gpio_unbanked = 8, /* really 16 ... skip muxed GPIOs */
|
|
- .serial_dev = &dm365_serial_device,
|
|
+ .serial_dev = dm365_serial_device,
|
|
.emac_pdata = &dm365_emac_pdata,
|
|
.sram_dma = 0x00010000,
|
|
.sram_len = SZ_32K,
|
|
diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c
|
|
index a49d182..490eb8c 100644
|
|
--- a/arch/arm/mach-davinci/dm644x.c
|
|
+++ b/arch/arm/mach-davinci/dm644x.c
|
|
@@ -303,9 +303,9 @@ static struct clk_lookup dm644x_clks[] = {
|
|
CLK("vpss", "master", &vpss_master_clk),
|
|
CLK("vpss", "slave", &vpss_slave_clk),
|
|
CLK(NULL, "arm", &arm_clk),
|
|
- CLK(NULL, "uart0", &uart0_clk),
|
|
- CLK(NULL, "uart1", &uart1_clk),
|
|
- CLK(NULL, "uart2", &uart2_clk),
|
|
+ CLK("serial8250.0", NULL, &uart0_clk),
|
|
+ CLK("serial8250.1", NULL, &uart1_clk),
|
|
+ CLK("serial8250.2", NULL, &uart2_clk),
|
|
CLK("davinci_emac.1", NULL, &emac_clk),
|
|
CLK("i2c_davinci.1", NULL, &i2c_clk),
|
|
CLK("palm_bk3710", NULL, &ide_clk),
|
|
@@ -813,7 +813,7 @@ static struct davinci_timer_info dm644x_timer_info = {
|
|
.clocksource_id = T0_TOP,
|
|
};
|
|
|
|
-static struct plat_serial8250_port dm644x_serial_platform_data[] = {
|
|
+static struct plat_serial8250_port dm644x_serial0_platform_data[] = {
|
|
{
|
|
.mapbase = DAVINCI_UART0_BASE,
|
|
.irq = IRQ_UARTINT0,
|
|
@@ -823,6 +823,11 @@ static struct plat_serial8250_port dm644x_serial_platform_data[] = {
|
|
.regshift = 2,
|
|
},
|
|
{
|
|
+ .flags = 0,
|
|
+ }
|
|
+};
|
|
+static struct plat_serial8250_port dm644x_serial1_platform_data[] = {
|
|
+ {
|
|
.mapbase = DAVINCI_UART1_BASE,
|
|
.irq = IRQ_UARTINT1,
|
|
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
|
|
@@ -831,6 +836,11 @@ static struct plat_serial8250_port dm644x_serial_platform_data[] = {
|
|
.regshift = 2,
|
|
},
|
|
{
|
|
+ .flags = 0,
|
|
+ }
|
|
+};
|
|
+static struct plat_serial8250_port dm644x_serial2_platform_data[] = {
|
|
+ {
|
|
.mapbase = DAVINCI_UART2_BASE,
|
|
.irq = IRQ_UARTINT2,
|
|
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
|
|
@@ -839,16 +849,34 @@ static struct plat_serial8250_port dm644x_serial_platform_data[] = {
|
|
.regshift = 2,
|
|
},
|
|
{
|
|
- .flags = 0
|
|
- },
|
|
+ .flags = 0,
|
|
+ }
|
|
};
|
|
|
|
-static struct platform_device dm644x_serial_device = {
|
|
- .name = "serial8250",
|
|
- .id = PLAT8250_DEV_PLATFORM,
|
|
- .dev = {
|
|
- .platform_data = dm644x_serial_platform_data,
|
|
+static struct platform_device dm644x_serial_device[] = {
|
|
+ {
|
|
+ .name = "serial8250",
|
|
+ .id = PLAT8250_DEV_PLATFORM,
|
|
+ .dev = {
|
|
+ .platform_data = dm644x_serial0_platform_data,
|
|
+ }
|
|
},
|
|
+ {
|
|
+ .name = "serial8250",
|
|
+ .id = PLAT8250_DEV_PLATFORM1,
|
|
+ .dev = {
|
|
+ .platform_data = dm644x_serial1_platform_data,
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ .name = "serial8250",
|
|
+ .id = PLAT8250_DEV_PLATFORM2,
|
|
+ .dev = {
|
|
+ .platform_data = dm644x_serial2_platform_data,
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ }
|
|
};
|
|
|
|
static struct davinci_soc_info davinci_soc_info_dm644x = {
|
|
@@ -872,7 +900,7 @@ static struct davinci_soc_info davinci_soc_info_dm644x = {
|
|
.gpio_base = DAVINCI_GPIO_BASE,
|
|
.gpio_num = 71,
|
|
.gpio_irq = IRQ_GPIOBNK0,
|
|
- .serial_dev = &dm644x_serial_device,
|
|
+ .serial_dev = dm644x_serial_device,
|
|
.emac_pdata = &dm644x_emac_pdata,
|
|
.sram_dma = 0x00008000,
|
|
.sram_len = SZ_16K,
|
|
diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c
|
|
index d1259e8..23609b1 100644
|
|
--- a/arch/arm/mach-davinci/dm646x.c
|
|
+++ b/arch/arm/mach-davinci/dm646x.c
|
|
@@ -342,9 +342,9 @@ static struct clk_lookup dm646x_clks[] = {
|
|
CLK(NULL, "edma_tc1", &edma_tc1_clk),
|
|
CLK(NULL, "edma_tc2", &edma_tc2_clk),
|
|
CLK(NULL, "edma_tc3", &edma_tc3_clk),
|
|
- CLK(NULL, "uart0", &uart0_clk),
|
|
- CLK(NULL, "uart1", &uart1_clk),
|
|
- CLK(NULL, "uart2", &uart2_clk),
|
|
+ CLK("serial8250.0", NULL, &uart0_clk),
|
|
+ CLK("serial8250.1", NULL, &uart1_clk),
|
|
+ CLK("serial8250.2", NULL, &uart2_clk),
|
|
CLK("i2c_davinci.1", NULL, &i2c_clk),
|
|
CLK(NULL, "gpio", &gpio_clk),
|
|
CLK("davinci-mcasp.0", NULL, &mcasp0_clk),
|
|
@@ -790,7 +790,7 @@ static struct davinci_timer_info dm646x_timer_info = {
|
|
.clocksource_id = T0_TOP,
|
|
};
|
|
|
|
-static struct plat_serial8250_port dm646x_serial_platform_data[] = {
|
|
+static struct plat_serial8250_port dm646x_serial0_platform_data[] = {
|
|
{
|
|
.mapbase = DAVINCI_UART0_BASE,
|
|
.irq = IRQ_UARTINT0,
|
|
@@ -800,6 +800,11 @@ static struct plat_serial8250_port dm646x_serial_platform_data[] = {
|
|
.regshift = 2,
|
|
},
|
|
{
|
|
+ .flags = 0,
|
|
+ }
|
|
+};
|
|
+static struct plat_serial8250_port dm646x_serial1_platform_data[] = {
|
|
+ {
|
|
.mapbase = DAVINCI_UART1_BASE,
|
|
.irq = IRQ_UARTINT1,
|
|
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
|
|
@@ -808,6 +813,11 @@ static struct plat_serial8250_port dm646x_serial_platform_data[] = {
|
|
.regshift = 2,
|
|
},
|
|
{
|
|
+ .flags = 0,
|
|
+ }
|
|
+};
|
|
+static struct plat_serial8250_port dm646x_serial2_platform_data[] = {
|
|
+ {
|
|
.mapbase = DAVINCI_UART2_BASE,
|
|
.irq = IRQ_DM646X_UARTINT2,
|
|
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
|
|
@@ -816,16 +826,34 @@ static struct plat_serial8250_port dm646x_serial_platform_data[] = {
|
|
.regshift = 2,
|
|
},
|
|
{
|
|
- .flags = 0
|
|
- },
|
|
+ .flags = 0,
|
|
+ }
|
|
};
|
|
|
|
-static struct platform_device dm646x_serial_device = {
|
|
- .name = "serial8250",
|
|
- .id = PLAT8250_DEV_PLATFORM,
|
|
- .dev = {
|
|
- .platform_data = dm646x_serial_platform_data,
|
|
+static struct platform_device dm646x_serial_device[] = {
|
|
+ {
|
|
+ .name = "serial8250",
|
|
+ .id = PLAT8250_DEV_PLATFORM,
|
|
+ .dev = {
|
|
+ .platform_data = dm646x_serial0_platform_data,
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ .name = "serial8250",
|
|
+ .id = PLAT8250_DEV_PLATFORM1,
|
|
+ .dev = {
|
|
+ .platform_data = dm646x_serial1_platform_data,
|
|
+ }
|
|
},
|
|
+ {
|
|
+ .name = "serial8250",
|
|
+ .id = PLAT8250_DEV_PLATFORM2,
|
|
+ .dev = {
|
|
+ .platform_data = dm646x_serial2_platform_data,
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ }
|
|
};
|
|
|
|
static struct davinci_soc_info davinci_soc_info_dm646x = {
|
|
@@ -849,7 +877,7 @@ static struct davinci_soc_info davinci_soc_info_dm646x = {
|
|
.gpio_base = DAVINCI_GPIO_BASE,
|
|
.gpio_num = 43, /* Only 33 usable */
|
|
.gpio_irq = IRQ_DM646X_GPIOBNK0,
|
|
- .serial_dev = &dm646x_serial_device,
|
|
+ .serial_dev = dm646x_serial_device,
|
|
.emac_pdata = &dm646x_emac_pdata,
|
|
.sram_dma = 0x10010000,
|
|
.sram_len = SZ_32K,
|
|
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
|
|
index 7b41a5e..aae5307 100644
|
|
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
|
|
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
|
|
@@ -111,7 +111,7 @@ void da8xx_restart(enum reboot_mode mode, const char *cmd);
|
|
void da8xx_rproc_reserve_cma(void);
|
|
int da8xx_register_rproc(void);
|
|
|
|
-extern struct platform_device da8xx_serial_device;
|
|
+extern struct platform_device da8xx_serial_device[];
|
|
extern struct emac_platform_data da8xx_emac_pdata;
|
|
extern struct da8xx_lcdc_platform_data sharp_lcd035q3dg01_pdata;
|
|
extern struct da8xx_lcdc_platform_data sharp_lk043t1dg01_pdata;
|
|
diff --git a/arch/arm/mach-davinci/include/mach/tnetv107x.h b/arch/arm/mach-davinci/include/mach/tnetv107x.h
|
|
index 16314c6..beb7c0e 100644
|
|
--- a/arch/arm/mach-davinci/include/mach/tnetv107x.h
|
|
+++ b/arch/arm/mach-davinci/include/mach/tnetv107x.h
|
|
@@ -50,7 +50,7 @@ struct tnetv107x_device_info {
|
|
};
|
|
|
|
extern struct platform_device tnetv107x_wdt_device;
|
|
-extern struct platform_device tnetv107x_serial_device;
|
|
+extern struct platform_device tnetv107x_serial_device[];
|
|
|
|
extern void tnetv107x_init(void);
|
|
extern void tnetv107x_devices_init(struct tnetv107x_device_info *);
|
|
diff --git a/arch/arm/mach-davinci/serial.c b/arch/arm/mach-davinci/serial.c
|
|
index f262581..57e6150 100644
|
|
--- a/arch/arm/mach-davinci/serial.c
|
|
+++ b/arch/arm/mach-davinci/serial.c
|
|
@@ -76,7 +76,7 @@ int __init davinci_serial_setup_clk(unsigned instance, unsigned int *rate)
|
|
char name[16];
|
|
struct clk *clk;
|
|
struct davinci_soc_info *soc_info = &davinci_soc_info;
|
|
- struct device *dev = &soc_info->serial_dev->dev;
|
|
+ struct device *dev = &soc_info->serial_dev[instance].dev;
|
|
|
|
sprintf(name, "uart%d", instance);
|
|
clk = clk_get(dev, name);
|
|
@@ -96,19 +96,25 @@ int __init davinci_serial_setup_clk(unsigned instance, unsigned int *rate)
|
|
|
|
int __init davinci_serial_init(struct davinci_uart_config *info)
|
|
{
|
|
- int i, ret;
|
|
+ int i, ret = 0;
|
|
struct davinci_soc_info *soc_info = &davinci_soc_info;
|
|
- struct device *dev = &soc_info->serial_dev->dev;
|
|
- struct plat_serial8250_port *p = dev->platform_data;
|
|
+ struct device *dev;
|
|
+ struct plat_serial8250_port *p;
|
|
|
|
/*
|
|
* Make sure the serial ports are muxed on at this point.
|
|
* You have to mux them off in device drivers later on if not needed.
|
|
*/
|
|
- for (i = 0; p->flags; i++, p++) {
|
|
+ for (i = 0; soc_info->serial_dev[i].dev.platform_data != NULL; i++) {
|
|
+ dev = &soc_info->serial_dev[i].dev;
|
|
+ p = dev->platform_data;
|
|
if (!(info->enabled_uarts & (1 << i)))
|
|
continue;
|
|
|
|
+ ret = platform_device_register(&soc_info->serial_dev[i]);
|
|
+ if (ret)
|
|
+ continue;
|
|
+
|
|
ret = davinci_serial_setup_clk(i, &p->uartclk);
|
|
if (ret)
|
|
continue;
|
|
@@ -125,6 +131,5 @@ int __init davinci_serial_init(struct davinci_uart_config *info)
|
|
if (p->membase && p->type != PORT_AR7)
|
|
davinci_serial_reset(p);
|
|
}
|
|
-
|
|
- return platform_device_register(soc_info->serial_dev);
|
|
+ return ret;
|
|
}
|
|
diff --git a/arch/arm/mach-davinci/tnetv107x.c b/arch/arm/mach-davinci/tnetv107x.c
|
|
index 4545667..f4d7fbb 100644
|
|
--- a/arch/arm/mach-davinci/tnetv107x.c
|
|
+++ b/arch/arm/mach-davinci/tnetv107x.c
|
|
@@ -264,7 +264,7 @@ static struct clk_lookup clks[] = {
|
|
CLK(NULL, "clk_chipcfg", &clk_chipcfg),
|
|
CLK("tnetv107x-ts.0", NULL, &clk_tsc),
|
|
CLK(NULL, "clk_rom", &clk_rom),
|
|
- CLK(NULL, "uart2", &clk_uart2),
|
|
+ CLK("serial8250.2", NULL, &clk_uart2),
|
|
CLK(NULL, "clk_pktsec", &clk_pktsec),
|
|
CLK("tnetv107x-rng.0", NULL, &clk_rng),
|
|
CLK("tnetv107x-pka.0", NULL, &clk_pka),
|
|
@@ -274,8 +274,8 @@ static struct clk_lookup clks[] = {
|
|
CLK(NULL, "clk_gpio", &clk_gpio),
|
|
CLK(NULL, "clk_mdio", &clk_mdio),
|
|
CLK("dm6441-mmc.0", NULL, &clk_sdio0),
|
|
- CLK(NULL, "uart0", &clk_uart0),
|
|
- CLK(NULL, "uart1", &clk_uart1),
|
|
+ CLK("serial8250.0", NULL, &clk_uart0),
|
|
+ CLK("serial8250.1", NULL, &clk_uart1),
|
|
CLK(NULL, "timer0", &clk_timer0),
|
|
CLK(NULL, "timer1", &clk_timer1),
|
|
CLK("tnetv107x_wdt.0", NULL, &clk_wdt_arm),
|
|
@@ -757,7 +757,7 @@ static struct davinci_soc_info tnetv107x_soc_info = {
|
|
.gpio_type = GPIO_TYPE_TNETV107X,
|
|
.gpio_num = TNETV107X_N_GPIO,
|
|
.timer_info = &timer_info,
|
|
- .serial_dev = &tnetv107x_serial_device,
|
|
+ .serial_dev = tnetv107x_serial_device,
|
|
};
|
|
|
|
void __init tnetv107x_init(void)
|
|
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
|
|
index d4f6715..7c0ef46 100644
|
|
--- a/arch/arm/mach-omap2/Makefile
|
|
+++ b/arch/arm/mach-omap2/Makefile
|
|
@@ -295,4 +295,7 @@ endif
|
|
emac-$(CONFIG_TI_DAVINCI_EMAC) := am35xx-emac.o
|
|
obj-y += $(emac-m) $(emac-y)
|
|
|
|
+cpsw-$(CONFIG_TI_CPSW) := am33xx-cpsw.o
|
|
+obj-y += $(cpsw-m) $(cpsw-y)
|
|
+
|
|
obj-y += common-board-devices.o twl-common.o dss-common.o
|
|
diff --git a/arch/arm/mach-omap2/am33xx-cpsw.c b/arch/arm/mach-omap2/am33xx-cpsw.c
|
|
new file mode 100644
|
|
index 0000000..5a674d9
|
|
--- /dev/null
|
|
+++ b/arch/arm/mach-omap2/am33xx-cpsw.c
|
|
@@ -0,0 +1,94 @@
|
|
+/*
|
|
+ * am335x specific cpsw dt fixups
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or
|
|
+ * modify it under the terms of the GNU General Public License as
|
|
+ * published by the Free Software Foundation version 2.
|
|
+ *
|
|
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
|
+ * kind, whether express or implied; without even the implied warranty
|
|
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ */
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/etherdevice.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_net.h>
|
|
+
|
|
+#include "soc.h"
|
|
+#include "control.h"
|
|
+
|
|
+/**
|
|
+ * am33xx_dt_cpsw_set_mac_from_efuse - Add mac-address property using
|
|
+ * ethernet hwaddr from efuse
|
|
+ * @np: Pointer to the cpsw slave to set mac address of
|
|
+ * @idx: Mac address index to use from efuse
|
|
+ */
|
|
+static void am33xx_dt_cpsw_set_mac_from_efuse(struct device_node *np, int idx)
|
|
+{
|
|
+ struct property *prop;
|
|
+ u32 lo, hi;
|
|
+ u8 *mac;
|
|
+
|
|
+ switch (idx) {
|
|
+ case 0:
|
|
+ lo = omap_ctrl_readl(AM33XX_CONTROL_MAC_ID0_LOW);
|
|
+ hi = omap_ctrl_readl(AM33XX_CONTROL_MAC_ID0_HIGH);
|
|
+ break;
|
|
+
|
|
+ case 1:
|
|
+ lo = omap_ctrl_readl(AM33XX_CONTROL_MAC_ID1_LOW);
|
|
+ hi = omap_ctrl_readl(AM33XX_CONTROL_MAC_ID1_HIGH);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ pr_err("cpsw.%d: too many slaves found\n", idx);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ prop = kzalloc(sizeof(*prop) + ETH_ALEN, GFP_KERNEL);
|
|
+ if (!prop)
|
|
+ return;
|
|
+
|
|
+ prop->value = prop + 1;
|
|
+ prop->length = ETH_ALEN;
|
|
+ prop->name = kstrdup("mac-address", GFP_KERNEL);
|
|
+ if (!prop->name) {
|
|
+ kfree(prop);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ mac = prop->value;
|
|
+
|
|
+ mac[0] = hi;
|
|
+ mac[1] = hi >> 8;
|
|
+ mac[2] = hi >> 16;
|
|
+ mac[3] = hi >> 24;
|
|
+ mac[4] = lo;
|
|
+ mac[5] = lo >> 8;
|
|
+
|
|
+ of_update_property(np, prop);
|
|
+
|
|
+ pr_info("cpsw.%d: No hwaddr in dt. Using %pM from efuse\n", idx, mac);
|
|
+}
|
|
+
|
|
+static int __init am33xx_dt_cpsw_mac_fixup(void)
|
|
+{
|
|
+ struct device_node *np, *slave;
|
|
+ int idx = 0;
|
|
+
|
|
+ if (!soc_is_am33xx())
|
|
+ return -ENODEV;
|
|
+
|
|
+ for_each_compatible_node(np, NULL, "ti,cpsw")
|
|
+ for_each_node_by_name(slave, "slave") {
|
|
+ if (!of_get_mac_address(slave))
|
|
+ am33xx_dt_cpsw_set_mac_from_efuse(slave, idx);
|
|
+ idx++;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+arch_initcall(am33xx_dt_cpsw_mac_fixup);
|
|
diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h
|
|
index f7d7c2e..5d684b7 100644
|
|
--- a/arch/arm/mach-omap2/control.h
|
|
+++ b/arch/arm/mach-omap2/control.h
|
|
@@ -352,6 +352,10 @@
|
|
/* AM33XX CONTROL_STATUS register */
|
|
#define AM33XX_CONTROL_STATUS 0x040
|
|
#define AM33XX_CONTROL_SEC_CLK_CTRL 0x1bc
|
|
+#define AM33XX_CONTROL_MAC_ID0_LOW 0x630
|
|
+#define AM33XX_CONTROL_MAC_ID0_HIGH 0x634
|
|
+#define AM33XX_CONTROL_MAC_ID1_LOW 0x638
|
|
+#define AM33XX_CONTROL_MAC_ID1_HIGH 0x63c
|
|
|
|
/* AM33XX CONTROL_STATUS bitfields (partial) */
|
|
#define AM33XX_CONTROL_STATUS_SYSBOOT1_SHIFT 22
|
|
diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c
|
|
index 5f3e532..cec9a12 100644
|
|
--- a/drivers/dma/edma.c
|
|
+++ b/drivers/dma/edma.c
|
|
@@ -70,6 +70,7 @@ struct edma_chan {
|
|
bool alloced;
|
|
int slot[EDMA_MAX_SLOTS];
|
|
struct dma_slave_config cfg;
|
|
+ struct dma_slave_sg_limits sg_limits;
|
|
};
|
|
|
|
struct edma_cc {
|
|
@@ -210,6 +211,198 @@ static int edma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
|
|
return ret;
|
|
}
|
|
|
|
+/*
|
|
+ * A clean implementation of a PaRAM set configuration abstraction
|
|
+ * @chan: Channel who's PaRAM set we're configuring
|
|
+ * @src_addr: Source address of the DMA
|
|
+ * @dst_addr: Destination address of the DMA
|
|
+ * @burst: In units of dev_width, how much to send
|
|
+ * @dev_width: How much is the dev_width
|
|
+ * @dma_length: Total length of the DMA transfer
|
|
+ * @direction: Direction of the transfer
|
|
+ */
|
|
+static int edma_config_pset(struct dma_chan *chan, struct edmacc_param *pset,
|
|
+ dma_addr_t src_addr, dma_addr_t dst_addr, u32 burst,
|
|
+ enum dma_slave_buswidth dev_width, unsigned int dma_length,
|
|
+ enum dma_transfer_direction direction)
|
|
+{
|
|
+ struct edma_chan *echan = to_edma_chan(chan);
|
|
+ struct device *dev = chan->device->dev;
|
|
+ int acnt, bcnt, ccnt, cidx;
|
|
+ int src_bidx, dst_bidx, src_cidx, dst_cidx;
|
|
+ int absync;
|
|
+
|
|
+ acnt = dev_width;
|
|
+ /*
|
|
+ * If the maxburst is equal to the fifo width, use
|
|
+ * A-synced transfers. This allows for large contiguous
|
|
+ * buffer transfers using only one PaRAM set.
|
|
+ */
|
|
+ if (burst == 1) {
|
|
+ absync = false;
|
|
+ /*
|
|
+ * For the A-sync case, bcnt and ccnt are the remainder
|
|
+ * and quotient respectively of the division of:
|
|
+ * (dma_length / acnt) by (SZ_64K -1). This is so
|
|
+ * that in case bcnt over flows, we have ccnt to use.
|
|
+ * Note: In A-sync tranfer only, bcntrld is used, but it
|
|
+ * only applies for sg_dma_len(sg) >= SZ_64K.
|
|
+ * In this case, the best way adopted is- bccnt for the
|
|
+ * first frame will be the remainder below. Then for
|
|
+ * every successive frame, bcnt will be SZ_64K-1. This
|
|
+ * is assured as bcntrld = 0xffff in end of function.
|
|
+ */
|
|
+ ccnt = dma_length / acnt / (SZ_64K - 1);
|
|
+ bcnt = dma_length / acnt - ccnt * (SZ_64K - 1);
|
|
+ /*
|
|
+ * If bcnt is non-zero, we have a remainder and hence an
|
|
+ * extra frame to transfer, so increment ccnt.
|
|
+ */
|
|
+ if (bcnt)
|
|
+ ccnt++;
|
|
+ else
|
|
+ bcnt = SZ_64K - 1;
|
|
+ cidx = acnt;
|
|
+ /*
|
|
+ * If maxburst is greater than the fifo address_width,
|
|
+ * use AB-synced transfers where A count is the fifo
|
|
+ * address_width and B count is the maxburst. In this
|
|
+ * case, we are limited to transfers of C count frames
|
|
+ * of (address_width * maxburst) where C count is limited
|
|
+ * to SZ_64K-1. This places an upper bound on the length
|
|
+ * of an SG segment that can be handled.
|
|
+ */
|
|
+ } else {
|
|
+ absync = true;
|
|
+ bcnt = burst;
|
|
+ ccnt = dma_length / (acnt * bcnt);
|
|
+ if (ccnt > (SZ_64K - 1)) {
|
|
+ dev_err(dev, "Exceeded max SG segment size\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ cidx = acnt * bcnt;
|
|
+ }
|
|
+
|
|
+ if (direction == DMA_MEM_TO_DEV) {
|
|
+ src_bidx = acnt;
|
|
+ src_cidx = cidx;
|
|
+ dst_bidx = 0;
|
|
+ dst_cidx = 0;
|
|
+ } else if (direction == DMA_DEV_TO_MEM) {
|
|
+ src_bidx = 0;
|
|
+ src_cidx = 0;
|
|
+ dst_bidx = acnt;
|
|
+ dst_cidx = cidx;
|
|
+ } else {
|
|
+ dev_err(dev, "%s: direction not implemented yet\n", __func__);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ pset->opt = EDMA_TCC(EDMA_CHAN_SLOT(echan->ch_num));
|
|
+ /* Configure A or AB synchronized transfers */
|
|
+ if (absync)
|
|
+ pset->opt |= SYNCDIM;
|
|
+
|
|
+ pset->src = src_addr;
|
|
+ pset->dst = dst_addr;
|
|
+
|
|
+ pset->src_dst_bidx = (dst_bidx << 16) | src_bidx;
|
|
+ pset->src_dst_cidx = (dst_cidx << 16) | src_cidx;
|
|
+
|
|
+ pset->a_b_cnt = bcnt << 16 | acnt;
|
|
+ pset->ccnt = ccnt;
|
|
+ /*
|
|
+ * Only time when (bcntrld) auto reload is required is for
|
|
+ * A-sync case, and in this case, a requirement of reload value
|
|
+ * of SZ_64K-1 only is assured. 'link' is initially set to NULL
|
|
+ * and then later will be populated by edma_execute.
|
|
+ */
|
|
+ pset->link_bcntrld = 0xffffffff;
|
|
+ return absync;
|
|
+}
|
|
+
|
|
+static struct dma_async_tx_descriptor *edma_prep_dma_cyclic(
|
|
+ struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
|
|
+ size_t period_len, enum dma_transfer_direction direction, unsigned long flags,
|
|
+ void *context)
|
|
+{
|
|
+ struct edma_chan *echan = to_edma_chan(chan);
|
|
+ struct device *dev = chan->device->dev;
|
|
+ struct edma_desc *edesc;
|
|
+ dma_addr_t src_addr, dst_addr;
|
|
+ enum dma_slave_buswidth dev_width;
|
|
+ u32 burst;
|
|
+ int i, ret, nr_periods;
|
|
+
|
|
+ if (unlikely(!echan || !buf_len || !period_len))
|
|
+ return NULL;
|
|
+
|
|
+ if (direction == DMA_DEV_TO_MEM) {
|
|
+ src_addr = echan->cfg.src_addr;
|
|
+ dst_addr = buf_addr;
|
|
+ dev_width = echan->cfg.src_addr_width;
|
|
+ burst = echan->cfg.src_maxburst;
|
|
+ } else if (direction == DMA_MEM_TO_DEV) {
|
|
+ src_addr = buf_addr;
|
|
+ dst_addr = echan->cfg.dst_addr;
|
|
+ dev_width = echan->cfg.dst_addr_width;
|
|
+ burst = echan->cfg.dst_maxburst;
|
|
+ } else {
|
|
+ dev_err(dev, "%s: bad direction?\n", __func__);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (dev_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) {
|
|
+ dev_err(dev, "Undefined slave buswidth\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if(unlikely(period_len % buf_len)) {
|
|
+ dev_err(dev, "Period should be multiple of Buf length\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ nr_periods = period_len / buf_len;
|
|
+
|
|
+ edesc = kzalloc(sizeof(*edesc) + nr_periods *
|
|
+ sizeof(edesc->pset[0]), GFP_ATOMIC);
|
|
+ if (!edesc) {
|
|
+ dev_dbg(dev, "Failed to allocate a descriptor\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ edesc->pset_nr = nr_periods;
|
|
+
|
|
+ for(i = 0; i < nr_periods; i++) {
|
|
+ /* Allocate a PaRAM slot, if needed */
|
|
+ if (echan->slot[i] < 0) {
|
|
+ echan->slot[i] =
|
|
+ edma_alloc_slot(EDMA_CTLR(echan->ch_num),
|
|
+ EDMA_SLOT_ANY);
|
|
+ if (echan->slot[i] < 0) {
|
|
+ dev_err(dev, "Failed to allocate slot\n");
|
|
+ return NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (direction == DMA_DEV_TO_MEM)
|
|
+ dst_addr += period_len;
|
|
+ else
|
|
+ src_addr += period_len;
|
|
+
|
|
+ ret = edma_config_pset(chan, &edesc->pset[i], src_addr, dst_addr,
|
|
+ burst, dev_width, period_len, direction);
|
|
+ if(ret < 0)
|
|
+ return NULL;
|
|
+
|
|
+ edesc->absync = ret;
|
|
+ if (i == nr_periods - 1)
|
|
+ edesc->pset[i].opt |= TCINTEN;
|
|
+ }
|
|
+ /* TODO tx_flags (last parameter) needs to be investigated...\n" */
|
|
+ return vchan_tx_prep(&echan->vchan, &edesc->vdesc, 0);
|
|
+}
|
|
+
|
|
static struct dma_async_tx_descriptor *edma_prep_slave_sg(
|
|
struct dma_chan *chan, struct scatterlist *sgl,
|
|
unsigned int sg_len, enum dma_transfer_direction direction,
|
|
@@ -218,23 +411,21 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg(
|
|
struct edma_chan *echan = to_edma_chan(chan);
|
|
struct device *dev = chan->device->dev;
|
|
struct edma_desc *edesc;
|
|
- dma_addr_t dev_addr;
|
|
+ dma_addr_t src_addr = 0, dst_addr = 0;
|
|
enum dma_slave_buswidth dev_width;
|
|
u32 burst;
|
|
struct scatterlist *sg;
|
|
- int i;
|
|
- int acnt, bcnt, ccnt, src, dst, cidx;
|
|
- int src_bidx, dst_bidx, src_cidx, dst_cidx;
|
|
+ int i, ret;
|
|
|
|
if (unlikely(!echan || !sgl || !sg_len))
|
|
return NULL;
|
|
|
|
if (direction == DMA_DEV_TO_MEM) {
|
|
- dev_addr = echan->cfg.src_addr;
|
|
+ src_addr = echan->cfg.src_addr;
|
|
dev_width = echan->cfg.src_addr_width;
|
|
burst = echan->cfg.src_maxburst;
|
|
} else if (direction == DMA_MEM_TO_DEV) {
|
|
- dev_addr = echan->cfg.dst_addr;
|
|
+ dst_addr = echan->cfg.dst_addr;
|
|
dev_width = echan->cfg.dst_addr_width;
|
|
burst = echan->cfg.dst_maxburst;
|
|
} else {
|
|
@@ -262,7 +453,14 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg(
|
|
|
|
edesc->pset_nr = sg_len;
|
|
|
|
+ /* Configure PaRAM sets for each SG */
|
|
for_each_sg(sgl, sg, sg_len, i) {
|
|
+ /* Get address for each SG */
|
|
+ if (direction == DMA_DEV_TO_MEM)
|
|
+ dst_addr = sg_dma_address(sg);
|
|
+ else
|
|
+ src_addr = sg_dma_address(sg);
|
|
+
|
|
/* Allocate a PaRAM slot, if needed */
|
|
if (echan->slot[i] < 0) {
|
|
echan->slot[i] =
|
|
@@ -274,76 +472,16 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg(
|
|
}
|
|
}
|
|
|
|
- acnt = dev_width;
|
|
-
|
|
- /*
|
|
- * If the maxburst is equal to the fifo width, use
|
|
- * A-synced transfers. This allows for large contiguous
|
|
- * buffer transfers using only one PaRAM set.
|
|
- */
|
|
- if (burst == 1) {
|
|
- edesc->absync = false;
|
|
- ccnt = sg_dma_len(sg) / acnt / (SZ_64K - 1);
|
|
- bcnt = sg_dma_len(sg) / acnt - ccnt * (SZ_64K - 1);
|
|
- if (bcnt)
|
|
- ccnt++;
|
|
- else
|
|
- bcnt = SZ_64K - 1;
|
|
- cidx = acnt;
|
|
- /*
|
|
- * If maxburst is greater than the fifo address_width,
|
|
- * use AB-synced transfers where A count is the fifo
|
|
- * address_width and B count is the maxburst. In this
|
|
- * case, we are limited to transfers of C count frames
|
|
- * of (address_width * maxburst) where C count is limited
|
|
- * to SZ_64K-1. This places an upper bound on the length
|
|
- * of an SG segment that can be handled.
|
|
- */
|
|
- } else {
|
|
- edesc->absync = true;
|
|
- bcnt = burst;
|
|
- ccnt = sg_dma_len(sg) / (acnt * bcnt);
|
|
- if (ccnt > (SZ_64K - 1)) {
|
|
- dev_err(dev, "Exceeded max SG segment size\n");
|
|
- return NULL;
|
|
- }
|
|
- cidx = acnt * bcnt;
|
|
- }
|
|
+ ret = edma_config_pset(chan, &edesc->pset[i], src_addr, dst_addr,
|
|
+ burst, dev_width, sg_dma_len(sg), direction);
|
|
+ if(ret < 0)
|
|
+ return NULL;
|
|
|
|
- if (direction == DMA_MEM_TO_DEV) {
|
|
- src = sg_dma_address(sg);
|
|
- dst = dev_addr;
|
|
- src_bidx = acnt;
|
|
- src_cidx = cidx;
|
|
- dst_bidx = 0;
|
|
- dst_cidx = 0;
|
|
- } else {
|
|
- src = dev_addr;
|
|
- dst = sg_dma_address(sg);
|
|
- src_bidx = 0;
|
|
- src_cidx = 0;
|
|
- dst_bidx = acnt;
|
|
- dst_cidx = cidx;
|
|
- }
|
|
+ edesc->absync = ret;
|
|
|
|
- edesc->pset[i].opt = EDMA_TCC(EDMA_CHAN_SLOT(echan->ch_num));
|
|
- /* Configure A or AB synchronized transfers */
|
|
- if (edesc->absync)
|
|
- edesc->pset[i].opt |= SYNCDIM;
|
|
/* If this is the last set, enable completion interrupt flag */
|
|
if (i == sg_len - 1)
|
|
edesc->pset[i].opt |= TCINTEN;
|
|
-
|
|
- edesc->pset[i].src = src;
|
|
- edesc->pset[i].dst = dst;
|
|
-
|
|
- edesc->pset[i].src_dst_bidx = (dst_bidx << 16) | src_bidx;
|
|
- edesc->pset[i].src_dst_cidx = (dst_cidx << 16) | src_cidx;
|
|
-
|
|
- edesc->pset[i].a_b_cnt = bcnt << 16 | acnt;
|
|
- edesc->pset[i].ccnt = ccnt;
|
|
- edesc->pset[i].link_bcntrld = 0xffffffff;
|
|
-
|
|
}
|
|
|
|
return vchan_tx_prep(&echan->vchan, &edesc->vdesc, tx_flags);
|
|
@@ -368,6 +506,8 @@ static void edma_callback(unsigned ch_num, u16 ch_status, void *data)
|
|
edesc = echan->edesc;
|
|
if (edesc) {
|
|
edma_execute(echan);
|
|
+ /* Note: that desc->callback must be setup by EDMA users so that
|
|
+ the virt-dma layer calls their callback on vchan_cookie_complete() */
|
|
vchan_cookie_complete(&edesc->vdesc);
|
|
}
|
|
|
|
@@ -462,6 +602,20 @@ static void edma_issue_pending(struct dma_chan *chan)
|
|
spin_unlock_irqrestore(&echan->vchan.lock, flags);
|
|
}
|
|
|
|
+static struct dma_slave_sg_limits
|
|
+*edma_get_slave_sg_limits(struct dma_chan *chan,
|
|
+ enum dma_slave_buswidth addr_width,
|
|
+ u32 maxburst)
|
|
+{
|
|
+ struct edma_chan *echan;
|
|
+
|
|
+ echan = to_edma_chan(chan);
|
|
+ echan->sg_limits.max_seg_len =
|
|
+ (SZ_64K - 1) * addr_width * maxburst;
|
|
+
|
|
+ return &echan->sg_limits;
|
|
+}
|
|
+
|
|
static size_t edma_desc_size(struct edma_desc *edesc)
|
|
{
|
|
int i;
|
|
@@ -521,6 +675,7 @@ static void __init edma_chan_init(struct edma_cc *ecc,
|
|
echan->ch_num = EDMA_CTLR_CHAN(ecc->ctlr, i);
|
|
echan->ecc = ecc;
|
|
echan->vchan.desc_free = edma_desc_free;
|
|
+ echan->sg_limits.max_seg_nr = MAX_NR_SG;
|
|
|
|
vchan_init(&echan->vchan, dma);
|
|
|
|
@@ -534,9 +689,11 @@ static void edma_dma_init(struct edma_cc *ecc, struct dma_device *dma,
|
|
struct device *dev)
|
|
{
|
|
dma->device_prep_slave_sg = edma_prep_slave_sg;
|
|
+ dma->device_prep_dma_cyclic = edma_prep_dma_cyclic;
|
|
dma->device_alloc_chan_resources = edma_alloc_chan_resources;
|
|
dma->device_free_chan_resources = edma_free_chan_resources;
|
|
dma->device_issue_pending = edma_issue_pending;
|
|
+ dma->device_slave_sg_limits = edma_get_slave_sg_limits;
|
|
dma->device_tx_status = edma_tx_status;
|
|
dma->device_control = edma_control;
|
|
dma->dev = dev;
|
|
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
|
|
index 1865321..1fe7469 100644
|
|
--- a/drivers/mmc/host/omap_hsmmc.c
|
|
+++ b/drivers/mmc/host/omap_hsmmc.c
|
|
@@ -40,6 +40,8 @@
|
|
#include <linux/pinctrl/consumer.h>
|
|
#include <linux/pm_runtime.h>
|
|
#include <linux/platform_data/mmc-omap.h>
|
|
+#include <linux/pinctrl/consumer.h>
|
|
+#include <linux/err.h>
|
|
|
|
/* OMAP HSMMC Host Controller Registers */
|
|
#define OMAP_HSMMC_SYSSTATUS 0x0014
|
|
@@ -171,7 +173,7 @@ struct omap_hsmmc_host {
|
|
unsigned char power_mode;
|
|
int suspended;
|
|
int irq;
|
|
- int use_dma, dma_ch;
|
|
+ int use_dma;
|
|
struct dma_chan *tx_chan;
|
|
struct dma_chan *rx_chan;
|
|
int slot_id;
|
|
@@ -180,10 +182,15 @@ struct omap_hsmmc_host {
|
|
int protect_card;
|
|
int reqs_blocked;
|
|
int use_reg;
|
|
- int req_in_progress;
|
|
struct omap_hsmmc_next next_data;
|
|
|
|
struct omap_mmc_platform_data *pdata;
|
|
+
|
|
+ unsigned int req_flags;
|
|
+#define RQF_REQ_IN_PROGRESS (1 << 0)
|
|
+#define RQF_DMA_IN_PROGRESS (1 << 1)
|
|
+#define RQF_REQ_DONE (1 << 2)
|
|
+#define RQF_DMA_DONE (1 << 3)
|
|
};
|
|
|
|
static int omap_hsmmc_card_detect(struct device *dev, int slot)
|
|
@@ -391,6 +398,7 @@ static inline int omap_hsmmc_have_reg(void)
|
|
static int omap_hsmmc_gpio_init(struct omap_mmc_platform_data *pdata)
|
|
{
|
|
int ret;
|
|
+ unsigned long flags;
|
|
|
|
if (gpio_is_valid(pdata->slots[0].switch_pin)) {
|
|
if (pdata->slots[0].cover)
|
|
@@ -420,6 +428,24 @@ static int omap_hsmmc_gpio_init(struct omap_mmc_platform_data *pdata)
|
|
} else
|
|
pdata->slots[0].gpio_wp = -EINVAL;
|
|
|
|
+ if (gpio_is_valid(pdata->slots[0].gpio_reset)) {
|
|
+ flags = pdata->slots[0].gpio_reset_active_low ?
|
|
+ GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH;
|
|
+ ret = gpio_request_one(pdata->slots[0].gpio_reset, flags,
|
|
+ "mmc_reset");
|
|
+ if (ret)
|
|
+ goto err_free_wp;
|
|
+
|
|
+ /* hold reset */
|
|
+ udelay(pdata->slots[0].gpio_reset_hold_us);
|
|
+
|
|
+ gpio_set_value(pdata->slots[0].gpio_reset,
|
|
+ !pdata->slots[0].gpio_reset_active_low);
|
|
+
|
|
+ } else
|
|
+ pdata->slots[0].gpio_reset = -EINVAL;
|
|
+
|
|
+
|
|
return 0;
|
|
|
|
err_free_wp:
|
|
@@ -433,6 +459,8 @@ err_free_sp:
|
|
|
|
static void omap_hsmmc_gpio_free(struct omap_mmc_platform_data *pdata)
|
|
{
|
|
+ if (gpio_is_valid(pdata->slots[0].gpio_reset))
|
|
+ gpio_free(pdata->slots[0].gpio_reset);
|
|
if (gpio_is_valid(pdata->slots[0].gpio_wp))
|
|
gpio_free(pdata->slots[0].gpio_wp);
|
|
if (gpio_is_valid(pdata->slots[0].switch_pin))
|
|
@@ -787,7 +815,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
|
|
* ac, bc, adtc, bcr. Only commands ending an open ended transfer need
|
|
* a val of 0x3, rest 0x0.
|
|
*/
|
|
- if (cmd == host->mrq->stop)
|
|
+ if (host->mrq && cmd == host->mrq->stop)
|
|
cmdtype = 0x3;
|
|
|
|
cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22);
|
|
@@ -803,7 +831,8 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
|
|
if (host->use_dma)
|
|
cmdreg |= DMAE;
|
|
|
|
- host->req_in_progress = 1;
|
|
+ host->req_flags |= RQF_REQ_IN_PROGRESS;
|
|
+ host->req_flags &= ~RQF_REQ_DONE;
|
|
|
|
OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg);
|
|
OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);
|
|
@@ -826,19 +855,36 @@ static struct dma_chan *omap_hsmmc_get_dma_chan(struct omap_hsmmc_host *host,
|
|
|
|
static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_request *mrq)
|
|
{
|
|
- int dma_ch;
|
|
+ int completed;
|
|
unsigned long flags;
|
|
|
|
+ BUG_ON(mrq == NULL);
|
|
+
|
|
spin_lock_irqsave(&host->irq_lock, flags);
|
|
- host->req_in_progress = 0;
|
|
- dma_ch = host->dma_ch;
|
|
- spin_unlock_irqrestore(&host->irq_lock, flags);
|
|
+
|
|
+ host->req_flags &= ~RQF_REQ_IN_PROGRESS;
|
|
+ host->req_flags |= RQF_REQ_DONE;
|
|
+
|
|
+ /* completed? */
|
|
+ if (mrq->data && host->use_dma)
|
|
+ completed = (host->req_flags & RQF_DMA_DONE) == RQF_DMA_DONE;
|
|
+ else
|
|
+ completed = 1;
|
|
|
|
omap_hsmmc_disable_irq(host);
|
|
+
|
|
/* Do not complete the request if DMA is still in progress */
|
|
- if (mrq->data && host->use_dma && dma_ch != -1)
|
|
+ if (!completed) {
|
|
+ spin_unlock_irqrestore(&host->irq_lock, flags);
|
|
+ pr_debug("%s: not completed!\n", __func__);
|
|
return;
|
|
+ }
|
|
+
|
|
+ /* clear the flags now */
|
|
+ host->req_flags &= ~(RQF_REQ_DONE | RQF_DMA_DONE);
|
|
host->mrq = NULL;
|
|
+ spin_unlock_irqrestore(&host->irq_lock, flags);
|
|
+
|
|
mmc_request_done(host->mmc, mrq);
|
|
}
|
|
|
|
@@ -855,6 +901,7 @@ omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
|
|
if (host->cmd && host->cmd->opcode == 6 &&
|
|
host->response_busy) {
|
|
host->response_busy = 0;
|
|
+ pr_debug("%s: response_busy = 0\n", __func__);
|
|
return;
|
|
}
|
|
|
|
@@ -870,9 +917,11 @@ omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
|
|
data->bytes_xfered = 0;
|
|
|
|
if (!data->stop) {
|
|
+ pr_debug("%s: calling omap_hsmmc_request_done\n", __func__);
|
|
omap_hsmmc_request_done(host, data->mrq);
|
|
return;
|
|
}
|
|
+ pr_debug("%s: calling omap_hsmmc_start_command\n", __func__);
|
|
omap_hsmmc_start_command(host, data->stop, NULL);
|
|
}
|
|
|
|
@@ -882,6 +931,8 @@ omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
|
|
static void
|
|
omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
|
|
{
|
|
+ unsigned long flags;
|
|
+
|
|
host->cmd = NULL;
|
|
|
|
if (cmd->flags & MMC_RSP_PRESENT) {
|
|
@@ -898,6 +949,18 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
|
|
}
|
|
if ((host->data == NULL && !host->response_busy) || cmd->error)
|
|
omap_hsmmc_request_done(host, cmd->mrq);
|
|
+ else {
|
|
+ spin_lock_irqsave(&host->irq_lock, flags);
|
|
+ /* we use DMA, and DMA is completed - kick the can */
|
|
+ if ((host->req_flags & RQF_DMA_DONE) != 0) {
|
|
+ host->req_flags &= ~(RQF_REQ_IN_PROGRESS | RQF_REQ_DONE | RQF_DMA_DONE);
|
|
+ host->mrq = NULL;
|
|
+ mmc_request_done(host->mmc, cmd->mrq);
|
|
+ } else {
|
|
+ pr_debug("%s: not calling omap_hsmmc_request_done!\n", __func__);
|
|
+ }
|
|
+ spin_unlock_irqrestore(&host->irq_lock, flags);
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
@@ -905,17 +968,19 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
|
|
*/
|
|
static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno)
|
|
{
|
|
- int dma_ch;
|
|
+ int dma_in_progress;
|
|
unsigned long flags;
|
|
|
|
host->data->error = errno;
|
|
|
|
spin_lock_irqsave(&host->irq_lock, flags);
|
|
- dma_ch = host->dma_ch;
|
|
- host->dma_ch = -1;
|
|
+ dma_in_progress = host->use_dma &&
|
|
+ (host->req_flags & RQF_DMA_IN_PROGRESS) != 0;
|
|
+ host->req_flags &= ~RQF_DMA_IN_PROGRESS;
|
|
+ host->req_flags |= RQF_DMA_DONE;
|
|
spin_unlock_irqrestore(&host->irq_lock, flags);
|
|
|
|
- if (host->use_dma && dma_ch != -1) {
|
|
+ if (dma_in_progress) {
|
|
struct dma_chan *chan = omap_hsmmc_get_dma_chan(host, host->data);
|
|
|
|
dmaengine_terminate_all(chan);
|
|
@@ -1005,16 +1070,22 @@ static void hsmmc_command_incomplete(struct omap_hsmmc_host *host,
|
|
int err, int end_cmd)
|
|
{
|
|
if (end_cmd) {
|
|
+ pr_debug("%s end_cmd\n", __func__);
|
|
omap_hsmmc_reset_controller_fsm(host, SRC);
|
|
if (host->cmd)
|
|
host->cmd->error = err;
|
|
}
|
|
|
|
if (host->data) {
|
|
+ pr_debug("%s host->data; resetting dma\n", __func__);
|
|
omap_hsmmc_reset_controller_fsm(host, SRD);
|
|
omap_hsmmc_dma_cleanup(host, err);
|
|
- } else if (host->mrq && host->mrq->cmd)
|
|
+ } else if (host->mrq && host->mrq->cmd) {
|
|
+ pr_debug("%s error\n", __func__);
|
|
host->mrq->cmd->error = err;
|
|
+ } else {
|
|
+ pr_debug("%s nothing\n", __func__);
|
|
+ }
|
|
}
|
|
|
|
static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
|
|
@@ -1055,13 +1126,13 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
|
|
struct omap_hsmmc_host *host = dev_id;
|
|
int status;
|
|
|
|
- status = OMAP_HSMMC_READ(host->base, STAT);
|
|
- while (status & INT_EN_MASK && host->req_in_progress) {
|
|
- omap_hsmmc_do_irq(host, status);
|
|
+ while ((status = OMAP_HSMMC_READ(host->base, STAT)) & INT_EN_MASK) {
|
|
+
|
|
+ if (host->req_flags & RQF_REQ_IN_PROGRESS)
|
|
+ omap_hsmmc_do_irq(host, status);
|
|
|
|
/* Flush posted write */
|
|
OMAP_HSMMC_WRITE(host->base, STAT, status);
|
|
- status = OMAP_HSMMC_READ(host->base, STAT);
|
|
}
|
|
|
|
return IRQ_HANDLED;
|
|
@@ -1199,13 +1270,15 @@ static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id)
|
|
static void omap_hsmmc_dma_callback(void *param)
|
|
{
|
|
struct omap_hsmmc_host *host = param;
|
|
+ struct mmc_request *mrq = host->mrq;
|
|
struct dma_chan *chan;
|
|
struct mmc_data *data;
|
|
- int req_in_progress;
|
|
+ int completed;
|
|
|
|
spin_lock_irq(&host->irq_lock);
|
|
- if (host->dma_ch < 0) {
|
|
+ if ((host->req_flags & RQF_DMA_IN_PROGRESS) == 0) {
|
|
spin_unlock_irq(&host->irq_lock);
|
|
+ pr_debug("%s: No DMA in progress!\n", __func__);
|
|
return;
|
|
}
|
|
|
|
@@ -1216,17 +1289,22 @@ static void omap_hsmmc_dma_callback(void *param)
|
|
data->sg, data->sg_len,
|
|
omap_hsmmc_get_dma_dir(host, data));
|
|
|
|
- req_in_progress = host->req_in_progress;
|
|
- host->dma_ch = -1;
|
|
- spin_unlock_irq(&host->irq_lock);
|
|
+ host->req_flags &= ~RQF_DMA_IN_PROGRESS;
|
|
+ host->req_flags |= RQF_DMA_DONE;
|
|
|
|
- /* If DMA has finished after TC, complete the request */
|
|
- if (!req_in_progress) {
|
|
- struct mmc_request *mrq = host->mrq;
|
|
+ completed = (host->req_flags & RQF_REQ_DONE) != 0;
|
|
|
|
- host->mrq = NULL;
|
|
- mmc_request_done(host->mmc, mrq);
|
|
+ if (!completed) {
|
|
+ spin_unlock_irq(&host->irq_lock);
|
|
+ pr_debug("%s: not completed\n", __func__);
|
|
+ return;
|
|
}
|
|
+
|
|
+ host->req_flags &= ~(RQF_REQ_DONE | RQF_DMA_DONE);
|
|
+ host->mrq = NULL;
|
|
+ spin_unlock_irq(&host->irq_lock);
|
|
+
|
|
+ mmc_request_done(host->mmc, mrq);
|
|
}
|
|
|
|
static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host,
|
|
@@ -1294,7 +1372,7 @@ static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,
|
|
*/
|
|
return -EINVAL;
|
|
|
|
- BUG_ON(host->dma_ch != -1);
|
|
+ BUG_ON((host->req_flags & RQF_DMA_IN_PROGRESS) != 0);
|
|
|
|
chan = omap_hsmmc_get_dma_chan(host, data);
|
|
|
|
@@ -1328,7 +1406,7 @@ static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,
|
|
/* Does not fail */
|
|
dmaengine_submit(tx);
|
|
|
|
- host->dma_ch = 1;
|
|
+ host->req_flags |= RQF_DMA_IN_PROGRESS;
|
|
|
|
dma_async_issue_pending(chan);
|
|
|
|
@@ -1448,8 +1526,11 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
|
|
struct omap_hsmmc_host *host = mmc_priv(mmc);
|
|
int err;
|
|
|
|
- BUG_ON(host->req_in_progress);
|
|
- BUG_ON(host->dma_ch != -1);
|
|
+ BUG_ON((host->req_flags & RQF_REQ_IN_PROGRESS) != 0);
|
|
+ BUG_ON((host->req_flags & RQF_REQ_DONE) != 0);
|
|
+ BUG_ON((host->req_flags & RQF_DMA_IN_PROGRESS) != 0);
|
|
+ BUG_ON((host->req_flags & RQF_DMA_DONE) != 0);
|
|
+
|
|
if (host->protect_card) {
|
|
if (host->reqs_blocked < 3) {
|
|
/*
|
|
@@ -1719,6 +1800,7 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
|
|
struct device_node *np = dev->of_node;
|
|
u32 bus_width, max_freq;
|
|
int cd_gpio, wp_gpio;
|
|
+ enum of_gpio_flags reset_flags;
|
|
|
|
cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);
|
|
wp_gpio = of_get_named_gpio(np, "wp-gpios", 0);
|
|
@@ -1736,6 +1818,14 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
|
|
pdata->nr_slots = 1;
|
|
pdata->slots[0].switch_pin = cd_gpio;
|
|
pdata->slots[0].gpio_wp = wp_gpio;
|
|
+ reset_flags = 0;
|
|
+ pdata->slots[0].gpio_reset = of_get_named_gpio_flags(np,
|
|
+ "reset-gpios", 0, &reset_flags);
|
|
+ pdata->slots[0].gpio_reset_active_low =
|
|
+ (reset_flags & OF_GPIO_ACTIVE_LOW) != 0;
|
|
+ pdata->slots[0].gpio_reset_hold_us = 100; /* default */
|
|
+ of_property_read_u32(np, "reset-gpio-hold-us",
|
|
+ &pdata->slots[0].gpio_reset_hold_us);
|
|
|
|
if (of_find_property(np, "ti,non-removable", NULL)) {
|
|
pdata->slots[0].nonremovable = true;
|
|
@@ -1776,6 +1866,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
|
|
const struct of_device_id *match;
|
|
dma_cap_mask_t mask;
|
|
unsigned tx_req, rx_req;
|
|
+ struct dma_slave_sg_limits *dma_sg_limits;
|
|
struct pinctrl *pinctrl;
|
|
|
|
match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev);
|
|
@@ -1801,6 +1892,10 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
|
|
return -ENXIO;
|
|
}
|
|
|
|
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
|
|
+ if (IS_ERR(pinctrl))
|
|
+ dev_warn(&pdev->dev, "unable to select pin group\n");
|
|
+
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
irq = platform_get_irq(pdev, 0);
|
|
if (res == NULL || irq < 0)
|
|
@@ -1825,13 +1920,13 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
|
|
host->pdata = pdata;
|
|
host->dev = &pdev->dev;
|
|
host->use_dma = 1;
|
|
- host->dma_ch = -1;
|
|
host->irq = irq;
|
|
host->slot_id = 0;
|
|
host->mapbase = res->start + pdata->reg_offset;
|
|
host->base = ioremap(host->mapbase, SZ_4K);
|
|
host->power_mode = MMC_POWER_OFF;
|
|
host->next_data.cookie = 1;
|
|
+ host->req_flags = 0;
|
|
|
|
platform_set_drvdata(pdev, host);
|
|
|
|
@@ -1892,6 +1987,16 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
|
|
* as we want. */
|
|
mmc->max_segs = 1024;
|
|
|
|
+ /* Eventually we should get our max_segs limitation for EDMA by
|
|
+ * querying the dmaengine API */
|
|
+ if (pdev->dev.of_node) {
|
|
+ struct device_node *parent = of_node_get(pdev->dev.of_node->parent);
|
|
+ struct device_node *node;
|
|
+ node = of_find_node_by_name(parent, "edma");
|
|
+ if (node)
|
|
+ mmc->max_segs = 16;
|
|
+ }
|
|
+
|
|
mmc->max_blk_size = 512; /* Block Length at max can be 1024 */
|
|
mmc->max_blk_count = 0xFFFF; /* No. of Blocks is 16 bits */
|
|
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
|
|
@@ -1952,6 +2057,13 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
|
|
goto err_irq;
|
|
}
|
|
|
|
+ /* Some DMA Engines only handle a limited number of SG segments */
|
|
+ dma_sg_limits = dma_get_slave_sg_limits(host->rx_chan,
|
|
+ DMA_SLAVE_BUSWIDTH_4_BYTES,
|
|
+ mmc->max_blk_size / 4);
|
|
+ if (dma_sg_limits && dma_sg_limits->max_seg_nr)
|
|
+ mmc->max_segs = dma_sg_limits->max_seg_nr;
|
|
+
|
|
/* Request IRQ for MMC operations */
|
|
ret = request_irq(host->irq, omap_hsmmc_irq, 0,
|
|
mmc_hostname(mmc), host);
|
|
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
|
|
index c9d04f7..1a862df 100644
|
|
--- a/drivers/reset/Kconfig
|
|
+++ b/drivers/reset/Kconfig
|
|
@@ -11,3 +11,14 @@ menuconfig RESET_CONTROLLER
|
|
via GPIOs or SoC-internal reset controller modules.
|
|
|
|
If unsure, say no.
|
|
+
|
|
+if RESET_CONTROLLER
|
|
+
|
|
+config RESET_GPIO
|
|
+ tristate "GPIO reset controller support"
|
|
+ depends on GPIOLIB && OF
|
|
+ help
|
|
+ This driver provides support for reset lines that are controlled
|
|
+ directly by GPIOs.
|
|
+
|
|
+endif
|
|
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
|
|
index 1e2d83f..b854f20 100644
|
|
--- a/drivers/reset/Makefile
|
|
+++ b/drivers/reset/Makefile
|
|
@@ -1 +1,2 @@
|
|
obj-$(CONFIG_RESET_CONTROLLER) += core.o
|
|
+obj-$(CONFIG_RESET_GPIO) += gpio-reset.o
|
|
diff --git a/drivers/reset/gpio-reset.c b/drivers/reset/gpio-reset.c
|
|
new file mode 100644
|
|
index 0000000..acc1076
|
|
--- /dev/null
|
|
+++ b/drivers/reset/gpio-reset.c
|
|
@@ -0,0 +1,169 @@
|
|
+/*
|
|
+ * GPIO Reset Controller driver
|
|
+ *
|
|
+ * Copyright 2013 Philipp Zabel, Pengutronix
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ */
|
|
+#include <linux/delay.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/gpio.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of_gpio.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/reset-controller.h>
|
|
+
|
|
+struct gpio_reset_data {
|
|
+ struct reset_controller_dev rcdev;
|
|
+ unsigned int gpio;
|
|
+ bool active_low;
|
|
+ u32 delay_us;
|
|
+};
|
|
+
|
|
+static void __gpio_reset_set(struct reset_controller_dev *rcdev, int asserted)
|
|
+{
|
|
+ struct gpio_reset_data *drvdata = container_of(rcdev,
|
|
+ struct gpio_reset_data, rcdev);
|
|
+ int value = asserted;
|
|
+
|
|
+ if (drvdata->active_low)
|
|
+ value = !value;
|
|
+
|
|
+ gpio_set_value(drvdata->gpio, value);
|
|
+}
|
|
+
|
|
+static int gpio_reset(struct reset_controller_dev *rcdev, unsigned long id)
|
|
+{
|
|
+ struct gpio_reset_data *drvdata = container_of(rcdev,
|
|
+ struct gpio_reset_data, rcdev);
|
|
+
|
|
+ if (drvdata->delay_us < 0)
|
|
+ return -ENOSYS;
|
|
+
|
|
+ __gpio_reset_set(rcdev, 1);
|
|
+ udelay(drvdata->delay_us);
|
|
+ __gpio_reset_set(rcdev, 0);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int gpio_reset_assert(struct reset_controller_dev *rcdev,
|
|
+ unsigned long id)
|
|
+{
|
|
+ __gpio_reset_set(rcdev, 1);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int gpio_reset_deassert(struct reset_controller_dev *rcdev,
|
|
+ unsigned long id)
|
|
+{
|
|
+ __gpio_reset_set(rcdev, 0);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct reset_control_ops gpio_reset_ops = {
|
|
+ .reset = gpio_reset,
|
|
+ .assert = gpio_reset_assert,
|
|
+ .deassert = gpio_reset_deassert,
|
|
+};
|
|
+
|
|
+static int of_gpio_reset_xlate(struct reset_controller_dev *rcdev,
|
|
+ const struct of_phandle_args *reset_spec)
|
|
+{
|
|
+ if (WARN_ON(reset_spec->args_count != 0))
|
|
+ return -EINVAL;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int gpio_reset_probe(struct platform_device *pdev)
|
|
+{
|
|
+ struct device_node *np = pdev->dev.of_node;
|
|
+ struct gpio_reset_data *drvdata;
|
|
+ enum of_gpio_flags flags;
|
|
+ unsigned long gpio_flags;
|
|
+ bool initially_in_reset;
|
|
+ int ret;
|
|
+
|
|
+ drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
|
|
+ if (drvdata == NULL)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ if (of_gpio_named_count(np, "reset-gpios") != 1)
|
|
+ return -EINVAL;
|
|
+
|
|
+ drvdata->gpio = of_get_named_gpio_flags(np, "reset-gpios", 0, &flags);
|
|
+ if (drvdata->gpio == -EPROBE_DEFER) {
|
|
+ return drvdata->gpio;
|
|
+ } else if (!gpio_is_valid(drvdata->gpio)) {
|
|
+ dev_err(&pdev->dev, "invalid reset gpio: %d\n", drvdata->gpio);
|
|
+ return drvdata->gpio;
|
|
+ }
|
|
+
|
|
+ drvdata->active_low = flags & OF_GPIO_ACTIVE_LOW;
|
|
+
|
|
+ ret = of_property_read_u32(np, "reset-delay-us", &drvdata->delay_us);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ initially_in_reset = of_property_read_bool(np, "initially-in-reset");
|
|
+ if (drvdata->active_low ^ initially_in_reset)
|
|
+ gpio_flags = GPIOF_OUT_INIT_HIGH;
|
|
+ else
|
|
+ gpio_flags = GPIOF_OUT_INIT_LOW;
|
|
+
|
|
+ ret = devm_gpio_request_one(&pdev->dev, drvdata->gpio, gpio_flags, NULL);
|
|
+ if (ret < 0) {
|
|
+ dev_err(&pdev->dev, "failed to request gpio %d: %d\n",
|
|
+ drvdata->gpio, ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ drvdata->rcdev.of_node = np;
|
|
+ drvdata->rcdev.owner = THIS_MODULE;
|
|
+ drvdata->rcdev.nr_resets = 1;
|
|
+ drvdata->rcdev.ops = &gpio_reset_ops;
|
|
+ drvdata->rcdev.of_xlate = of_gpio_reset_xlate;
|
|
+ reset_controller_register(&drvdata->rcdev);
|
|
+
|
|
+ platform_set_drvdata(pdev, drvdata);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int gpio_reset_remove(struct platform_device *pdev)
|
|
+{
|
|
+ struct gpio_reset_data *drvdata = platform_get_drvdata(pdev);
|
|
+
|
|
+ reset_controller_unregister(&drvdata->rcdev);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct of_device_id gpio_reset_dt_ids[] = {
|
|
+ { .compatible = "gpio-reset" },
|
|
+ { }
|
|
+};
|
|
+
|
|
+static struct platform_driver gpio_reset_driver = {
|
|
+ .probe = gpio_reset_probe,
|
|
+ .remove = gpio_reset_remove,
|
|
+ .driver = {
|
|
+ .name = "gpio-reset",
|
|
+ .owner = THIS_MODULE,
|
|
+ .of_match_table = of_match_ptr(gpio_reset_dt_ids),
|
|
+ },
|
|
+};
|
|
+
|
|
+module_platform_driver(gpio_reset_driver);
|
|
+
|
|
+MODULE_AUTHOR("Philipp Zabel <p.zabel@pengutronix.de>");
|
|
+MODULE_DESCRIPTION("gpio reset controller");
|
|
+MODULE_LICENSE("GPL");
|
|
+MODULE_ALIAS("platform:gpio-reset");
|
|
+MODULE_DEVICE_TABLE(of, gpio_reset_dt_ids);
|
|
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
|
|
index cb286b1..d71fe5d 100644
|
|
--- a/include/linux/dmaengine.h
|
|
+++ b/include/linux/dmaengine.h
|
|
@@ -370,6 +370,18 @@ struct dma_slave_config {
|
|
unsigned int slave_id;
|
|
};
|
|
|
|
+/* struct dma_slave_sg_limits - expose SG transfer limits of a channel
|
|
+ *
|
|
+ * @max_seg_nr: maximum number of SG segments supported on a SG/SLAVE
|
|
+ * channel (0 for no maximum or not a SG/SLAVE channel)
|
|
+ * @max_seg_len: maximum length of SG segments supported on a SG/SLAVE
|
|
+ * channel (0 for no maximum or not a SG/SLAVE channel)
|
|
+ */
|
|
+struct dma_slave_sg_limits {
|
|
+ u32 max_seg_nr;
|
|
+ u32 max_seg_len;
|
|
+};
|
|
+
|
|
static inline const char *dma_chan_name(struct dma_chan *chan)
|
|
{
|
|
return dev_name(&chan->dev->device);
|
|
@@ -532,6 +544,7 @@ struct dma_tx_state {
|
|
* struct with auxiliary transfer status information, otherwise the call
|
|
* will just return a simple status code
|
|
* @device_issue_pending: push pending transactions to hardware
|
|
+ * @device_slave_sg_limits: return the slave SG capabilities
|
|
*/
|
|
struct dma_device {
|
|
|
|
@@ -597,6 +610,9 @@ struct dma_device {
|
|
dma_cookie_t cookie,
|
|
struct dma_tx_state *txstate);
|
|
void (*device_issue_pending)(struct dma_chan *chan);
|
|
+ struct dma_slave_sg_limits *(*device_slave_sg_limits)(
|
|
+ struct dma_chan *chan, enum dma_slave_buswidth addr_width,
|
|
+ u32 maxburst);
|
|
};
|
|
|
|
static inline int dmaengine_device_control(struct dma_chan *chan,
|
|
@@ -958,6 +974,29 @@ dma_set_tx_state(struct dma_tx_state *st, dma_cookie_t last, dma_cookie_t used,
|
|
}
|
|
}
|
|
|
|
+/**
|
|
+ * dma_get_slave_sg_limits - get DMAC SG transfer capabilities
|
|
+ * @chan: target DMA channel
|
|
+ * @addr_width: address width of the DMA transfer
|
|
+ * @maxburst: maximum DMA transfer burst size
|
|
+ *
|
|
+ * Get SG transfer capabilities for a specified channel. If the dmaengine
|
|
+ * driver does not implement SG transfer capabilities then NULL is
|
|
+ * returned.
|
|
+ */
|
|
+static inline struct dma_slave_sg_limits
|
|
+*dma_get_slave_sg_limits(struct dma_chan *chan,
|
|
+ enum dma_slave_buswidth addr_width,
|
|
+ u32 maxburst)
|
|
+{
|
|
+ if (chan->device->device_slave_sg_limits)
|
|
+ return chan->device->device_slave_sg_limits(chan,
|
|
+ addr_width,
|
|
+ maxburst);
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie);
|
|
#ifdef CONFIG_DMA_ENGINE
|
|
enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx);
|
|
diff --git a/include/linux/platform_data/mmc-omap.h b/include/linux/platform_data/mmc-omap.h
|
|
index 2bf1b30..d5489941 100644
|
|
--- a/include/linux/platform_data/mmc-omap.h
|
|
+++ b/include/linux/platform_data/mmc-omap.h
|
|
@@ -115,6 +115,9 @@ struct omap_mmc_platform_data {
|
|
|
|
int switch_pin; /* gpio (card detect) */
|
|
int gpio_wp; /* gpio (write protect) */
|
|
+ int gpio_reset; /* gpio (reset) */
|
|
+ int gpio_reset_active_low; /* 1 if reset is active low */
|
|
+ u32 gpio_reset_hold_us; /* time to hold in us */
|
|
|
|
int (*set_bus_mode)(struct device *dev, int slot, int bus_mode);
|
|
int (*set_power)(struct device *dev, int slot,
|
|
diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/soc/soc-dmaengine-pcm.c
|
|
index aa924d9..461fe4f 100644
|
|
--- a/sound/soc/soc-dmaengine-pcm.c
|
|
+++ b/sound/soc/soc-dmaengine-pcm.c
|
|
@@ -276,6 +276,16 @@ struct dma_chan *snd_dmaengine_pcm_request_channel(dma_filter_fn filter_fn,
|
|
}
|
|
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_request_channel);
|
|
|
|
+struct dma_chan *snd_dmaengine_pcm_request_slave_channel(
|
|
+ struct snd_pcm_substream *substream, char *name)
|
|
+{
|
|
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
+ struct device *dev = snd_soc_dai_get_drvdata(rtd->cpu_dai);
|
|
+
|
|
+ return dma_request_slave_channel(dev, name);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_request_slave_channel);
|
|
+
|
|
/**
|
|
* snd_dmaengine_pcm_open - Open a dmaengine based PCM substream
|
|
* @substream: PCM substream
|
|
@@ -334,6 +344,18 @@ int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream,
|
|
}
|
|
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_chan);
|
|
|
|
+int snd_dmaengine_pcm_open_request_slave_chan(struct snd_pcm_substream *substream, char *name)
|
|
+{
|
|
+ if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
+ return snd_dmaengine_pcm_open(substream,
|
|
+ snd_dmaengine_pcm_request_slave_channel(substream, "tx"));
|
|
+ } else {
|
|
+ return snd_dmaengine_pcm_open(substream,
|
|
+ snd_dmaengine_pcm_request_slave_channel(substream, "rx"));
|
|
+ }
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_slave_chan);
|
|
+
|
|
/**
|
|
* snd_dmaengine_pcm_close - Close a dmaengine based PCM substream
|
|
* @substream: PCM substream
|