* [RFC PATCH 0/2] arm64: memory-hotplug: Add Memory Hotplug support
From: Xishi Qiu @ 2016-12-02 1:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480637999-4320-1-git-send-email-scott.branden@broadcom.com>
On 2016/12/2 8:19, Scott Branden wrote:
> This patchset is sent for comment to add memory hotplug support for ARM64
> based platforms. It follows hotplug code added for other architectures
> in the linux kernel.
>
> I tried testing the memory hotplug feature following documentation from
> Documentation/memory-hotplug.txt. I don't think it is working as expected
> - see below:
>
> To add memory to the system I did the following:
> echo 0x400000000 > /sys/devices/system/memory/probe
>
> The memory is displayed as system ram:
> cat /proc/iomem:
> 74000000-77ffffff : System RAM
> 74080000-748dffff : Kernel code
> 74950000-749d2fff : Kernel data
> 400000000-43fffffff : System RAM
>
> But does not seem to be added to the kernel memory.
> /proc/meminfo did not change.
>
> What else needs to be done so the memory is added to the kernel memory
> pool for normal allocation?
>
Hi Scott,
Do you mean it still don't support hod-add after apply this patchset?
Thanks,
Xishi Qiu
> Scott Branden (2):
> arm64: memory-hotplug: Add MEMORY_HOTPLUG, MEMORY_HOTREMOVE,
> MEMORY_PROBE
> arm64: defconfig: enable MEMORY_HOTPLUG config options
>
> arch/arm64/Kconfig | 10 ++++++++++
> arch/arm64/configs/defconfig | 3 +++
> arch/arm64/mm/init.c | 42 ++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 55 insertions(+)
>
^ permalink raw reply
* [PATCH] arm: dts: mt2701: Sort DT nodes by register address
From: James Liao @ 2016-12-02 2:06 UTC (permalink / raw)
To: linux-arm-kernel
This patch rearrange MT2701 DT nodes to keep them in ascending order.
Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
---
This patch is based on latest v4.9-next/dts branch of [1], to fix MT2701
DT nodes ordering.
[1] https://github.com/mbgg/linux-mediatek/tree/v4.9-next/dts
arch/arm/boot/dts/mt2701.dtsi | 36 ++++++++++++++++++------------------
1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
index 7eab6f4..73f4b7c 100644
--- a/arch/arm/boot/dts/mt2701.dtsi
+++ b/arch/arm/boot/dts/mt2701.dtsi
@@ -96,24 +96,6 @@
<GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
};
- pio: pinctrl at 10005000 {
- compatible = "mediatek,mt2701-pinctrl";
- reg = <0 0x1000b000 0 0x1000>;
- mediatek,pctl-regmap = <&syscfg_pctl_a>;
- pins-are-numbered;
- gpio-controller;
- #gpio-cells = <2>;
- interrupt-controller;
- #interrupt-cells = <2>;
- interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
- };
-
- syscfg_pctl_a: syscfg at 10005000 {
- compatible = "mediatek,mt2701-pctl-a-syscfg", "syscon";
- reg = <0 0x10005000 0 0x1000>;
- };
-
topckgen: syscon at 10000000 {
compatible = "mediatek,mt2701-topckgen", "syscon";
reg = <0 0x10000000 0 0x1000>;
@@ -134,6 +116,24 @@
#reset-cells = <1>;
};
+ pio: pinctrl at 10005000 {
+ compatible = "mediatek,mt2701-pinctrl";
+ reg = <0 0x1000b000 0 0x1000>;
+ mediatek,pctl-regmap = <&syscfg_pctl_a>;
+ pins-are-numbered;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ syscfg_pctl_a: syscfg at 10005000 {
+ compatible = "mediatek,mt2701-pctl-a-syscfg", "syscon";
+ reg = <0 0x10005000 0 0x1000>;
+ };
+
watchdog: watchdog at 10007000 {
compatible = "mediatek,mt2701-wdt",
"mediatek,mt6589-wdt";
--
1.9.1
^ permalink raw reply related
* [PATCH v2] PCI: Add information about describing PCI in ACPI
From: Bjorn Helgaas @ 2016-12-02 2:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAJZ5v0gtG6++GqyOb_B=o-=R4YuFia8PH6W3NFiCZuay=pV7TA@mail.gmail.com>
On Fri, Dec 02, 2016 at 01:28:50AM +0100, Rafael J. Wysocki wrote:
> On Fri, Dec 2, 2016 at 12:27 AM, Bjorn Helgaas <helgaas@kernel.org> wrote:
> > On Thu, Dec 01, 2016 at 11:37:39PM +0100, Rafael J. Wysocki wrote:
> >> On Thursday, December 01, 2016 04:36:04 PM Bjorn Helgaas wrote:
> >> > On Tue, Nov 29, 2016 at 03:39:48PM -0600, Bjorn Helgaas wrote:
> >> > > Here's another stab at this writeup. I'd appreciate any comments!
> >> > >
> >> > > Changes from v1 to v2:
> >> > > - Consumer/Producer is defined for Extended Address Space descriptors;
> >> > > should be ignored for QWord/DWord/Word Address Space descriptors
> >> > > - New arches may use Extended Address Space descriptors in PNP0A03 for
> >> > > bridge registers, including ECAM (if the arch adds support for this)
> >> > > - Add more details about MCFG and _CBA (Lv's suggestion)
> >> > > - Incorporate Rafael's suggestions
> >> > >
> >> > > ---
> >> > >
> >> > > Bjorn Helgaas (1):
> >> > > PCI: Add information about describing PCI in ACPI
> >> > >
> >> > >
> >> > > Documentation/PCI/00-INDEX | 2
> >> > > Documentation/PCI/acpi-info.txt | 180 +++++++++++++++++++++++++++++++++++++++
> >> > > 2 files changed, 182 insertions(+)
> >> > > create mode 100644 Documentation/PCI/acpi-info.txt
> >> >
> >> > It's very late in the cycle, but I'm considering trying to squeeze
> >> > this into v4.9 on the grounds that:
> >> >
> >> > - It's only a documentation change and can't break anything, and
> >> >
> >> > - Distributing it more widely may help the arm64 firmware ecosystem
> >> >
> >> > But I don't want to disseminate misleading or incorrect information,
> >> > so if it needs clarification or wordsmithing, or even just maturation,
> >> > I'll wait until v4.10.
> >> >
> >> > The Consumer/Producer stuff, in particular, doesn't seem 100% settled
> >> > yet. Your thoughts, and especially your improvements, are welcome!
> >>
> >> Well, what's the drawback if it doesn't go into 4.9?
> >
> > Only that it's not as easily accessible. ARM64 ACPI firmware is brand
> > new. Neither the firmware nor the kernel developers, nor even the
> > hardware designers, have the benefit of all the x86/ia64 history, so I
> > wrote this to try to come to a common understanding of what Linux
> > expects.
> >
> > The first generation of ARM64 hardware is already in the field, and it
> > has teething problems in hardware, firmware, and kernel. For example,
> > the current MCFG quirk situation: the ECAM hardware doesn't work quite
> > per spec, the ACPI firmware doesn't describe the address space
> > completely, and we don't really have consensus on how the firmware
> > should communicate register space to the kernel.
> >
> > We're hoping the second generation can fix some of these problems, and
> > I think this is the time to try to influence that.
>
> Well, I would be super-careful if I were you, then. :-)
>
> I'm not sure if squeezing it into 4.9.0 buys you anything here. If
> you get it into 4.10-rc, you can request -stable to pick it up (at
> least in principle) and then it will show up in 4.9.y at one point
> which should suffice I suppose?
You're right, there's no real hurry, and the rate of change is a good
indication that we need to let things settle out for a while.
^ permalink raw reply
* [PATCH v4 1/1] PCI/ACPI: xgene: Add ECAM quirk for X-Gene PCIe controller
From: Duc Dang @ 2016-12-02 2:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161201183350.GF30746@bhelgaas-glaptop.roam.corp.google.com>
PCIe controllers in X-Gene SoCs is not ECAM compliant: software
needs to configure additional controller's register to address
device at bus:dev:function.
The quirk will discover controller MMIO register space and configure
controller registers to select and address the target secondary device.
The quirk will only be applied for X-Gene PCIe MCFG table with
OEM revison 1, 2, 3 or 4 (PCIe controller v1 and v2 on X-Gene SoCs).
Signed-off-by: Duc Dang <dhdang@apm.com>
---
v4:
- Rebase on top of pci/ecam tree
- Introduce xgene_get_csr_resource to discover MMIO register space
(per Mark's test code).
- Refactor .init functions for pci_ecam_ops to reuse common code
- Introduce pcie_bus_to_port to extract X-Gene 'port' information
from 'bus' device.
- Kconfig/Makefile changes to only compile required code for ACPI
v3:
- Rebase on top of pci/ecam-v6 tree.
- Use DEFINE_RES_MEM_NAMED to declare controller register space
with name "PCIe CSR"
v2:
RFC v2: https://patchwork.ozlabs.org/patch/686846/
v1:
RFC v1: https://patchwork.kernel.org/patch/9337115/
---
drivers/acpi/pci_mcfg.c | 25 +++++++++
drivers/pci/host/Kconfig | 4 +-
drivers/pci/host/Makefile | 2 +-
drivers/pci/host/pci-xgene.c | 127 ++++++++++++++++++++++++++++++++++++++++---
include/linux/pci-ecam.h | 2 +
5 files changed, 150 insertions(+), 10 deletions(-)
diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
index d34d196..7319188 100644
--- a/drivers/acpi/pci_mcfg.c
+++ b/drivers/acpi/pci_mcfg.c
@@ -108,6 +108,31 @@ struct mcfg_fixup {
THUNDER_ECAM_QUIRK(2, 11),
THUNDER_ECAM_QUIRK(2, 12),
THUNDER_ECAM_QUIRK(2, 13),
+
+#define XGENE_V1_ECAM_MCFG(rev, seg) \
+ {"APM ", "XGENE ", rev, seg, MCFG_BUS_ANY, \
+ &xgene_v1_pcie_ecam_ops }
+#define XGENE_V2_ECAM_MCFG(rev, seg) \
+ {"APM ", "XGENE ", rev, seg, MCFG_BUS_ANY, \
+ &xgene_v2_pcie_ecam_ops }
+ /* X-Gene SoC with v1 PCIe controller */
+ XGENE_V1_ECAM_MCFG(1, 0),
+ XGENE_V1_ECAM_MCFG(1, 1),
+ XGENE_V1_ECAM_MCFG(1, 2),
+ XGENE_V1_ECAM_MCFG(1, 3),
+ XGENE_V1_ECAM_MCFG(1, 4),
+ XGENE_V1_ECAM_MCFG(2, 0),
+ XGENE_V1_ECAM_MCFG(2, 1),
+ XGENE_V1_ECAM_MCFG(2, 2),
+ XGENE_V1_ECAM_MCFG(2, 3),
+ XGENE_V1_ECAM_MCFG(2, 4),
+ /* X-Gene SoC with v2.1 PCIe controller */
+ XGENE_V2_ECAM_MCFG(3, 0),
+ XGENE_V2_ECAM_MCFG(3, 1),
+ /* X-Gene SoC with v2.2 PCIe controller */
+ XGENE_V2_ECAM_MCFG(4, 0),
+ XGENE_V2_ECAM_MCFG(4, 1),
+ XGENE_V2_ECAM_MCFG(4, 2),
};
static char mcfg_oem_id[ACPI_OEM_ID_SIZE];
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index c983892..1fb5518 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -133,8 +133,8 @@ config PCIE_XILINX
config PCI_XGENE
bool "X-Gene PCIe controller"
- depends on ARCH_XGENE
- depends on OF
+ depends on ARM64
+ depends on OF || (ACPI && PCI_QUIRKS)
select PCIEPORTBUS
help
Say Y here if you want internal PCI support on APM X-Gene SoC.
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 639494a..6cc84b4 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -15,7 +15,7 @@ obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o
obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o
obj-$(CONFIG_PCIE_XILINX_NWL) += pcie-xilinx-nwl.o
-obj-$(CONFIG_PCI_XGENE) += pci-xgene.o
+obj-$(CONFIG_ARM64) += pci-xgene.o
obj-$(CONFIG_PCI_XGENE_MSI) += pci-xgene-msi.o
obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o
obj-$(CONFIG_PCI_VERSATILE) += pci-versatile.o
diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c
index 1de23d7..6edcac7 100644
--- a/drivers/pci/host/pci-xgene.c
+++ b/drivers/pci/host/pci-xgene.c
@@ -27,6 +27,8 @@
#include <linux/of_irq.h>
#include <linux/of_pci.h>
#include <linux/pci.h>
+#include <linux/pci-acpi.h>
+#include <linux/pci-ecam.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -64,7 +66,9 @@
/* PCIe IP version */
#define XGENE_PCIE_IP_VER_UNKN 0
#define XGENE_PCIE_IP_VER_1 1
+#define XGENE_PCIE_IP_VER_2 2
+#if defined(CONFIG_PCI_XGENE) || (defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS))
struct xgene_pcie_port {
struct device_node *node;
struct device *dev;
@@ -91,13 +95,24 @@ static inline u32 pcie_bar_low_val(u32 addr, u32 flags)
return (addr & PCI_BASE_ADDRESS_MEM_MASK) | flags;
}
+static inline struct xgene_pcie_port *pcie_bus_to_port(struct pci_bus *bus)
+{
+ struct pci_config_window *cfg;
+
+ if (acpi_disabled)
+ return (struct xgene_pcie_port *)(bus->sysdata);
+
+ cfg = bus->sysdata;
+ return (struct xgene_pcie_port *)(cfg->priv);
+}
+
/*
* When the address bit [17:16] is 2'b01, the Configuration access will be
* treated as Type 1 and it will be forwarded to external PCIe device.
*/
static void __iomem *xgene_pcie_get_cfg_base(struct pci_bus *bus)
{
- struct xgene_pcie_port *port = bus->sysdata;
+ struct xgene_pcie_port *port = pcie_bus_to_port(bus);
if (bus->number >= (bus->primary + 1))
return port->cfg_base + AXI_EP_CFG_ACCESS;
@@ -111,7 +126,7 @@ static void __iomem *xgene_pcie_get_cfg_base(struct pci_bus *bus)
*/
static void xgene_pcie_set_rtdid_reg(struct pci_bus *bus, uint devfn)
{
- struct xgene_pcie_port *port = bus->sysdata;
+ struct xgene_pcie_port *port = pcie_bus_to_port(bus);
unsigned int b, d, f;
u32 rtdid_val = 0;
@@ -158,7 +173,7 @@ static void __iomem *xgene_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
static int xgene_pcie_config_read32(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 *val)
{
- struct xgene_pcie_port *port = bus->sysdata;
+ struct xgene_pcie_port *port = pcie_bus_to_port(bus);
if (pci_generic_config_read32(bus, devfn, where & ~0x3, 4, val) !=
PCIBIOS_SUCCESSFUL)
@@ -182,13 +197,104 @@ static int xgene_pcie_config_read32(struct pci_bus *bus, unsigned int devfn,
return PCIBIOS_SUCCESSFUL;
}
+#endif
-static struct pci_ops xgene_pcie_ops = {
- .map_bus = xgene_pcie_map_bus,
- .read = xgene_pcie_config_read32,
- .write = pci_generic_config_write32,
+#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
+static int xgene_get_csr_resource(struct acpi_device *adev,
+ struct resource *res)
+{
+ struct device *dev = &adev->dev;
+ struct resource_entry *entry;
+ struct list_head list;
+ unsigned long flags;
+ int ret;
+
+ INIT_LIST_HEAD(&list);
+ flags = IORESOURCE_MEM;
+ ret = acpi_dev_get_resources(adev, &list,
+ acpi_dev_filter_resource_type_cb,
+ (void *) flags);
+ if (ret < 0) {
+ dev_err(dev, "failed to parse _CRS method, error code %d\n",
+ ret);
+ return ret;
+ }
+
+ if (ret == 0) {
+ dev_err(dev, "no IO and memory resources present in _CRS\n");
+ return -EINVAL;
+ }
+
+ entry = list_first_entry(&list, struct resource_entry, node);
+ *res = *entry->res;
+ acpi_dev_free_resource_list(&list);
+ return 0;
+}
+
+static int xgene_pcie_ecam_init(struct pci_config_window *cfg, u32 ipversion)
+{
+ struct acpi_device *adev = to_acpi_device(cfg->parent);
+ struct device *dev = cfg->parent;
+ struct xgene_pcie_port *port;
+ struct resource csr;
+ int ret;
+
+ port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return -ENOMEM;
+
+ ret = xgene_get_csr_resource(adev, &csr);
+ if (ret) {
+ dev_err(dev, "can't get CSR resource\n");
+ kfree(port);
+ return ret;
+ }
+ port->csr_base = devm_ioremap_resource(dev, &csr);
+ if (IS_ERR(port->csr_base)) {
+ kfree(port);
+ return -ENOMEM;
+ }
+
+ port->cfg_base = cfg->win;
+ port->version = ipversion;
+
+ cfg->priv = port;
+
+ return 0;
+}
+
+static int xgene_v1_pcie_ecam_init(struct pci_config_window *cfg)
+{
+ return xgene_pcie_ecam_init(cfg, XGENE_PCIE_IP_VER_1);
+}
+
+struct pci_ecam_ops xgene_v1_pcie_ecam_ops = {
+ .bus_shift = 16,
+ .init = xgene_v1_pcie_ecam_init,
+ .pci_ops = {
+ .map_bus = xgene_pcie_map_bus,
+ .read = xgene_pcie_config_read32,
+ .write = pci_generic_config_write,
+ }
+};
+
+static int xgene_v2_pcie_ecam_init(struct pci_config_window *cfg)
+{
+ return xgene_pcie_ecam_init(cfg, XGENE_PCIE_IP_VER_2);
+}
+
+struct pci_ecam_ops xgene_v2_pcie_ecam_ops = {
+ .bus_shift = 16,
+ .init = xgene_v2_pcie_ecam_init,
+ .pci_ops = {
+ .map_bus = xgene_pcie_map_bus,
+ .read = xgene_pcie_config_read32,
+ .write = pci_generic_config_write,
+ }
};
+#endif
+#if defined(CONFIG_PCI_XGENE)
static u64 xgene_pcie_set_ib_mask(struct xgene_pcie_port *port, u32 addr,
u32 flags, u64 size)
{
@@ -521,6 +627,12 @@ static int xgene_pcie_setup(struct xgene_pcie_port *port,
return 0;
}
+static struct pci_ops xgene_pcie_ops = {
+ .map_bus = xgene_pcie_map_bus,
+ .read = xgene_pcie_config_read32,
+ .write = pci_generic_config_write32,
+};
+
static int xgene_pcie_probe_bridge(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -591,3 +703,4 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev)
.probe = xgene_pcie_probe_bridge,
};
builtin_platform_driver(xgene_pcie_driver);
+#endif
diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h
index 00eb8eb..f0d2b94 100644
--- a/include/linux/pci-ecam.h
+++ b/include/linux/pci-ecam.h
@@ -64,6 +64,8 @@ void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn,
extern struct pci_ecam_ops hisi_pcie_ops; /* HiSilicon */
extern struct pci_ecam_ops thunder_pem_ecam_ops; /* Cavium ThunderX 1.x & 2.x */
extern struct pci_ecam_ops pci_thunder_ecam_ops; /* Cavium ThunderX 1.x */
+extern struct pci_ecam_ops xgene_v1_pcie_ecam_ops; /* APM X-Gene PCIe v1 */
+extern struct pci_ecam_ops xgene_v2_pcie_ecam_ops; /* APM X-Gene PCIe v2.x */
#endif
#ifdef CONFIG_PCI_HOST_GENERIC
--
1.9.1
^ permalink raw reply related
* [PATCH 0/9] arm64: dts: rockchip: support Google Kevin
From: Brian Norris @ 2016-12-02 2:27 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
This series adds basic support for Google Kevin, a board in the Gru device
family. I do not add a leaf .dts board file for Gru, but I have retained the
split between "things that apply to the Gru family" (rk3399-gru.dtsi) and
"things that apply to Kevin only" (rk3399-gru-kevin.dtsi).
I've included resends of two patches (adding cros-ec*.dtsi symlinks, and adding
RK3399 DWC3). The former is unmodified, but the latter is rewritten to match
current upstream bindings better, and to allow it to function w/o extcon
support (USB2 only).
AFAICT, all these bindings are in -next, except for the root node compatible
property (added doc in this series) and some of the HID digitizer bindings (see
patch 9; bindings were sent separately).
I elaborate on what's working/not working below, but one of the big missing
pieces is cpufreq support. We still need some more work on getting good
bindings and driver support upstream for the PWM regulator + OVP circuit on
these boards. See patch 8 for more info.
Working and tested (to some extent):
* EC support -- including keyboard, battery, PWM, and probably more
* UART / console
* Thermal
* Touchscreen
* Touchpad
* Digitizer (regulator still WIP)
* PCIe / Wifi
* Bluetooth / Webcam
* SD card
* eMMC
* USB2 on TypeC
- This works much of the time, but USB3 devices may or may not detect
properly. Waiting on proper extcon support for USB3 over TypeC.
- Depends on XHCI/DWC3 fixes for ARM64 that still haven't landed
* Backlight
Not working:
* CPUFreq -- relies on special OVP support for our PWM regulator
circuits
* EC / extcon support -- and with it, USB3/TypeC/DP
* DRM -- won't even build on ARM64, so all display, eDP, etc. is not
enabled
Not tested:
* Audio
Brian Norris (8):
arm64: dts: rockchip: add rk3399 thermal_zones phandle
arm64: dts: rockchip: add rk3399 eDP HPD pinctrl
arm64: dts: rockchip: support dwc3 USB for rk3399
arm64: dts: rockchip: add rk3399 OPPs
dt-bindings: Document rk3399 Gru/Kevin
arm64: dts: rockchip: add Gru/Kevin DTS
arm64: dts: rockchip: partially describe PWM regulators for Gru
arm64: dts: rockchip: add regulator info for Kevin digitizer
Douglas Anderson (1):
arm64: dts: Add symlinks for cros-ec-keyboard and cros-ec-sbs
Documentation/devicetree/bindings/arm/rockchip.txt | 20 +
.../boot/dts/include/common/cros-ec-keyboard.dtsi | 1 +
.../arm64/boot/dts/include/common/cros-ec-sbs.dtsi | 1 +
arch/arm64/boot/dts/rockchip/Makefile | 1 +
arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts | 315 ++++++
arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi | 1152 ++++++++++++++++++++
arch/arm64/boot/dts/rockchip/rk3399-opp.dtsi | 145 +++
arch/arm64/boot/dts/rockchip/rk3399.dtsi | 70 +-
8 files changed, 1704 insertions(+), 1 deletion(-)
create mode 120000 arch/arm64/boot/dts/include/common/cros-ec-keyboard.dtsi
create mode 120000 arch/arm64/boot/dts/include/common/cros-ec-sbs.dtsi
create mode 100644 arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
create mode 100644 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
create mode 100644 arch/arm64/boot/dts/rockchip/rk3399-opp.dtsi
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply
* [PATCH 1/9] arm64: dts: Add symlinks for cros-ec-keyboard and cros-ec-sbs
From: Brian Norris @ 2016-12-02 2:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480645653-36943-1-git-send-email-briannorris@chromium.org>
From: Douglas Anderson <dianders@chromium.org>
We'd like to be able to use the cros-ec-keyboard.dtsi and
cros-ec-sbs.dtsi snippets for arm64 devices. Currently those files live
in the arm/boot/dts directory.
Let's follow the convention set by commit 8ee57b8182c4 ("ARM64: dts:
vexpress: Use a symlink to vexpress-v2m-rs1.dtsi from arch=arm") and use
a symlink. Note that in this case we put the files in a new
"include/common" directory since these snippets may need to be
referenced by dts files in many different subdirectories.
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: Brian Norris <briannorris@chromium.org>
Reviewed-by: Heiko Stueber <heiko@sntech.de>
Tested-by: Heiko Stuebner <heiko@sntech.de>
---
This was submitted months ago but had no users
arch/arm64/boot/dts/include/common/cros-ec-keyboard.dtsi | 1 +
arch/arm64/boot/dts/include/common/cros-ec-sbs.dtsi | 1 +
2 files changed, 2 insertions(+)
create mode 120000 arch/arm64/boot/dts/include/common/cros-ec-keyboard.dtsi
create mode 120000 arch/arm64/boot/dts/include/common/cros-ec-sbs.dtsi
diff --git a/arch/arm64/boot/dts/include/common/cros-ec-keyboard.dtsi b/arch/arm64/boot/dts/include/common/cros-ec-keyboard.dtsi
new file mode 120000
index 000000000000..1c1889f0a791
--- /dev/null
+++ b/arch/arm64/boot/dts/include/common/cros-ec-keyboard.dtsi
@@ -0,0 +1 @@
+../../../../../arm/boot/dts/cros-ec-keyboard.dtsi
\ No newline at end of file
diff --git a/arch/arm64/boot/dts/include/common/cros-ec-sbs.dtsi b/arch/arm64/boot/dts/include/common/cros-ec-sbs.dtsi
new file mode 120000
index 000000000000..3d7ae9c88bcd
--- /dev/null
+++ b/arch/arm64/boot/dts/include/common/cros-ec-sbs.dtsi
@@ -0,0 +1 @@
+../../../../../arm/boot/dts/cros-ec-sbs.dtsi
\ No newline at end of file
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* [PATCH 2/9] arm64: dts: rockchip: add rk3399 thermal_zones phandle
From: Brian Norris @ 2016-12-02 2:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480645653-36943-1-git-send-email-briannorris@chromium.org>
We're going to need to amend this table in board files.
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
arch/arm64/boot/dts/rockchip/rk3399.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 66a11d1a6eac..28772f6e77f0 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -606,7 +606,7 @@
status = "disabled";
};
- thermal-zones {
+ thermal_zones: thermal-zones {
cpu_thermal: cpu {
polling-delay-passive = <100>;
polling-delay = <1000>;
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* [PATCH 3/9] arm64: dts: rockchip: add rk3399 eDP HPD pinctrl
From: Brian Norris @ 2016-12-02 2:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480645653-36943-1-git-send-email-briannorris@chromium.org>
We haven't enabled eDP support yet, but we might as well describe the
pin now.
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
arch/arm64/boot/dts/rockchip/rk3399.dtsi | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 28772f6e77f0..4ca8f9a7601c 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -1435,6 +1435,13 @@
};
};
+ edp {
+ edp_hpd: edp-hpd {
+ rockchip,pins =
+ <4 23 RK_FUNC_2 &pcfg_pull_none>;
+ };
+ };
+
gmac {
rgmii_pins: rgmii-pins {
rockchip,pins =
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* [PATCH 4/9] arm64: dts: rockchip: support dwc3 USB for rk3399
From: Brian Norris @ 2016-12-02 2:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480645653-36943-1-git-send-email-briannorris@chromium.org>
Add the dwc3 usb needed node information for rk3399.
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
Somewhat rewritten from Caesar's reposting (v2) of my patch.
Changes:
* Include USB2 PHY (which is now in -next)
* Don't include USB3 PHY, as extcon support is not ready yet
* Drop non-upstream properties
* Fixup whitespace a bit
---
arch/arm64/boot/dts/rockchip/rk3399.dtsi | 60 ++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 4ca8f9a7601c..1e97fb8c6415 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -316,6 +316,66 @@
};
};
+ usbdrd3_0: usb at fe800000 {
+ compatible = "rockchip,rk3399-dwc3";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ clocks = <&cru SCLK_USB3OTG0_REF>, <&cru SCLK_USB3OTG0_SUSPEND>,
+ <&cru ACLK_USB3OTG0>, <&cru ACLK_USB3_RKSOC_AXI_PERF>,
+ <&cru ACLK_USB3>, <&cru ACLK_USB3_GRF>;
+ clock-names = "clk_usb3otg0_ref", "clk_usb3otg0_suspend",
+ "aclk_usb3otg0", "aclk_usb3_rksoc_axi_perf",
+ "aclk_usb3", "aclk_usb3_grf";
+ resets = <&cru SRST_A_USB3_OTG0>;
+ reset-names = "usb3-otg";
+ status = "disabled";
+
+ usbdrd_dwc3_0: dwc3 {
+ compatible = "snps,dwc3";
+ reg = <0x0 0xfe800000 0x0 0x100000>;
+ interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH 0>;
+ dr_mode = "otg";
+ phys = <&u2phy0_otg>;
+ phy-names = "usb2-phy";
+ snps,dis_enblslpm_quirk;
+ snps,dis-u2-freeclk-exists-quirk;
+ snps,dis_u2_susphy_quirk;
+ snps,dis-del-phy-power-chg-quirk;
+ status = "disabled";
+ };
+ };
+
+ usbdrd3_1: usb at fe900000 {
+ compatible = "rockchip,rk3399-dwc3";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ clocks = <&cru SCLK_USB3OTG1_REF>, <&cru SCLK_USB3OTG1_SUSPEND>,
+ <&cru ACLK_USB3OTG1>, <&cru ACLK_USB3_RKSOC_AXI_PERF>,
+ <&cru ACLK_USB3>, <&cru ACLK_USB3_GRF>;
+ clock-names = "clk_usb3otg1_ref", "clk_usb3otg1_suspend",
+ "aclk_usb3otg1", "aclk_usb3_rksoc_axi_perf",
+ "aclk_usb3", "aclk_usb3_grf";
+ resets = <&cru SRST_A_USB3_OTG1>;
+ reset-names = "usb3-otg";
+ status = "disabled";
+
+ usbdrd_dwc3_1: dwc3 {
+ compatible = "snps,dwc3";
+ reg = <0x0 0xfe900000 0x0 0x100000>;
+ interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH 0>;
+ dr_mode = "otg";
+ phys = <&u2phy1_otg>;
+ phy-names = "usb2-phy";
+ snps,dis_enblslpm_quirk;
+ snps,dis-u2-freeclk-exists-quirk;
+ snps,dis_u2_susphy_quirk;
+ snps,dis-del-phy-power-chg-quirk;
+ status = "disabled";
+ };
+ };
+
usb_host0_ehci: usb at fe380000 {
compatible = "generic-ehci";
reg = <0x0 0xfe380000 0x0 0x20000>;
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* [PATCH 5/9] arm64: dts: rockchip: add rk3399 OPPs
From: Brian Norris @ 2016-12-02 2:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480645653-36943-1-git-send-email-briannorris@chromium.org>
Used for Gru/Kevin, but they should be conservative enough for all
boards. (And ideally, any board-to-board differences can be represented
via, e.g., describing regulator offsets.)
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
arch/arm64/boot/dts/rockchip/rk3399-opp.dtsi | 145 +++++++++++++++++++++++++++
arch/arm64/boot/dts/rockchip/rk3399.dtsi | 1 +
2 files changed, 146 insertions(+)
create mode 100644 arch/arm64/boot/dts/rockchip/rk3399-opp.dtsi
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-opp.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-opp.dtsi
new file mode 100644
index 000000000000..e1038cd92ce5
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3399-opp.dtsi
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2016 Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library 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.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/ {
+ cluster0_opp: opp-table0 {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+ opp00 {
+ opp-hz = /bits/ 64 <408000000>;
+ opp-microvolt = <800000>;
+ clock-latency-ns = <40000>;
+ };
+ opp01 {
+ opp-hz = /bits/ 64 <600000000>;
+ opp-microvolt = <800000>;
+ };
+ opp02 {
+ opp-hz = /bits/ 64 <816000000>;
+ opp-microvolt = <800000>;
+ };
+ opp03 {
+ opp-hz = /bits/ 64 <1008000000>;
+ opp-microvolt = <875000>;
+ };
+ opp04 {
+ opp-hz = /bits/ 64 <1200000000>;
+ opp-microvolt = <925000>;
+ };
+ opp05 {
+ opp-hz = /bits/ 64 <1416000000>;
+ opp-microvolt = <1050000>;
+ };
+ opp06 {
+ opp-hz = /bits/ 64 <1512000000>;
+ opp-microvolt = <1125000>;
+ };
+ };
+
+ cluster1_opp: opp-table1 {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+ opp00 {
+ opp-hz = /bits/ 64 <408000000>;
+ opp-microvolt = <800000>;
+ clock-latency-ns = <40000>;
+ };
+ opp01 {
+ opp-hz = /bits/ 64 <600000000>;
+ opp-microvolt = <800000>;
+ };
+ opp02 {
+ opp-hz = /bits/ 64 <816000000>;
+ opp-microvolt = <825000>;
+ };
+ opp03 {
+ opp-hz = /bits/ 64 <1008000000>;
+ opp-microvolt = <875000>;
+ };
+ opp04 {
+ opp-hz = /bits/ 64 <1200000000>;
+ opp-microvolt = <950000>;
+ };
+ opp05 {
+ opp-hz = /bits/ 64 <1416000000>;
+ opp-microvolt = <1025000>;
+ };
+ opp06 {
+ opp-hz = /bits/ 64 <1608000000>;
+ opp-microvolt = <1075000>;
+ };
+ opp07 {
+ opp-hz = /bits/ 64 <1800000000>;
+ opp-microvolt = <1150000>;
+ };
+ opp08 {
+ opp-hz = /bits/ 64 <2016000000>;
+ opp-microvolt = <1250000>;
+ };
+ };
+};
+
+&cpu_l0 {
+ operating-points-v2 = <&cluster0_opp>;
+};
+
+&cpu_l1 {
+ operating-points-v2 = <&cluster0_opp>;
+};
+
+&cpu_l2 {
+ operating-points-v2 = <&cluster0_opp>;
+};
+
+&cpu_l3 {
+ operating-points-v2 = <&cluster0_opp>;
+};
+
+&cpu_b0 {
+ operating-points-v2 = <&cluster1_opp>;
+};
+
+&cpu_b1 {
+ operating-points-v2 = <&cluster1_opp>;
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 1e97fb8c6415..02392c084607 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -1948,3 +1948,4 @@
};
};
+#include "rk3399-opp.dtsi"
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* [PATCH 6/9] dt-bindings: Document rk3399 Gru/Kevin
From: Brian Norris @ 2016-12-02 2:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480645653-36943-1-git-send-email-briannorris@chromium.org>
Gru is a base dev board for a family of devices, including Kevin. Both
utilize Rockchip RK3399, and they share much of their design.
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
Documentation/devicetree/bindings/arm/rockchip.txt | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/rockchip.txt b/Documentation/devicetree/bindings/arm/rockchip.txt
index cc4ace6397ab..830e13f5890c 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.txt
+++ b/Documentation/devicetree/bindings/arm/rockchip.txt
@@ -99,6 +99,26 @@ Rockchip platforms device tree bindings
"google,veyron-speedy-rev3", "google,veyron-speedy-rev2",
"google,veyron-speedy", "google,veyron", "rockchip,rk3288";
+- Google Gru (dev-board):
+ Required root node properties:
+ - compatible = "google,gru-rev15", "google,gru-rev14",
+ "google,gru-rev13", "google,gru-rev12",
+ "google,gru-rev11", "google,gru-rev10",
+ "google,gru-rev9", "google,gru-rev8",
+ "google,gru-rev7", "google,gru-rev6",
+ "google,gru-rev5", "google,gru-rev4",
+ "google,gru-rev3", "google,gru-rev2",
+ "google,gru", "rockchip,rk3399";
+
+- Google Kevin:
+ Required root node properties:
+ - compatible = "google,kevin-rev15", "google,kevin-rev14",
+ "google,kevin-rev13", "google,kevin-rev12",
+ "google,kevin-rev11", "google,kevin-rev10",
+ "google,kevin-rev9", "google,kevin-rev8",
+ "google,kevin-rev7", "google,kevin-rev6",
+ "google,kevin", "google,gru", "rockchip,rk3399";
+
- mqmaker MiQi:
Required root node properties:
- compatible = "mqmaker,miqi", "rockchip,rk3288";
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* [PATCH 7/9] arm64: dts: rockchip: add Gru/Kevin DTS
From: Brian Norris @ 2016-12-02 2:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480645653-36943-1-git-send-email-briannorris@chromium.org>
Kevin is part of a family of boards called Gru. As best as possible, the
properties shared by the Gru family are placed in rk3399-gru.dtsi, while
Kevin-specific bits are in rk3399-gru-kevin.dts. This does not add full
support for the base Gru board.
Working and tested (to some extent):
* EC support -- including keyboard, battery, PWM, and probably more
* UART / console
* Thermal
* Touchscreen
* Touchpad
* Digitizer (regulator still WIP)
* PCIe / Wifi
* Bluetooth / Webcam
* SD card
* eMMC
* USB2 on TypeC
- This works much of the time, but USB3 devices may or may not detect
properly. Waiting on proper extcon support for USB3 over TypeC.
- Depends on XHCI/DWC3 fixes for ARM64 that still haven't landed
* Backlight
Not working:
* CPUFreq -- relies on special OVP support for our PWM regulator
circuits
* EC / extcon support -- and with it, USB3/TypeC/DP
* DRM -- won't even build on ARM64, so all display, eDP, etc. is not
enabled
Not tested:
* Audio
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
arch/arm64/boot/dts/rockchip/Makefile | 1 +
arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts | 312 +++++++
arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi | 1006 +++++++++++++++++++++
3 files changed, 1319 insertions(+)
create mode 100644 arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
create mode 100644 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index 3a862894ea44..b82f7b61ab6f 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -4,6 +4,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-orion-r68-meta.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-px5-evb.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-r88.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-evb.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-gru-kevin.dtb
always := $(dtb-y)
subdir-y := $(dts-dirs)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
new file mode 100644
index 000000000000..66db785375a8
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
@@ -0,0 +1,312 @@
+/*
+ * Google Gru-Kevin Rev 6+ board device tree source
+ *
+ * Copyright 2016 Google, Inc
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file 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.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "rk3399-gru.dtsi"
+#include <include/dt-bindings/input/linux-event-codes.h>
+
+/*
+ * Kevin-specific things
+ *
+ * Things in this section should use names from Kevin schematic since no
+ * equivalent exists in Gru schematic. If referring to signals that exist
+ * in Gru we use the Gru names, though. Confusing enough for you?
+ */
+/ {
+ model = "Google Kevin";
+ compatible = "google,kevin-rev15", "google,kevin-rev14",
+ "google,kevin-rev13", "google,kevin-rev12",
+ "google,kevin-rev11", "google,kevin-rev10",
+ "google,kevin-rev9", "google,kevin-rev8",
+ "google,kevin-rev7", "google,kevin-rev6",
+ "google,kevin", "google,gru", "rockchip,rk3399";
+
+ /* Power tree */
+
+ /* pp3300 children */
+
+ p3_3v_dig: p3-3v-dig {
+ compatible = "regulator-fixed";
+ regulator-name = "p3.3v_dig";
+ pinctrl-names = "default";
+ pinctrl-0 = <&cpu3_pen_pwr_en>;
+
+ enable-active-high;
+ gpio = <&gpio4 30 GPIO_ACTIVE_HIGH>;
+ vin-supply = <&pp3300>;
+ };
+
+ /* END REGULATORS */
+
+ backlight: backlight {
+ compatible = "pwm-backlight";
+ pwms = <&cros_ec_pwm 1>;
+ brightness-levels = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+ 17 18 19 20 21 22 23 24 25 26 27 28 29 30
+ 31 32 33 34 35 36 37 38 39 40 41 42 43 44
+ 45 46 47 48 49 50 51 52 53 54 55 56 57 58
+ 59 60 61 62 63 64 65 66 67 68 69 70 71 72
+ 73 74 75 76 77 78 79 80 81 82 83 84 85 86
+ 87 88 89 90 91 92 93 94 95 96 97 98 99 100>;
+ default-brightness-level = <51>;
+ enable-gpios = <&gpio1 17 GPIO_ACTIVE_HIGH>;
+ power-supply = <&pp3300_disp>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&bl_en>;
+ pwm-delay-us = <10000>;
+ };
+
+ thermistor_ppvar_bigcpu: thermistor-ppvar-bigcpu {
+ compatible = "murata,ncp15wb473";
+ pullup-uv = <1800000>;
+ pullup-ohm = <25500>;
+ pulldown-ohm = <0>;
+ io-channels = <&saradc 2>;
+ #thermal-sensor-cells = <0>;
+ };
+
+ thermistor_ppvar_litcpu: thermistor-ppvar-litcpu {
+ compatible = "murata,ncp15wb473";
+ pullup-uv = <1800000>;
+ pullup-ohm = <25500>;
+ pulldown-ohm = <0>;
+ io-channels = <&saradc 3>;
+ #thermal-sensor-cells = <0>;
+ };
+};
+
+&gpio_keys {
+ pinctrl-names = "default";
+ pinctrl-0 = <&bt_host_wake_l>, <&cpu1_pen_eject>;
+
+ pen-insert {
+ label = "Pen Insert";
+ /* Insert = low, eject = high */
+ gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
+ linux,code = <SW_PEN_INSERTED>;
+ linux,input-type = <EV_SW>;
+ wakeup-source;
+ };
+};
+
+&thermal_zones {
+ bigcpu_reg_thermal: bigcpu-reg-thermal {
+ polling-delay-passive = <100>; /* milliseconds */
+ polling-delay = <1000>; /* milliseconds */
+ thermal-sensors = <&thermistor_ppvar_bigcpu 0>;
+ sustainable-power = <4000>;
+
+ ppvar_bigcpu_trips: trips {
+ ppvar_bigcpu_on: ppvar-bigcpu-on {
+ temperature = <40000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "passive";
+ };
+
+ ppvar_bigcpu_alert: ppvar-bigcpu-alert {
+ temperature = <50000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "passive";
+ };
+
+ ppvar_bigcpu_crit: ppvar-bigcpu-crit {
+ temperature = <90000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ map0 {
+ trip = <&ppvar_bigcpu_alert>;
+ cooling-device =
+ <&cpu_l0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ contribution = <4096>;
+ };
+ map1 {
+ trip = <&ppvar_bigcpu_alert>;
+ cooling-device =
+ <&cpu_b0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ contribution = <1024>;
+ };
+ };
+ };
+
+ litcpu_reg_thermal: litcpu-reg-thermal {
+ polling-delay-passive = <100>; /* milliseconds */
+ polling-delay = <1000>; /* milliseconds */
+ thermal-sensors = <&thermistor_ppvar_litcpu 0>;
+ sustainable-power = <4000>;
+
+ ppvar_litcpu_trips: trips {
+ ppvar_litcpu_on: ppvar-litcpu-on {
+ temperature = <40000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "passive";
+ };
+
+ ppvar_litcpu_alert: ppvar-litcpu-alert {
+ temperature = <50000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "passive";
+ };
+
+ ppvar_litcpu_crit: ppvar-litcpu-crit {
+ temperature = <90000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+};
+
+ap_i2c_tpm: &i2c0 {
+ status = "okay";
+
+ clock-frequency = <400000>;
+
+ /* These are relatively safe rise/fall times. */
+ i2c-scl-falling-time-ns = <50>;
+ i2c-scl-rising-time-ns = <300>;
+
+ tpm: tpm at 20 {
+ compatible = "infineon,slb9645tt";
+ reg = <0x20>;
+ powered-while-suspended;
+ };
+};
+
+ap_i2c_dig: &i2c2 {
+ status = "okay";
+
+ clock-frequency = <400000>;
+
+ /* These are relatively safe rise/fall times. */
+ i2c-scl-falling-time-ns = <50>;
+ i2c-scl-rising-time-ns = <300>;
+
+ digitizer: digitizer at 9 {
+ compatible = "hid-over-i2c";
+ reg = <0x9>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&cpu1_dig_irq_l &cpu1_dig_pdct_l>;
+
+ interrupt-parent = <&gpio2>;
+ interrupts = <4 IRQ_TYPE_LEVEL_LOW>;
+
+ hid-descr-addr = <0x1>;
+ };
+};
+
+/* Adjustments to things in the gru baseboard */
+
+&ap_i2c_tp {
+ trackpad at 4a {
+ compatible = "atmel,atmel_mxt_tp";
+ reg = <0x4a>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&trackpad_int_l>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <4 IRQ_TYPE_LEVEL_LOW>;
+ wakeup-source;
+ };
+};
+
+&ap_i2c_ts {
+ touchscreen at 4b {
+ compatible = "atmel,atmel_mxt_ts";
+ reg = <0x4b>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&touch_int_l>;
+ interrupt-parent = <&gpio3>;
+ interrupts = <13 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+&saradc {
+ status = "okay";
+ vref-supply = <&pp1800_ap_io>;
+};
+
+&mvl_wifi {
+ marvell,wakeup-pin = <14>; /* GPIO_14 on Marvell */
+};
+
+/* PINCTRL: always below everything else */
+
+&pinctrl {
+ digitizer {
+ /* Has external pullup */
+ cpu1_dig_irq_l: cpu1-dig-irq-l {
+ rockchip,pins = <2 4 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ /* Has external pullup */
+ cpu1_dig_pdct_l: cpu1-dig-pdct-l {
+ rockchip,pins = <2 5 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ discrete-regulators {
+ cpu3_pen_pwr_en: cpu3-pen-pwr-en {
+ rockchip,pins = <4 30 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ pen {
+ cpu1_pen_eject: cpu1-pen-eject {
+ rockchip,pins = <0 13 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+
+ wifi {
+ wlan_host_wake_l: wlan-host-wake-l {
+ rockchip,pins = <0 8 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+};
+
+/* DON'T PUT ANYTHING BELOW HERE. PUT IT ABOVE PINCTRL */
+/* DON'T PUT ANYTHING BELOW HERE. PUT IT ABOVE PINCTRL */
+/* DON'T PUT ANYTHING BELOW HERE. PUT IT ABOVE PINCTRL */
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
new file mode 100644
index 000000000000..59b452504106
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
@@ -0,0 +1,1006 @@
+/*
+ * Google Gru (and derivatives) board device tree source
+ *
+ * Copyright 2016 Google, Inc
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file 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.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dt-bindings/input/input.h>
+#include "rk3399.dtsi"
+
+/ {
+ chosen {
+ stdout-path = "serial2:115200n8";
+ };
+
+ /*
+ * Power Tree
+ *
+ * In general an attempt is made to include all rails called out by
+ * the schematic as long as those rails interact in some way with
+ * the AP. AKA:
+ * - Rails that only connect to the EC (or devices that the EC talks to)
+ * are not included.
+ * - Rails _are_ included if the rails go to the AP even if the AP
+ * doesn't currently care about them / they are always on. The idea
+ * here is that it makes it easier to map to the schematic or extend
+ * later.
+ *
+ * If two rails are substantially the same from the AP's point of
+ * view, though, we won't create a full fixed regulator. We'll just
+ * put the child rail as an alias of the parent rail. Sometimes rails
+ * look the same to the AP because one of these is true:
+ * - The EC controls the enable and the EC always enables a rail as
+ * long as the AP is running.
+ * - The rails are actually connected to each other by a jumper and
+ * the distinction is just there to add clarity/flexibility to the
+ * schematic.
+ */
+
+ /* parentless regulators */
+
+ ppvar_sys: ppvar-sys {
+ compatible = "regulator-fixed";
+ regulator-name = "ppvar_sys";
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ /* ppvar_sys children, sorted by name */
+
+ pp900_ap: pp900-ap {
+ compatible = "regulator-fixed";
+ regulator-name = "pp900_ap";
+
+ /* EC turns on w/ pp900_ap_en; always on for AP */
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <900000>;
+
+ vin-supply = <&ppvar_sys>;
+ };
+
+ pp1200_lpddr: pp1200-lpddr {
+ compatible = "regulator-fixed";
+ regulator-name = "pp1200_lpddr";
+
+ /* EC turns on w/ lpddr_pwr_en; always on for AP */
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+
+ vin-supply = <&ppvar_sys>;
+ };
+
+ pp1800: pp1800 {
+ compatible = "regulator-fixed";
+ regulator-name = "pp1800";
+
+ /* Always on when ppvar_sys shows power good */
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ vin-supply = <&ppvar_sys>;
+ };
+
+ pp3000: pp3000 {
+ compatible = "regulator-fixed";
+ regulator-name = "pp3000";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pp3000_en>;
+
+ enable-active-high;
+ gpio = <&gpio0 12 GPIO_ACTIVE_HIGH>;
+
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+
+ vin-supply = <&ppvar_sys>;
+ };
+
+ pp3300: pp3300 {
+ compatible = "regulator-fixed";
+ regulator-name = "pp3300";
+
+ /* Always on; plain and simple */
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ vin-supply = <&ppvar_sys>;
+ };
+
+ pp5000: pp5000 {
+ compatible = "regulator-fixed";
+ regulator-name = "pp5000";
+
+ /* EC turns on w/ pp5000_en; always on for AP */
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+
+ vin-supply = <&ppvar_sys>;
+ };
+
+ /* Schematics call this PPVAR even though it's fixed */
+ ppvar_logic: ppvar-logic {
+ compatible = "regulator-fixed";
+ regulator-name = "ppvar_logic";
+
+ /* EC turns on w/ ppvar_logic_en; always on for AP */
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <900000>;
+
+ vin-supply = <&ppvar_sys>;
+ };
+
+ /* pp900_ap aliases; these are always on for AP so just use alias */
+
+ /* EC turns on w/ pp900_ddrpll_en */
+ pp900_ddrpll: pp900-ap {
+ };
+
+ /* EC turns on w/ pp900_pcie_en */
+ pp900_pcie: pp900-ap {
+ };
+
+ /* EC turns on w/ pp900_pll_en */
+ pp900_pll: pp900-ap {
+ };
+
+ /* EC turns on w/ pp900_pmu_en */
+ pp900_pmu: pp900-ap {
+ };
+
+ /* EC turns on w/ pp900_usb_en */
+ pp900_usb: pp900-ap {
+ };
+
+ /* pp1800 aliases; these are always on for AP so just use alias */
+
+ /* EC turns on w/ pp1800_s0_en_l */
+ pp1800_ap_io: pp1800_emmc: pp1800_nfc: pp1800_s0: pp1800 {
+ };
+
+ /* EC turns on w/ pp1800_avdd_en_l */
+ pp1800_avdd: pp1800 {
+ };
+
+ /* EC turns on w/ pp1800_lid_en_l */
+ pp1800_lid: pp1800_mic: pp1800 {
+ };
+
+ /* EC turns on w/ lpddr_pwr_en */
+ pp1800_lpddr: pp1800 {
+ };
+
+ /* EC turns on w/ pp1800_pmu_en_l */
+ pp1800_pmu: pp1800 {
+ };
+
+ /* EC turns on w/ pp1800_usb_en_l */
+ pp1800_usb: pp1800 {
+ };
+
+ /* pp1800 children */
+
+ pp1500_ap_io: pp1500-ap-io {
+ compatible = "regulator-fixed";
+ regulator-name = "pp1500_ap_io";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pp1500_en>;
+
+ enable-active-high;
+ gpio = <&gpio0 10 GPIO_ACTIVE_HIGH>;
+
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+
+ vin-supply = <&pp1800>;
+ };
+
+ pp1800_audio: pp1800-audio {
+ compatible = "regulator-fixed";
+ regulator-name = "pp1800_audio";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pp1800_audio_en>;
+
+ regulator-always-on;
+ regulator-boot-on;
+
+ enable-active-high;
+ gpio = <&gpio0 2 GPIO_ACTIVE_HIGH>;
+
+ vin-supply = <&pp1800>;
+ };
+
+ pp1800_pcie: pp1800-pcie {
+ compatible = "regulator-fixed";
+ regulator-name = "pp1800_pcie";
+ pinctrl-names = "default";
+ pinctrl-0 = <&wlan_module_pd_l>;
+
+ /*
+ * Need to wait 1ms + ramp-up time before we can power on WiFi.
+ * This has been approximated as 8ms total.
+ */
+ regulator-enable-ramp-delay = <8000>;
+
+ enable-active-high;
+ gpio = <&gpio0 4 GPIO_ACTIVE_HIGH>;
+
+ vin-supply = <&pp1800>;
+ };
+
+ /*
+ * See http://crosbug.com/p/56069/
+ *
+ * This is a bit of a hack. The WiFi module should be reset at least
+ * 1ms after its regulators have ramped up (max rampup time is ~7ms).
+ * With some stretching of the imagination, we can call the 1.8V
+ * regulator a supply.
+ */
+ wlan_pd_n: wlan-pd-n {
+ compatible = "regulator-fixed";
+ regulator-name = "wlan_pd_n";
+
+ /* Note the wlan_module_reset_l pinctrl */
+ enable-active-high;
+ gpio = <&gpio1 11 GPIO_ACTIVE_HIGH>;
+
+ vin-supply = <&pp1800_pcie>;
+ };
+
+ /* pp3000 aliases; these are always on for AP so just use alias */
+
+ /* Always on; plain and simple */
+ pp3000_ap: pp3000_emmc: pp3000 {
+ };
+
+ /* pp3000 children */
+
+ pp3000_sd_slot: pp3000-sd-slot {
+ compatible = "regulator-fixed";
+ regulator-name = "pp3000_sd_slot";
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd_slot_pwr_en>;
+
+ enable-active-high;
+ gpio = <&gpio4 29 GPIO_ACTIVE_HIGH>;
+
+ vin-supply = <&pp3000>;
+ };
+
+ /*
+ * Technically, this is a small abuse of 'regulator-gpio'; this
+ * regulator is a mux between pp1800 and pp3300. pp1800 and pp3300 are
+ * always on though, so it is sufficient to simply control the mux
+ * here.
+ */
+ ppvar_sd_card_io: ppvar-sd-card-io {
+ compatible = "regulator-gpio";
+ regulator-name = "ppvar_sd_card_io";
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd_io_pwr_en &sd_pwr_1800_sel>;
+
+ enable-active-high;
+ enable-gpio = <&gpio2 2 GPIO_ACTIVE_HIGH>;
+ gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>;
+ states = <1800000 0x1
+ 3000000 0x0>;
+
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3000000>;
+ };
+
+ /* pp3300 aliases; these are always on for AP so just use alias */
+
+ /* EC turns on w/ pp3300_trackpad_en_l */
+ pp3300_trackpad: pp3300-trackpad {
+ };
+
+ /* EC turns on w/ pp3300_usb_en_l */
+ pp3300_usb: pp3300 {
+ };
+
+ /* pp3300 children */
+
+ pp3300_disp: pp3300-disp {
+ compatible = "regulator-fixed";
+ regulator-name = "pp3300_disp";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pp3300_disp_en>;
+
+ enable-active-high;
+
+ gpio = <&gpio4 27 GPIO_ACTIVE_HIGH>;
+
+ startup-delay-us = <2000>;
+ vin-supply = <&pp3300>;
+ };
+
+ pp3300_wifi_bt: pp3300-wifi-bt {
+ compatible = "regulator-fixed";
+ regulator-name = "pp3300_wifi_bt";
+ /* NOTE: wlan_module_pd_l pinctrl in pp1800_pcie */
+
+ enable-active-high;
+
+ /* NOTE: this GPIO also used in pp1800_pcie */
+ gpio = <&gpio0 4 GPIO_ACTIVE_HIGH>;
+
+ vin-supply = <&pp3300>;
+ };
+
+ /* pp5000 aliases; these are always on for AP so just use alias */
+
+ /* EC turns on w/ usb_a_en */
+ pp5000_usb_a_vbus: pp5000 {
+ };
+
+ /* END REGULATORS */
+
+ io-domains {
+ compatible = "rockchip,rk3399-io-voltage-domain";
+ rockchip,grf = <&grf>;
+
+ bt656-supply = <&pp1800_ap_io>; /* APIO2_VDD; 2a 2b */
+ audio-supply = <&pp1800_audio>; /* APIO5_VDD; 3d 4a */
+ sdmmc-supply = <&ppvar_sd_card_io>; /* SDMMC0_VDD; 4b */
+ gpio1830-supply = <&pp3000_ap>; /* APIO4_VDD; 4c 4d */
+ };
+
+ max98357a: max98357a {
+ #sound-dai-cells = <0>;
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmode_en>;
+
+ compatible = "maxim,max98357a";
+ sdmode-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
+ sdmode-delay = <2>;
+ };
+
+ pmu-io-domains {
+ compatible = "rockchip,rk3399-pmu-io-voltage-domain";
+ rockchip,grf = <&pmugrf>;
+
+ pmu1830-supply = <&pp1800_pmu>; /* PMUIO2_VDD */
+ };
+
+ sound {
+ compatible = "rockchip,rk3399-gru-sound";
+ rockchip,cpu = <&i2s0 &i2s2>;
+ rockchip,codec = <&max98357a &headsetcodec &codec>;
+ };
+
+ gpio_keys: gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&bt_host_wake_l>;
+
+ wake-on-bt {
+ label = "Wake-on-Bluetooth";
+ gpios = <&gpio0 3 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_WAKEUP>;
+ wakeup-source;
+ };
+ };
+};
+
+&cru {
+ assigned-clocks =
+ <&cru PLL_GPLL>, <&cru PLL_CPLL>,
+ <&cru PLL_NPLL>,
+ <&cru ACLK_PERIHP>, <&cru HCLK_PERIHP>,
+ <&cru PCLK_PERIHP>,
+ <&cru ACLK_PERILP0>, <&cru HCLK_PERILP0>,
+ <&cru PCLK_PERILP0>, <&cru ACLK_CCI>,
+ <&cru HCLK_PERILP1>, <&cru PCLK_PERILP1>;
+ assigned-clock-rates =
+ <594000000>, <800000000>,
+ <1000000000>,
+ <150000000>, <75000000>,
+ <37500000>,
+ <100000000>, <100000000>,
+ <50000000>, <800000000>,
+ <100000000>, <50000000>;
+};
+
+&emmc_phy {
+ status = "okay";
+};
+
+ap_i2c_mic: &i2c1 {
+ status = "okay";
+
+ clock-frequency = <400000>;
+
+ /* These are relatively safe rise/fall times */
+ i2c-scl-falling-time-ns = <50>;
+ i2c-scl-rising-time-ns = <300>;
+
+ headsetcodec: rt5514 at 57 {
+ compatible = "realtek,rt5514";
+ reg = <0x57>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mic_int>;
+
+ interrupt-parent = <&gpio1>;
+ interrupts = <13 IRQ_TYPE_LEVEL_HIGH>;
+
+ realtek,dmic-init-delay = <20>;
+ wakeup-source;
+ };
+};
+
+ap_i2c_ts: &i2c3 {
+ status = "okay";
+
+ clock-frequency = <400000>;
+
+ /* These are relatively safe rise/fall times */
+ i2c-scl-falling-time-ns = <50>;
+ i2c-scl-rising-time-ns = <300>;
+};
+
+ap_i2c_tp: &i2c5 {
+ status = "okay";
+
+ /*
+ * Note strange pullup enable. Apparently this avoids leakage but
+ * still allows us to get nice 4.7K pullups for high speed i2c
+ * transfers. Basically we want the pullup on whenever the ap is
+ * alive, so the "en" pin just gets set to output high.
+ */
+ pinctrl-0 = <&i2c5_xfer &ap_i2c_tp_pu_en>;
+
+ clock-frequency = <400000>;
+
+ /* These are relatively safe rise/fall times */
+ i2c-scl-falling-time-ns = <50>;
+ i2c-scl-rising-time-ns = <300>;
+};
+
+ap_i2c_audio: &i2c8 {
+ status = "okay";
+
+ clock-frequency = <400000>;
+
+ /* These are relatively safe rise/fall times */
+ i2c-scl-falling-time-ns = <50>;
+ i2c-scl-rising-time-ns = <300>;
+
+ codec: da7219 at 1a {
+ compatible = "dlg,da7219";
+ reg = <0x1a>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&headset_int_l>;
+
+ interrupt-parent = <&gpio1>;
+ interrupts = <23 IRQ_TYPE_LEVEL_LOW>;
+
+ VDD-supply = <&pp1800>;
+ VDDMIC-supply = <&pp3300>;
+ VDDIO-supply = <&pp1800>;
+
+ clocks = <&cru SCLK_I2S_8CH_OUT>;
+ clock-names = "mclk";
+
+ dlg,ldo-lvl = <1200>;
+ dlg,micbias-lvl = <2600>;
+ dlg,mic-amp-in-sel = "diff";
+
+ da7219_aad {
+ dlg,btn-cfg = <50>;
+ dlg,mic-det-thr = <500>;
+ dlg,jack-ins-deb = <20>;
+ dlg,jack-det-rate = "32ms_64ms";
+ dlg,jack-rem-deb = <1>;
+
+ dlg,a-d-btn-thr = <0xa>;
+ dlg,d-b-btn-thr = <0x16>;
+ dlg,b-c-btn-thr = <0x21>;
+ dlg,c-mic-btn-thr = <0x3E>;
+
+ dlg,btn-avg = <4>;
+ dlg,adc-1bit-rpt = <1>;
+ };
+ };
+};
+
+&i2s0 {
+ status = "okay";
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&pcie0 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie_clkreqn_cpm>, <&wifi_perst_l>;
+ ep-gpios = <&gpio2 27 GPIO_ACTIVE_HIGH>;
+
+ max-link-speed = <1>;
+
+ vpcie3v3-supply = <&pp3300_wifi_bt>;
+ vpcie1v8-supply = <&wlan_pd_n>; /* HACK: see &wlan_pd_n */
+ vpcie0v9-supply = <&pp900_pcie>;
+
+ pci_rootport: pcie at 0,0 {
+ reg = <0x83000000 0x0 0x00000000 0x0 0x00000000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+
+ mvl_wifi: wifi at 0,0 {
+ compatible = "pci1b4b,2b42";
+ reg = <0x83010000 0x0 0x00000000 0x0 0x00100000
+ 0x83010000 0x0 0x00100000 0x0 0x00100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&wlan_host_wake_l>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <8 IRQ_TYPE_LEVEL_LOW>;
+ wakeup-source;
+ };
+ };
+};
+
+&pcie_phy {
+ status = "okay";
+};
+
+&pwm0 {
+ status = "okay";
+};
+
+&pwm1 {
+ status = "okay";
+};
+
+&pwm2 {
+ status = "okay";
+};
+
+&pwm3 {
+ status = "okay";
+};
+
+&sdhci {
+ /*
+ * Signal integrity isn't great at 200 MHz and 150 MHz (DDR) gives the
+ * same (or nearly the same) performance for all eMMC that are intended
+ * to be used.
+ */
+ assigned-clock-rates = <150000000>;
+
+ bus-width = <8>;
+ mmc-hs400-1_8v;
+ mmc-hs400-enhanced-strobe;
+ non-removable;
+ status = "okay";
+};
+
+&sdmmc {
+ status = "okay";
+
+ /*
+ * Note: configure "sdmmc_cd" as card detect even though it's actually
+ * hooked to ground. Because we specified "cd-gpios" below dw_mmc
+ * should be ignoring card detect anyway. Specifying the pin as
+ * sdmmc_cd means that even if you've got GRF_SOC_CON7[12] (force_jtag)
+ * turned on that the system will still make sure the port is
+ * configured as SDMMC and not JTAG.
+ */
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_cd_gpio
+ &sdmmc_bus4>;
+
+ bus-width = <4>;
+ cd-gpios = <&gpio4 24 GPIO_ACTIVE_LOW>;
+ disable-wp;
+
+ cap-mmc-highspeed;
+ cap-sd-highspeed;
+ sd-uhs-sdr12;
+ sd-uhs-sdr25;
+ sd-uhs-sdr50;
+ sd-uhs-sdr104;
+
+ vmmc-supply = <&pp3000_sd_slot>;
+ vqmmc-supply = <&ppvar_sd_card_io>;
+};
+
+&spi1 {
+ status = "okay";
+
+ spiflash at 0 {
+ compatible = "jedec,spi-nor";
+
+ /* May run faster once verified. */
+ spi-max-frequency = <10000000>;
+ reg = <0>;
+ };
+};
+
+&spi2 {
+ status = "okay";
+
+ wacky_spi_audio: spi2 at 0 {
+ compatible = "realtek,rt5514";
+ reg = <0>;
+
+ /* May run faster once verified. */
+ spi-max-frequency = <10000000>;
+ };
+};
+
+&spi5 {
+ status = "okay";
+
+ cros_ec: ec at 0 {
+ compatible = "google,cros-ec-spi";
+ reg = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&ec_ap_int_l>;
+
+ google,cros-ec-spi-pre-delay = <30>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
+ spi-max-frequency = <3000000>;
+
+ i2c_tunnel: i2c-tunnel {
+ compatible = "google,cros-ec-i2c-tunnel";
+ google,remote-bus = <4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ cros_ec_pwm: ec-pwm {
+ compatible = "google,cros-ec-pwm";
+ #pwm-cells = <1>;
+ };
+ };
+};
+
+&tsadc {
+ status = "okay";
+
+ rockchip,hw-tshut-mode = <1>; /* tshut mode 0:CRU 1:GPIO */
+ rockchip,hw-tshut-polarity = <1>; /* tshut polarity 0:LOW 1:HIGH */
+};
+
+&u2phy0 {
+ status = "okay";
+};
+
+&u2phy1 {
+ status = "okay";
+};
+
+&u2phy0_host {
+ status = "okay";
+};
+
+&u2phy1_host {
+ status = "okay";
+};
+
+&u2phy0_otg {
+ status = "okay";
+};
+
+&u2phy1_otg {
+ status = "okay";
+};
+
+&uart2 {
+ status = "okay";
+};
+
+&usb_host0_ehci {
+ status = "okay";
+};
+
+&usb_host0_ohci {
+ status = "okay";
+};
+
+&usb_host1_ehci {
+ status = "okay";
+};
+
+&usb_host1_ohci {
+ status = "okay";
+};
+
+&usbdrd3_0 {
+ status = "okay";
+};
+
+&usbdrd_dwc3_0 {
+ status = "okay";
+ dr_mode = "host";
+};
+
+&usbdrd3_1 {
+ status = "okay";
+};
+
+&usbdrd_dwc3_1 {
+ status = "okay";
+ dr_mode = "host";
+};
+
+#include "common/cros-ec-keyboard.dtsi"
+#include "common/cros-ec-sbs.dtsi"
+
+/* PINCTRL: always below everything else */
+
+&pinctrl {
+ /*
+ * pinctrl settings for pins that have no real owners.
+ *
+ * At the moment settings are identical for S0 and S3, but if we later
+ * need to configure things differently for S3 we'll adjust here.
+ */
+ pinctrl-names = "default";
+ pinctrl-0 = <
+ &ap_pwroff /* AP will auto-assert this when in S3 */
+ &clk_32k /* This pin is always 32k on gru boards */
+
+ /*
+ * We want this driven low ASAP; firmware should help us, but
+ * we can help ourselves too.
+ */
+ &wlan_module_reset_l
+ >;
+
+ pcfg_output_low: pcfg-output-low {
+ output-low;
+ };
+
+ pcfg_output_high: pcfg-output-high {
+ output-high;
+ };
+
+ pcfg_pull_none_8ma: pcfg-pull-none-8ma {
+ bias-disable;
+ drive-strength = <8>;
+ };
+
+ cros-ec {
+ ec_ap_int_l: ec-ap-int-l {
+ rockchip,pins = <RK_GPIO0 1 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+
+ discrete-regulators {
+ pp1500_en: pp1500-en {
+ rockchip,pins = <RK_GPIO0 10 RK_FUNC_GPIO
+ &pcfg_pull_none>;
+ };
+
+ pp1800_audio_en: pp1800-audio-en {
+ rockchip,pins = <RK_GPIO0 2 RK_FUNC_GPIO
+ &pcfg_pull_down>;
+ };
+
+ pp3300_disp_en: pp3300-disp-en {
+ rockchip,pins = <RK_GPIO4 27 RK_FUNC_GPIO
+ &pcfg_pull_none>;
+ };
+
+ pp3000_en: pp3000-en {
+ rockchip,pins = <RK_GPIO0 12 RK_FUNC_GPIO
+ &pcfg_pull_none>;
+ };
+
+ sd_io_pwr_en: sd-io-pwr-en {
+ rockchip,pins = <RK_GPIO2 2 RK_FUNC_GPIO
+ &pcfg_pull_none>;
+ };
+
+ sd_pwr_1800_sel: sd-pwr-1800-sel {
+ rockchip,pins = <RK_GPIO2 28 RK_FUNC_GPIO
+ &pcfg_pull_none>;
+ };
+
+ sd_slot_pwr_en: sd-slot-pwr-en {
+ rockchip,pins = <RK_GPIO4 29 RK_FUNC_GPIO
+ &pcfg_pull_none>;
+ };
+
+ wlan_module_pd_l: wlan-module-pd-l {
+ rockchip,pins = <RK_GPIO0 4 RK_FUNC_GPIO
+ &pcfg_pull_down>;
+ };
+ };
+
+ codec {
+ /* Has external pullup */
+ headset_int_l: headset-int-l {
+ rockchip,pins = <1 23 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ mic_int: mic-int {
+ rockchip,pins = <1 13 RK_FUNC_GPIO &pcfg_pull_down>;
+ };
+ };
+
+ max98357a {
+ sdmode_en: sdmode-en {
+ rockchip,pins = <1 2 RK_FUNC_GPIO &pcfg_pull_down>;
+ };
+ };
+
+ sdmmc {
+ /*
+ * We run sdmmc at max speed; bump up drive strength.
+ * We also have external pulls, so disable the internal ones.
+ */
+ sdmmc_bus4: sdmmc-bus4 {
+ rockchip,pins =
+ <4 8 RK_FUNC_1 &pcfg_pull_none_8ma>,
+ <4 9 RK_FUNC_1 &pcfg_pull_none_8ma>,
+ <4 10 RK_FUNC_1 &pcfg_pull_none_8ma>,
+ <4 11 RK_FUNC_1 &pcfg_pull_none_8ma>;
+ };
+
+ sdmmc_clk: sdmmc-clk {
+ rockchip,pins =
+ <4 12 RK_FUNC_1 &pcfg_pull_none_8ma>;
+ };
+
+ sdmmc_cmd: sdmmc-cmd {
+ rockchip,pins =
+ <4 13 RK_FUNC_1 &pcfg_pull_none_8ma>;
+ };
+
+ /*
+ * In our case the official card detect is hooked to ground
+ * to avoid getting access to JTAG just by sticking something
+ * in the SD card slot (see the force_jtag bit in the TRM).
+ *
+ * We still configure it as card detect because it doesn't
+ * hurt and dw_mmc will ignore it. We make sure to disable
+ * the pull though so we don't burn needless power.
+ */
+ sdmmc_cd: sdmcc-cd {
+ rockchip,pins =
+ <0 7 RK_FUNC_1 &pcfg_pull_none>;
+ };
+
+ /* This is where we actually hook up CD; has external pull */
+ sdmmc_cd_gpio: sdmmc-cd-gpio {
+ rockchip,pins = <4 24 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ trackpad {
+ ap_i2c_tp_pu_en: ap-i2c-tp-pu-en {
+ rockchip,pins = <3 12 RK_FUNC_GPIO &pcfg_output_high>;
+ };
+
+ trackpad_int_l: trackpad-int-l {
+ rockchip,pins = <1 4 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+
+ touchscreen {
+ touch_int_l: touch-int-l {
+ rockchip,pins = <3 13 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+
+ touch_reset_l: touch-reset-l {
+ rockchip,pins = <4 26 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ wifi {
+ wifi_perst_l: wifi-perst-l {
+ rockchip,pins = <2 27 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ wlan_module_reset_l: wlan-module-reset-l {
+ /*
+ * We want this driven low ASAP (As {Soon,Strongly} As
+ * Possible), to avoid leakage through the powered-down
+ * WiFi.
+ */
+ rockchip,pins = <1 11 RK_FUNC_GPIO &pcfg_output_low>;
+ };
+
+ bt_host_wake_l: bt-host-wake-l {
+ /* Kevin has an external pull up, but Gru does not */
+ rockchip,pins = <0 3 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+
+ backlight-enable {
+ bl_en: bl-en {
+ rockchip,pins = <1 17 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ write-protect {
+ ap_fw_wp: ap-fw-wp {
+ rockchip,pins = <1 18 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+
+ pcie {
+ pcie_clkreqn_cpm: pci-clkreqn-cpm {
+ /*
+ * Since our pcie doesn't support ClockPM(CPM), we want
+ * to hack this as gpio, so the EP could be able to
+ * de-assert it along and make ClockPM(CPM) work.
+ */
+ rockchip,pins = <2 26 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+};
+
+/* DON'T PUT ANYTHING BELOW HERE. PUT IT ABOVE PINCTRL */
+/* DON'T PUT ANYTHING BELOW HERE. PUT IT ABOVE PINCTRL */
+/* DON'T PUT ANYTHING BELOW HERE. PUT IT ABOVE PINCTRL */
+
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* [PATCH 8/9] arm64: dts: rockchip: partially describe PWM regulators for Gru
From: Brian Norris @ 2016-12-02 2:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480645653-36943-1-git-send-email-briannorris@chromium.org>
We need to add regulators to the CPU nodes, so cpufreq doesn't think it
can crank up the clock speed without changing the voltage. However, we
don't yet have the DT bindings to fully describe the Over Voltage
Protection (OVP) circuits on these boards. Without that description, we
might end up changing the voltage too much, too fast.
Add the pwm-regulator descriptions and associate the CPU OPPs, but leave
them disabled.
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi | 146 +++++++++++++++++++++++++++
1 file changed, 146 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
index 59b452504106..90adfb5cba38 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
@@ -172,6 +172,98 @@
vin-supply = <&ppvar_sys>;
};
+ ppvar_bigcpu: ppvar-bigcpu {
+ compatible = "pwm-regulator";
+ regulator-name = "ppvar_bigcpu";
+ /*
+ * OVP circuit requires special handling which is not yet
+ * represented. Keep disabled for now.
+ */
+ status = "disabled";
+
+ pwms = <&pwm1 0 3337 0>;
+
+ /* EC turns on w/ ap_core_en; always on for AP */
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-min-microvolt = <798674>;
+ regulator-max-microvolt = <1302172>;
+
+ pwm-supply = <&ppvar_sys>;
+ pwm-dutycycle-range = <100 0>;
+ pwm-dutycycle-unit = <100>;
+ };
+
+ ppvar_litcpu: ppvar-litcpu {
+ compatible = "pwm-regulator";
+ regulator-name = "ppvar_litcpu";
+ /*
+ * OVP circuit requires special handling which is not yet
+ * represented. Keep disabled for now.
+ */
+ status = "disabled";
+
+ pwms = <&pwm2 0 3337 0>;
+
+ /* EC turns on w/ ap_core_en; always on for AP */
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-min-microvolt = <799065>;
+ regulator-max-microvolt = <1303738>;
+
+ pwm-supply = <&ppvar_sys>;
+ pwm-dutycycle-range = <100 0>;
+ pwm-dutycycle-unit = <100>;
+ };
+
+ ppvar_gpu: ppvar-gpu {
+ compatible = "pwm-regulator";
+ regulator-name = "ppvar_gpu";
+ /*
+ * OVP circuit requires special handling which is not yet
+ * represented. Keep disabled for now.
+ */
+ status = "disabled";
+
+ pwms = <&pwm0 0 3337 0>;
+
+ /* EC turns on w/ ap_core_en; always on for AP */
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-min-microvolt = <785782>;
+ regulator-max-microvolt = <1217729>;
+
+ pwm-supply = <&ppvar_sys>;
+ pwm-dutycycle-range = <100 0>;
+ pwm-dutycycle-unit = <100>;
+ };
+
+ ppvar_centerlogic: ppvar-centerlogic {
+ compatible = "pwm-regulator";
+ regulator-name = "ppvar_centerlogic";
+ /*
+ * OVP circuit requires special handling which is not yet
+ * represented. Keep disabled for now.
+ */
+ status = "disabled";
+
+ pwms = <&pwm3 0 3337 0>;
+
+ /* EC turns on w/ ppvar_centerlogic_en; always on for AP */
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-min-microvolt = <800069>;
+ regulator-max-microvolt = <1049692>;
+
+ pwm-supply = <&ppvar_sys>;
+ pwm-dutycycle-range = <100 0>;
+ pwm-dutycycle-unit = <100>;
+ };
+
/* Schematics call this PPVAR even though it's fixed */
ppvar_logic: ppvar-logic {
compatible = "regulator-fixed";
@@ -444,6 +536,60 @@
};
};
+/*
+ * Set some suspend operating points to avoid OVP in suspend
+ *
+ * When we go into S3 ARM Trusted Firmware will transition our PWM regulators
+ * from wherever they're at back to the "default" operating point (whatever
+ * voltage we get when we set the PWM pins to "input").
+ *
+ * This quick transition under light load has the possibility to trigger the
+ * regulator "over voltage protection" (OVP).
+ *
+ * To make extra certain that we don't hit this OVP at suspend time, we'll
+ * transition to a voltage that's much closer to the default (~1.0 V) so that
+ * there will not be a big jump. Technically we only need to get within 200 mV
+ * of the default voltage, but the speed here should be fast enough and we need
+ * suspend/resume to be rock solid.
+ */
+
+&cluster0_opp {
+ opp05 {
+ opp-suspend;
+ };
+};
+
+&cluster1_opp {
+ opp06 {
+ opp-suspend;
+ };
+};
+
+&cpu_l0 {
+ cpu-supply = <&ppvar_litcpu>;
+};
+
+&cpu_l1 {
+ cpu-supply = <&ppvar_litcpu>;
+};
+
+&cpu_l2 {
+ cpu-supply = <&ppvar_litcpu>;
+};
+
+&cpu_l3 {
+ cpu-supply = <&ppvar_litcpu>;
+};
+
+&cpu_b0 {
+ cpu-supply = <&ppvar_bigcpu>;
+};
+
+&cpu_b1 {
+ cpu-supply = <&ppvar_bigcpu>;
+};
+
+
&cru {
assigned-clocks =
<&cru PLL_GPLL>, <&cru PLL_CPLL>,
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* [PATCH 9/9] arm64: dts: rockchip: add regulator info for Kevin digitizer
From: Brian Norris @ 2016-12-02 2:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480645653-36943-1-git-send-email-briannorris@chromium.org>
We need to enable this regulator before the digitizer can be used. Wacom
recommended waiting for 100 ms before talking to the HID.
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
Uses WIP bindings:
[PATCH v3 1/2] devicetree: i2c-hid: Add regulator support
https://patchwork.kernel.org/patch/9457493/
---
arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
index 66db785375a8..d260079de2ab 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
@@ -232,6 +232,9 @@ ap_i2c_dig: &i2c2 {
pinctrl-names = "default";
pinctrl-0 = <&cpu1_dig_irq_l &cpu1_dig_pdct_l>;
+ vdd-supply = <&p3_3v_dig>;
+ init-delay-ms = <100>;
+
interrupt-parent = <&gpio2>;
interrupts = <4 IRQ_TYPE_LEVEL_LOW>;
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* arm64: dts: zx: support cpu-freq for zx296718
From: Shawn Guo @ 2016-12-02 2:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480594135-27273-1-git-send-email-baoyou.xie@linaro.org>
+ Viresh, the author of the bindings.
On Thu, Dec 01, 2016 at 08:08:55PM +0800, Baoyou Xie wrote:
> This patch adds the CPU clock phandle in CPU's node
> and uses operating-points-v2 to register operating points.
>
> So it can be used by cpufreq-dt driver.
>
> Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
Just out of curiosity, why is there no '[PATCH]' prefix in the subject?
> ---
> arch/arm64/boot/dts/zte/zx296718.dtsi | 37 +++++++++++++++++++++++++++++++++++
> 1 file changed, 37 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/zte/zx296718.dtsi b/arch/arm64/boot/dts/zte/zx296718.dtsi
> index 7a1aed7..16f7d5e 100644
> --- a/arch/arm64/boot/dts/zte/zx296718.dtsi
> +++ b/arch/arm64/boot/dts/zte/zx296718.dtsi
> @@ -44,6 +44,7 @@
> #include <dt-bindings/input/input.h>
> #include <dt-bindings/interrupt-controller/arm-gic.h>
> #include <dt-bindings/gpio/gpio.h>
> +#include <dt-bindings/clock/zx296718-clock.h>
>
> / {
> compatible = "zte,zx296718";
> @@ -81,6 +82,8 @@
> compatible = "arm,cortex-a53","arm,armv8";
> reg = <0x0 0x0>;
> enable-method = "psci";
> + clocks = <&topcrm A53_GATE>;
> + operating-points-v2 = <&cluster0_opp>;
> };
>
> cpu1: cpu at 1 {
> @@ -88,6 +91,7 @@
> compatible = "arm,cortex-a53","arm,armv8";
> reg = <0x0 0x1>;
> enable-method = "psci";
> + operating-points-v2 = <&cluster0_opp>;
> };
>
> cpu2: cpu at 2 {
> @@ -95,6 +99,7 @@
> compatible = "arm,cortex-a53","arm,armv8";
> reg = <0x0 0x2>;
> enable-method = "psci";
> + operating-points-v2 = <&cluster0_opp>;
> };
>
> cpu3: cpu at 3 {
> @@ -102,6 +107,38 @@
> compatible = "arm,cortex-a53","arm,armv8";
> reg = <0x0 0x3>;
> enable-method = "psci";
> + operating-points-v2 = <&cluster0_opp>;
> + };
> + };
> +
> + cluster0_opp: opp_table0 {
I know this is how examples in the bindings doc written, but it's
recommended to use hyphen rather than underscore in node name. That
said, the following naming form is better.
cluster0_opp: opp-table0
> + compatible = "operating-points-v2";
> + opp-shared;
> +
> + opp at 500000000 {
> + opp-hz = /bits/ 64 <500000000>;
> + opp-microvolt = <857000>;
> + clock-latency-ns = <500000>;
> + };
We prefer to have a newline between nodes.
> + opp at 648000000 {
> + opp-hz = /bits/ 64 <648000000>;
> + opp-microvolt = <857000>;
> + clock-latency-ns = <500000>;
> + };
> + opp at 800000000 {
> + opp-hz = /bits/ 64 <800000000>;
> + opp-microvolt = <882000>;
> + clock-latency-ns = <500000>;
> + };
> + opp at 1000000000 {
> + opp-hz = /bits/ 64 <1000000000>;
> + opp-microvolt = <892000>;
> + clock-latency-ns = <500000>;
> + };
> + opp at 1188000000 {
> + opp-hz = /bits/ 64 <1188000000>;
> + opp-microvolt = <1009000>;
So we have 5 setpoints with different frequency-voltage pair. I have
seen 'clocks' specified in cpu0 node and understand how frequency
scaling works. But what about voltage scaling? There is no
'cpu-supply' defined, and how does voltage scale among these
opp-microvolt settings?
Another related question: if we do not support voltage scaling for now,
what's the actually voltage when system is up running? Is that voltage
safe for cpu to run at all those 5 frequencies?
Shawn
> + clock-latency-ns = <500000>;
> };
> };
>
> --
> 2.7.4
>
^ permalink raw reply
* [PATCH v1] mtk-vcodec: use V4L2_DEC_CMD_STOP to implement flush
From: Wu-Cheng Li @ 2016-12-02 2:38 UTC (permalink / raw)
To: linux-arm-kernel
From: Wu-Cheng Li <wuchengli@google.com>
This patch uses V4L2_DEC_CMD_STOP to implement flush -- requesting
the remaining images to be returned to userspace. The old unofficial
way was to use a size-0 input buffer and the code is removed.
Tiffany Lin (1):
mtk-vcodec: use V4L2_DEC_CMD_STOP to implement flush
drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c | 151 ++++++++++++++-------
.../media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 14 ++
drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h | 2 +
3 files changed, 117 insertions(+), 50 deletions(-)
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply
* [PATCH v1] mtk-vcodec: use V4L2_DEC_CMD_STOP to implement flush
From: Wu-Cheng Li @ 2016-12-02 2:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480646314-75478-1-git-send-email-wuchengli@chromium.org>
From: Tiffany Lin <tiffany.lin@mediatek.com>
Also remove the code using size-0 OUTPUT buffer to flush.
Singed-off-by: Tiffany Lin <tiffany.lin@mediatek.com>
Signed-off-by: Wu-Cheng Li <wuchengli@chromium.org>
Reviewed-by: Kuang-che Wu <kcwu@chromium.org>
---
drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c | 151 ++++++++++++++-------
.../media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 14 ++
drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h | 2 +
3 files changed, 117 insertions(+), 50 deletions(-)
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
index 0746592..407c8ba 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
@@ -351,16 +351,6 @@ static void mtk_vdec_worker(struct work_struct *work)
dst_vb2_v4l2 = container_of(dst_buf, struct vb2_v4l2_buffer, vb2_buf);
dst_buf_info = container_of(dst_vb2_v4l2, struct mtk_video_dec_buf, vb);
- buf.va = vb2_plane_vaddr(src_buf, 0);
- buf.dma_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
- buf.size = (size_t)src_buf->planes[0].bytesused;
- if (!buf.va) {
- v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
- mtk_v4l2_err("[%d] id=%d src_addr is NULL!!",
- ctx->id, src_buf->index);
- return;
- }
-
pfb = &dst_buf_info->frame_buffer;
pfb->base_y.va = vb2_plane_vaddr(dst_buf, 0);
pfb->base_y.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
@@ -371,8 +361,6 @@ static void mtk_vdec_worker(struct work_struct *work)
pfb->base_c.size = ctx->picinfo.c_bs_sz + ctx->picinfo.c_len_sz;
pfb->status = 0;
mtk_v4l2_debug(3, "===>[%d] vdec_if_decode() ===>", ctx->id);
- mtk_v4l2_debug(3, "[%d] Bitstream VA=%p DMA=%pad Size=%zx vb=%p",
- ctx->id, buf.va, &buf.dma_addr, buf.size, src_buf);
mtk_v4l2_debug(3,
"id=%d Framebuf pfb=%p VA=%p Y_DMA=%pad C_DMA=%pad Size=%zx",
@@ -381,24 +369,36 @@ static void mtk_vdec_worker(struct work_struct *work)
&pfb->base_c.dma_addr, pfb->base_y.size);
if (src_buf_info->lastframe) {
- /* update src buf status */
+ mtk_v4l2_debug(1, "Got empty flush input buffer.");
src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
- src_buf_info->lastframe = false;
- v4l2_m2m_buf_done(&src_buf_info->vb, VB2_BUF_STATE_DONE);
/* update dst buf status */
dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+ mutex_lock(&ctx->lock);
dst_buf_info->used = false;
+ mutex_unlock(&ctx->lock);
vdec_if_decode(ctx, NULL, NULL, &res_chg);
clean_display_buffer(ctx);
vb2_set_plane_payload(&dst_buf_info->vb.vb2_buf, 0, 0);
vb2_set_plane_payload(&dst_buf_info->vb.vb2_buf, 1, 0);
+ dst_vb2_v4l2->flags |= V4L2_BUF_FLAG_LAST;
v4l2_m2m_buf_done(&dst_buf_info->vb, VB2_BUF_STATE_DONE);
clean_free_buffer(ctx);
v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
return;
}
+ buf.va = vb2_plane_vaddr(src_buf, 0);
+ buf.dma_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+ buf.size = (size_t)src_buf->planes[0].bytesused;
+ if (!buf.va) {
+ v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
+ mtk_v4l2_err("[%d] id=%d src_addr is NULL!!",
+ ctx->id, src_buf->index);
+ return;
+ }
+ mtk_v4l2_debug(3, "[%d] Bitstream VA=%p DMA=%pad Size=%zx vb=%p",
+ ctx->id, buf.va, &buf.dma_addr, buf.size, src_buf);
dst_buf_info->vb.vb2_buf.timestamp
= src_buf_info->vb.vb2_buf.timestamp;
dst_buf_info->vb.timecode
@@ -412,10 +412,9 @@ static void mtk_vdec_worker(struct work_struct *work)
if (ret) {
mtk_v4l2_err(
- " <===[%d], src_buf[%d]%d sz=0x%zx pts=%llu dst_buf[%d] vdec_if_decode() ret=%d res_chg=%d===>",
+ " <===[%d], src_buf[%d] sz=0x%zx pts=%llu dst_buf[%d] vdec_if_decode() ret=%d res_chg=%d===>",
ctx->id,
src_buf->index,
- src_buf_info->lastframe,
buf.size,
src_buf_info->vb.vb2_buf.timestamp,
dst_buf->index,
@@ -456,6 +455,65 @@ static void mtk_vdec_worker(struct work_struct *work)
v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
}
+static int vidioc_try_decoder_cmd(struct file *file, void *priv,
+ struct v4l2_decoder_cmd *cmd)
+{
+ switch (cmd->cmd) {
+ case V4L2_DEC_CMD_STOP:
+ case V4L2_DEC_CMD_START:
+ if (cmd->flags != 0) {
+ mtk_v4l2_err("cmd->flags=%u", cmd->flags);
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+
+static int vidioc_decoder_cmd(struct file *file, void *priv,
+ struct v4l2_decoder_cmd *cmd)
+{
+ struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+ struct vb2_queue *src_vq, *dst_vq;
+ int ret;
+
+ ret = vidioc_try_decoder_cmd(file, priv, cmd);
+ if (ret)
+ return ret;
+
+ mtk_v4l2_debug(1, "decoder cmd=%u", cmd->cmd);
+ dst_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+ switch (cmd->cmd) {
+ case V4L2_DEC_CMD_STOP:
+ src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
+ V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+ if (!vb2_is_streaming(src_vq)) {
+ mtk_v4l2_debug(1, "Output stream is off. No need to flush.");
+ return 0;
+ }
+ if (!vb2_is_streaming(dst_vq)) {
+ mtk_v4l2_debug(1, "Capture stream is off. No need to flush.");
+ return 0;
+ }
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, &ctx->empty_flush_buf->vb);
+ v4l2_m2m_try_schedule(ctx->m2m_ctx);
+ break;
+
+ case V4L2_DEC_CMD_START:
+ vb2_clear_last_buffer_dequeued(dst_vq);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
void mtk_vdec_unlock(struct mtk_vcodec_ctx *ctx)
{
mutex_unlock(&ctx->dev->dec_mutex);
@@ -521,10 +579,6 @@ static int vidioc_vdec_qbuf(struct file *file, void *priv,
struct v4l2_buffer *buf)
{
struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
- struct vb2_queue *vq;
- struct vb2_buffer *vb;
- struct mtk_video_dec_buf *mtkbuf;
- struct vb2_v4l2_buffer *vb2_v4l2;
if (ctx->state == MTK_STATE_ABORT) {
mtk_v4l2_err("[%d] Call on QBUF after unrecoverable error",
@@ -532,25 +586,6 @@ static int vidioc_vdec_qbuf(struct file *file, void *priv,
return -EIO;
}
- vq = v4l2_m2m_get_vq(ctx->m2m_ctx, buf->type);
- if (buf->index >= vq->num_buffers) {
- mtk_v4l2_debug(1, "buffer index %d out of range", buf->index);
- return -EINVAL;
- }
- vb = vq->bufs[buf->index];
- vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
- mtkbuf = container_of(vb2_v4l2, struct mtk_video_dec_buf, vb);
-
- if ((buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) &&
- (buf->m.planes[0].bytesused == 0)) {
- mtkbuf->lastframe = true;
- mtk_v4l2_debug(1, "[%d] (%d) id=%d lastframe=%d (%d,%d, %d) vb=%p",
- ctx->id, buf->type, buf->index,
- mtkbuf->lastframe, buf->bytesused,
- buf->m.planes[0].bytesused, buf->length,
- vb);
- }
-
return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
}
@@ -1067,10 +1102,8 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb)
int ret = 0;
unsigned int dpbsize = 1;
struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
- struct vb2_v4l2_buffer *vb2_v4l2 = container_of(vb,
- struct vb2_v4l2_buffer, vb2_buf);
- struct mtk_video_dec_buf *buf = container_of(vb2_v4l2,
- struct mtk_video_dec_buf, vb);
+ struct vb2_v4l2_buffer *vb2_v4l2 = NULL;
+ struct mtk_video_dec_buf *buf = NULL;
mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p",
ctx->id, vb->vb2_queue->type,
@@ -1079,10 +1112,11 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb)
* check if this buffer is ready to be used after decode
*/
if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ vb2_v4l2 = to_vb2_v4l2_buffer(vb);
+ buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, vb);
mutex_lock(&ctx->lock);
if (buf->used == false) {
- v4l2_m2m_buf_queue(ctx->m2m_ctx,
- to_vb2_v4l2_buffer(vb));
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2);
buf->queued_in_vb2 = true;
buf->queued_in_v4l2 = true;
buf->ready_to_display = false;
@@ -1095,7 +1129,7 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb)
return;
}
- v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2);
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb));
if (ctx->state != MTK_STATE_INIT) {
mtk_v4l2_debug(3, "[%d] already init driver %d",
@@ -1108,6 +1142,14 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb)
mtk_v4l2_err("No src buffer");
return;
}
+ vb2_v4l2 = to_vb2_v4l2_buffer(src_buf);
+ buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, vb);
+ if (buf->lastframe) {
+ /* This shouldn't happen. Just in case. */
+ mtk_v4l2_err("Invalid flush buffer.");
+ v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+ return;
+ }
src_mem.va = vb2_plane_vaddr(src_buf, 0);
src_mem.dma_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
@@ -1224,9 +1266,15 @@ static void vb2ops_vdec_stop_streaming(struct vb2_queue *q)
ctx->id, q->type, ctx->state, ctx->decoded_frame_cnt);
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- while ((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx)))
- v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf),
- VB2_BUF_STATE_ERROR);
+ while ((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) {
+ struct vb2_v4l2_buffer *vb2_v4l2 =
+ to_vb2_v4l2_buffer(src_buf);
+ struct mtk_video_dec_buf *buf_info = container_of(
+ vb2_v4l2, struct mtk_video_dec_buf, vb);
+ if (!buf_info->lastframe)
+ v4l2_m2m_buf_done(vb2_v4l2,
+ VB2_BUF_STATE_ERROR);
+ }
return;
}
@@ -1406,6 +1454,9 @@ const struct v4l2_ioctl_ops mtk_vdec_ioctl_ops = {
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
.vidioc_g_selection = vidioc_vdec_g_selection,
.vidioc_s_selection = vidioc_vdec_s_selection,
+
+ .vidioc_decoder_cmd = vidioc_decoder_cmd,
+ .vidioc_try_decoder_cmd = vidioc_try_decoder_cmd,
};
int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq,
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
index d48287c..4334b73 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
@@ -105,13 +105,21 @@ static int fops_vcodec_open(struct file *file)
{
struct mtk_vcodec_dev *dev = video_drvdata(file);
struct mtk_vcodec_ctx *ctx = NULL;
+ struct mtk_video_dec_buf *mtk_buf = NULL;
int ret = 0;
+ struct vb2_queue *src_vq;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
+ mtk_buf = kzalloc(sizeof(*mtk_buf), GFP_KERNEL);
+ if (!mtk_buf) {
+ kfree(ctx);
+ return -ENOMEM;
+ }
mutex_lock(&dev->dev_mutex);
+ ctx->empty_flush_buf = mtk_buf;
ctx->id = dev->id_counter++;
v4l2_fh_init(&ctx->fh, video_devdata(file));
file->private_data = &ctx->fh;
@@ -135,6 +143,10 @@ static int fops_vcodec_open(struct file *file)
ret);
goto err_m2m_ctx_init;
}
+ src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
+ V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+ ctx->empty_flush_buf->vb.vb2_buf.vb2_queue = src_vq;
+ ctx->empty_flush_buf->lastframe = true;
mtk_vcodec_dec_set_default_params(ctx);
if (v4l2_fh_is_singular(&ctx->fh)) {
@@ -173,6 +185,7 @@ static int fops_vcodec_open(struct file *file)
err_ctrls_setup:
v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh);
+ kfree(ctx->empty_flush_buf);
kfree(ctx);
mutex_unlock(&dev->dev_mutex);
@@ -203,6 +216,7 @@ static int fops_vcodec_release(struct file *file)
v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
list_del_init(&ctx->list);
+ kfree(ctx->empty_flush_buf);
kfree(ctx);
mutex_unlock(&dev->dev_mutex);
return 0;
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
index d7eb8ef..3cffb38 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
@@ -254,6 +254,7 @@ struct vdec_pic_info {
* @decode_work: worker for the decoding
* @encode_work: worker for the encoding
* @last_decoded_picinfo: pic information get from latest decode
+ * @empty_flush_buf: a fake size-0 capture buffer that indicates flush
*
* @colorspace: enum v4l2_colorspace; supplemental to pixelformat
* @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding
@@ -291,6 +292,7 @@ struct mtk_vcodec_ctx {
struct work_struct decode_work;
struct work_struct encode_work;
struct vdec_pic_info last_decoded_picinfo;
+ struct mtk_video_dec_buf *empty_flush_buf;
enum v4l2_colorspace colorspace;
enum v4l2_ycbcr_encoding ycbcr_enc;
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* [RFC PATCH 0/2] arm64: memory-hotplug: Add Memory Hotplug support
From: Scott Branden @ 2016-12-02 2:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <5840D333.9050801@huawei.com>
Hi Xishi,
Thanks for the reply - please see comments below.
On 16-12-01 05:49 PM, Xishi Qiu wrote:
> On 2016/12/2 8:19, Scott Branden wrote:
>
>> This patchset is sent for comment to add memory hotplug support for ARM64
>> based platforms. It follows hotplug code added for other architectures
>> in the linux kernel.
>>
>> I tried testing the memory hotplug feature following documentation from
>> Documentation/memory-hotplug.txt. I don't think it is working as expected
>> - see below:
>>
>> To add memory to the system I did the following:
>> echo 0x400000000 > /sys/devices/system/memory/probe
>>
>> The memory is displayed as system ram:
>> cat /proc/iomem:
>> 74000000-77ffffff : System RAM
>> 74080000-748dffff : Kernel code
>> 74950000-749d2fff : Kernel data
>> 400000000-43fffffff : System RAM
>>
>> But does not seem to be added to the kernel memory.
>> /proc/meminfo did not change.
>>
>> What else needs to be done so the memory is added to the kernel memory
>> pool for normal allocation?
>>
>
> Hi Scott,
>
> Do you mean it still don't support hod-add after apply this patchset?
After applying the patch it appears to partially support hot-add.
Please let me know if you think it is working as expected?
The memory probe functions in that the memory is registered with the
system and shows up in /proc/iomem. But, the memory is not available in
/proc/meminfo. Do you think something else needs to be adjusted for
ARM64 to hotadd the memory
I just found another clue:
under /sys/devices/system/memory I only see one memory entry (before or
after I try to hotadd additional memory).
/sys/devices/system/memory # ls
auto_online_blocks memory0 uevent
block_size_bytes probe
In arch/arm64/include/asm/sparsemem.h if I change SECTION_SIZE_BITS from
30 to 28 and recompile I get the following:
/sys/devices/system/memory # ls
auto_online_blocks memory7 uevent
block_size_bytes probe
In arch/arm64/include/asm/sparsemem.h if I change SECTION_SIZE_BITS from
30 to 27 and recompile I get the following:
/sys/devices/system/memory # ls
auto_online_blocks memory14 uevent
block_size_bytes probe
If looks to me like something is not working properly in the ARM64
implementation. I should expect to see multiple memoryX entries under
/sys/devices/system/memory?
>
> Thanks,
> Xishi Qiu
>
>> Scott Branden (2):
>> arm64: memory-hotplug: Add MEMORY_HOTPLUG, MEMORY_HOTREMOVE,
>> MEMORY_PROBE
>> arm64: defconfig: enable MEMORY_HOTPLUG config options
>>
>> arch/arm64/Kconfig | 10 ++++++++++
>> arch/arm64/configs/defconfig | 3 +++
>> arch/arm64/mm/init.c | 42 ++++++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 55 insertions(+)
>>
>
>
>
^ permalink raw reply
* [PATCH v3] PCI/ACPI: xgene: Add ECAM quirk for X-Gene PCIe controller
From: Duc Dang @ 2016-12-02 2:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161201183350.GF30746@bhelgaas-glaptop.roam.corp.google.com>
On Thu, Dec 1, 2016 at 10:33 AM, Bjorn Helgaas <helgaas@kernel.org> wrote:
> Hi Duc,
>
> On Wed, Nov 30, 2016 at 03:42:53PM -0800, Duc Dang wrote:
>> PCIe controllers in X-Gene SoCs is not ECAM compliant: software
>> needs to configure additional controller's register to address
>> device at bus:dev:function.
>>
>> The quirk will only be applied for X-Gene PCIe MCFG table with
>> OEM revison 1, 2, 3 or 4 (PCIe controller v1 and v2 on X-Gene SoCs).
>>
>> The quirk declares the X-Gene PCIe controller register space as 64KB
>> fixed memory resource with name "PCIe CSR". This name will be showed
>> next to the resource range in the output of "cat /proc/iomem".
>>
>> Signed-off-by: Duc Dang <dhdang@apm.com>
>> ---
>> v3:
>> - Rebase on top of pci/ecam-v6 tree.
>> - Use DEFINE_RES_MEM_NAMED to declare controller register space
>> with name "PCIe CSR"
>> v2:
>> RFC v2: https://patchwork.ozlabs.org/patch/686846/
>> v1:
>> RFC v1: https://patchwork.kernel.org/patch/9337115/
>>
>> drivers/acpi/pci_mcfg.c | 31 ++++++++
>> drivers/pci/host/pci-xgene.c | 165 ++++++++++++++++++++++++++++++++++++++++++-
>> include/linux/pci-ecam.h | 7 ++
>> 3 files changed, 200 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
>> index ac21db3..eb6125b 100644
>> --- a/drivers/acpi/pci_mcfg.c
>> +++ b/drivers/acpi/pci_mcfg.c
>> @@ -57,6 +57,37 @@ struct mcfg_fixup {
>> { "QCOM ", "QDF2432 ", 1, 5, MCFG_BUS_ANY, &pci_32b_ops },
>> { "QCOM ", "QDF2432 ", 1, 6, MCFG_BUS_ANY, &pci_32b_ops },
>> { "QCOM ", "QDF2432 ", 1, 7, MCFG_BUS_ANY, &pci_32b_ops },
>> +
>> +#ifdef CONFIG_PCI_XGENE
>
> As you've no doubt noticed, I'm proposing to add these quirks without
> CONFIG_PCI_XGENE, so we don't have to select each device when building
> a generic ACPI kernel.
>
> I'm also proposing some Kconfig and Makefile changes so we don't build
> the platform driver part in a generic ACPI kernel (unless we *also*
> explicitly select the platform driver).
>
> Here's an example:
> https://git.kernel.org/cgit/linux/kernel/git/helgaas/pci.git/commit/?h=pci/ecam&id=f80edf4d6c05
I made similar changes in v4 patch. The ECAM quirk will be built when
ACPI and PCI_QUIRKS are enabled.
When building for DT only, the ECAM quirk won't be compiled.
>
>> +#define XGENE_V1_ECAM_MCFG(rev, seg) \
>> + {"APM ", "XGENE ", rev, seg, MCFG_BUS_ANY, \
>> + &xgene_v1_pcie_ecam_ops }
>> +#define XGENE_V2_1_ECAM_MCFG(rev, seg) \
>> + {"APM ", "XGENE ", rev, seg, MCFG_BUS_ANY, \
>> + &xgene_v2_1_pcie_ecam_ops }
>> +#define XGENE_V2_2_ECAM_MCFG(rev, seg) \
>> + {"APM ", "XGENE ", rev, seg, MCFG_BUS_ANY, \
>> + &xgene_v2_2_pcie_ecam_ops }
>> +
>> + /* X-Gene SoC with v1 PCIe controller */
>> + XGENE_V1_ECAM_MCFG(1, 0),
>> + XGENE_V1_ECAM_MCFG(1, 1),
>
>> @@ -64,6 +66,7 @@
>> /* PCIe IP version */
>> #define XGENE_PCIE_IP_VER_UNKN 0
>> #define XGENE_PCIE_IP_VER_1 1
>> +#define XGENE_PCIE_IP_VER_2 2
>
> This isn't used anywhere, which makes me wonder whether it's worth
> keeping it.
V2 controller will use this XGENE_PCIE_IP_VER_2 (port->version =
XGENE_PCIE_IP_VER_2). This will be used to indicate that the
controller is V2, and to enable configuration request retry status
feature (by not disable it like V1 controller).
>
>> static void __iomem *xgene_pcie_get_cfg_base(struct pci_bus *bus)
>> {
>> - struct xgene_pcie_port *port = bus->sysdata;
>> + struct pci_config_window *cfg;
>> + struct xgene_pcie_port *port;
>> +
>> + if (acpi_disabled)
>> + port = bus->sysdata;
>> + else {
>> + cfg = bus->sysdata;
>> + port = cfg->priv;
>> + }
>
> I would really, really like to figure out a way to get rid of these
> "if (acpi_disabled)" checks sprinkled through here. Is there any way
> we can set up bus->sysdata to be the same, regardless of whether we're
> using this as a platform driver or an ACPI quirk?
Right now, I created a inline function to extract xgene_pcie_port from
pci_bus. In order to get rid of acpi_disabled, I will need to make
sysdata in DT case also point to pci_config_window structure, which
means I will need to convert and test the DT driver to use ecam ops.
It is a separate patch itself. So I think I should do it at later time
(after this ECAM quirk patch). I hope you are ok with this.
>
>> +#ifdef CONFIG_ACPI
>
> You've probably noticed that I've been using
>
> #if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
>
> in this situation, mostly to make it clear that this is part of a
> workaround. I don't want people to blindly copy this stuff without
> realizing that it's a workaround for a hardware issue.
Yes, I used defined(CONFIG_PCI_QUIRKS) in v4 patch as well.
>
>> +static struct resource xgene_v1_csr_res[] = {
>> + [0] = DEFINE_RES_MEM_NAMED(0x1f2b0000UL, SZ_64K, "PCIe CSR"),
>> + [1] = DEFINE_RES_MEM_NAMED(0x1f2c0000UL, SZ_64K, "PCIe CSR"),
>> + [2] = DEFINE_RES_MEM_NAMED(0x1f2d0000UL, SZ_64K, "PCIe CSR"),
>> + [3] = DEFINE_RES_MEM_NAMED(0x1f500000UL, SZ_64K, "PCIe CSR"),
>> + [4] = DEFINE_RES_MEM_NAMED(0x1f510000UL, SZ_64K, "PCIe CSR"),
>
> I assume these ranges are not the actual ECAM space, right?
> If they *were* ECAM, I assume you would have included them in the
> quirk itself in the mcfg_quirks[] table.
Yes, as Mark also pointed out. These are MMIO space for controller registers.
>
>> +static int xgene_v1_pcie_ecam_init(struct pci_config_window *cfg)
>> +{
>> + struct acpi_device *adev = to_acpi_device(cfg->parent);
>> + struct acpi_pci_root *root = acpi_driver_data(adev);
>> + struct device *dev = cfg->parent;
>> + struct xgene_pcie_port *port;
>> + struct resource *csr;
>> +
>> + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
>> + if (!port)
>> + return -ENOMEM;
>> +
>> + csr = &xgene_v1_csr_res[root->segment];
>
> This makes me nervous because root->segment comes from the ACPI _SEG,
> and if firmware gives us junk in _SEG, we will reference something in
> the weeds.
I use Mark's approach in v4 patch (discover the MMIO space using
acpi_dev_get_resources. Both approach have pros and cons. I can also
fallback to hard-coded resource array if you want to, but as you
mentioned right above, we will need to rely on firmware for correct
_SEG information.
I need to define the function (xgene_get_csr_resource()) inside
pci-xgene.c to duplicate the code of acpi_get_rc_addr. The reason is
X-Gene firmware does not have a dedicate PNP0C02 node to declare the
resource, and if I use acpi_get_rc_resources() with "PNP0A08", I got
error due to acpi_bus_get_device() returns error.
>
>> + port->csr_base = devm_ioremap_resource(dev, csr);
>> + if (IS_ERR(port->csr_base)) {
>> + kfree(port);
>> + return -ENOMEM;
>> + }
>> +
>> + port->cfg_base = cfg->win;
>> + port->version = XGENE_PCIE_IP_VER_1;
>> +
>> + cfg->priv = port;
>
> All these init functions are almost identical. Can we factor this out
> by having wrappers that do nothing more than pass in the table and
> version, and put the kzalloc and ioremap in a shared back-end?
I refactor-ed these .init functions. And as a result, there are only 2
ecam ops left: xgene_v1_pcie_ecam_ops and xgene_v2_pcie_ecam_ops.
>
> We're so close I can taste it! I can't wait to see all this work come
> to fruition.
>
> Bjorn
Regards,
Duc Dang.
^ permalink raw reply
* arm64: dts: zx: support cpu-freq for zx296718
From: Viresh Kumar @ 2016-12-02 2:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161202023627.GA6657@dragon>
On 02-12-16, 10:36, Shawn Guo wrote:
> + Viresh, the author of the bindings.
>
> On Thu, Dec 01, 2016 at 08:08:55PM +0800, Baoyou Xie wrote:
> > This patch adds the CPU clock phandle in CPU's node
> > and uses operating-points-v2 to register operating points.
> >
> > So it can be used by cpufreq-dt driver.
> >
> > Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
>
> Just out of curiosity, why is there no '[PATCH]' prefix in the subject?
>
> > ---
> > arch/arm64/boot/dts/zte/zx296718.dtsi | 37 +++++++++++++++++++++++++++++++++++
> > 1 file changed, 37 insertions(+)
> >
> > diff --git a/arch/arm64/boot/dts/zte/zx296718.dtsi b/arch/arm64/boot/dts/zte/zx296718.dtsi
> > index 7a1aed7..16f7d5e 100644
> > --- a/arch/arm64/boot/dts/zte/zx296718.dtsi
> > +++ b/arch/arm64/boot/dts/zte/zx296718.dtsi
> > @@ -44,6 +44,7 @@
> > #include <dt-bindings/input/input.h>
> > #include <dt-bindings/interrupt-controller/arm-gic.h>
> > #include <dt-bindings/gpio/gpio.h>
> > +#include <dt-bindings/clock/zx296718-clock.h>
> >
> > / {
> > compatible = "zte,zx296718";
> > @@ -81,6 +82,8 @@
> > compatible = "arm,cortex-a53","arm,armv8";
> > reg = <0x0 0x0>;
> > enable-method = "psci";
> > + clocks = <&topcrm A53_GATE>;
> > + operating-points-v2 = <&cluster0_opp>;
> > };
> >
> > cpu1: cpu at 1 {
> > @@ -88,6 +91,7 @@
> > compatible = "arm,cortex-a53","arm,armv8";
> > reg = <0x0 0x1>;
> > enable-method = "psci";
> > + operating-points-v2 = <&cluster0_opp>;
> > };
> >
> > cpu2: cpu at 2 {
> > @@ -95,6 +99,7 @@
> > compatible = "arm,cortex-a53","arm,armv8";
> > reg = <0x0 0x2>;
> > enable-method = "psci";
> > + operating-points-v2 = <&cluster0_opp>;
> > };
> >
> > cpu3: cpu at 3 {
> > @@ -102,6 +107,38 @@
> > compatible = "arm,cortex-a53","arm,armv8";
> > reg = <0x0 0x3>;
> > enable-method = "psci";
> > + operating-points-v2 = <&cluster0_opp>;
> > + };
> > + };
> > +
> > + cluster0_opp: opp_table0 {
Also, you better add "clocks" property in all above nodes.
--
viresh
^ permalink raw reply
* [RFC PATCH 0/2] arm64: memory-hotplug: Add Memory Hotplug support
From: Xishi Qiu @ 2016-12-02 3:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <9cfa95ca-a9e9-299d-d020-7e565562dcf5@broadcom.com>
On 2016/12/2 10:38, Scott Branden wrote:
> Hi Xishi,
>
> Thanks for the reply - please see comments below.
>
> On 16-12-01 05:49 PM, Xishi Qiu wrote:
>> On 2016/12/2 8:19, Scott Branden wrote:
>>
>>> This patchset is sent for comment to add memory hotplug support for ARM64
>>> based platforms. It follows hotplug code added for other architectures
>>> in the linux kernel.
>>>
>>> I tried testing the memory hotplug feature following documentation from
>>> Documentation/memory-hotplug.txt. I don't think it is working as expected
>>> - see below:
>>>
>>> To add memory to the system I did the following:
>>> echo 0x400000000 > /sys/devices/system/memory/probe
>>>
>>> The memory is displayed as system ram:
>>> cat /proc/iomem:
>>> 74000000-77ffffff : System RAM
>>> 74080000-748dffff : Kernel code
>>> 74950000-749d2fff : Kernel data
>>> 400000000-43fffffff : System RAM
>>>
>>> But does not seem to be added to the kernel memory.
>>> /proc/meminfo did not change.
>>>
>>> What else needs to be done so the memory is added to the kernel memory
>>> pool for normal allocation?
>>>
>>
>> Hi Scott,
>>
>> Do you mean it still don't support hod-add after apply this patchset?
>
> After applying the patch it appears to partially support hot-add. Please let me know if you think it is working as expected?
>
> The memory probe functions in that the memory is registered with the system and shows up in /proc/iomem. But, the memory is not available in /proc/meminfo. Do you think something else needs to be adjusted for ARM64 to hotadd the memory
>
> I just found another clue:
> under /sys/devices/system/memory I only see one memory entry (before or after I try to hotadd additional memory).
>
> /sys/devices/system/memory # ls
> auto_online_blocks memory0 uevent
> block_size_bytes probe
>
> In arch/arm64/include/asm/sparsemem.h if I change SECTION_SIZE_BITS from 30 to 28 and recompile I get the following:
> /sys/devices/system/memory # ls
> auto_online_blocks memory7 uevent
> block_size_bytes probe
>
>
> In arch/arm64/include/asm/sparsemem.h if I change SECTION_SIZE_BITS from 30 to 27 and recompile I get the following:
> /sys/devices/system/memory # ls
> auto_online_blocks memory14 uevent
> block_size_bytes probe
>
> If looks to me like something is not working properly in the ARM64 implementation. I should expect to see multiple memoryX entries under /sys/devices/system/memory?
>
Hi Scott,
1. Do you enable the following configs?
CONFIG_SPARSEMEM
MEMORY_HOTPLUG
CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE
2. I find you missed create mapping in arch_add_memory(), and x86 has it.
3. We will add memblock first, so pfn_valid() maybe always return true(in the
following function), and this will lead __add_section() failed. Please check
it.
int pfn_valid(unsigned long pfn)
{
return (pfn & PFN_MASK) == pfn && memblock_is_memory(pfn << PAGE_SHIFT);
}
add_memory
add_memory_resource
memblock_add_node
arch_add_memory
__add_pages
__add_section
pfn_valid
Thanks,
Xishi Qiu
>
>
>>
>> Thanks,
>> Xishi Qiu
>>
>>> Scott Branden (2):
>>> arm64: memory-hotplug: Add MEMORY_HOTPLUG, MEMORY_HOTREMOVE,
>>> MEMORY_PROBE
>>> arm64: defconfig: enable MEMORY_HOTPLUG config options
>>>
>>> arch/arm64/Kconfig | 10 ++++++++++
>>> arch/arm64/configs/defconfig | 3 +++
>>> arch/arm64/mm/init.c | 42 ++++++++++++++++++++++++++++++++++++++++++
>>> 3 files changed, 55 insertions(+)
>>>
>>
>>
>>
>
> .
>
^ permalink raw reply
* [PATCH 0/2] Add MediaTek crypto acclelrator driver
From: Ryder Lee @ 2016-12-02 3:26 UTC (permalink / raw)
To: linux-arm-kernel
This adds support for the MediaTek hardware accelerator on
mt7623 SoC.
This driver currently implement:
- SHA1 and SHA2 family(HMAC) hash alogrithms.
- AES block cipher in CBC/ECB mode with 128/196/256 bits keys.
Ryder Lee (2):
Add crypto driver support for some MediaTek chips
crypto: mediatek - add DT bindings documentation
.../devicetree/bindings/crypto/mediatek-crypto.txt | 32 +
drivers/crypto/Kconfig | 17 +
drivers/crypto/Makefile | 1 +
drivers/crypto/mediatek/Makefile | 2 +
drivers/crypto/mediatek/mtk-aes.c | 734 +++++++++++
drivers/crypto/mediatek/mtk-platform.c | 575 ++++++++
drivers/crypto/mediatek/mtk-platform.h | 230 ++++
drivers/crypto/mediatek/mtk-regs.h | 194 +++
drivers/crypto/mediatek/mtk-sha.c | 1384 ++++++++++++++++++++
9 files changed, 3169 insertions(+)
create mode 100644 Documentation/devicetree/bindings/crypto/mediatek-crypto.txt
create mode 100644 drivers/crypto/mediatek/Makefile
create mode 100644 drivers/crypto/mediatek/mtk-aes.c
create mode 100644 drivers/crypto/mediatek/mtk-platform.c
create mode 100644 drivers/crypto/mediatek/mtk-platform.h
create mode 100644 drivers/crypto/mediatek/mtk-regs.h
create mode 100644 drivers/crypto/mediatek/mtk-sha.c
--
1.9.1
^ permalink raw reply
* [PATCH 1/2] Add crypto driver support for some MediaTek chips
From: Ryder Lee @ 2016-12-02 3:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480649205-52695-1-git-send-email-ryder.lee@mediatek.com>
This adds support for the MediaTek hardware accelerator on
mt7623/mt2701/mt8521p SoC.
This driver currently implement:
- SHA1 and SHA2 family(HMAC) hash alogrithms.
- AES block cipher in CBC/ECB mode with 128/196/256 bits keys.
Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
---
drivers/crypto/Kconfig | 17 +
drivers/crypto/Makefile | 1 +
drivers/crypto/mediatek/Makefile | 2 +
drivers/crypto/mediatek/mtk-aes.c | 734 +++++++++++++++++
drivers/crypto/mediatek/mtk-platform.c | 575 +++++++++++++
drivers/crypto/mediatek/mtk-platform.h | 230 ++++++
drivers/crypto/mediatek/mtk-regs.h | 194 +++++
drivers/crypto/mediatek/mtk-sha.c | 1384 ++++++++++++++++++++++++++++++++
8 files changed, 3137 insertions(+)
create mode 100644 drivers/crypto/mediatek/Makefile
create mode 100644 drivers/crypto/mediatek/mtk-aes.c
create mode 100644 drivers/crypto/mediatek/mtk-platform.c
create mode 100644 drivers/crypto/mediatek/mtk-platform.h
create mode 100644 drivers/crypto/mediatek/mtk-regs.h
create mode 100644 drivers/crypto/mediatek/mtk-sha.c
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 4d2b81f..5d9c803 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -553,6 +553,23 @@ config CRYPTO_DEV_ROCKCHIP
This driver interfaces with the hardware crypto accelerator.
Supporting cbc/ecb chainmode, and aes/des/des3_ede cipher mode.
+config CRYPTO_DEV_MEDIATEK
+ tristate "MediaTek's Cryptographic Engine driver"
+ depends on ARM && ARCH_MEDIATEK
+ select NEON
+ select KERNEL_MODE_NEON
+ select ARM_CRYPTO
+ select CRYPTO_AES
+ select CRYPTO_BLKCIPHER
+ select CRYPTO_SHA1_ARM_NEON
+ select CRYPTO_SHA256_ARM
+ select CRYPTO_SHA512_ARM
+ select CRYPTO_HMAC
+ help
+ This driver allows you to utilize the hardware crypto accelerator
+ which can be found on the MT7623 MT2701, MT8521p, etc ....
+ Select this if you want to use it for AES/SHA1/SHA2 algorithms.
+
source "drivers/crypto/chelsio/Kconfig"
endif # CRYPTO_HW
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index ad7250f..272b51a 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_CRYPTO_DEV_IMGTEC_HASH) += img-hash.o
obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o
obj-$(CONFIG_CRYPTO_DEV_MV_CESA) += mv_cesa.o
obj-$(CONFIG_CRYPTO_DEV_MARVELL_CESA) += marvell/
+obj-$(CONFIG_CRYPTO_DEV_MEDIATEK) += mediatek/
obj-$(CONFIG_CRYPTO_DEV_MXS_DCP) += mxs-dcp.o
obj-$(CONFIG_CRYPTO_DEV_NIAGARA2) += n2_crypto.o
n2_crypto-y := n2_core.o n2_asm.o
diff --git a/drivers/crypto/mediatek/Makefile b/drivers/crypto/mediatek/Makefile
new file mode 100644
index 0000000..187be79
--- /dev/null
+++ b/drivers/crypto/mediatek/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_CRYPTO_DEV_MEDIATEK) += mtk-crypto.o
+mtk-crypto-objs:= mtk-platform.o mtk-aes.o mtk-sha.o
diff --git a/drivers/crypto/mediatek/mtk-aes.c b/drivers/crypto/mediatek/mtk-aes.c
new file mode 100644
index 0000000..feb0e57
--- /dev/null
+++ b/drivers/crypto/mediatek/mtk-aes.c
@@ -0,0 +1,734 @@
+/*
+ * Cryptographic API.
+ *
+ * Support for MediaTek AES hardware accelerator.
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.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.
+ *
+ * Some ideas are from atmel-aes.c drivers.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/algapi.h>
+#include <crypto/aes.h>
+#include "mtk-platform.h"
+#include "mtk-regs.h"
+
+#define AES_QUEUE_LENGTH 512
+#define AES_BUFFER_ORDER 2
+#define AES_BUFFER_SIZE ((PAGE_SIZE << AES_BUFFER_ORDER) \
+ & ~(AES_BLOCK_SIZE - 1))
+
+/* AES command token */
+#define AES_CT_SIZE_ECB 2
+#define AES_CT_SIZE_CBC 3
+#define AES_CT_CTRL_HDR 0x00220000
+#define AES_COMMAND0 0x05000000
+#define AES_COMMAND1 0x2d060000
+#define AES_COMMAND2 0xe4a63806
+
+/* AES transform information */
+#define AES_TFM_ECB (0x0 << 0)
+#define AES_TFM_CBC (0x1 << 0)
+#define AES_TFM_DECRYPT (0x5 << 0)
+#define AES_TFM_ENCRYPT (0x4 << 0)
+#define AES_TFM_SIZE(x) ((x) << 8)
+#define AES_TFM_128BITS (0xb << 16)
+#define AES_TFM_192BITS (0xd << 16)
+#define AES_TFM_256BITS (0xf << 16)
+#define AES_TFM_FULL_IV (0xf << 5)
+
+/* AES flags */
+#define AES_FLAGS_MODE_MSK GENMASK(2, 0)
+#define AES_FLAGS_ECB BIT(0)
+#define AES_FLAGS_CBC BIT(1)
+#define AES_FLAGS_ENCRYPT BIT(2)
+#define AES_FLAGS_BUSY BIT(3)
+
+/* AES command token */
+struct mtk_aes_ct {
+ u32 ct_ctrl0;
+ u32 ct_ctrl1;
+ u32 ct_ctrl2;
+};
+
+/* AES transform info */
+struct mtk_aes_tfm {
+ u32 tfm_ctrl0;
+ u32 tfm_ctrl1;
+
+ /* keys and IVs */
+ u8 state[AES_KEYSIZE_256 + AES_BLOCK_SIZE] __aligned(sizeof(u32));
+};
+
+struct mtk_aes_info {
+ struct mtk_aes_ct ct;
+ struct mtk_aes_tfm tfm;
+};
+
+struct mtk_aes_reqctx {
+ u64 mode;
+};
+
+struct mtk_aes_ctx {
+ struct mtk_cryp *cryp;
+ struct mtk_aes_info info;
+ u32 keylen;
+
+ unsigned long flags;
+};
+
+struct mtk_aes_drv {
+ struct list_head dev_list;
+ /* device list lock */
+ spinlock_t lock;
+};
+
+static struct mtk_aes_drv mtk_aes = {
+ .dev_list = LIST_HEAD_INIT(mtk_aes.dev_list),
+ .lock = __SPIN_LOCK_UNLOCKED(mtk_aes.lock),
+};
+
+static inline u32 mtk_aes_read(struct mtk_cryp *cryp, u32 offset)
+{
+ return readl_relaxed(cryp->base + offset);
+}
+
+static inline void mtk_aes_write(struct mtk_cryp *cryp,
+ u32 offset, u32 value)
+{
+ writel_relaxed(value, cryp->base + offset);
+}
+
+static struct mtk_cryp *mtk_aes_find_dev(struct mtk_aes_ctx *ctx)
+{
+ struct mtk_cryp *cryp = NULL;
+ struct mtk_cryp *tmp;
+
+ spin_lock_bh(&mtk_aes.lock);
+ if (!ctx->cryp) {
+ list_for_each_entry(tmp, &mtk_aes.dev_list, aes_list) {
+ cryp = tmp;
+ break;
+ }
+ ctx->cryp = cryp;
+ } else {
+ cryp = ctx->cryp;
+ }
+ spin_unlock_bh(&mtk_aes.lock);
+
+ return cryp;
+}
+
+static inline size_t mtk_aes_padlen(size_t len)
+{
+ len &= AES_BLOCK_SIZE - 1;
+ return len ? AES_BLOCK_SIZE - len : 0;
+}
+
+static bool mtk_aes_check_aligned(struct scatterlist *sg,
+ size_t len, struct mtk_aes_dma *dma)
+{
+ int nents;
+
+ if (!IS_ALIGNED(len, AES_BLOCK_SIZE))
+ return false;
+
+ for (nents = 0; sg; sg = sg_next(sg), ++nents) {
+ if (!IS_ALIGNED(sg->offset, sizeof(u32)))
+ return false;
+
+ if (len <= sg->length) {
+ if (!IS_ALIGNED(len, AES_BLOCK_SIZE))
+ return false;
+
+ dma->nents = nents + 1;
+ dma->remainder = sg->length - len;
+ sg->length = len;
+ return true;
+ }
+
+ if (!IS_ALIGNED(sg->length, AES_BLOCK_SIZE))
+ return false;
+
+ len -= sg->length;
+ }
+
+ return false;
+}
+
+static int mtk_aes_info_map(struct mtk_cryp *cryp,
+ struct mtk_aes *aes, size_t len)
+{
+ struct mtk_aes_ctx *ctx = crypto_ablkcipher_ctx(
+ crypto_ablkcipher_reqtfm(aes->req));
+ struct mtk_aes_info *info = aes->info;
+ struct mtk_aes_ct *ct = &info->ct;
+ struct mtk_aes_tfm *tfm = &info->tfm;
+ u32 keylen = ctx->keylen;
+
+ aes->ct_hdr = AES_CT_CTRL_HDR | len;
+ ct->ct_ctrl0 = AES_COMMAND0 | len;
+ ct->ct_ctrl1 = AES_COMMAND1;
+
+ if (aes->flags & AES_FLAGS_ENCRYPT)
+ tfm->tfm_ctrl0 = AES_TFM_ENCRYPT;
+ else
+ tfm->tfm_ctrl0 = AES_TFM_DECRYPT;
+
+ if (aes->flags & AES_FLAGS_CBC) {
+ aes->ct_size = AES_CT_SIZE_CBC;
+ ct->ct_ctrl2 = AES_COMMAND2;
+
+ tfm->tfm_ctrl0 |= AES_TFM_SIZE(WORD(keylen + AES_BLOCK_SIZE));
+ tfm->tfm_ctrl1 = AES_TFM_CBC;
+ tfm->tfm_ctrl1 |= AES_TFM_FULL_IV;
+
+ memcpy(tfm->state + keylen, aes->req->info, AES_BLOCK_SIZE);
+ } else if (aes->flags & AES_FLAGS_ECB) {
+ aes->ct_size = AES_CT_SIZE_ECB;
+ tfm->tfm_ctrl0 |= AES_TFM_SIZE(WORD(keylen));
+ tfm->tfm_ctrl1 = AES_TFM_ECB;
+ }
+
+ if (keylen == AES_KEYSIZE_128)
+ tfm->tfm_ctrl0 |= AES_TFM_128BITS;
+ else if (keylen == AES_KEYSIZE_256)
+ tfm->tfm_ctrl0 |= AES_TFM_256BITS;
+ else if (keylen == AES_KEYSIZE_192)
+ tfm->tfm_ctrl0 |= AES_TFM_192BITS;
+
+ aes->ct_dma = dma_map_single(cryp->dev, info, sizeof(*info),
+ DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(cryp->dev, aes->ct_dma))) {
+ dev_err(cryp->dev, "dma %d bytes error\n", sizeof(*info));
+ return -EINVAL;
+ }
+ aes->tfm_dma = aes->ct_dma + sizeof(*ct);
+
+ return 0;
+}
+
+static int mtk_aes_xmit(struct mtk_cryp *cryp, struct mtk_aes *aes)
+{
+ struct mtk_ring *ring = cryp->ring[aes->id];
+ struct mtk_desc *cmd = NULL, *res = NULL;
+ struct scatterlist *ssg, *dsg;
+ u32 len = aes->src.sg_len;
+ int nents;
+
+ for (nents = 0; nents < len; ++nents) {
+ ssg = &aes->src.sg[nents];
+ dsg = &aes->dst.sg[nents];
+
+ cmd = ring->cmd_base + ring->pos;
+ res = ring->res_base + ring->pos;
+
+ res->hdr = MTK_DESC_BUF_LEN(dsg->length);
+ res->buf = sg_dma_address(dsg);
+
+ cmd->hdr = MTK_DESC_BUF_LEN(ssg->length);
+ cmd->buf = sg_dma_address(ssg);
+
+ if (nents == 0) {
+ res->hdr |= MTK_DESC_FIRST;
+ cmd->hdr |= MTK_DESC_FIRST;
+ cmd->hdr |= MTK_DESC_CT_LEN(aes->ct_size);
+ cmd->ct = aes->ct_dma;
+ cmd->ct_hdr = aes->ct_hdr;
+ cmd->tfm = aes->tfm_dma;
+ }
+
+ if (++ring->pos == MTK_MAX_DESC_NUM)
+ ring->pos = 0;
+ }
+
+ cmd->hdr |= MTK_DESC_LAST;
+ res->hdr |= MTK_DESC_LAST;
+
+ /* make sure all descriptor are filled done */
+ wmb();
+ mtk_aes_write(cryp, RDR_PREP_COUNT(aes->id), MTK_DESC_CNT(len));
+ mtk_aes_write(cryp, CDR_PREP_COUNT(aes->id), MTK_DESC_CNT(len));
+
+ return -EINPROGRESS;
+}
+
+static inline void mtk_aes_restore_sg(const struct mtk_aes_dma *dma)
+{
+ struct scatterlist *sg = dma->sg;
+ int nents = dma->nents;
+
+ if (!dma->remainder)
+ return;
+
+ while (--nents > 0 && sg)
+ sg = sg_next(sg);
+
+ if (!sg)
+ return;
+
+ sg->length += dma->remainder;
+}
+
+static int mtk_aes_map(struct mtk_cryp *cryp, struct mtk_aes *aes)
+{
+ struct scatterlist *src = aes->req->src;
+ struct scatterlist *dst = aes->req->dst;
+ size_t len = aes->req->nbytes;
+ size_t padlen = 0;
+ bool src_aligned, dst_aligned;
+
+ aes->total = len;
+ aes->src.sg = src;
+ aes->dst.sg = dst;
+ aes->real_dst = dst;
+
+ src_aligned = mtk_aes_check_aligned(src, len, &aes->src);
+ if (src == dst)
+ dst_aligned = src_aligned;
+ else
+ dst_aligned = mtk_aes_check_aligned(dst, len, &aes->dst);
+
+ if (!src_aligned || !dst_aligned) {
+ padlen = mtk_aes_padlen(len);
+
+ if (len + padlen > AES_BUFFER_SIZE)
+ return -ENOMEM;
+
+ if (!src_aligned) {
+ sg_copy_to_buffer(src, sg_nents(src), aes->buf, len);
+ aes->src.sg = &aes->aligned_sg;
+ aes->src.nents = 1;
+ aes->src.remainder = 0;
+ }
+
+ if (!dst_aligned) {
+ aes->dst.sg = &aes->aligned_sg;
+ aes->dst.nents = 1;
+ aes->dst.remainder = 0;
+ }
+
+ sg_init_table(&aes->aligned_sg, 1);
+ sg_set_buf(&aes->aligned_sg, aes->buf, len + padlen);
+ }
+
+ if (aes->src.sg == aes->dst.sg) {
+ aes->src.sg_len = dma_map_sg(cryp->dev, aes->src.sg,
+ aes->src.nents, DMA_BIDIRECTIONAL);
+ aes->dst.sg_len = aes->src.sg_len;
+ if (unlikely(!aes->src.sg_len))
+ return -EFAULT;
+ } else {
+ aes->src.sg_len = dma_map_sg(cryp->dev, aes->src.sg,
+ aes->src.nents, DMA_TO_DEVICE);
+ if (unlikely(!aes->src.sg_len))
+ return -EFAULT;
+
+ aes->dst.sg_len = dma_map_sg(cryp->dev, aes->dst.sg,
+ aes->dst.nents, DMA_FROM_DEVICE);
+ if (unlikely(!aes->dst.sg_len)) {
+ dma_unmap_sg(cryp->dev, aes->src.sg,
+ aes->src.nents, DMA_TO_DEVICE);
+ return -EFAULT;
+ }
+ }
+
+ return mtk_aes_info_map(cryp, aes, len + padlen);
+}
+
+static int mtk_aes_handle_queue(struct mtk_cryp *cryp, u8 id,
+ struct ablkcipher_request *req)
+{
+ struct mtk_aes *aes = cryp->aes[id];
+ struct crypto_async_request *areq, *backlog;
+ struct mtk_aes_reqctx *rctx;
+ struct mtk_aes_ctx *ctx;
+ unsigned long flags;
+ int err, ret = 0;
+
+ spin_lock_irqsave(&aes->lock, flags);
+ if (req)
+ ret = ablkcipher_enqueue_request(&aes->queue, req);
+ if (aes->flags & AES_FLAGS_BUSY) {
+ spin_unlock_irqrestore(&aes->lock, flags);
+ return ret;
+ }
+ backlog = crypto_get_backlog(&aes->queue);
+ areq = crypto_dequeue_request(&aes->queue);
+ if (areq)
+ aes->flags |= AES_FLAGS_BUSY;
+ spin_unlock_irqrestore(&aes->lock, flags);
+
+ if (!areq)
+ return ret;
+
+ if (backlog)
+ backlog->complete(backlog, -EINPROGRESS);
+
+ req = ablkcipher_request_cast(areq);
+ ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req));
+ rctx = ablkcipher_request_ctx(req);
+ rctx->mode &= AES_FLAGS_MODE_MSK;
+ /* assign new request to device */
+ aes->req = req;
+ aes->info = &ctx->info;
+ aes->flags = (aes->flags & ~AES_FLAGS_MODE_MSK) | rctx->mode;
+
+ err = mtk_aes_map(cryp, aes);
+ if (err)
+ return err;
+
+ return mtk_aes_xmit(cryp, aes);
+}
+
+static void mtk_aes_unmap(struct mtk_cryp *cryp, struct mtk_aes *aes)
+{
+ dma_unmap_single(cryp->dev, aes->ct_dma,
+ sizeof(struct mtk_aes_info), DMA_TO_DEVICE);
+
+ if (aes->src.sg == aes->dst.sg) {
+ dma_unmap_sg(cryp->dev, aes->src.sg,
+ aes->src.nents, DMA_BIDIRECTIONAL);
+
+ if (aes->src.sg != &aes->aligned_sg)
+ mtk_aes_restore_sg(&aes->src);
+ } else {
+ dma_unmap_sg(cryp->dev, aes->dst.sg,
+ aes->dst.nents, DMA_FROM_DEVICE);
+
+ if (aes->dst.sg != &aes->aligned_sg)
+ mtk_aes_restore_sg(&aes->dst);
+
+ dma_unmap_sg(cryp->dev, aes->src.sg,
+ aes->src.nents, DMA_TO_DEVICE);
+
+ if (aes->src.sg != &aes->aligned_sg)
+ mtk_aes_restore_sg(&aes->src);
+ }
+
+ if (aes->dst.sg == &aes->aligned_sg)
+ sg_copy_from_buffer(aes->real_dst,
+ sg_nents(aes->real_dst),
+ aes->buf, aes->total);
+}
+
+static inline void mtk_aes_complete(struct mtk_cryp *cryp,
+ struct mtk_aes *aes)
+{
+ aes->flags &= ~AES_FLAGS_BUSY;
+
+ aes->req->base.complete(&aes->req->base, 0);
+
+ mtk_aes_handle_queue(cryp, aes->id, NULL);
+}
+
+static int mtk_aes_setkey(struct crypto_ablkcipher *tfm,
+ const u8 *key, u32 keylen)
+{
+ struct mtk_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+ u8 *state = ctx->info.tfm.state;
+
+ if (keylen != AES_KEYSIZE_128 &&
+ keylen != AES_KEYSIZE_192 &&
+ keylen != AES_KEYSIZE_256) {
+ crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+ }
+
+ ctx->keylen = keylen;
+ memcpy(state, key, keylen);
+
+ return 0;
+}
+
+static int mtk_aes_crypt(struct ablkcipher_request *req, u64 mode)
+{
+ struct mtk_aes_ctx *ctx = crypto_ablkcipher_ctx(
+ crypto_ablkcipher_reqtfm(req));
+ struct mtk_aes_reqctx *rctx = ablkcipher_request_ctx(req);
+
+ rctx->mode = mode;
+
+ return mtk_aes_handle_queue(ctx->cryp,
+ !(mode & AES_FLAGS_ENCRYPT), req);
+}
+
+static int mtk_ecb_encrypt(struct ablkcipher_request *req)
+{
+ return mtk_aes_crypt(req, AES_FLAGS_ENCRYPT | AES_FLAGS_ECB);
+}
+
+static int mtk_ecb_decrypt(struct ablkcipher_request *req)
+{
+ return mtk_aes_crypt(req, AES_FLAGS_ECB);
+}
+
+static int mtk_cbc_encrypt(struct ablkcipher_request *req)
+{
+ return mtk_aes_crypt(req, AES_FLAGS_ENCRYPT | AES_FLAGS_CBC);
+}
+
+static int mtk_cbc_decrypt(struct ablkcipher_request *req)
+{
+ return mtk_aes_crypt(req, AES_FLAGS_CBC);
+}
+
+static int mtk_aes_cra_init(struct crypto_tfm *tfm)
+{
+ struct mtk_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct mtk_cryp *cryp = NULL;
+
+ tfm->crt_ablkcipher.reqsize = sizeof(struct mtk_aes_reqctx);
+
+ cryp = mtk_aes_find_dev(ctx);
+ if (!cryp) {
+ pr_err("can't find crypto device\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static struct crypto_alg aes_algs[] = {
+{
+ .cra_name = "cbc(aes)",
+ .cra_driver_name = "cbc-aes-mtk",
+ .cra_priority = 400,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC,
+ .cra_init = mtk_aes_cra_init,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct mtk_aes_ctx),
+ .cra_alignmask = 15,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_u.ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = mtk_aes_setkey,
+ .encrypt = mtk_cbc_encrypt,
+ .decrypt = mtk_cbc_decrypt,
+ .ivsize = AES_BLOCK_SIZE,
+ }
+},
+{
+ .cra_name = "ecb(aes)",
+ .cra_driver_name = "ecb-aes-mtk",
+ .cra_priority = 400,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC,
+ .cra_init = mtk_aes_cra_init,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct mtk_aes_ctx),
+ .cra_alignmask = 15,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_u.ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = mtk_aes_setkey,
+ .encrypt = mtk_ecb_encrypt,
+ .decrypt = mtk_ecb_decrypt,
+ }
+},
+};
+
+static void mtk_aes_enc_task(unsigned long data)
+{
+ struct mtk_cryp *cryp = (struct mtk_cryp *)data;
+ struct mtk_aes *aes = cryp->aes[0];
+
+ mtk_aes_unmap(cryp, aes);
+ mtk_aes_complete(cryp, aes);
+}
+
+static void mtk_aes_dec_task(unsigned long data)
+{
+ struct mtk_cryp *cryp = (struct mtk_cryp *)data;
+ struct mtk_aes *aes = cryp->aes[1];
+
+ mtk_aes_unmap(cryp, aes);
+ mtk_aes_complete(cryp, aes);
+}
+
+static irqreturn_t mtk_aes_enc_irq(int irq, void *dev_id)
+{
+ struct mtk_cryp *cryp = (struct mtk_cryp *)dev_id;
+ struct mtk_aes *aes = cryp->aes[0];
+ u32 val = mtk_aes_read(cryp, RDR_STAT(RING0));
+
+ mtk_aes_write(cryp, RDR_STAT(RING0), val);
+
+ if (likely(AES_FLAGS_BUSY & aes->flags)) {
+ mtk_aes_write(cryp, RDR_PROC_COUNT(RING0), MTK_DESC_CNT_CLR);
+ mtk_aes_write(cryp, RDR_THRESH(RING0), MTK_RDR_THRESH_DEF);
+
+ tasklet_schedule(&aes->task);
+ } else {
+ dev_warn(cryp->dev, "AES interrupt when no active requests.\n");
+ }
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mtk_aes_dec_irq(int irq, void *dev_id)
+{
+ struct mtk_cryp *cryp = (struct mtk_cryp *)dev_id;
+ struct mtk_aes *aes = cryp->aes[1];
+ u32 val = mtk_aes_read(cryp, RDR_STAT(RING1));
+
+ mtk_aes_write(cryp, RDR_STAT(RING1), val);
+
+ if (likely(AES_FLAGS_BUSY & aes->flags)) {
+ mtk_aes_write(cryp, RDR_PROC_COUNT(RING1), MTK_DESC_CNT_CLR);
+ mtk_aes_write(cryp, RDR_THRESH(RING1), MTK_RDR_THRESH_DEF);
+
+ tasklet_schedule(&aes->task);
+ } else {
+ dev_warn(cryp->dev, "AES interrupt when no active requests.\n");
+ }
+ return IRQ_HANDLED;
+}
+
+/* AES encryption record and decryption record */
+static int mtk_aes_record_init(struct mtk_cryp *cryp)
+{
+ struct mtk_aes **aes = cryp->aes;
+ int i, err = -ENOMEM;
+
+ for (i = 0; i < RECORD_NUM; i++) {
+ aes[i] = kzalloc(sizeof(**aes), GFP_KERNEL);
+ if (!aes[i])
+ goto err_cleanup;
+
+ aes[i]->buf = (void *)__get_free_pages(GFP_KERNEL,
+ AES_BUFFER_ORDER);
+ if (!aes[i]->buf)
+ goto err_cleanup;
+
+ aes[i]->id = i;
+
+ spin_lock_init(&aes[i]->lock);
+ crypto_init_queue(&aes[i]->queue, AES_QUEUE_LENGTH);
+ }
+
+ tasklet_init(&aes[0]->task, mtk_aes_enc_task, (unsigned long)cryp);
+ tasklet_init(&aes[1]->task, mtk_aes_dec_task, (unsigned long)cryp);
+
+ return 0;
+
+err_cleanup:
+ for (; i--; ) {
+ free_page((unsigned long)aes[i]->buf);
+ kfree(aes[i]);
+ }
+
+ return err;
+}
+
+static void mtk_aes_record_free(struct mtk_cryp *cryp)
+{
+ int i;
+
+ for (i = 0; i < RECORD_NUM; i++) {
+ tasklet_kill(&cryp->aes[i]->task);
+ free_page((unsigned long)cryp->aes[i]->buf);
+ kfree(cryp->aes[i]);
+ }
+}
+
+static void mtk_aes_unregister_algs(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(aes_algs); i++)
+ crypto_unregister_alg(&aes_algs[i]);
+}
+
+static int mtk_aes_register_algs(void)
+{
+ int err, i, j;
+
+ for (i = 0; i < ARRAY_SIZE(aes_algs); i++) {
+ err = crypto_register_alg(&aes_algs[i]);
+ if (err)
+ goto err_aes_algs;
+ }
+
+ return 0;
+
+err_aes_algs:
+ for (j = 0; j < i; j++)
+ crypto_unregister_alg(&aes_algs[j]);
+
+ return err;
+}
+
+int mtk_cipher_alg_register(struct mtk_cryp *cryp)
+{
+ int ret;
+
+ INIT_LIST_HEAD(&cryp->aes_list);
+
+ ret = mtk_aes_record_init(cryp);
+ if (ret)
+ goto err_record;
+
+ ret = devm_request_irq(cryp->dev, cryp->irq[RING0], mtk_aes_enc_irq,
+ IRQF_TRIGGER_LOW, "mtk-aes", cryp);
+ if (ret) {
+ dev_err(cryp->dev, "unable to request AES encryption irq.\n");
+ goto err_res;
+ }
+
+ ret = devm_request_irq(cryp->dev, cryp->irq[RING1], mtk_aes_dec_irq,
+ IRQF_TRIGGER_LOW, "mtk-aes", cryp);
+ if (ret) {
+ dev_err(cryp->dev, "unable to request AES decryption irq.\n");
+ goto err_res;
+ }
+
+ /* enable ring0 and ring1 interrupt for cipher */
+ mtk_aes_write(cryp, AIC_ENABLE_SET(RING0), MTK_IRQ_RDR0);
+ mtk_aes_write(cryp, AIC_ENABLE_SET(RING1), MTK_IRQ_RDR1);
+
+ spin_lock(&mtk_aes.lock);
+ list_add_tail(&cryp->aes_list, &mtk_aes.dev_list);
+ spin_unlock(&mtk_aes.lock);
+
+ ret = mtk_aes_register_algs();
+ if (ret)
+ goto err_algs;
+
+ return 0;
+
+err_algs:
+ spin_lock(&mtk_aes.lock);
+ list_del(&cryp->aes_list);
+ spin_unlock(&mtk_aes.lock);
+err_res:
+ mtk_aes_record_free(cryp);
+err_record:
+
+ dev_err(cryp->dev, "mtk-aes initialization failed.\n");
+ return ret;
+}
+EXPORT_SYMBOL(mtk_cipher_alg_register);
+
+void mtk_cipher_alg_release(struct mtk_cryp *cryp)
+{
+ spin_lock(&mtk_aes.lock);
+ list_del(&cryp->aes_list);
+ spin_unlock(&mtk_aes.lock);
+
+ mtk_aes_unregister_algs();
+ mtk_aes_record_free(cryp);
+}
+EXPORT_SYMBOL(mtk_cipher_alg_release);
diff --git a/drivers/crypto/mediatek/mtk-platform.c b/drivers/crypto/mediatek/mtk-platform.c
new file mode 100644
index 0000000..d3a465f
--- /dev/null
+++ b/drivers/crypto/mediatek/mtk-platform.c
@@ -0,0 +1,575 @@
+/*
+ * Support for MediaTek cryptographic accelerator.
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include "mtk-platform.h"
+#include "mtk-regs.h"
+
+#define MTK_BURST_SIZE(x, y) (((x) & ~0xf0) | ((y) << 4))
+#define MTK_DESC_SIZE_SET(x) ((x) << 0)
+#define MTK_DESC_OFFSET_SET(x) ((x) << 16)
+#define MTK_DFSE_RING_ID(x) (((x) >> 12) & 0xf)
+#define MTK_DSE_MIN_DATA(x) ((x) << 0)
+#define MTK_DSE_MAX_DATA(x) ((x) << 8)
+#define MTK_DFE_MIN_DATA(x) ((x) << 0)
+#define MTK_DFE_MAX_DATA(x) ((x) << 8)
+#define MTK_DFE_MIN_CTRL(x) ((x) << 16)
+#define MTK_DFE_MAX_CTRL(x) ((x) << 24)
+#define MTK_FETCH_SIZE_SET(x) ((x) << 0)
+#define MTK_FETCH_THRESH_SET(x) ((x) << 16)
+#define MTK_IN_BUF_MIN_THRESH(x) ((x) << 8)
+#define MTK_IN_BUF_MAX_THRESH(x) ((x) << 12)
+#define MTK_OUT_BUF_MIN_THRESH(x) ((x) << 0)
+#define MTK_OUT_BUF_MAX_THRESH(x) ((x) << 4)
+#define MTK_CMD_FIFO_SIZE(x) (((x) >> 8) & 0xf)
+#define MTK_RES_FIFO_SIZE(x) (((x) >> 12) & 0xf)
+#define MTK_HIA_DATA_WIDTH(x) (((x) >> 25) & 0x3)
+#define MTK_HIA_DMA_LENGTH(x) (((x) >> 20) & 0x1f)
+#define MTK_IN_TBUF_SIZE(x) (((x) >> 4) & 0xf)
+#define MTK_IN_DBUF_SIZE(x) (((x) >> 8) & 0xf)
+#define MTK_OUT_DBUF_SIZE(x) (((x) >> 16) & 0xf)
+#define MTK_AIC_INT_NUM(x) ((x) & 0x3f)
+#define MTK_AIC_VER_GET(x) ((x) & 0x0ff0ffff)
+#define MTK_PE_TOKEN_CTRL_DEF 0x00014004
+#define MTK_PE_INT_CTRL_DEF 0xc00f400f
+#define MTK_PRNG_CTRL_EN BIT(0)
+#define MTK_PRNG_CTRL_AUTO BIT(1)
+#define MTK_TOKEN_TIMEOUT_EN BIT(22)
+#define MTK_OVL_IRQ_EN BIT(25)
+#define MTK_ATP_PRESENT BIT(30)
+#define MTK_DFSE_THR_CTRL_EN BIT(30)
+#define MTK_DFSE_THR_CTRL_RESET BIT(31)
+#define MTK_HIA_SIGNATURE ((u16)0x35ca)
+#define MTK_CDR_STAT_CLR 0x1f
+#define MTK_RDR_STAT_CLR 0xff
+#define MTK_AIC_VER11 0x011036C9
+#define MTK_AIC_VER12 0x012036C9
+#define MTK_AIC_GLOBAL_CLR 0x7FF00000
+#define MTK_DFSE_IDLE 0xf
+
+/* Cryptographic engine capabilities */
+struct mtk_sys_cap {
+ /* Host interface adapter */
+ u32 hia_ver;
+ u32 hia_opt;
+
+ /* Packet engine */
+ u32 pkt_eng_opt;
+
+ /* Global hardware */
+ u32 hw_opt;
+};
+
+static void mtk_prng_reseed(struct mtk_cryp *cryp)
+{
+ /* 8 words to seed the PRNG to provide IVs */
+ void __iomem *base = cryp->base;
+ const u32 prng_key[8] = {0x48c24cfd, 0x6c07f742,
+ 0xaee75681, 0x0f27c239,
+ 0x79947198, 0xe2991275,
+ 0x21ac3c7c, 0xd008c4b4};
+
+ /* Disable PRNG and set PRNG manual mode */
+ writel(0, base + PE_PRNG_CTRL);
+
+ /* Write new seed data */
+ writel(prng_key[0], base + PE_PRNG_SEED_L);
+ writel(prng_key[1], base + PE_PRNG_SEED_H);
+
+ /* Write new key data */
+ writel(prng_key[2], base + PE_PRNG_KEY_0_L);
+ writel(prng_key[3], base + PE_PRNG_KEY_0_H);
+ writel(prng_key[4], base + PE_PRNG_KEY_1_L);
+ writel(prng_key[5], base + PE_PRNG_KEY_1_H);
+
+ /* Write new LFSR data */
+ writel(prng_key[6], base + PE_PRNG_LFSR_L);
+ writel(prng_key[7], base + PE_PRNG_LFSR_H);
+
+ /* Enable PRNG and set PRNG auto mode */
+ writel(MTK_PRNG_CTRL_EN | MTK_PRNG_CTRL_AUTO, base + PE_PRNG_CTRL);
+}
+
+static void mtk_desc_ring_link(struct mtk_cryp *cryp, u32 mask)
+{
+ /* Assign rings to DFE DSE thread and enable it */
+ writel(MTK_DFSE_THR_CTRL_EN | mask, cryp->base + DFE_THR_CTRL);
+ writel(MTK_DFSE_THR_CTRL_EN | mask, cryp->base + DSE_THR_CTRL);
+}
+
+static void mtk_dfe_dse_buf_setup(struct mtk_cryp *cryp,
+ struct mtk_sys_cap *cap)
+{
+ u32 width = MTK_HIA_DATA_WIDTH(cap->hia_opt) + 2;
+ u32 len = MTK_HIA_DMA_LENGTH(cap->hia_opt) - 1;
+ u32 ipbuf = min(MTK_IN_DBUF_SIZE(cap->hw_opt) + width, len);
+ u32 opbuf = min(MTK_OUT_DBUF_SIZE(cap->hw_opt) + width, len);
+ u32 itbuf = min(MTK_IN_TBUF_SIZE(cap->hw_opt) + width, len);
+ u32 val;
+
+ val = MTK_DFE_MIN_DATA(ipbuf - 1) | MTK_DFE_MAX_DATA(ipbuf) |
+ MTK_DFE_MIN_CTRL(itbuf - 1) | MTK_DFE_MAX_CTRL(itbuf);
+ writel(val, cryp->base + DFE_CFG);
+
+ val = MTK_DFE_MIN_DATA(opbuf - 1) | MTK_DFE_MAX_DATA(opbuf);
+ writel(val, cryp->base + DSE_CFG);
+
+ val = MTK_IN_BUF_MIN_THRESH(ipbuf - 1) | MTK_IN_BUF_MAX_THRESH(ipbuf);
+ writel(val, cryp->base + PE_IN_DBUF_THRESH);
+
+ val = MTK_IN_BUF_MIN_THRESH(itbuf - 1) | MTK_IN_BUF_MAX_THRESH(itbuf);
+ writel(val, cryp->base + PE_IN_TBUF_THRESH);
+
+ val = MTK_OUT_BUF_MIN_THRESH(opbuf - 1) | MTK_OUT_BUF_MAX_THRESH(opbuf);
+ writel(val, cryp->base + PE_OUT_DBUF_THRESH);
+
+ writel(0, cryp->base + PE_OUT_TBUF_THRESH);
+ writel(0, cryp->base + PE_OUT_BUF_CTRL);
+}
+
+static int mtk_dfe_dse_state_check(struct mtk_cryp *cryp)
+{
+ int ret = -EINVAL;
+ u32 val;
+
+ /* Check for completion of all DMA transfers */
+ val = readl(cryp->base + DFE_THR_STAT);
+ if (MTK_DFSE_RING_ID(val) == MTK_DFSE_IDLE) {
+ val = readl(cryp->base + DSE_THR_STAT);
+ if (MTK_DFSE_RING_ID(val) == MTK_DFSE_IDLE)
+ ret = 0;
+ }
+
+ if (!ret) {
+ /* Take DFE and DSE thread out of reset */
+ writel(0, cryp->base + DFE_THR_CTRL);
+ writel(0, cryp->base + DSE_THR_CTRL);
+ } else {
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int mtk_dfe_dse_reset(struct mtk_cryp *cryp)
+{
+ int err;
+
+ /* Reset DSE DFE and correct system priorities for all rings. */
+ writel(MTK_DFSE_THR_CTRL_RESET, cryp->base + DFE_THR_CTRL);
+ writel(0, cryp->base + DFE_PRIO_0);
+ writel(0, cryp->base + DFE_PRIO_1);
+ writel(0, cryp->base + DFE_PRIO_2);
+ writel(0, cryp->base + DFE_PRIO_3);
+
+ writel(MTK_DFSE_THR_CTRL_RESET, cryp->base + DSE_THR_CTRL);
+ writel(0, cryp->base + DSE_PRIO_0);
+ writel(0, cryp->base + DSE_PRIO_1);
+ writel(0, cryp->base + DSE_PRIO_2);
+ writel(0, cryp->base + DSE_PRIO_3);
+
+ err = mtk_dfe_dse_state_check(cryp);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static void mtk_cmd_desc_ring_setup(struct mtk_cryp *cryp,
+ int i, struct mtk_sys_cap *cap)
+{
+ /* Full descriptor that fits FIFO minus one */
+ u32 count =
+ ((1 << MTK_CMD_FIFO_SIZE(cap->hia_opt)) / MTK_DESC_SIZE) - 1;
+ u32 size = count * MTK_DESC_OFFSET;
+ u32 thresh = count * MTK_DESC_SIZE;
+ u32 val;
+
+ /* Temporarily disable external triggering */
+ writel(0, cryp->base + CDR_CFG(i));
+
+ /* Clear CDR count */
+ writel(MTK_DESC_CNT_CLR, cryp->base + CDR_PREP_COUNT(i));
+ writel(MTK_DESC_CNT_CLR, cryp->base + CDR_PROC_COUNT(i));
+
+ writel(0, cryp->base + CDR_PREP_PNTR(i));
+ writel(0, cryp->base + CDR_PROC_PNTR(i));
+ writel(0, cryp->base + CDR_DMA_CFG(i));
+
+ /* Configure command ring host address space */
+ writel(0, cryp->base + CDR_BASE_ADDR_HI(i));
+ writel(cryp->ring[i]->cmd_dma, cryp->base + CDR_BASE_ADDR_LO(i));
+
+ writel(MTK_MAX_RING_SIZE, cryp->base + CDR_RING_SIZE(i));
+
+ /* Clear and disable all CDR interrupts */
+ writel(MTK_CDR_STAT_CLR, cryp->base + CDR_STAT(i));
+
+ /*
+ * Set command descriptor offset and enable additional
+ * token present in descriptor.
+ */
+ val = MTK_DESC_SIZE_SET(MTK_DESC_SIZE) |
+ MTK_DESC_OFFSET_SET(MTK_DESC_OFFSET) |
+ MTK_ATP_PRESENT;
+ writel(val, cryp->base + CDR_DESC_SIZE(i));
+
+ val = MTK_FETCH_SIZE_SET(size) | MTK_FETCH_THRESH_SET(thresh);
+ writel(val, cryp->base + CDR_CFG(i));
+}
+
+static void mtk_res_desc_ring_setup(struct mtk_cryp *cryp,
+ int i, struct mtk_sys_cap *cap)
+{
+ u32 rndup = 2;
+ u32 count = ((1 << MTK_RES_FIFO_SIZE(cap->hia_opt)) / rndup) - 1;
+ u32 size = count * MTK_DESC_OFFSET;
+ u32 thresh = count * rndup;
+ u32 val;
+
+ writel(0, cryp->base + RDR_CFG(i));
+
+ writel(MTK_DESC_CNT_CLR, cryp->base + RDR_PREP_COUNT(i));
+ writel(MTK_DESC_CNT_CLR, cryp->base + RDR_PROC_COUNT(i));
+
+ writel(0, cryp->base + RDR_PREP_PNTR(i));
+ writel(0, cryp->base + RDR_PROC_PNTR(i));
+ writel(0, cryp->base + RDR_DMA_CFG(i));
+
+ writel(0, cryp->base + RDR_BASE_ADDR_HI(i));
+ writel(cryp->ring[i]->res_dma, cryp->base + RDR_BASE_ADDR_LO(i));
+
+ writel(MTK_MAX_RING_SIZE, cryp->base + RDR_RING_SIZE(i));
+ writel(MTK_RDR_STAT_CLR, cryp->base + RDR_STAT(i));
+
+ /*
+ * RDR manager generates update interrupts on a per-completed-packet,
+ * and the rd_proc_thresh_irq interrupt is fired when proc_pkt_count
+ * for the RDR exceeds the number of packets.
+ */
+ writel(MTK_RDR_THRESH_DEF, cryp->base + RDR_THRESH(i));
+
+ /*
+ * Configure a threshold and time-out value for the processed
+ * result descriptors (or complete packets) that are written to
+ * the RDR.
+ */
+ val = MTK_DESC_SIZE_SET(MTK_DESC_SIZE) |
+ MTK_DESC_OFFSET_SET(MTK_DESC_OFFSET);
+ writel(val, cryp->base + RDR_DESC_SIZE(i));
+
+ /*
+ * Configure HIA fetch size and fetch threshold that are used to
+ * fetch blocks of multiple descriptors.
+ */
+ val = MTK_FETCH_SIZE_SET(size) |
+ MTK_FETCH_THRESH_SET(thresh) |
+ MTK_OVL_IRQ_EN;
+ writel(val, cryp->base + RDR_CFG(i));
+}
+
+static int mtk_packet_engine_setup(struct mtk_cryp *cryp)
+{
+ struct mtk_sys_cap cap;
+ int i, err;
+ u32 val;
+
+ cap.hia_ver = readl(cryp->base + HIA_VERSION);
+ cap.hia_opt = readl(cryp->base + HIA_OPTIONS);
+ cap.hw_opt = readl(cryp->base + EIP97_OPTIONS);
+
+ if (!(((u16)cap.hia_ver) == MTK_HIA_SIGNATURE))
+ return -EINVAL;
+
+ /* Configure endianness conversion method for master (DMA) interface */
+ writel(0, cryp->base + EIP97_MST_CTRL);
+
+ /* Set HIA burst size */
+ val = readl(cryp->base + HIA_MST_CTRL);
+ writel(MTK_BURST_SIZE(val, 5), cryp->base + HIA_MST_CTRL);
+
+ err = mtk_dfe_dse_reset(cryp);
+ if (err) {
+ dev_err(cryp->dev, "Failed to reset DFE and DSE.\n");
+ return err;
+ }
+
+ mtk_dfe_dse_buf_setup(cryp, &cap);
+
+ /* Enable the 4 rings for the packet engines. */
+ mtk_desc_ring_link(cryp, 0xf);
+
+ for (i = 0; i < RING_MAX; i++) {
+ mtk_cmd_desc_ring_setup(cryp, i, &cap);
+ mtk_res_desc_ring_setup(cryp, i, &cap);
+ }
+
+ val = MTK_PE_TOKEN_CTRL_DEF | MTK_TOKEN_TIMEOUT_EN;
+ writel(val, cryp->base + PE_TOKEN_CTRL_STAT);
+
+ /* Clear all pending interrupts */
+ writel(MTK_AIC_GLOBAL_CLR, cryp->base + AIC_G_ACK);
+ writel(MTK_PE_INT_CTRL_DEF, cryp->base + PE_INTERRUPT_CTRL_STAT);
+
+ return 0;
+}
+
+static int mtk_aic_cap_check(struct mtk_cryp *cryp, int hw)
+{
+ u32 val;
+
+ if (hw == RING_MAX)
+ val = readl(cryp->base + AIC_G_VERSION);
+ else
+ val = readl(cryp->base + AIC_VERSION(hw));
+
+ val = MTK_AIC_VER_GET(val);
+ if (val != MTK_AIC_VER11 && val != MTK_AIC_VER12)
+ return -ENXIO;
+
+ if (hw == RING_MAX)
+ val = readl(cryp->base + AIC_G_OPTIONS);
+ else
+ val = readl(cryp->base + AIC_OPTIONS(hw));
+
+ val = MTK_AIC_INT_NUM(val);
+ if (!val || val > 32)
+ return -ENXIO;
+
+ return 0;
+}
+
+static int mtk_aic_init(struct mtk_cryp *cryp, int hw)
+{
+ int err;
+
+ err = mtk_aic_cap_check(cryp, hw);
+ if (err)
+ return err;
+
+ /* Disable all interrupts and set initial configuration */
+ if (hw == RING_MAX) {
+ writel(0, cryp->base + AIC_G_ENABLE_CTRL);
+ writel(0, cryp->base + AIC_G_POL_CTRL);
+ writel(0, cryp->base + AIC_G_TYPE_CTRL);
+ writel(0, cryp->base + AIC_G_ENABLE_SET);
+ } else {
+ writel(0, cryp->base + AIC_ENABLE_CTRL(hw));
+ writel(0, cryp->base + AIC_POL_CTRL(hw));
+ writel(0, cryp->base + AIC_TYPE_CTRL(hw));
+ writel(0, cryp->base + AIC_ENABLE_SET(hw));
+ }
+
+ return 0;
+}
+
+static int mtk_accelerator_init(struct mtk_cryp *cryp)
+{
+ int i, err;
+
+ /* Initialize advanced interrupt controller(AIC) */
+ for (i = 0; i < 5; i++) {
+ err = mtk_aic_init(cryp, i);
+ if (err) {
+ dev_err(cryp->dev, "Failed to initialize AIC.\n");
+ return err;
+ }
+ }
+
+ /* Initialize packet engine */
+ err = mtk_packet_engine_setup(cryp);
+ if (err) {
+ dev_err(cryp->dev, "Failed to configure packet engine.\n");
+ return err;
+ }
+
+ mtk_prng_reseed(cryp);
+ return 0;
+}
+
+static void mtk_desc_dma_free(struct mtk_cryp *cryp)
+{
+ int i;
+
+ for (i = 0; i < RING_MAX; i++) {
+ dma_free_coherent(cryp->dev, MTK_MAX_RING_SIZE,
+ cryp->ring[i]->res_base,
+ cryp->ring[i]->res_dma);
+ dma_free_coherent(cryp->dev, MTK_MAX_RING_SIZE,
+ cryp->ring[i]->cmd_base,
+ cryp->ring[i]->cmd_dma);
+ kfree(cryp->ring[i]);
+ }
+}
+
+static int mtk_desc_ring_alloc(struct mtk_cryp *cryp)
+{
+ struct mtk_ring **ring = cryp->ring;
+ int i, err = ENOMEM;
+
+ for (i = 0; i < RING_MAX; i++) {
+ ring[i] = kzalloc(sizeof(**ring), GFP_KERNEL);
+ if (!ring[i])
+ goto err_cleanup;
+
+ ring[i]->cmd_base = dma_zalloc_coherent(cryp->dev,
+ MTK_MAX_RING_SIZE, &ring[i]->cmd_dma,
+ GFP_KERNEL);
+ if (!ring[i]->cmd_base)
+ goto err_cleanup;
+
+ ring[i]->res_base = dma_zalloc_coherent(cryp->dev,
+ MTK_MAX_RING_SIZE, &ring[i]->res_dma,
+ GFP_KERNEL);
+ if (!ring[i]->res_base)
+ goto err_cleanup;
+ }
+ return 0;
+
+err_cleanup:
+ for (; i--; ) {
+ dma_free_coherent(cryp->dev, MTK_MAX_RING_SIZE,
+ ring[i]->res_base, ring[i]->res_dma);
+ dma_free_coherent(cryp->dev, MTK_MAX_RING_SIZE,
+ ring[i]->cmd_base, ring[i]->cmd_dma);
+ kfree(ring[i]);
+ }
+ return err;
+}
+
+static int mtk_crypto_probe(struct platform_device *pdev)
+{
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct mtk_cryp *cryp;
+ int i, err;
+
+ cryp = devm_kzalloc(&pdev->dev, sizeof(*cryp), GFP_KERNEL);
+ if (!cryp)
+ return -ENOMEM;
+
+ cryp->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(cryp->base))
+ return PTR_ERR(cryp->base);
+
+ for (i = 0; i < 5; i++) {
+ cryp->irq[i] = platform_get_irq(pdev, i);
+ if (cryp->irq[i] < 0) {
+ dev_err(cryp->dev, "no IRQ:%d resource info\n", i);
+ return -ENXIO;
+ }
+ }
+
+ cryp->clk_ethif = devm_clk_get(&pdev->dev, "ethif");
+ cryp->clk_cryp = devm_clk_get(&pdev->dev, "cryp");
+ if (IS_ERR(cryp->clk_ethif) || IS_ERR(cryp->clk_cryp))
+ return -EPROBE_DEFER;
+
+ cryp->dev = &pdev->dev;
+ pm_runtime_enable(cryp->dev);
+ pm_runtime_get_sync(cryp->dev);
+
+ err = clk_prepare_enable(cryp->clk_ethif);
+ if (err)
+ goto err_clk_ethif;
+
+ err = clk_prepare_enable(cryp->clk_cryp);
+ if (err)
+ goto err_clk_cryp;
+
+ err = mtk_desc_ring_alloc(cryp);
+ if (err) {
+ dev_err(cryp->dev, "Unable to allocate descriptor rings.\n");
+ goto err_resource;
+ }
+
+ err = mtk_accelerator_init(cryp);
+ if (err) {
+ dev_err(cryp->dev, "Failed to initialize cryptographic engine.\n");
+ goto err_engine;
+ }
+
+ err = mtk_cipher_alg_register(cryp);
+ if (err) {
+ dev_err(cryp->dev, "Unable to register MTK-AES.\n");
+ goto err_cipher;
+ }
+
+ err = mtk_hash_alg_register(cryp);
+ if (err) {
+ dev_err(cryp->dev, "Unable to register MTK-SHA.\n");
+ goto err_hash;
+ }
+
+ platform_set_drvdata(pdev, cryp);
+ return 0;
+
+err_hash:
+ mtk_cipher_alg_release(cryp);
+err_cipher:
+ mtk_dfe_dse_reset(cryp);
+err_engine:
+ mtk_desc_dma_free(cryp);
+err_resource:
+ clk_disable_unprepare(cryp->clk_cryp);
+err_clk_cryp:
+ clk_disable_unprepare(cryp->clk_ethif);
+err_clk_ethif:
+ pm_runtime_put_sync(cryp->dev);
+ pm_runtime_disable(cryp->dev);
+
+ return err;
+}
+
+static int mtk_crypto_remove(struct platform_device *pdev)
+{
+ struct mtk_cryp *cryp = platform_get_drvdata(pdev);
+
+ mtk_hash_alg_release(cryp);
+ mtk_cipher_alg_release(cryp);
+ mtk_desc_dma_free(cryp);
+
+ clk_disable_unprepare(cryp->clk_cryp);
+ clk_disable_unprepare(cryp->clk_ethif);
+
+ pm_runtime_put_sync(cryp->dev);
+ pm_runtime_disable(cryp->dev);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+const struct of_device_id of_crypto_id[] = {
+ { .compatible = "mediatek,mt7623-crypto" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, of_crypto_id);
+
+static struct platform_driver mtk_crypto_driver = {
+ .probe = mtk_crypto_probe,
+ .remove = mtk_crypto_remove,
+ .driver = {
+ .name = "mtk-crypto",
+ .owner = THIS_MODULE,
+ .of_match_table = of_crypto_id,
+ },
+};
+module_platform_driver(mtk_crypto_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ryder Lee <ryder.lee@mediatek.com>");
+MODULE_DESCRIPTION("Cryptographic accelerator driver for MediaTek SoC");
diff --git a/drivers/crypto/mediatek/mtk-platform.h b/drivers/crypto/mediatek/mtk-platform.h
new file mode 100644
index 0000000..5390ef4
--- /dev/null
+++ b/drivers/crypto/mediatek/mtk-platform.h
@@ -0,0 +1,230 @@
+/*
+ * Support for MediaTek cryptographic accelerator.
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ *
+ * 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.
+ *
+ */
+
+#ifndef __MTK_PLATFORM_H_
+#define __MTK_PLATFORM_H_
+
+#include <linux/crypto.h>
+#include <crypto/internal/hash.h>
+#include <linux/interrupt.h>
+
+#define MTK_RDR_THRESH_DEF 0x800001
+
+#define MTK_IRQ_RDR0 BIT(1)
+#define MTK_IRQ_RDR1 BIT(3)
+#define MTK_IRQ_RDR2 BIT(5)
+#define MTK_IRQ_RDR3 BIT(7)
+
+#define MTK_DESC_CNT_CLR BIT(31)
+#define MTK_DESC_LAST BIT(22)
+#define MTK_DESC_FIRST BIT(23)
+#define MTK_DESC_BUF_LEN(x) ((x) & 0x1ffff)
+#define MTK_DESC_CT_LEN(x) (((x) & 0xff) << 24)
+
+#define WORD(x) ((x) >> 2)
+
+/**
+ * Ring 0/1 are used by AES encrypt and decrypt.
+ * Ring 2/3 are used by SHA.
+ */
+enum {
+ RING0 = 0,
+ RING1,
+ RING2,
+ RING3,
+ RING_MAX,
+};
+
+#define RECORD_NUM (RING_MAX / 2)
+
+/**
+ * struct mtk_desc - DMA descriptor
+ * @hdr: the descriptor control header
+ * @buf: DMA address of input buffer
+ * @ct: the command token that control operation flow
+ * @ct_hdr: the command token control header
+ * @tag: the user-defined field
+ * @tfm: DMA address of transform state
+ * @bound: align descriptors offset boundary
+ *
+ * Structure passed to the crypto engine to describe the crypto
+ * operation to be executed.
+ */
+struct mtk_desc {
+ u32 hdr;
+ u32 buf;
+ u32 ct;
+ u32 ct_hdr;
+ u32 tag;
+ u32 tfm;
+ u32 bound[2];
+};
+
+/**
+ * struct mtk_ring - Descriptor ring
+ * @cmd_base: pointer to command descriptor ring base
+ * @cmd_dma: DMA address of command descriptor ring
+ * @res_base: pointer to result descriptor ring base
+ * @res_dma: DMA address of result descriptor ring
+ * @pos: current position in the ring
+ */
+struct mtk_ring {
+ struct mtk_desc *cmd_base;
+ dma_addr_t cmd_dma;
+ struct mtk_desc *res_base;
+ dma_addr_t res_dma;
+ u32 pos;
+};
+
+#define MTK_MAX_DESC_NUM 512
+#define MTK_DESC_OFFSET WORD(sizeof(struct mtk_desc))
+#define MTK_DESC_SIZE (MTK_DESC_OFFSET - 2)
+#define MTK_MAX_RING_SIZE ((sizeof(struct mtk_desc) * MTK_MAX_DESC_NUM))
+#define MTK_DESC_CNT(x) ((MTK_DESC_OFFSET * (x)) << 2)
+
+/**
+ * struct mtk_aes_dma - Structure that holds sg list info
+ * @sg: pointer to scatter-gather list
+ * @nents: number of entries in the sg list
+ * @remainder: remainder of sg list
+ * @sg_len: number of entries in the sg mapped list
+ */
+struct mtk_aes_dma {
+ struct scatterlist *sg;
+ int nents;
+ u32 remainder;
+ u32 sg_len;
+};
+
+/**
+ * struct mtk_aes - AES operation record
+ * @queue: crypto request queue
+ * @req: pointer to ablkcipher request
+ * @task: the tasklet is use in AES interrupt
+ * @src: the structure that holds source sg list info
+ * @dst: the structure that holds destination sg list info
+ * @aligned_sg: the scatter list is use to alignment
+ * @real_dst: pointer to the destination sg list
+ * @total: request buffer length
+ * @buf: pointer to page buffer
+ * @info: pointer to AES transform state and command token
+ * @ct_hdr: AES command token control field
+ * @ct_size: size of AES command token
+ * @ct_dma: DMA address of AES command token
+ * @tfm_dma: DMA address of AES transform state
+ * @id: record identification
+ * @flags: it's describing AES operation state
+ * @lock: the ablkcipher queue lock
+ *
+ * Structure used to record AES execution state
+ */
+struct mtk_aes {
+ struct crypto_queue queue;
+ struct ablkcipher_request *req;
+ struct tasklet_struct task;
+ struct mtk_aes_dma src;
+ struct mtk_aes_dma dst;
+
+ struct scatterlist aligned_sg;
+ struct scatterlist *real_dst;
+
+ size_t total;
+ void *buf;
+
+ void *info;
+ u32 ct_hdr;
+ u32 ct_size;
+ dma_addr_t ct_dma;
+ dma_addr_t tfm_dma;
+
+ u8 id;
+ unsigned long flags;
+ /* queue lock */
+ spinlock_t lock;
+};
+
+/**
+ * struct mtk_sha - SHA operation record
+ * @queue: crypto request queue
+ * @req: pointer to ahash request
+ * @task: the tasklet is use in SHA interrupt
+ * @info: pointer to SHA transform state and command token
+ * @ct_hdr: SHA command token control field
+ * @ct_size: size of SHA command token
+ * @ct_dma: DMA address of SHA command token
+ * @tfm_dma: DMA address of SHA transform state
+ * @id: record identification
+ * @flags: it's describing SHA operation state
+ * @lock: the ablkcipher queue lock
+ *
+ * Structure used to record SHA execution state.
+ */
+struct mtk_sha {
+ struct crypto_queue queue;
+ struct ahash_request *req;
+ struct tasklet_struct task;
+
+ void *info;
+ u32 ct_hdr;
+ u32 ct_size;
+ dma_addr_t ct_dma;
+ dma_addr_t tfm_dma;
+
+ u8 id;
+ unsigned long flags;
+ /* queue lock */
+ spinlock_t lock;
+};
+
+/**
+ * struct mtk_cryp - Cryptographic device
+ * @base: pointer to mapped register I/O base
+ * @dev: pointer to device
+ * @clk_ethif: pointer to ethif clock
+ * @clk_cryp: pointer to crypto clock
+ * @irq: global system and rings IRQ
+ * @ring: pointer to execution state of AES
+ * @aes: pointer to execution state of SHA
+ * @sha: each execution record map to a ring
+ * @aes_list: device list of AES
+ * @sha_list: device list of SHA
+ * @tmp: pointer to temporary buffer for internal use
+ * @tmp_dma: DMA address of temporary buffer
+ * @rec: it's used to select SHA record for tfm
+ *
+ * Structure storing cryptographic device information.
+ */
+struct mtk_cryp {
+ void __iomem *base;
+ struct device *dev;
+ struct clk *clk_ethif;
+ struct clk *clk_cryp;
+ int irq[5];
+
+ struct mtk_ring *ring[RING_MAX];
+ struct mtk_aes *aes[RECORD_NUM];
+ struct mtk_sha *sha[RECORD_NUM];
+
+ struct list_head aes_list;
+ struct list_head sha_list;
+
+ void *tmp;
+ dma_addr_t tmp_dma;
+ bool rec;
+};
+
+int mtk_cipher_alg_register(struct mtk_cryp *cryp);
+void mtk_cipher_alg_release(struct mtk_cryp *cryp);
+int mtk_hash_alg_register(struct mtk_cryp *cryp);
+void mtk_hash_alg_release(struct mtk_cryp *cryp);
+
+#endif /* __MTK_PLATFORM_H_ */
diff --git a/drivers/crypto/mediatek/mtk-regs.h b/drivers/crypto/mediatek/mtk-regs.h
new file mode 100644
index 0000000..94f4eb8
--- /dev/null
+++ b/drivers/crypto/mediatek/mtk-regs.h
@@ -0,0 +1,194 @@
+/*
+ * Support for MediaTek cryptographic accelerator.
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ *
+ * 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.
+ *
+ */
+
+#ifndef __MTK_REGS_H__
+#define __MTK_REGS_H__
+
+/* HIA, Command Descriptor Ring Manager */
+#define CDR_BASE_ADDR_LO(x) (0x0 + ((x) << 12))
+#define CDR_BASE_ADDR_HI(x) (0x4 + ((x) << 12))
+#define CDR_DATA_BASE_ADDR_LO(x) (0x8 + ((x) << 12))
+#define CDR_DATA_BASE_ADDR_HI(x) (0xC + ((x) << 12))
+#define CDR_ACD_BASE_ADDR_LO(x) (0x10 + ((x) << 12))
+#define CDR_ACD_BASE_ADDR_HI(x) (0x14 + ((x) << 12))
+#define CDR_RING_SIZE(x) (0x18 + ((x) << 12))
+#define CDR_DESC_SIZE(x) (0x1C + ((x) << 12))
+#define CDR_CFG(x) (0x20 + ((x) << 12))
+#define CDR_DMA_CFG(x) (0x24 + ((x) << 12))
+#define CDR_THRESH(x) (0x28 + ((x) << 12))
+#define CDR_PREP_COUNT(x) (0x2C + ((x) << 12))
+#define CDR_PROC_COUNT(x) (0x30 + ((x) << 12))
+#define CDR_PREP_PNTR(x) (0x34 + ((x) << 12))
+#define CDR_PROC_PNTR(x) (0x38 + ((x) << 12))
+#define CDR_STAT(x) (0x3C + ((x) << 12))
+
+/* HIA, Result Descriptor Ring Manager */
+#define RDR_BASE_ADDR_LO(x) (0x800 + ((x) << 12))
+#define RDR_BASE_ADDR_HI(x) (0x804 + ((x) << 12))
+#define RDR_DATA_BASE_ADDR_LO(x) (0x808 + ((x) << 12))
+#define RDR_DATA_BASE_ADDR_HI(x) (0x80C + ((x) << 12))
+#define RDR_ACD_BASE_ADDR_LO(x) (0x810 + ((x) << 12))
+#define RDR_ACD_BASE_ADDR_HI(x) (0x814 + ((x) << 12))
+#define RDR_RING_SIZE(x) (0x818 + ((x) << 12))
+#define RDR_DESC_SIZE(x) (0x81C + ((x) << 12))
+#define RDR_CFG(x) (0x820 + ((x) << 12))
+#define RDR_DMA_CFG(x) (0x824 + ((x) << 12))
+#define RDR_THRESH(x) (0x828 + ((x) << 12))
+#define RDR_PREP_COUNT(x) (0x82C + ((x) << 12))
+#define RDR_PROC_COUNT(x) (0x830 + ((x) << 12))
+#define RDR_PREP_PNTR(x) (0x834 + ((x) << 12))
+#define RDR_PROC_PNTR(x) (0x838 + ((x) << 12))
+#define RDR_STAT(x) (0x83C + ((x) << 12))
+
+/* HIA, Ring AIC */
+#define AIC_POL_CTRL(x) (0xE000 - ((x) << 12))
+#define AIC_TYPE_CTRL(x) (0xE004 - ((x) << 12))
+#define AIC_ENABLE_CTRL(x) (0xE008 - ((x) << 12))
+#define AIC_RAW_STAL(x) (0xE00C - ((x) << 12))
+#define AIC_ENABLE_SET(x) (0xE00C - ((x) << 12))
+#define AIC_ENABLED_STAT(x) (0xE010 - ((x) << 12))
+#define AIC_ACK(x) (0xE010 - ((x) << 12))
+#define AIC_ENABLE_CLR(x) (0xE014 - ((x) << 12))
+#define AIC_OPTIONS(x) (0xE018 - ((x) << 12))
+#define AIC_VERSION(x) (0xE01C - ((x) << 12))
+
+/* HIA, Global AIC */
+#define AIC_G_POL_CTRL 0xF800
+#define AIC_G_TYPE_CTRL 0xF804
+#define AIC_G_ENABLE_CTRL 0xF808
+#define AIC_G_RAW_STAT 0xF80C
+#define AIC_G_ENABLE_SET 0xF80C
+#define AIC_G_ENABLED_STAT 0xF810
+#define AIC_G_ACK 0xF810
+#define AIC_G_ENABLE_CLR 0xF814
+#define AIC_G_OPTIONS 0xF818
+#define AIC_G_VERSION 0xF81C
+
+/* HIA, Data Fetch Engine */
+#define DFE_CFG 0xF000
+#define DFE_PRIO_0 0xF010
+#define DFE_PRIO_1 0xF014
+#define DFE_PRIO_2 0xF018
+#define DFE_PRIO_3 0xF01C
+
+/* HIA, Data Fetch Engine access monitoring for CDR */
+#define DFE_RING_REGION_LO(x) (0xF080 + ((x) << 3))
+#define DFE_RING_REGION_HI(x) (0xF084 + ((x) << 3))
+
+/* HIA, Data Fetch Engine thread control and status for thread */
+#define DFE_THR_CTRL 0xF200
+#define DFE_THR_STAT 0xF204
+#define DFE_THR_DESC_CTRL 0xF208
+#define DFE_THR_DESC_DPTR_LO 0xF210
+#define DFE_THR_DESC_DPTR_HI 0xF214
+#define DFE_THR_DESC_ACDPTR_LO 0xF218
+#define DFE_THR_DESC_ACDPTR_HI 0xF21C
+
+/* HIA, Data Store Engine */
+#define DSE_CFG 0xF400
+#define DSE_PRIO_0 0xF410
+#define DSE_PRIO_1 0xF414
+#define DSE_PRIO_2 0xF418
+#define DSE_PRIO_3 0xF41C
+
+/* HIA, Data Store Engine access monitoring for RDR */
+#define DSE_RING_REGION_LO(x) (0xF480 + ((x) << 3))
+#define DSE_RING_REGION_HI(x) (0xF484 + ((x) << 3))
+
+/* HIA, Data Store Engine thread control and status for thread */
+#define DSE_THR_CTRL 0xF600
+#define DSE_THR_STAT 0xF604
+#define DSE_THR_DESC_CTRL 0xF608
+#define DSE_THR_DESC_DPTR_LO 0xF610
+#define DSE_THR_DESC_DPTR_HI 0xF614
+#define DSE_THR_DESC_S_DPTR_LO 0xF618
+#define DSE_THR_DESC_S_DPTR_HI 0xF61C
+#define DSE_THR_ERROR_STAT 0xF620
+
+/* HIA Global */
+#define HIA_MST_CTRL 0xFFF4
+#define HIA_OPTIONS 0xFFF8
+#define HIA_VERSION 0xFFFC
+
+/* Processing Engine Input Side, Processing Engine */
+#define PE_IN_DBUF_THRESH 0x10000
+#define PE_IN_TBUF_THRESH 0x10100
+
+/* Packet Engine Configuration / Status Registers */
+#define PE_TOKEN_CTRL_STAT 0x11000
+#define PE_FUNCTION_EN 0x11004
+#define PE_CONTEXT_CTRL 0x11008
+#define PE_INTERRUPT_CTRL_STAT 0x11010
+#define PE_CONTEXT_STAT 0x1100C
+#define PE_OUT_TRANS_CTRL_STAT 0x11018
+#define PE_OUT_BUF_CTRL 0x1101C
+
+/* Packet Engine PRNG Registers */
+#define PE_PRNG_STAT 0x11040
+#define PE_PRNG_CTRL 0x11044
+#define PE_PRNG_SEED_L 0x11048
+#define PE_PRNG_SEED_H 0x1104C
+#define PE_PRNG_KEY_0_L 0x11050
+#define PE_PRNG_KEY_0_H 0x11054
+#define PE_PRNG_KEY_1_L 0x11058
+#define PE_PRNG_KEY_1_H 0x1105C
+#define PE_PRNG_RES_0 0x11060
+#define PE_PRNG_RES_1 0x11064
+#define PE_PRNG_RES_2 0x11068
+#define PE_PRNG_RES_3 0x1106C
+#define PE_PRNG_LFSR_L 0x11070
+#define PE_PRNG_LFSR_H 0x11074
+
+/* Packet Engine AIC */
+#define PE_EIP96_AIC_POL_CTRL 0x113C0
+#define PE_EIP96_AIC_TYPE_CTRL 0x113C4
+#define PE_EIP96_AIC_ENABLE_CTRL 0x113C8
+#define PE_EIP96_AIC_RAW_STAT 0x113CC
+#define PE_EIP96_AIC_ENABLE_SET 0x113CC
+#define PE_EIP96_AIC_ENABLED_STAT 0x113D0
+#define PE_EIP96_AIC_ACK 0x113D0
+#define PE_EIP96_AIC_ENABLE_CLR 0x113D4
+#define PE_EIP96_AIC_OPTIONS 0x113D8
+#define PE_EIP96_AIC_VERSION 0x113DC
+
+/* Packet Engine Options & Version Registers */
+#define PE_EIP96_OPTIONS 0x113F8
+#define PE_EIP96_VERSION 0x113FC
+
+/* Processing Engine Output Side */
+#define PE_OUT_DBUF_THRESH 0x11C00
+#define PE_OUT_TBUF_THRESH 0x11D00
+
+/* Processing Engine Local AIC */
+#define PE_AIC_POL_CTRL 0x11F00
+#define PE_AIC_TYPE_CTRL 0x11F04
+#define PE_AIC_ENABLE_CTRL 0x11F08
+#define PE_AIC_RAW_STAT 0x11F0C
+#define PE_AIC_ENABLE_SET 0x11F0C
+#define PE_AIC_ENABLED_STAT 0x11F10
+#define PE_AIC_ENABLE_CLR 0x11F14
+#define PE_AIC_OPTIONS 0x11F18
+#define PE_AIC_VERSION 0x11F1C
+
+/* Processing Engine General Configuration and Version */
+#define PE_IN_FLIGHT 0x11FF0
+#define PE_OPTIONS 0x11FF8
+#define PE_VERSION 0x11FFC
+
+/* EIP-97 - Global */
+#define EIP97_CLOCK_STATE 0x1FFE4
+#define EIP97_FORCE_CLOCK_ON 0x1FFE8
+#define EIP97_FORCE_CLOCK_OFF 0x1FFEC
+#define EIP97_MST_CTRL 0x1FFF4
+#define EIP97_OPTIONS 0x1FFF8
+#define EIP97_VERSION 0x1FFFC
+#endif /* __MTK_REGS_H__ */
diff --git a/drivers/crypto/mediatek/mtk-sha.c b/drivers/crypto/mediatek/mtk-sha.c
new file mode 100644
index 0000000..45479bb
--- /dev/null
+++ b/drivers/crypto/mediatek/mtk-sha.c
@@ -0,0 +1,1384 @@
+/*
+ * Cryptographic API.
+ *
+ * Support for MediaTek SHA1/SHA2 hardware accelerator.
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.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.
+ *
+ * Some ideas are from atmel-sha.c and omap-sham.c drivers.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/crypto.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/algapi.h>
+#include <crypto/sha.h>
+#include <crypto/internal/hash.h>
+#include "mtk-platform.h"
+#include "mtk-regs.h"
+
+#define SHA_ALIGN_MSK (sizeof(u32) - 1)
+#define SHA_QUEUE_SIZE 512
+#define SHA_TMP_STATE_SIZE 512
+
+#define SHA_DATA_LEN_MSK GENMASK(16, 0)
+#define SHA_BUFFER_LEN ((u32)PAGE_SIZE)
+
+#define SHA_OP_UPDATE 1
+#define SHA_OP_FINAL 2
+
+/* SHA command token */
+#define SHA_CT_SIZE 5
+#define SHA_CT_CTRL_HDR 0x02220000
+#define SHA_COMMAND0 0x03020000
+#define SHA_COMMAND1 0x21060000
+#define SHA_COMMAND2 0xe0e63802
+
+/* SHA transform information */
+#define SHA_TFM_HASH (0x2 << 0)
+#define SHA_TFM_DIG_TYPE (0x1 << 21)
+#define SHA_TFM_SIZE(x) ((x) << 8)
+#define SHA_TFM_START (0x1 << 4)
+#define SHA_TFM_CONTINUE (0x1 << 5)
+#define SHA_TFM_HASH_STORE (0x1 << 19)
+#define SHA_TFM_SHA1 (0x2 << 23)
+#define SHA_TFM_SHA256 (0x3 << 23)
+#define SHA_TFM_SHA224 (0x4 << 23)
+#define SHA_TFM_SHA512 (0x5 << 23)
+#define SHA_TFM_SHA384 (0x6 << 23)
+#define SHA_TFM_DIGEST(x) (((x) & 0xf) << 24)
+
+/* SHA flags */
+#define SHA_FLAGS_BUSY BIT(0)
+#define SHA_FLAGS_FINAL BIT(1)
+#define SHA_FLAGS_FINUP BIT(2)
+#define SHA_FLAGS_SG BIT(3)
+#define SHA_FLAGS_ALGO_MASK GENMASK(8, 4)
+#define SHA_FLAGS_SHA1 BIT(4)
+#define SHA_FLAGS_SHA224 BIT(5)
+#define SHA_FLAGS_SHA256 BIT(6)
+#define SHA_FLAGS_SHA384 BIT(7)
+#define SHA_FLAGS_SHA512 BIT(8)
+#define SHA_FLAGS_HMAC BIT(9)
+#define SHA_FLAGS_PAD BIT(10)
+
+/* SHA command token */
+struct mtk_sha_ct {
+ u32 tfm_ctrl0;
+ u32 tfm_ctrl1;
+ u32 ct_ctrl0;
+ u32 ct_ctrl1;
+ u32 ct_ctrl2;
+};
+
+/* SHA transform state */
+struct mtk_sha_tfm {
+ u32 tfm_ctrl0;
+ u32 tfm_ctrl1;
+ u8 digest[SHA512_DIGEST_SIZE] __aligned(sizeof(u32));
+};
+
+struct mtk_sha_info {
+ struct mtk_sha_ct ct;
+ struct mtk_sha_tfm tfm;
+};
+
+struct mtk_sha_reqctx {
+ struct mtk_sha_info info;
+ unsigned long flags;
+ unsigned long op;
+
+ u64 digcnt;
+ bool start;
+ size_t bufcnt;
+ dma_addr_t dma_addr;
+
+ /* walk state */
+ struct scatterlist *sg;
+ u32 offset; /* offset in current sg */
+ u32 total; /* total request */
+ size_t ds;
+ size_t bs;
+
+ u8 *buffer;
+};
+
+struct mtk_sha_hmac_ctx {
+ struct crypto_shash *shash;
+ u8 ipad[SHA512_BLOCK_SIZE] __aligned(sizeof(u32));
+ u8 opad[SHA512_BLOCK_SIZE] __aligned(sizeof(u32));
+};
+
+struct mtk_sha_ctx {
+ struct mtk_cryp *cryp;
+ unsigned long flags;
+ u8 id;
+ u8 buf[SHA_BUFFER_LEN] __aligned(sizeof(u32));
+
+ struct mtk_sha_hmac_ctx base[0];
+};
+
+struct mtk_sha_drv {
+ struct list_head dev_list;
+ /* device list lock */
+ spinlock_t lock;
+};
+
+static struct mtk_sha_drv mtk_sha = {
+ .dev_list = LIST_HEAD_INIT(mtk_sha.dev_list),
+ .lock = __SPIN_LOCK_UNLOCKED(mtk_sha.lock),
+};
+
+static int mtk_sha_handle_queue(struct mtk_cryp *cryp, u8 id,
+ struct ahash_request *req);
+
+static inline u32 mtk_sha_read(struct mtk_cryp *cryp, u32 offset)
+{
+ return readl_relaxed(cryp->base + offset);
+}
+
+static inline void mtk_sha_write(struct mtk_cryp *cryp,
+ u32 offset, u32 value)
+{
+ writel_relaxed(value, cryp->base + offset);
+}
+
+static struct mtk_cryp *mtk_sha_find_dev(struct mtk_sha_ctx *tctx)
+{
+ struct mtk_cryp *cryp = NULL;
+ struct mtk_cryp *tmp;
+
+ spin_lock_bh(&mtk_sha.lock);
+ if (!tctx->cryp) {
+ list_for_each_entry(tmp, &mtk_sha.dev_list, sha_list) {
+ cryp = tmp;
+ break;
+ }
+ tctx->cryp = cryp;
+ } else {
+ cryp = tctx->cryp;
+ }
+
+ /*
+ * Assign record id to tfm in round-robin fashion, and this
+ * help us to link to descriptor ring and record.
+ */
+ tctx->id = cryp->rec;
+ cryp->rec = !cryp->rec;
+
+ spin_unlock_bh(&mtk_sha.lock);
+
+ return cryp;
+}
+
+static int mtk_sha_append_sg(struct mtk_sha_reqctx *ctx)
+{
+ size_t count;
+
+ while ((ctx->bufcnt < SHA_BUFFER_LEN) && ctx->total) {
+ count = min(ctx->sg->length - ctx->offset, ctx->total);
+ count = min(count, SHA_BUFFER_LEN - ctx->bufcnt);
+
+ if (count <= 0) {
+ /*
+ * Check if count <= 0 because the buffer is full or
+ * because the sg length is 0. In the latest case,
+ * check if there is another sg in the list, a 0 length
+ * sg doesn't necessarily mean the end of the sg list.
+ */
+ if ((ctx->sg->length == 0) && !sg_is_last(ctx->sg)) {
+ ctx->sg = sg_next(ctx->sg);
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ scatterwalk_map_and_copy(ctx->buffer + ctx->bufcnt, ctx->sg,
+ ctx->offset, count, 0);
+
+ ctx->bufcnt += count;
+ ctx->offset += count;
+ ctx->total -= count;
+
+ if (ctx->offset == ctx->sg->length) {
+ ctx->sg = sg_next(ctx->sg);
+ if (ctx->sg)
+ ctx->offset = 0;
+ else
+ ctx->total = 0;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * The purpose of this padding is to ensure that the padded message is a
+ * multiple of 512 bits (SHA1/SHA224/SHA256) or 1024 bits (SHA384/SHA512).
+ * The bit "1" is appended at the end of the message followed by
+ * "padlen-1" zero bits. Then a 64 bits block (SHA1/SHA224/SHA256) or
+ * 128 bits block (SHA384/SHA512) equals to the message length in bits
+ * is appended.
+ *
+ * For SHA1/SHA224/SHA256, padlen is calculated as followed:
+ * - if message length < 56 bytes then padlen = 56 - message length
+ * - else padlen = 64 + 56 - message length
+ *
+ * For SHA384/SHA512, padlen is calculated as followed:
+ * - if message length < 112 bytes then padlen = 112 - message length
+ * - else padlen = 128 + 112 - message length
+ */
+static void mtk_sha_fill_padding(struct mtk_sha_reqctx *ctx, u32 len)
+{
+ u32 index, padlen;
+ u64 bits[2];
+ u64 size = ctx->digcnt;
+
+ size += ctx->bufcnt;
+ size += len;
+
+ bits[1] = cpu_to_be64(size << 3);
+ bits[0] = cpu_to_be64(size >> 61);
+
+ if (ctx->flags & (SHA_FLAGS_SHA384 | SHA_FLAGS_SHA512)) {
+ index = ctx->bufcnt & 0x7f;
+ padlen = (index < 112) ? (112 - index) : ((128 + 112) - index);
+ *(ctx->buffer + ctx->bufcnt) = 0x80;
+ memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen - 1);
+ memcpy(ctx->buffer + ctx->bufcnt + padlen, bits, 16);
+ ctx->bufcnt += padlen + 16;
+ ctx->flags |= SHA_FLAGS_PAD;
+ } else {
+ index = ctx->bufcnt & 0x3f;
+ padlen = (index < 56) ? (56 - index) : ((64 + 56) - index);
+ *(ctx->buffer + ctx->bufcnt) = 0x80;
+ memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen - 1);
+ memcpy(ctx->buffer + ctx->bufcnt + padlen, &bits[1], 8);
+ ctx->bufcnt += padlen + 8;
+ ctx->flags |= SHA_FLAGS_PAD;
+ }
+}
+
+static void mtk_sha_info_init(struct mtk_sha *sha,
+ struct mtk_sha_reqctx *ctx)
+{
+ struct mtk_sha_info *info = sha->info;
+ struct mtk_sha_ct *ct = &info->ct;
+ struct mtk_sha_tfm *tfm = &info->tfm;
+
+ sha->ct_hdr = SHA_CT_CTRL_HDR;
+ sha->ct_size = SHA_CT_SIZE;
+
+ tfm->tfm_ctrl0 = SHA_TFM_HASH | SHA_TFM_DIG_TYPE |
+ SHA_TFM_SIZE(WORD(ctx->ds));
+
+ switch (ctx->flags & SHA_FLAGS_ALGO_MASK) {
+ case SHA_FLAGS_SHA1:
+ tfm->tfm_ctrl0 |= SHA_TFM_SHA1;
+ break;
+ case SHA_FLAGS_SHA224:
+ tfm->tfm_ctrl0 |= SHA_TFM_SHA224;
+ break;
+ case SHA_FLAGS_SHA256:
+ tfm->tfm_ctrl0 |= SHA_TFM_SHA256;
+ break;
+ case SHA_FLAGS_SHA384:
+ tfm->tfm_ctrl0 |= SHA_TFM_SHA384;
+ break;
+ case SHA_FLAGS_SHA512:
+ tfm->tfm_ctrl0 |= SHA_TFM_SHA512;
+ break;
+
+ default:
+ /* Should not happen... */
+ return;
+ }
+
+ tfm->tfm_ctrl1 = SHA_TFM_HASH_STORE;
+ ct->tfm_ctrl0 = tfm->tfm_ctrl0 | SHA_TFM_CONTINUE | SHA_TFM_START;
+ ct->tfm_ctrl1 = tfm->tfm_ctrl1;
+
+ ct->ct_ctrl0 = SHA_COMMAND0;
+ ct->ct_ctrl1 = SHA_COMMAND1;
+ ct->ct_ctrl2 = SHA_COMMAND2 | SHA_TFM_DIGEST(WORD(ctx->ds));
+}
+
+static int mtk_sha_info_map(struct mtk_cryp *cryp,
+ struct mtk_sha *sha, size_t len)
+{
+ struct mtk_sha_reqctx *ctx = ahash_request_ctx(sha->req);
+ struct mtk_sha_info *info = sha->info;
+ struct mtk_sha_ct *ct = &info->ct;
+
+ if (ctx->start)
+ ctx->start = false;
+ else
+ ct->tfm_ctrl0 &= ~SHA_TFM_START;
+
+ sha->ct_hdr = (sha->ct_hdr & ~SHA_DATA_LEN_MSK) | len;
+ ct->ct_ctrl0 = (ct->ct_ctrl0 & ~SHA_DATA_LEN_MSK) | len;
+
+ ctx->digcnt += len;
+
+ sha->ct_dma = dma_map_single(cryp->dev, info, sizeof(*info),
+ DMA_BIDIRECTIONAL);
+ if (unlikely(dma_mapping_error(cryp->dev, sha->ct_dma))) {
+ dev_err(cryp->dev, "dma %d bytes error\n", sizeof(*info));
+ return -EINVAL;
+ }
+ sha->tfm_dma = sha->ct_dma + sizeof(*ct);
+
+ return 0;
+}
+
+static int mtk_sha_finish_hmac(struct ahash_request *req)
+{
+ struct mtk_sha_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
+ struct mtk_sha_hmac_ctx *bctx = tctx->base;
+ struct mtk_sha_reqctx *ctx = ahash_request_ctx(req);
+
+ SHASH_DESC_ON_STACK(shash, bctx->shash);
+
+ shash->tfm = bctx->shash;
+ shash->flags = 0; /* not CRYPTO_TFM_REQ_MAY_SLEEP */
+
+ return crypto_shash_init(shash) ?:
+ crypto_shash_update(shash, bctx->opad, ctx->bs) ?:
+ crypto_shash_finup(shash, req->result, ctx->ds, req->result);
+}
+
+static int mtk_sha_init(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct mtk_sha_ctx *tctx = crypto_ahash_ctx(tfm);
+ struct mtk_sha_reqctx *ctx = ahash_request_ctx(req);
+
+ ctx->flags = 0;
+ ctx->ds = crypto_ahash_digestsize(tfm);
+
+ switch (ctx->ds) {
+ case SHA1_DIGEST_SIZE:
+ ctx->flags |= SHA_FLAGS_SHA1;
+ ctx->bs = SHA1_BLOCK_SIZE;
+ break;
+ case SHA224_DIGEST_SIZE:
+ ctx->flags |= SHA_FLAGS_SHA224;
+ ctx->bs = SHA224_BLOCK_SIZE;
+ break;
+ case SHA256_DIGEST_SIZE:
+ ctx->flags |= SHA_FLAGS_SHA256;
+ ctx->bs = SHA256_BLOCK_SIZE;
+ break;
+ case SHA384_DIGEST_SIZE:
+ ctx->flags |= SHA_FLAGS_SHA384;
+ ctx->bs = SHA384_BLOCK_SIZE;
+ break;
+ case SHA512_DIGEST_SIZE:
+ ctx->flags |= SHA_FLAGS_SHA512;
+ ctx->bs = SHA512_BLOCK_SIZE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ctx->bufcnt = 0;
+ ctx->digcnt = 0;
+ ctx->buffer = tctx->buf;
+ ctx->start = true;
+
+ if (tctx->flags & SHA_FLAGS_HMAC) {
+ struct mtk_sha_hmac_ctx *bctx = tctx->base;
+
+ memcpy(ctx->buffer, bctx->ipad, ctx->bs);
+ ctx->bufcnt = ctx->bs;
+ ctx->flags |= SHA_FLAGS_HMAC;
+ }
+
+ return 0;
+}
+
+static int mtk_sha_xmit(struct mtk_cryp *cryp, struct mtk_sha *sha,
+ dma_addr_t addr, size_t len)
+{
+ struct mtk_ring *ring = cryp->ring[sha->id];
+ struct mtk_desc *cmd = ring->cmd_base + ring->pos;
+ struct mtk_desc *res = ring->res_base + ring->pos;
+ int err;
+
+ err = mtk_sha_info_map(cryp, sha, len);
+ if (err)
+ return err;
+
+ res->hdr = MTK_DESC_FIRST | MTK_DESC_LAST |
+ MTK_DESC_BUF_LEN(len);
+
+ res->buf = cryp->tmp_dma;
+
+ cmd->hdr = MTK_DESC_FIRST | MTK_DESC_LAST |
+ MTK_DESC_BUF_LEN(len) |
+ MTK_DESC_CT_LEN(sha->ct_size);
+
+ cmd->buf = addr;
+ cmd->ct = sha->ct_dma;
+ cmd->ct_hdr = sha->ct_hdr;
+ cmd->tfm = sha->tfm_dma;
+
+ if (++ring->pos == MTK_MAX_DESC_NUM)
+ ring->pos = 0;
+
+ /* make sure all descriptor are filled done */
+ wmb();
+ mtk_sha_write(cryp, RDR_PREP_COUNT(sha->id), MTK_DESC_CNT(1));
+ mtk_sha_write(cryp, CDR_PREP_COUNT(sha->id), MTK_DESC_CNT(1));
+
+ return -EINPROGRESS;
+}
+
+static int mtk_sha_xmit2(struct mtk_cryp *cryp, struct mtk_sha *sha,
+ struct mtk_sha_reqctx *ctx, size_t len1, size_t len2)
+{
+ struct mtk_ring *ring = cryp->ring[sha->id];
+ struct mtk_desc *cmd = ring->cmd_base + ring->pos;
+ struct mtk_desc *res = ring->res_base + ring->pos;
+ int err;
+
+ err = mtk_sha_info_map(cryp, sha, len1 + len2);
+ if (err)
+ return err;
+
+ res->hdr = MTK_DESC_BUF_LEN(len1) | MTK_DESC_FIRST;
+ res->buf = cryp->tmp_dma;
+
+ cmd->hdr = MTK_DESC_BUF_LEN(len1) | MTK_DESC_FIRST |
+ MTK_DESC_CT_LEN(sha->ct_size);
+ cmd->buf = sg_dma_address(ctx->sg);
+ cmd->ct = sha->ct_dma;
+ cmd->ct_hdr = sha->ct_hdr;
+ cmd->tfm = sha->tfm_dma;
+
+ if (++ring->pos == MTK_MAX_DESC_NUM)
+ ring->pos = 0;
+
+ cmd = ring->cmd_base + ring->pos;
+ res = ring->res_base + ring->pos;
+
+ res->hdr = MTK_DESC_BUF_LEN(len2) | MTK_DESC_LAST;
+ res->buf = cryp->tmp_dma;
+
+ cmd->hdr = MTK_DESC_BUF_LEN(len2) | MTK_DESC_LAST;
+ cmd->buf = ctx->dma_addr;
+
+ if (++ring->pos == MTK_MAX_DESC_NUM)
+ ring->pos = 0;
+
+ /* make sure all descriptor are filled done */
+ wmb();
+ mtk_sha_write(cryp, RDR_PREP_COUNT(sha->id), MTK_DESC_CNT(2));
+ mtk_sha_write(cryp, CDR_PREP_COUNT(sha->id), MTK_DESC_CNT(2));
+
+ return -EINPROGRESS;
+}
+
+static int mtk_sha_dma_map(struct mtk_cryp *cryp, struct mtk_sha *sha,
+ struct mtk_sha_reqctx *ctx, size_t count)
+{
+ ctx->dma_addr = dma_map_single(cryp->dev, ctx->buffer,
+ SHA_BUFFER_LEN, DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(cryp->dev, ctx->dma_addr))) {
+ dev_err(cryp->dev, "dma map error\n");
+ return -EINVAL;
+ }
+
+ ctx->flags &= ~SHA_FLAGS_SG;
+
+ return mtk_sha_xmit(cryp, sha, ctx->dma_addr, count);
+}
+
+static int mtk_sha_update_slow(struct mtk_cryp *cryp, struct mtk_sha *sha)
+{
+ struct mtk_sha_reqctx *ctx = ahash_request_ctx(sha->req);
+ size_t count;
+ u32 final;
+
+ mtk_sha_append_sg(ctx);
+
+ final = (ctx->flags & SHA_FLAGS_FINUP) && !ctx->total;
+
+ dev_dbg(cryp->dev, "slow: bufcnt: %u\n", ctx->bufcnt);
+
+ if (final) {
+ sha->flags |= SHA_FLAGS_FINAL;
+ mtk_sha_fill_padding(ctx, 0);
+ }
+
+ if (final || (ctx->bufcnt == SHA_BUFFER_LEN && ctx->total)) {
+ count = ctx->bufcnt;
+ ctx->bufcnt = 0;
+
+ return mtk_sha_dma_map(cryp, sha, ctx, count);
+ }
+ return 0;
+}
+
+static int mtk_sha_update_req(struct mtk_cryp *cryp, struct mtk_sha *sha)
+{
+ struct mtk_sha_reqctx *ctx = ahash_request_ctx(sha->req);
+ u32 len, final, tail;
+ struct scatterlist *sg;
+
+ if (!ctx->total)
+ return 0;
+
+ if (ctx->bufcnt || ctx->offset)
+ return mtk_sha_update_slow(cryp, sha);
+
+ sg = ctx->sg;
+
+ if (!IS_ALIGNED(sg->offset, sizeof(u32)))
+ return mtk_sha_update_slow(cryp, sha);
+
+ if (!sg_is_last(sg) && !IS_ALIGNED(sg->length, ctx->bs))
+ /* size is not bs aligned */
+ return mtk_sha_update_slow(cryp, sha);
+
+ len = min(ctx->total, sg->length);
+
+ if (sg_is_last(sg)) {
+ if (!(ctx->flags & SHA_FLAGS_FINUP)) {
+ /* not last sg must be bs aligned */
+ tail = len & (ctx->bs - 1);
+ len -= tail;
+ }
+ }
+
+ ctx->total -= len;
+ ctx->offset = len; /* offset where to start slow */
+
+ final = (ctx->flags & SHA_FLAGS_FINUP) && !ctx->total;
+
+ /* Add padding */
+ if (final) {
+ size_t count;
+
+ tail = len & (ctx->bs - 1);
+ len -= tail;
+ ctx->total += tail;
+ ctx->offset = len; /* offset where to start slow */
+
+ sg = ctx->sg;
+ mtk_sha_append_sg(ctx);
+ mtk_sha_fill_padding(ctx, len);
+
+ ctx->dma_addr = dma_map_single(cryp->dev, ctx->buffer,
+ SHA_BUFFER_LEN, DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(cryp->dev, ctx->dma_addr))) {
+ dev_err(cryp->dev, "dma map bytes error\n");
+ return -EINVAL;
+ }
+
+ sha->flags |= SHA_FLAGS_FINAL;
+ count = ctx->bufcnt;
+ ctx->bufcnt = 0;
+
+ if (len == 0) {
+ ctx->flags &= ~SHA_FLAGS_SG;
+ return mtk_sha_xmit(cryp, sha, ctx->dma_addr, count);
+
+ } else {
+ ctx->sg = sg;
+ if (!dma_map_sg(cryp->dev, ctx->sg, 1, DMA_TO_DEVICE)) {
+ dev_err(cryp->dev, "dma_map_sg error\n");
+ return -EINVAL;
+ }
+
+ ctx->flags |= SHA_FLAGS_SG;
+ return mtk_sha_xmit2(cryp, sha, ctx, len, count);
+ }
+ }
+
+ if (!dma_map_sg(cryp->dev, ctx->sg, 1, DMA_TO_DEVICE)) {
+ dev_err(cryp->dev, "dma_map_sg error\n");
+ return -EINVAL;
+ }
+
+ ctx->flags |= SHA_FLAGS_SG;
+
+ return mtk_sha_xmit(cryp, sha, sg_dma_address(ctx->sg), len);
+}
+
+static int mtk_sha_final_req(struct mtk_cryp *cryp, struct mtk_sha *sha)
+{
+ struct ahash_request *req = sha->req;
+ struct mtk_sha_reqctx *ctx = ahash_request_ctx(req);
+ size_t count;
+
+ mtk_sha_fill_padding(ctx, 0);
+
+ sha->flags |= SHA_FLAGS_FINAL;
+ count = ctx->bufcnt;
+ ctx->bufcnt = 0;
+
+ return mtk_sha_dma_map(cryp, sha, ctx, count);
+}
+
+static int mtk_sha_finish(struct ahash_request *req)
+{
+ struct mtk_sha_reqctx *ctx = ahash_request_ctx(req);
+ u8 *digest = ctx->info.tfm.digest;
+
+ memcpy(req->result, digest, ctx->ds);
+
+ if (ctx->flags & SHA_FLAGS_HMAC)
+ return mtk_sha_finish_hmac(req);
+
+ return 0;
+}
+
+static void mtk_sha_finish_req(struct mtk_cryp *cryp,
+ struct mtk_sha *sha, int err)
+{
+ if (likely(!err && (SHA_FLAGS_FINAL & sha->flags)))
+ err = mtk_sha_finish(sha->req);
+
+ sha->flags &= ~(SHA_FLAGS_BUSY | SHA_FLAGS_FINAL);
+
+ sha->req->base.complete(&sha->req->base, err);
+ mtk_sha_handle_queue(cryp, sha->id - RING2, NULL);
+}
+
+static int mtk_sha_handle_queue(struct mtk_cryp *cryp, u8 id,
+ struct ahash_request *req)
+{
+ struct mtk_sha *sha = cryp->sha[id];
+ struct crypto_async_request *async_req, *backlog;
+ struct mtk_sha_reqctx *ctx;
+ unsigned long flags;
+ int err = 0, ret = 0;
+
+ spin_lock_irqsave(&sha->lock, flags);
+ if (req)
+ ret = ahash_enqueue_request(&sha->queue, req);
+
+ if (SHA_FLAGS_BUSY & sha->flags) {
+ spin_unlock_irqrestore(&sha->lock, flags);
+ return ret;
+ }
+
+ backlog = crypto_get_backlog(&sha->queue);
+ async_req = crypto_dequeue_request(&sha->queue);
+ if (async_req)
+ sha->flags |= SHA_FLAGS_BUSY;
+ spin_unlock_irqrestore(&sha->lock, flags);
+
+ if (!async_req)
+ return ret;
+
+ if (backlog)
+ backlog->complete(backlog, -EINPROGRESS);
+
+ req = ahash_request_cast(async_req);
+ ctx = ahash_request_ctx(req);
+
+ sha->req = req;
+ sha->info = &ctx->info;
+
+ mtk_sha_info_init(sha, ctx);
+
+ if (ctx->op == SHA_OP_UPDATE) {
+ err = mtk_sha_update_req(cryp, sha);
+ if (err != -EINPROGRESS && (ctx->flags & SHA_FLAGS_FINUP))
+ /* no final() after finup() */
+ err = mtk_sha_final_req(cryp, sha);
+ } else if (ctx->op == SHA_OP_FINAL) {
+ err = mtk_sha_final_req(cryp, sha);
+ }
+
+ if (unlikely(err != -EINPROGRESS))
+ /* task will not finish it, so do it here */
+ mtk_sha_finish_req(cryp, sha, err);
+
+ return ret;
+}
+
+static int mtk_sha_enqueue(struct ahash_request *req, u32 op)
+{
+ struct mtk_sha_reqctx *ctx = ahash_request_ctx(req);
+ struct mtk_sha_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
+
+ ctx->op = op;
+
+ return mtk_sha_handle_queue(tctx->cryp, tctx->id, req);
+}
+
+static void mtk_sha_unmap(struct mtk_cryp *cryp, struct mtk_sha *sha)
+{
+ struct mtk_sha_reqctx *ctx = ahash_request_ctx(sha->req);
+
+ dma_unmap_single(cryp->dev, sha->ct_dma,
+ sizeof(struct mtk_sha_info), DMA_BIDIRECTIONAL);
+
+ if (ctx->flags & SHA_FLAGS_SG) {
+ dma_unmap_sg(cryp->dev, ctx->sg, 1, DMA_TO_DEVICE);
+ if (ctx->sg->length == ctx->offset) {
+ ctx->sg = sg_next(ctx->sg);
+ if (ctx->sg)
+ ctx->offset = 0;
+ }
+ if (ctx->flags & SHA_FLAGS_PAD) {
+ dma_unmap_single(cryp->dev, ctx->dma_addr,
+ SHA_BUFFER_LEN, DMA_TO_DEVICE);
+ }
+ } else
+ dma_unmap_single(cryp->dev, ctx->dma_addr,
+ SHA_BUFFER_LEN, DMA_TO_DEVICE);
+}
+
+static void mtk_sha_complete(struct mtk_cryp *cryp, struct mtk_sha *sha)
+{
+ int err = 0;
+
+ err = mtk_sha_update_req(cryp, sha);
+ if (err != -EINPROGRESS)
+ mtk_sha_finish_req(cryp, sha, err);
+}
+
+static int mtk_sha_update(struct ahash_request *req)
+{
+ struct mtk_sha_reqctx *ctx = ahash_request_ctx(req);
+
+ ctx->total = req->nbytes;
+ ctx->sg = req->src;
+ ctx->offset = 0;
+
+ if ((ctx->bufcnt + ctx->total < SHA_BUFFER_LEN) &&
+ !(ctx->flags & SHA_FLAGS_FINUP))
+ return mtk_sha_append_sg(ctx);
+
+ return mtk_sha_enqueue(req, SHA_OP_UPDATE);
+}
+
+static int mtk_sha_final(struct ahash_request *req)
+{
+ struct mtk_sha_reqctx *ctx = ahash_request_ctx(req);
+
+ ctx->flags |= SHA_FLAGS_FINUP;
+
+ if (ctx->flags & SHA_FLAGS_PAD)
+ return mtk_sha_finish(req);
+
+ return mtk_sha_enqueue(req, SHA_OP_FINAL);
+}
+
+static int mtk_sha_finup(struct ahash_request *req)
+{
+ struct mtk_sha_reqctx *ctx = ahash_request_ctx(req);
+ int err1, err2;
+
+ ctx->flags |= SHA_FLAGS_FINUP;
+
+ err1 = mtk_sha_update(req);
+ if (err1 == -EINPROGRESS || err1 == -EBUSY)
+ return err1;
+ /*
+ * final() has to be always called to cleanup resources
+ * even if update() failed
+ */
+ err2 = mtk_sha_final(req);
+
+ return err1 ?: err2;
+}
+
+static int mtk_sha_digest(struct ahash_request *req)
+{
+ return mtk_sha_init(req) ?: mtk_sha_finup(req);
+}
+
+static int mtk_sha_setkey(struct crypto_ahash *tfm,
+ const unsigned char *key, u32 keylen)
+{
+ struct mtk_sha_ctx *tctx = crypto_ahash_ctx(tfm);
+ struct mtk_sha_hmac_ctx *bctx = tctx->base;
+ size_t bs = crypto_shash_blocksize(bctx->shash);
+ size_t ds = crypto_shash_digestsize(bctx->shash);
+ int err, i;
+
+ SHASH_DESC_ON_STACK(shash, bctx->shash);
+
+ shash->tfm = bctx->shash;
+ shash->flags = crypto_shash_get_flags(bctx->shash) &
+ CRYPTO_TFM_REQ_MAY_SLEEP;
+
+ if (keylen > bs) {
+ err = crypto_shash_digest(shash, key, keylen, bctx->ipad);
+ if (err)
+ return err;
+ keylen = ds;
+ } else {
+ memcpy(bctx->ipad, key, keylen);
+ }
+
+ memset(bctx->ipad + keylen, 0, bs - keylen);
+ memcpy(bctx->opad, bctx->ipad, bs);
+
+ for (i = 0; i < bs; i++) {
+ bctx->ipad[i] ^= 0x36;
+ bctx->opad[i] ^= 0x5c;
+ }
+
+ return err;
+}
+
+static int mtk_sha_export(struct ahash_request *req, void *out)
+{
+ const struct mtk_sha_reqctx *ctx = ahash_request_ctx(req);
+
+ memcpy(out, ctx, sizeof(*ctx));
+ return 0;
+}
+
+static int mtk_sha_import(struct ahash_request *req, const void *in)
+{
+ struct mtk_sha_reqctx *ctx = ahash_request_ctx(req);
+
+ memcpy(ctx, in, sizeof(*ctx));
+ return 0;
+}
+
+static int mtk_sha_cra_init_alg(struct crypto_tfm *tfm,
+ const char *alg_base)
+{
+ struct mtk_sha_ctx *tctx = crypto_tfm_ctx(tfm);
+ struct mtk_cryp *cryp = NULL;
+
+ cryp = mtk_sha_find_dev(tctx);
+ if (!cryp)
+ return -ENODEV;
+
+ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+ sizeof(struct mtk_sha_reqctx));
+
+ if (alg_base) {
+ struct mtk_sha_hmac_ctx *bctx = tctx->base;
+
+ tctx->flags |= SHA_FLAGS_HMAC;
+ bctx->shash = crypto_alloc_shash(alg_base, 0,
+ CRYPTO_ALG_NEED_FALLBACK);
+ if (IS_ERR(bctx->shash)) {
+ pr_err("base driver %s could not be loaded.\n",
+ alg_base);
+
+ return PTR_ERR(bctx->shash);
+ }
+ }
+ return 0;
+}
+
+static int mtk_sha_cra_init(struct crypto_tfm *tfm)
+{
+ return mtk_sha_cra_init_alg(tfm, NULL);
+}
+
+static int mtk_sha_cra_sha1_init(struct crypto_tfm *tfm)
+{
+ return mtk_sha_cra_init_alg(tfm, "sha1");
+}
+
+static int mtk_sha_cra_sha224_init(struct crypto_tfm *tfm)
+{
+ return mtk_sha_cra_init_alg(tfm, "sha224");
+}
+
+static int mtk_sha_cra_sha256_init(struct crypto_tfm *tfm)
+{
+ return mtk_sha_cra_init_alg(tfm, "sha256");
+}
+
+static int mtk_sha_cra_sha384_init(struct crypto_tfm *tfm)
+{
+ return mtk_sha_cra_init_alg(tfm, "sha384");
+}
+
+static int mtk_sha_cra_sha512_init(struct crypto_tfm *tfm)
+{
+ return mtk_sha_cra_init_alg(tfm, "sha512");
+}
+
+static void mtk_sha_cra_exit(struct crypto_tfm *tfm)
+{
+ struct mtk_sha_ctx *tctx = crypto_tfm_ctx(tfm);
+
+ if (tctx->flags & SHA_FLAGS_HMAC) {
+ struct mtk_sha_hmac_ctx *bctx = tctx->base;
+
+ crypto_free_shash(bctx->shash);
+ }
+}
+
+static struct ahash_alg algs_sha1_sha224_sha256[] = {
+{
+ .init = mtk_sha_init,
+ .update = mtk_sha_update,
+ .final = mtk_sha_final,
+ .finup = mtk_sha_finup,
+ .digest = mtk_sha_digest,
+ .export = mtk_sha_export,
+ .import = mtk_sha_import,
+ .halg.digestsize = SHA1_DIGEST_SIZE,
+ .halg.statesize = sizeof(struct mtk_sha_reqctx),
+ .halg.base = {
+ .cra_name = "sha1",
+ .cra_driver_name = "mtk-sha1",
+ .cra_priority = 400,
+ .cra_flags = CRYPTO_ALG_ASYNC,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct mtk_sha_ctx),
+ .cra_alignmask = SHA_ALIGN_MSK,
+ .cra_module = THIS_MODULE,
+ .cra_init = mtk_sha_cra_init,
+ .cra_exit = mtk_sha_cra_exit,
+ }
+},
+{
+ .init = mtk_sha_init,
+ .update = mtk_sha_update,
+ .final = mtk_sha_final,
+ .finup = mtk_sha_finup,
+ .digest = mtk_sha_digest,
+ .export = mtk_sha_export,
+ .import = mtk_sha_import,
+ .halg.digestsize = SHA224_DIGEST_SIZE,
+ .halg.statesize = sizeof(struct mtk_sha_reqctx),
+ .halg.base = {
+ .cra_name = "sha224",
+ .cra_driver_name = "mtk-sha224",
+ .cra_priority = 400,
+ .cra_flags = CRYPTO_ALG_ASYNC,
+ .cra_blocksize = SHA224_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct mtk_sha_ctx),
+ .cra_alignmask = SHA_ALIGN_MSK,
+ .cra_module = THIS_MODULE,
+ .cra_init = mtk_sha_cra_init,
+ .cra_exit = mtk_sha_cra_exit,
+ }
+},
+{
+ .init = mtk_sha_init,
+ .update = mtk_sha_update,
+ .final = mtk_sha_final,
+ .finup = mtk_sha_finup,
+ .digest = mtk_sha_digest,
+ .export = mtk_sha_export,
+ .import = mtk_sha_import,
+ .halg.digestsize = SHA256_DIGEST_SIZE,
+ .halg.statesize = sizeof(struct mtk_sha_reqctx),
+ .halg.base = {
+ .cra_name = "sha256",
+ .cra_driver_name = "mtk-sha256",
+ .cra_priority = 400,
+ .cra_flags = CRYPTO_ALG_ASYNC,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct mtk_sha_ctx),
+ .cra_alignmask = SHA_ALIGN_MSK,
+ .cra_module = THIS_MODULE,
+ .cra_init = mtk_sha_cra_init,
+ .cra_exit = mtk_sha_cra_exit,
+ }
+},
+{
+ .init = mtk_sha_init,
+ .update = mtk_sha_update,
+ .final = mtk_sha_final,
+ .finup = mtk_sha_finup,
+ .digest = mtk_sha_digest,
+ .export = mtk_sha_export,
+ .import = mtk_sha_import,
+ .setkey = mtk_sha_setkey,
+ .halg.digestsize = SHA1_DIGEST_SIZE,
+ .halg.statesize = sizeof(struct mtk_sha_reqctx),
+ .halg.base = {
+ .cra_name = "hmac(sha1)",
+ .cra_driver_name = "mtk-hmac-sha1",
+ .cra_priority = 400,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct mtk_sha_ctx) +
+ sizeof(struct mtk_sha_hmac_ctx),
+ .cra_alignmask = SHA_ALIGN_MSK,
+ .cra_module = THIS_MODULE,
+ .cra_init = mtk_sha_cra_sha1_init,
+ .cra_exit = mtk_sha_cra_exit,
+ }
+},
+{
+ .init = mtk_sha_init,
+ .update = mtk_sha_update,
+ .final = mtk_sha_final,
+ .finup = mtk_sha_finup,
+ .digest = mtk_sha_digest,
+ .export = mtk_sha_export,
+ .import = mtk_sha_import,
+ .setkey = mtk_sha_setkey,
+ .halg.digestsize = SHA224_DIGEST_SIZE,
+ .halg.statesize = sizeof(struct mtk_sha_reqctx),
+ .halg.base = {
+ .cra_name = "hmac(sha224)",
+ .cra_driver_name = "mtk-hmac-sha224",
+ .cra_priority = 400,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA224_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct mtk_sha_ctx) +
+ sizeof(struct mtk_sha_hmac_ctx),
+ .cra_alignmask = SHA_ALIGN_MSK,
+ .cra_module = THIS_MODULE,
+ .cra_init = mtk_sha_cra_sha224_init,
+ .cra_exit = mtk_sha_cra_exit,
+ }
+},
+{
+ .init = mtk_sha_init,
+ .update = mtk_sha_update,
+ .final = mtk_sha_final,
+ .finup = mtk_sha_finup,
+ .digest = mtk_sha_digest,
+ .export = mtk_sha_export,
+ .import = mtk_sha_import,
+ .setkey = mtk_sha_setkey,
+ .halg.digestsize = SHA256_DIGEST_SIZE,
+ .halg.statesize = sizeof(struct mtk_sha_reqctx),
+ .halg.base = {
+ .cra_name = "hmac(sha256)",
+ .cra_driver_name = "mtk-hmac-sha256",
+ .cra_priority = 400,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct mtk_sha_ctx) +
+ sizeof(struct mtk_sha_hmac_ctx),
+ .cra_alignmask = SHA_ALIGN_MSK,
+ .cra_module = THIS_MODULE,
+ .cra_init = mtk_sha_cra_sha256_init,
+ .cra_exit = mtk_sha_cra_exit,
+ }
+},
+};
+
+static struct ahash_alg algs_sha384_sha512[] = {
+{
+ .init = mtk_sha_init,
+ .update = mtk_sha_update,
+ .final = mtk_sha_final,
+ .finup = mtk_sha_finup,
+ .digest = mtk_sha_digest,
+ .export = mtk_sha_export,
+ .import = mtk_sha_import,
+ .halg.digestsize = SHA384_DIGEST_SIZE,
+ .halg.statesize = sizeof(struct mtk_sha_reqctx),
+ .halg.base = {
+ .cra_name = "sha384",
+ .cra_driver_name = "mtk-sha384",
+ .cra_priority = 400,
+ .cra_flags = CRYPTO_ALG_ASYNC,
+ .cra_blocksize = SHA384_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct mtk_sha_ctx),
+ .cra_alignmask = SHA_ALIGN_MSK,
+ .cra_module = THIS_MODULE,
+ .cra_init = mtk_sha_cra_init,
+ .cra_exit = mtk_sha_cra_exit,
+ }
+},
+{
+ .init = mtk_sha_init,
+ .update = mtk_sha_update,
+ .final = mtk_sha_final,
+ .finup = mtk_sha_finup,
+ .digest = mtk_sha_digest,
+ .export = mtk_sha_export,
+ .import = mtk_sha_import,
+ .halg.digestsize = SHA512_DIGEST_SIZE,
+ .halg.statesize = sizeof(struct mtk_sha_reqctx),
+ .halg.base = {
+ .cra_name = "sha512",
+ .cra_driver_name = "mtk-sha512",
+ .cra_priority = 400,
+ .cra_flags = CRYPTO_ALG_ASYNC,
+ .cra_blocksize = SHA512_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct mtk_sha_ctx),
+ .cra_alignmask = SHA_ALIGN_MSK,
+ .cra_module = THIS_MODULE,
+ .cra_init = mtk_sha_cra_init,
+ .cra_exit = mtk_sha_cra_exit,
+ }
+},
+{
+ .init = mtk_sha_init,
+ .update = mtk_sha_update,
+ .final = mtk_sha_final,
+ .finup = mtk_sha_finup,
+ .digest = mtk_sha_digest,
+ .export = mtk_sha_export,
+ .import = mtk_sha_import,
+ .setkey = mtk_sha_setkey,
+ .halg.digestsize = SHA384_DIGEST_SIZE,
+ .halg.statesize = sizeof(struct mtk_sha_reqctx),
+ .halg.base = {
+ .cra_name = "hmac(sha384)",
+ .cra_driver_name = "mtk-hmac-sha384",
+ .cra_priority = 400,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA384_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct mtk_sha_ctx) +
+ sizeof(struct mtk_sha_hmac_ctx),
+ .cra_alignmask = SHA_ALIGN_MSK,
+ .cra_module = THIS_MODULE,
+ .cra_init = mtk_sha_cra_sha384_init,
+ .cra_exit = mtk_sha_cra_exit,
+ }
+},
+{
+ .init = mtk_sha_init,
+ .update = mtk_sha_update,
+ .final = mtk_sha_final,
+ .finup = mtk_sha_finup,
+ .digest = mtk_sha_digest,
+ .export = mtk_sha_export,
+ .import = mtk_sha_import,
+ .setkey = mtk_sha_setkey,
+ .halg.digestsize = SHA512_DIGEST_SIZE,
+ .halg.statesize = sizeof(struct mtk_sha_reqctx),
+ .halg.base = {
+ .cra_name = "hmac(sha512)",
+ .cra_driver_name = "mtk-hmac-sha512",
+ .cra_priority = 400,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA512_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct mtk_sha_ctx) +
+ sizeof(struct mtk_sha_hmac_ctx),
+ .cra_alignmask = SHA_ALIGN_MSK,
+ .cra_module = THIS_MODULE,
+ .cra_init = mtk_sha_cra_sha512_init,
+ .cra_exit = mtk_sha_cra_exit,
+ }
+},
+};
+
+static void mtk_sha_task0(unsigned long data)
+{
+ struct mtk_cryp *cryp = (struct mtk_cryp *)data;
+ struct mtk_sha *sha = cryp->sha[0];
+
+ mtk_sha_unmap(cryp, sha);
+ mtk_sha_complete(cryp, sha);
+}
+
+static void mtk_sha_task1(unsigned long data)
+{
+ struct mtk_cryp *cryp = (struct mtk_cryp *)data;
+ struct mtk_sha *sha = cryp->sha[1];
+
+ mtk_sha_unmap(cryp, sha);
+ mtk_sha_complete(cryp, sha);
+}
+
+static irqreturn_t mtk_sha_ring2_irq(int irq, void *dev_id)
+{
+ struct mtk_cryp *cryp = (struct mtk_cryp *)dev_id;
+ struct mtk_sha *sha = cryp->sha[0];
+ u32 val = mtk_sha_read(cryp, RDR_STAT(RING2));
+
+ mtk_sha_write(cryp, RDR_STAT(RING2), val);
+
+ if (likely((SHA_FLAGS_BUSY & sha->flags))) {
+ mtk_sha_write(cryp, RDR_PROC_COUNT(RING2), MTK_DESC_CNT_CLR);
+ mtk_sha_write(cryp, RDR_THRESH(RING2), MTK_RDR_THRESH_DEF);
+
+ tasklet_schedule(&sha->task);
+ } else {
+ dev_warn(cryp->dev, "AES interrupt when no active requests.\n");
+ }
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mtk_sha_ring3_irq(int irq, void *dev_id)
+{
+ struct mtk_cryp *cryp = (struct mtk_cryp *)dev_id;
+ struct mtk_sha *sha = cryp->sha[1];
+ u32 val = mtk_sha_read(cryp, RDR_STAT(RING3));
+
+ mtk_sha_write(cryp, RDR_STAT(RING3), val);
+
+ if (likely((SHA_FLAGS_BUSY & sha->flags))) {
+ mtk_sha_write(cryp, RDR_PROC_COUNT(RING3), MTK_DESC_CNT_CLR);
+ mtk_sha_write(cryp, RDR_THRESH(RING3), MTK_RDR_THRESH_DEF);
+
+ tasklet_schedule(&sha->task);
+ } else {
+ dev_warn(cryp->dev, "AES interrupt when no active requests.\n");
+ }
+ return IRQ_HANDLED;
+}
+
+static int mtk_sha_record_init(struct mtk_cryp *cryp)
+{
+ struct mtk_sha **sha = cryp->sha;
+ int i, err = -ENOMEM;
+
+ for (i = 0; i < RECORD_NUM; i++) {
+ sha[i] = kzalloc(sizeof(**sha), GFP_KERNEL);
+ if (!sha[i])
+ goto err_cleanup;
+
+ sha[i]->id = i + RING2;
+
+ spin_lock_init(&sha[i]->lock);
+ crypto_init_queue(&sha[i]->queue, SHA_QUEUE_SIZE);
+ }
+
+ tasklet_init(&sha[0]->task, mtk_sha_task0, (unsigned long)cryp);
+ tasklet_init(&sha[1]->task, mtk_sha_task1, (unsigned long)cryp);
+
+ cryp->rec = 1;
+
+ return 0;
+
+err_cleanup:
+ for (; i--; )
+ kfree(sha[i]);
+ return err;
+}
+
+static void mtk_sha_record_free(struct mtk_cryp *cryp)
+{
+ int i;
+
+ for (i = 0; i < RECORD_NUM; i++) {
+ tasklet_kill(&cryp->sha[i]->task);
+ kfree(cryp->sha[i]);
+ }
+}
+
+static void mtk_sha_unregister_algs(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(algs_sha1_sha224_sha256); i++)
+ crypto_unregister_ahash(&algs_sha1_sha224_sha256[i]);
+
+ for (i = 0; i < ARRAY_SIZE(algs_sha384_sha512); i++)
+ crypto_unregister_ahash(&algs_sha384_sha512[i]);
+}
+
+static int mtk_sha_register_algs(void)
+{
+ int err, i;
+
+ for (i = 0; i < ARRAY_SIZE(algs_sha1_sha224_sha256); i++) {
+ err = crypto_register_ahash(&algs_sha1_sha224_sha256[i]);
+ if (err)
+ goto err_sha_224_256_algs;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(algs_sha384_sha512); i++) {
+ err = crypto_register_ahash(&algs_sha384_sha512[i]);
+ if (err)
+ goto err_sha_384_512_algs;
+ }
+
+ return 0;
+
+err_sha_384_512_algs:
+ for (; i--; )
+ crypto_unregister_ahash(&algs_sha384_sha512[i]);
+ i = ARRAY_SIZE(algs_sha1_sha224_sha256);
+err_sha_224_256_algs:
+ for (; i--; )
+ crypto_unregister_ahash(&algs_sha1_sha224_sha256[i]);
+
+ return err;
+}
+
+int mtk_hash_alg_register(struct mtk_cryp *cryp)
+{
+ int err;
+
+ INIT_LIST_HEAD(&cryp->sha_list);
+
+ err = mtk_sha_record_init(cryp);
+ if (err)
+ goto err_record;
+
+ err = devm_request_irq(cryp->dev, cryp->irq[RING2],
+ mtk_sha_ring2_irq, IRQF_TRIGGER_LOW,
+ "mtk-sha", cryp);
+ if (err) {
+ dev_err(cryp->dev, "unable to request sha irq0.\n");
+ goto err_res;
+ }
+
+ err = devm_request_irq(cryp->dev, cryp->irq[RING3],
+ mtk_sha_ring3_irq, IRQF_TRIGGER_LOW,
+ "mtk-sha", cryp);
+ if (err) {
+ dev_err(cryp->dev, "unable to request sha irq1.\n");
+ goto err_res;
+ }
+
+ /* enable ring2 and ring3 interrupt for hash */
+ mtk_sha_write(cryp, AIC_ENABLE_SET(RING2), MTK_IRQ_RDR2);
+ mtk_sha_write(cryp, AIC_ENABLE_SET(RING3), MTK_IRQ_RDR3);
+
+ cryp->tmp = dma_alloc_coherent(cryp->dev, SHA_TMP_STATE_SIZE,
+ &cryp->tmp_dma, GFP_KERNEL);
+ if (!cryp->tmp) {
+ dev_err(cryp->dev, "unable to allocate tmp buffer.\n");
+ err = -EINVAL;
+ goto err_res;
+ }
+
+ spin_lock(&mtk_sha.lock);
+ list_add_tail(&cryp->sha_list, &mtk_sha.dev_list);
+ spin_unlock(&mtk_sha.lock);
+
+ err = mtk_sha_register_algs();
+ if (err)
+ goto err_algs;
+
+ return 0;
+
+err_algs:
+ spin_lock(&mtk_sha.lock);
+ list_del(&cryp->sha_list);
+ spin_unlock(&mtk_sha.lock);
+ dma_free_coherent(cryp->dev, SHA_TMP_STATE_SIZE,
+ cryp->tmp, cryp->tmp_dma);
+err_res:
+ mtk_sha_record_free(cryp);
+err_record:
+
+ dev_err(cryp->dev, "mtk-sha initialization failed.\n");
+ return err;
+}
+EXPORT_SYMBOL(mtk_hash_alg_register);
+
+void mtk_hash_alg_release(struct mtk_cryp *cryp)
+{
+ spin_lock(&mtk_sha.lock);
+ list_del(&cryp->sha_list);
+ spin_unlock(&mtk_sha.lock);
+
+ mtk_sha_unregister_algs();
+ dma_free_coherent(cryp->dev, SHA_TMP_STATE_SIZE,
+ cryp->tmp, cryp->tmp_dma);
+ mtk_sha_record_free(cryp);
+}
+EXPORT_SYMBOL(mtk_hash_alg_release);
--
1.9.1
^ permalink raw reply related
* [PATCH 2/2] crypto: mediatek - add DT bindings documentation
From: Ryder Lee @ 2016-12-02 3:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480649205-52695-1-git-send-email-ryder.lee@mediatek.com>
Add DT bindings documentation for the crypto driver
Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
---
.../devicetree/bindings/crypto/mediatek-crypto.txt | 32 ++++++++++++++++++++++
1 file changed, 32 insertions(+)
create mode 100644 Documentation/devicetree/bindings/crypto/mediatek-crypto.txt
diff --git a/Documentation/devicetree/bindings/crypto/mediatek-crypto.txt b/Documentation/devicetree/bindings/crypto/mediatek-crypto.txt
new file mode 100644
index 0000000..8b1db08
--- /dev/null
+++ b/Documentation/devicetree/bindings/crypto/mediatek-crypto.txt
@@ -0,0 +1,32 @@
+MediaTek cryptographic accelerators
+
+Required properties:
+- compatible: Should be "mediatek,mt7623-crypto"
+- reg: Address and length of the register set for the device
+- interrupts: Should contain the five crypto engines interrupts in numeric
+ order. These are global system and four descriptor rings.
+- clocks: the clock used by the core
+- clock-names: the names of the clock listed in the clocks property. These are
+ "ethif", "cryp"
+- power-domains: Must contain a reference to the PM domain.
+
+
+Optional properties:
+- interrupt-parent: Should be the phandle for the interrupt controller
+ that services interrupts for this device
+
+
+Example:
+ crypto: crypto at 1b240000 {
+ compatible = "mediatek,mt7623-crypto";
+ reg = <0 0x1b240000 0 0x20000>;
+ interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 83 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 84 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 91 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 97 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&topckgen CLK_TOP_ETHIF_SEL>,
+ <ðsys CLK_ETHSYS_CRYPTO>;
+ clock-names = "ethif","cryp";
+ power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>;
+ };
--
1.9.1
^ permalink raw reply related
* [PATCH v3] PCI/ACPI: xgene: Add ECAM quirk for X-Gene PCIe controller
From: Jon Masters @ 2016-12-02 4:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CADaLND=Ss8d-jv7wffbrtytrjj=SUnjDn9bognKUszhKguRV1A@mail.gmail.com>
Hi Bjorn, Duc, Mark,
I switched my brain to the on mode and went and read some specs, and a few
tables, so here's my 2 cents on this...
On 12/01/2016 06:22 PM, Duc Dang wrote:
> On Thu, Dec 1, 2016 at 3:07 PM, Bjorn Helgaas <helgaas@kernel.org> wrote:
>> On Thu, Dec 01, 2016 at 02:10:10PM -0800, Duc Dang wrote:
>>>>> The SoC provide some number of RC bridges, each with a different base
>>>>> for some mmio registers. Even if segment is legitimate in MCFG, there
>>>>> is still a problem if a platform doesn't use the segment ordering
>>>>> implied by the code. But the PNP0A03 _CRS does have this base address
>>>>> as the first memory resource, so we could get it from there and not
>>>>> have hard-coded addresses and implied ording in the quirk code.
>>>>
>>>> I'm confused. Doesn't the current code treat every item in PNP0A03
>>>> _CRS as a window? Do you mean the first resource is handled
>>>> differently somehow? The Consumer/Producer bit could allow us to do
>>>> this by marking the RC MMIO space as "Consumer", but I didn't think
>>>> that strategy was quite working yet.
Let's see if I summarized this correctly...
1. The MMIO registers for the host bridge itself need to be described
somewhere, especially if we need to find those in a quirk and poke
them. Since those registers are very much part of the bridge device,
it makes sense for them to be in the _CRS for PNP0A08/PNP0A03.
2. The address space covering these registers MUST be described as a
ResourceConsumer in order to avoid accidentally exposing them as
available for use by downstream devices on the PCI bus.
3. The ACPI specification allows for resources of the type "Memory32Fixed".
This is a macro that doesn't have the notion of a producer or consumer.
HOWEVER various interpretations seem to be that this could/should
default to being interpreted as a consumed region.
4. At one point, a regression was added to the kernel:
63f1789ec716 ("x86/PCI/ACPI: Ignore resources consumed by
host bridge itself")
Which lead to a series on conversations about what should happen
for bridge resources (e.g. https://lkml.org/lkml/2015/3/24/962 )
5. This resulted in the following commit reverting point 4:
2c62e8492ed7 ("x86/PCI/ACPI: Make all resources except [io 0xcf8-0xcff]
available on PCI bus")
Which also stated that:
"This solution will also ease the way to consolidate ACPI PCI host
bridge common code from x86, ia64 and ARM64"
End of summary.
So it seems that generally there is an aversion to having bridge resources
be described in this manner and you would like to require that they be
described e.g. using QWordMemory with a ResourceConsumer type?
BUT if we were to do that, it would break existing shipping systems since
there are quirks out there that use this form to find the base CSR:
if (acpi_res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) {
fixed32 = &acpi_res->data.fixed_memory32;
port->csr_base = ioremap(fixed32->address,
fixed32->address_length);
return AE_CTRL_TERMINATE;
}
That's what's shipping in at least RHEL(SA) today, and probably in other
distros. So if we get vendors to take that out, existing stuff will break,
which will have the downside that customers will have to choose between
whether to run a given distro or be able to use upstream kernels. In
that sense, to me, there are shipping platforms out there, which may well
be doing the "wrong" thing, but they are deployed and they are doing it.
Which makes me wonder a couple of things (I think should NOT be done):
1. What would happen if we had both. A FixedMemory32 and the same region
described again using the longer form as a consumed region. I doubt
that's legal, and the current code would still add the region if it
saw the FixedMemory32 first when walking the tree. I don't like it,
but I'm mentioning it in case that leads to some helpful thinking.
2. What would happen if we had a difference policy on arm64 for such
resources. x86 has an "exception" for accessing the config space
using IO port 0xCF8-0xCFF (a fairly reasonable exception!) and
we can make the rules for a new platform (i.e. actually prescribe
exactly what the behavior is, rather than have it not be defined).
This is of course terrible in that existing BIOS vendors and so on
won't necessarily know this when working on ARM ACPI later on.
I don't like either of these obviously. I'm hoping there's some way we
can say that this is tolerated in this one quirk (allow the use of
FixedMemory32 in this case) on the grounds that the driver claims
this bridge region and can be annotated to explain such.
Once you let us know what you prefer, we will go and update the ARM
SBBR to spell out that future platforms should not make this mistake
again. We can prescribe whatever you'd like in terms of how bridge
resources consumed by the bridge are exposed. I have spoken about
this kind of situation within MS in the past, but they didn't have
specific guidance since they don't really tolerate such quirks. I
can, however, consult them before we change the SBBR as well.
>>> The first resource is defined like below. It was introduced long time
>>> ago to use with older version of X-Gene ECAM quirks.
>>> Memory32Fixed(ReadWrite, 0x1F2B0000, 0x10000, )
Indeed. And in the case of m400, it is currently this in shipping systems:
Memory32Fixed (ReadWrite,
0x1F500000, // Address Base
0x00010000, // Address Length
)
The spec isn't clear on whether these are produced or consumed but the
implication is that these are consumed resources in most cases. Not that
this changes any of the above, but one can understand why it happened.
>>> [ 0.822990] pci_bus 0000:00: root bus resource [mem 0x1f2b0000-0x1f2bffff]
>>
>> I think this is wrong. The PCI core thinks [mem 0x1f2b0000-0x1f2bffff]
>> is available for use by devices on bus 0000:00, but I think you're
>> saying it is consumed by the bridge itself, not forwarded down to PCI.
Indeed.
>> What's in your /proc/iomem? I see that your quirks do call
>> devm_ioremap_resource(), which calls devm_request_mem_region()
>> internally, so the driver does at least request that region, which
>> should keep us from assigning it to PCI devices.
I'm hoping you can grant an exception on the grounds that the quirk will
keep the region from actually being used. And then somehow we document
this in the driver.
>> But it still isn't quite right to tell the PCI core that the region is
>> available on the root bus.
>
> This is /proc/iomem output on my Mustang board. The 64K "PCIe CSR"
> region is consumed completely.
> 1f2b0000-1f2bffff : PCI Bus 0000:00
> 1f2b0000-1f2bffff : PCIe CSR
>
> e040000000-e07fffffff : PCI Bus 0000:00
> e040000000-e0401fffff : PCI Bus 0000:01
> e040000000-e0400fffff : 0000:01:00.0
> e040000000-e0400fffff : mlx4_core
> e040100000-e0401fffff : 0000:01:00.0
> e0d0000000-e0dfffffff : PCI ECAM
> f000000000-ffffffffff : PCI Bus 0000:00
> f000000000-f001ffffff : PCI Bus 0000:01
> f000000000-f001ffffff : 0000:01:00.0
> f000000000-f001ffffff : mlx4_core
>
> Using hard-coded resources for mmio space make the quirk rely on the
> segment number passing from the firmware. Using Mark's method or
> acpi_get_rc_resource can discover the mmio space and consume all of
> the space, but as you mentioned, it leaves the defect that PCI core
> considers the mmio space as available resource for secondary devices
> although it will never allocate the mmio space to secondary devices as
> the RC already reserves and consumes all of the space.
Indeed. It's not clean, but perhaps we can get away with it on the
grounds that there are existing systems out there and this won't
be allowed to happen again in the future :)
Jon.
--
Computer Architect | Sent from my Fedora powered laptop
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox