Commit f3ea4962 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc

Pull ARM SoC driver updates from Olof Johansson:
 "Some of the larger changes this merge window:

   - Removal of drivers for Exynos5440, a Samsung SoC that never saw
     widespread use.

   - Uniphier support for USB3 and SPI reset handling

   - Syste control and SRAM drivers and bindings for Allwinner platforms

   - Qualcomm AOSS (Always-on subsystem) reset controller drivers

   - Raspberry Pi hwmon driver for voltage

   - Mediatek pwrap (pmic) support for MT6797 SoC"

* tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (52 commits)
  drivers/firmware: psci_checker: stash and use topology_core_cpumask for hotplug tests
  soc: fsl: cleanup Kconfig menu
  soc: fsl: dpio: Convert DPIO documentation to .rst
  staging: fsl-mc: Remove remaining files
  staging: fsl-mc: Move DPIO from staging to drivers/soc/fsl
  staging: fsl-dpaa2: eth: move generic FD defines to DPIO
  soc: fsl: qe: gpio: Add qe_gpio_set_multiple
  usb: host: exynos: Remove support for Exynos5440
  clk: samsung: Remove support for Exynos5440
  soc: sunxi: Add the A13, A23 and H3 system control compatibles
  reset: uniphier: add reset control support for SPI
  cpufreq: exynos: Remove support for Exynos5440
  ata: ahci-platform: Remove support for Exynos5440
  soc: imx6qp: Use GENPD_FLAG_ALWAYS_ON for PU errata
  soc: mediatek: pwrap: add mt6351 driver for mt6797 SoCs
  soc: mediatek: pwrap: add pwrap driver for mt6797 SoCs
  soc: mediatek: pwrap: fix cipher init setting error
  dt-bindings: pwrap: mediatek: add pwrap support for MT6797
  reset: uniphier: add USB3 core reset control
  dt-bindings: reset: uniphier: add USB3 core reset support
  ...
parents 9e259f93 29ed45ff
......@@ -189,7 +189,11 @@ Power-Down (SRPD), among other things.
Required properties:
- compatible : should contain one of these
"brcm,brcmstb-memc-ddr-rev-b.2.1"
"brcm,brcmstb-memc-ddr-rev-b.2.2"
"brcm,brcmstb-memc-ddr-rev-b.2.3"
"brcm,brcmstb-memc-ddr-rev-b.3.0"
"brcm,brcmstb-memc-ddr-rev-b.3.1"
"brcm,brcmstb-memc-ddr"
- reg : the MEMC DDR register range
......
......@@ -17,7 +17,6 @@ Required properties:
- "marvell,armada-380-ahci"
- "marvell,armada-3700-ahci"
- "snps,dwc-ahci"
- "snps,exynos5440-ahci"
- "snps,spear-ahci"
- "generic-ahci"
- interrupts : <interrupt mapping for SATA IRQ>
......
Device tree bindings for Allwinner A64 DE2 bus
The Allwinner A64 DE2 is on a special bus, which needs a SRAM region (SRAM C)
to be claimed for enabling the access.
Required properties:
- compatible: Should contain "allwinner,sun50i-a64-de2"
- reg: A resource specifier for the register space
- #address-cells: Must be set to 1
- #size-cells: Must be set to 1
- ranges: Must be set up to map the address space inside the
DE2, for the sub-blocks of DE2.
- allwinner,sram: the SRAM that needs to be claimed
Example:
de2@1000000 {
compatible = "allwinner,sun50i-a64-de2";
reg = <0x1000000 0x400000>;
allwinner,sram = <&de2_sram 1>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0x1000000 0x400000>;
display_clocks: clock@0 {
compatible = "allwinner,sun50i-a64-de2-clk";
reg = <0x0 0x100000>;
clocks = <&ccu CLK_DE>,
<&ccu CLK_BUS_DE>;
clock-names = "mod",
"bus";
resets = <&ccu RST_BUS_DE>;
#clock-cells = <1>;
#reset-cells = <1>;
};
};
......@@ -36,6 +36,7 @@ Required standard properties:
"ti,sysc-omap-aes"
"ti,sysc-mcasp"
"ti,sysc-usb-host-fs"
"ti,sysc-dra7-mcan"
- reg shall have register areas implemented for the interconnect
target module in question such as revision, sysc and syss
......
* Samsung Exynos5440 Clock Controller
The Exynos5440 clock controller generates and supplies clock to various
controllers within the Exynos5440 SoC.
Required Properties:
- compatible: should be "samsung,exynos5440-clock".
- reg: physical base address of the controller and length of memory mapped
region.
- #clock-cells: should be 1.
Each clock is assigned an identifier and client nodes can use this identifier
to specify the clock which they consume.
All available clocks are defined as preprocessor macros in
dt-bindings/clock/exynos5440.h header and can be used in device
tree sources.
Example: An example of a clock controller node is listed below.
clock: clock-controller@10010000 {
compatible = "samsung,exynos5440-clock";
reg = <0x160000 0x10000>;
#clock-cells = <1>;
};
Exynos5440 cpufreq driver
-------------------
Exynos5440 SoC cpufreq driver for CPU frequency scaling.
Required properties:
- interrupts: Interrupt to know the completion of cpu frequency change.
- operating-points: Table of frequencies and voltage CPU could be transitioned into,
in the decreasing order. Frequency should be in KHz units and voltage
should be in microvolts.
Optional properties:
- clock-latency: Clock monitor latency in microsecond.
All the required listed above must be defined under node cpufreq.
Example:
--------
cpufreq@160000 {
compatible = "samsung,exynos5440-cpufreq";
reg = <0x160000 0x1000>;
interrupts = <0 57 0>;
operating-points = <
1000000 975000
800000 925000>;
clock-latency = <100000>;
};
Qualcomm AOSS Reset Controller
======================================
This binding describes a reset-controller found on AOSS-CC (always on subsystem)
for Qualcomm SDM845 SoCs.
Required properties:
- compatible:
Usage: required
Value type: <string>
Definition: must be:
"qcom,sdm845-aoss-cc"
- reg:
Usage: required
Value type: <prop-encoded-array>
Definition: must specify the base address and size of the register
space.
- #reset-cells:
Usage: required
Value type: <uint>
Definition: must be 1; cell entry represents the reset index.
Example:
aoss_reset: reset-controller@c2a0000 {
compatible = "qcom,sdm845-aoss-cc";
reg = <0xc2a0000 0x31000>;
#reset-cells = <1>;
};
Specifying reset lines connected to IP modules
==============================================
Device nodes that need access to reset lines should
specify them as a reset phandle in their corresponding node as
specified in reset.txt.
For list of all valid reset indicies see
<dt-bindings/reset/qcom,sdm845-aoss.h>
Example:
modem-pil@4080000 {
...
resets = <&aoss_reset AOSS_CC_MSS_RESTART>;
reset-names = "mss_restart";
...
};
......@@ -118,3 +118,59 @@ Example:
other nodes ...
};
USB3 core reset
---------------
USB3 core reset belongs to USB3 glue layer. Before using the core reset,
it is necessary to control the clocks and resets to enable this layer.
These clocks and resets should be described in each property.
Required properties:
- compatible: Should be
"socionext,uniphier-pro4-usb3-reset" - for Pro4 SoC
"socionext,uniphier-pxs2-usb3-reset" - for PXs2 SoC
"socionext,uniphier-ld20-usb3-reset" - for LD20 SoC
"socionext,uniphier-pxs3-usb3-reset" - for PXs3 SoC
- #reset-cells: Should be 1.
- reg: Specifies offset and length of the register set for the device.
- clocks: A list of phandles to the clock gate for USB3 glue layer.
According to the clock-names, appropriate clocks are required.
- clock-names: Should contain
"gio", "link" - for Pro4 SoC
"link" - for others
- resets: A list of phandles to the reset control for USB3 glue layer.
According to the reset-names, appropriate resets are required.
- reset-names: Should contain
"gio", "link" - for Pro4 SoC
"link" - for others
Example:
usb-glue@65b00000 {
compatible = "socionext,uniphier-ld20-dwc3-glue",
"simple-mfd";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0x65b00000 0x400>;
usb_rst: reset@0 {
compatible = "socionext,uniphier-ld20-usb3-reset";
reg = <0x0 0x4>;
#reset-cells = <1>;
clock-names = "link";
clocks = <&sys_clk 14>;
reset-names = "link";
resets = <&sys_rst 14>;
};
regulator {
...
};
phy {
...
};
...
};
......@@ -19,6 +19,7 @@ IP Pairing
Required properties in pwrap device node.
- compatible:
"mediatek,mt2701-pwrap" for MT2701/7623 SoCs
"mediatek,mt6797-pwrap" for MT6797 SoCs
"mediatek,mt7622-pwrap" for MT7622 SoCs
"mediatek,mt8135-pwrap" for MT8135 SoCs
"mediatek,mt8173-pwrap" for MT8173 SoCs
......
......@@ -10,8 +10,14 @@ Controller Node
Required properties:
- compatible : should be:
- "allwinner,sun4i-a10-sram-controller"
- "allwinner,sun50i-a64-sram-controller"
- "allwinner,sun4i-a10-sram-controller" (deprecated)
- "allwinner,sun4i-a10-system-control"
- "allwinner,sun5i-a13-system-control"
- "allwinner,sun7i-a20-system-control", "allwinner,sun4i-a10-system-control"
- "allwinner,sun8i-a23-system-control"
- "allwinner,sun8i-h3-system-control"
- "allwinner,sun50i-a64-sram-controller" (deprecated)
- "allwinner,sun50i-a64-system-control"
- reg : sram controller register offset + length
SRAM nodes
......@@ -26,8 +32,25 @@ once again the representation described in the mmio-sram binding.
The valid sections compatible for A10 are:
- allwinner,sun4i-a10-sram-a3-a4
- allwinner,sun4i-a10-sram-c1
- allwinner,sun4i-a10-sram-d
The valid sections compatible for A13 are:
- allwinner,sun5i-a13-sram-a3-a4, allwinner,sun4i-a10-sram-a3-a4
- allwinner,sun5i-a13-sram-c1, allwinner,sun4i-a10-sram-c1
- allwinner,sun5i-a13-sram-d, allwinner,sun4i-a10-sram-d
The valid sections compatible for A20 are:
- allwinner,sun7i-a20-sram-a3-a4, allwinner,sun4i-a10-sram-a3-a4
- allwinner,sun7i-a20-sram-c1, allwinner,sun4i-a10-sram-c1
- allwinner,sun7i-a20-sram-d, allwinner,sun4i-a10-sram-d
The valid sections compatible for A23/A33 are:
- allwinner,sun8i-a23-sram-c1, allwinner,sun4i-a10-sram-c1
The valid sections compatible for H3 are:
- allwinner,sun8i-h3-sram-c1, allwinner,sun4i-a10-sram-c1
The valid sections compatible for A64 are:
- allwinner,sun50i-a64-sram-c
......@@ -47,8 +70,8 @@ This valid values for this argument are:
Example
-------
sram-controller@1c00000 {
compatible = "allwinner,sun4i-a10-sram-controller";
system-control@1c00000 {
compatible = "allwinner,sun4i-a10-system-control";
reg = <0x01c00000 0x30>;
#address-cells = <1>;
#size-cells = <1>;
......
Kernel driver raspberrypi-hwmon
===============================
Supported boards:
* Raspberry Pi A+ (via GPIO on SoC)
* Raspberry Pi B+ (via GPIO on SoC)
* Raspberry Pi 2 B (via GPIO on SoC)
* Raspberry Pi 3 B (via GPIO on port expander)
* Raspberry Pi 3 B+ (via PMIC)
Author: Stefan Wahren <stefan.wahren@i2se.com>
Description
-----------
This driver periodically polls a mailbox property of the VC4 firmware to detect
undervoltage conditions.
Sysfs entries
-------------
in0_lcrit_alarm Undervoltage alarm
Copyright 2016 NXP
.. include:: <isonum.txt>
DPAA2 DPIO (Data Path I/O) Overview
===================================
:Copyright: |copy| 2016-2018 NXP
This document provides an overview of the Freescale DPAA2 DPIO
drivers
Introduction
------------
============
A DPAA2 DPIO (Data Path I/O) is a hardware object that provides
interfaces to enqueue and dequeue frames to/from network interfaces
......@@ -27,8 +35,11 @@ provides services that:
The Linux DPIO driver consists of 3 primary components--
DPIO object driver-- fsl-mc driver that manages the DPIO object
DPIO service-- provides APIs to other Linux drivers for services
QBman portal interface-- sends portal commands, gets responses
::
fsl-mc other
bus drivers
......@@ -45,8 +56,9 @@ The Linux DPIO driver consists of 3 primary components--
|
hardware
The diagram below shows how the DPIO driver components fit with the other
DPAA2 Linux driver components:
DPAA2 Linux driver components::
+------------+
| OS Network |
| Stack |
......@@ -98,20 +110,29 @@ DPIO service (dpio-service.c, dpaa2-io.h)
Notification handling
dpaa2_io_service_register()
dpaa2_io_service_deregister()
dpaa2_io_service_rearm()
Queuing
dpaa2_io_service_pull_fq()
dpaa2_io_service_pull_channel()
dpaa2_io_service_enqueue_fq()
dpaa2_io_service_enqueue_qd()
dpaa2_io_store_create()
dpaa2_io_store_destroy()
dpaa2_io_store_next()
Buffer pool management
dpaa2_io_service_release()
dpaa2_io_service_acquire()
QBman portal interface (qbman-portal.c)
......@@ -120,7 +141,9 @@ QBman portal interface (qbman-portal.c)
The qbman-portal component provides APIs to do the low level hardware
bit twiddling for operations such as:
-initializing Qman software portals
-building and sending portal commands
-portal interrupt configuration and processing
The qbman-portal APIs are not public to other drivers, and are
......
......@@ -6,3 +6,4 @@ DPAA2 Documentation
:maxdepth: 1
overview
dpio-driver
......@@ -4512,7 +4512,7 @@ DPAA2 DATAPATH I/O (DPIO) DRIVER
M: Roy Pledge <Roy.Pledge@nxp.com>
L: linux-kernel@vger.kernel.org
S: Maintained
F: drivers/staging/fsl-mc/bus/dpio
F: drivers/soc/fsl/dpio
DPAA2 ETHERNET DRIVER
M: Ioana Radulescu <ruxandra.radulescu@nxp.com>
......
......@@ -75,7 +75,6 @@ static const struct of_device_id ahci_of_match[] = {
{ .compatible = "generic-ahci", },
/* Keep the following compatibles for device tree compatibility */
{ .compatible = "snps,spear-ahci", },
{ .compatible = "snps,exynos5440-ahci", },
{ .compatible = "ibm,476gtr-ahci", },
{ .compatible = "snps,dwc-ahci", },
{ .compatible = "hisilicon,hisi-ahci", },
......
......@@ -103,6 +103,16 @@ config SIMPLE_PM_BUS
Controller (BSC, sometimes called "LBSC within Bus Bridge", or
"External Bus Interface") as found on several Renesas ARM SoCs.
config SUN50I_DE2_BUS
bool "Allwinner A64 DE2 Bus Driver"
default ARM64
depends on ARCH_SUNXI
select SUNXI_SRAM
help
Say y here to enable support for Allwinner A64 DE2 bus driver. It's
mostly transparent, but a SRAM region needs to be claimed in the SRAM
controller to make the all blocks in the DE2 part accessible.
config SUNXI_RSB
tristate "Allwinner sunXi Reduced Serial Bus Driver"
default MACH_SUN8I || MACH_SUN9I || ARM64
......
......@@ -21,6 +21,7 @@ obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o
obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o
obj-$(CONFIG_QCOM_EBI2) += qcom-ebi2.o
obj-$(CONFIG_SUN50I_DE2_BUS) += sun50i-de2.o
obj-$(CONFIG_SUNXI_RSB) += sunxi-rsb.o
obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o
obj-$(CONFIG_TEGRA_ACONNECT) += tegra-aconnect.o
......
// SPDX-License-Identifier: GPL-2.0
/*
* Allwinner A64 Display Engine 2.0 Bus Driver
*
* Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io>
*/
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/soc/sunxi/sunxi_sram.h>
static int sun50i_de2_bus_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
int ret;
ret = sunxi_sram_claim(&pdev->dev);
if (ret) {
dev_err(&pdev->dev, "Error couldn't map SRAM to device\n");
return ret;
}
of_platform_populate(np, NULL, NULL, &pdev->dev);
return 0;
}
static int sun50i_de2_bus_remove(struct platform_device *pdev)
{
sunxi_sram_release(&pdev->dev);
return 0;
}
static const struct of_device_id sun50i_de2_bus_of_match[] = {
{ .compatible = "allwinner,sun50i-a64-de2", },
{ /* sentinel */ }
};
static struct platform_driver sun50i_de2_bus_driver = {
.probe = sun50i_de2_bus_probe,
.remove = sun50i_de2_bus_remove,
.driver = {
.name = "sun50i-de2-bus",
.of_match_table = sun50i_de2_bus_of_match,
},
};
builtin_platform_driver(sun50i_de2_bus_driver);
......@@ -23,11 +23,14 @@
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/slab.h>
#include <linux/iopoll.h>
#include <linux/platform_data/ti-sysc.h>
#include <dt-bindings/bus/ti-sysc.h>
#define MAX_MODULE_SOFTRESET_WAIT 10000
static const char * const reg_names[] = { "rev", "sysc", "syss", };
enum sysc_clocks {
......@@ -88,6 +91,11 @@ struct sysc {
struct delayed_work idle_work;
};
void sysc_write(struct sysc *ddata, int offset, u32 value)
{
writel_relaxed(value, ddata->module_va + offset);
}
static u32 sysc_read(struct sysc *ddata, int offset)
{
if (ddata->cfg.quirks & SYSC_QUIRK_16BIT) {
......@@ -943,6 +951,36 @@ static void sysc_init_revision_quirks(struct sysc *ddata)
}
}
static int sysc_reset(struct sysc *ddata)
{
int offset = ddata->offsets[SYSC_SYSCONFIG];
int val;
if (ddata->legacy_mode || offset < 0 ||
ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)
return 0;
/*
* Currently only support reset status in sysstatus.
* Warn and return error in all other cases
*/
if (!ddata->cfg.syss_mask) {
dev_err(ddata->dev, "No ti,syss-mask. Reset failed\n");
return -EINVAL;
}
val = sysc_read(ddata, offset);
val |= (0x1 << ddata->cap->regbits->srst_shift);
sysc_write(ddata, offset, val);
/* Poll on reset status */
offset = ddata->offsets[SYSC_SYSSTATUS];
return readl_poll_timeout(ddata->module_va + offset, val,
(val & ddata->cfg.syss_mask) == 0x0,
100, MAX_MODULE_SOFTRESET_WAIT);
}
/* At this point the module is configured enough to read the revision */
static int sysc_init_module(struct sysc *ddata)
{
......@@ -960,6 +998,14 @@ static int sysc_init_module(struct sysc *ddata)
return 0;
}
error = sysc_reset(ddata);
if (error) {
dev_err(ddata->dev, "Reset failed with %d\n", error);
pm_runtime_put_sync(ddata->dev);
return error;
}
ddata->revision = sysc_read_revision(ddata);
pm_runtime_put_sync(ddata->dev);
......@@ -1552,6 +1598,23 @@ static const struct sysc_capabilities sysc_omap4_usb_host_fs = {
.regbits = &sysc_regbits_omap4_usb_host_fs,
};
static const struct sysc_regbits sysc_regbits_dra7_mcan = {
.dmadisable_shift = -ENODEV,
.midle_shift = -ENODEV,
.sidle_shift = -ENODEV,
.clkact_shift = -ENODEV,
.enwkup_shift = 4,
.srst_shift = 0,
.emufree_shift = -ENODEV,
.autoidle_shift = -ENODEV,
};
static const struct sysc_capabilities sysc_dra7_mcan = {
.type = TI_SYSC_DRA7_MCAN,
.sysc_mask = SYSC_DRA7_MCAN_ENAWAKEUP | SYSC_OMAP4_SOFTRESET,
.regbits = &sysc_regbits_dra7_mcan,
};
static int sysc_init_pdata(struct sysc *ddata)
{
struct ti_sysc_platform_data *pdata = dev_get_platdata(ddata->dev);
......@@ -1743,6 +1806,7 @@ static const struct of_device_id sysc_match[] = {
{ .compatible = "ti,sysc-mcasp", .data = &sysc_omap4_mcasp, },
{ .compatible = "ti,sysc-usb-host-fs",
.data = &sysc_omap4_usb_host_fs, },
{ .compatible = "ti,sysc-dra7-mcan", .data = &sysc_dra7_mcan, },
{ },
};
MODULE_DEVICE_TABLE(of, sysc_match);
......
......@@ -14,7 +14,6 @@ obj-$(CONFIG_SOC_EXYNOS5410) += clk-exynos5410.o
obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o
obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5-subcmu.o
obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos5433.o
obj-$(CONFIG_SOC_EXYNOS5440) += clk-exynos5440.o
obj-$(CONFIG_EXYNOS_AUDSS_CLK_CON) += clk-exynos-audss.o
obj-$(CONFIG_ARCH_EXYNOS) += clk-exynos-clkout.o
obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos7.o
......
/*
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* Author: Thomas Abraham <thomas.ab@samsung.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.
*
* Common Clock Framework support for Exynos5440 SoC.
*/
#include <dt-bindings/clock/exynos5440.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include "clk.h"
#include "clk-pll.h"
#define CLKEN_OV_VAL 0xf8
#define CPU_CLK_STATUS 0xfc
#define MISC_DOUT1 0x558
static void __iomem *reg_base;
/* parent clock name list */
PNAME(mout_armclk_p) = { "cplla", "cpllb" };
PNAME(mout_spi_p) = { "div125", "div200" };
/* fixed rate clocks generated outside the soc */
static struct samsung_fixed_rate_clock exynos5440_fixed_rate_ext_clks[] __initdata = {
FRATE(0, "xtal", NULL, 0, 0),
};
/* fixed rate clocks */
static const struct samsung_fixed_rate_clock exynos5440_fixed_rate_clks[] __initconst = {
FRATE(0, "ppll", NULL, 0, 1000000000),
FRATE(0, "usb_phy0", NULL, 0, 60000000),
FRATE(0, "usb_phy1", NULL, 0, 60000000),
FRATE(0, "usb_ohci12", NULL, 0, 12000000),
FRATE(0, "usb_ohci48", NULL, 0, 48000000),
};
/* fixed factor clocks */
static const struct samsung_fixed_factor_clock exynos5440_fixed_factor_clks[] __initconst = {
FFACTOR(0, "div250", "ppll", 1, 4, 0),
FFACTOR(0, "div200", "ppll", 1, 5, 0),
FFACTOR(0, "div125", "div250", 1, 2, 0),
};
/* mux clocks */
static const struct samsung_mux_clock exynos5440_mux_clks[] __initconst = {
MUX(0, "mout_spi", mout_spi_p, MISC_DOUT1, 5, 1),
MUX(CLK_ARM_CLK, "arm_clk", mout_armclk_p, CPU_CLK_STATUS, 0, 1),
};
/* divider clocks */
static const struct samsung_div_clock exynos5440_div_clks[] __initconst = {
DIV(CLK_SPI_BAUD, "div_spi", "mout_spi", MISC_DOUT1, 3, 2),
};
/* gate clocks */
static const struct samsung_gate_clock exynos5440_gate_clks[] __initconst = {
GATE(CLK_PB0_250, "pb0_250", "div250", CLKEN_OV_VAL, 3, 0, 0),
GATE(CLK_PR0_250, "pr0_250", "div250", CLKEN_OV_VAL, 4, 0, 0),
GATE(CLK_PR1_250, "pr1_250", "div250", CLKEN_OV_VAL, 5, 0, 0),
GATE(CLK_B_250, "b_250", "div250", CLKEN_OV_VAL, 9, 0, 0),
GATE(CLK_B_125, "b_125", "div125", CLKEN_OV_VAL, 10, 0, 0),
GATE(CLK_B_200, "b_200", "div200", CLKEN_OV_VAL, 11, 0, 0),
GATE(CLK_SATA, "sata", "div200", CLKEN_OV_VAL, 12, 0, 0),
GATE(CLK_USB, "usb", "div200", CLKEN_OV_VAL, 13, 0, 0),
GATE(CLK_GMAC0, "gmac0", "div200", CLKEN_OV_VAL, 14, 0, 0),
GATE(CLK_CS250, "cs250", "div250", CLKEN_OV_VAL, 19, 0, 0),
GATE(CLK_PB0_250_O, "pb0_250_o", "pb0_250", CLKEN_OV_VAL, 3, 0, 0),
GATE(CLK_PR0_250_O, "pr0_250_o", "pr0_250", CLKEN_OV_VAL, 4, 0, 0),
GATE(CLK_PR1_250_O, "pr1_250_o", "pr1_250", CLKEN_OV_VAL, 5, 0, 0),
GATE(CLK_B_250_O, "b_250_o", "b_250", CLKEN_OV_VAL, 9, 0, 0),
GATE(CLK_B_125_O, "b_125_o", "b_125", CLKEN_OV_VAL, 10, 0, 0),
GATE(CLK_B_200_O, "b_200_o", "b_200", CLKEN_OV_VAL, 11, 0, 0),
GATE(CLK_SATA_O, "sata_o", "sata", CLKEN_OV_VAL, 12, 0, 0),
GATE(CLK_USB_O, "usb_o", "usb", CLKEN_OV_VAL, 13, 0, 0),
GATE(CLK_GMAC0_O, "gmac0_o", "gmac", CLKEN_OV_VAL, 14, 0, 0),
GATE(CLK_CS250_O, "cs250_o", "cs250", CLKEN_OV_VAL, 19, 0, 0),
};
static const struct of_device_id ext_clk_match[] __initconst = {
{ .compatible = "samsung,clock-xtal", .data = (void *)0, },
{},
};
static int exynos5440_clk_restart_notify(struct notifier_block *this,
unsigned long code, void *unused)
{
u32 val, status;
status = readl_relaxed(reg_base + 0xbc);
val = readl_relaxed(reg_base + 0xcc);
val = (val & 0xffff0000) | (status & 0xffff);
writel_relaxed(val, reg_base + 0xcc);
return NOTIFY_DONE;
}
/*
* Exynos5440 Clock restart notifier, handles restart functionality
*/
static struct notifier_block exynos5440_clk_restart_handler = {
.notifier_call = exynos5440_clk_restart_notify,
.priority = 128,
};
static const struct samsung_pll_clock exynos5440_plls[] __initconst = {
PLL(pll_2550x, CLK_CPLLA, "cplla", "xtal", 0, 0x4c, NULL),
PLL(pll_2550x, CLK_CPLLB, "cpllb", "xtal", 0, 0x50, NULL),
};
/*
* Clock aliases for legacy clkdev look-up.
*/
static const struct samsung_clock_alias exynos5440_aliases[] __initconst = {
ALIAS(CLK_ARM_CLK, NULL, "armclk"),
};
/* register exynos5440 clocks */
static void __init exynos5440_clk_init(struct device_node *np)
{
struct samsung_clk_provider *ctx;
reg_base = of_iomap(np, 0);
if (!reg_base) {
pr_err("%s: failed to map clock controller registers,"
" aborting clock initialization\n", __func__);
return;
}
ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS);
samsung_clk_of_register_fixed_ext(ctx, exynos5440_fixed_rate_ext_clks,
ARRAY_SIZE(exynos5440_fixed_rate_ext_clks), ext_clk_match);
samsung_clk_register_pll(ctx, exynos5440_plls,
ARRAY_SIZE(exynos5440_plls), ctx->reg_base);
samsung_clk_register_fixed_rate(ctx, exynos5440_fixed_rate_clks,
ARRAY_SIZE(exynos5440_fixed_rate_clks));
samsung_clk_register_fixed_factor(ctx, exynos5440_fixed_factor_clks,
ARRAY_SIZE(exynos5440_fixed_factor_clks));
samsung_clk_register_mux(ctx, exynos5440_mux_clks,
ARRAY_SIZE(exynos5440_mux_clks));
samsung_clk_register_div(ctx, exynos5440_div_clks,
ARRAY_SIZE(exynos5440_div_clks));
samsung_clk_register_gate(ctx, exynos5440_gate_clks,
ARRAY_SIZE(exynos5440_gate_clks));
samsung_clk_register_alias(ctx, exynos5440_aliases,
ARRAY_SIZE(exynos5440_aliases));
samsung_clk_of_add_provider(np, ctx);
if (register_restart_handler(&exynos5440_clk_restart_handler))
pr_warn("exynos5440 clock can't register restart handler\n");
pr_info("Exynos5440: arm_clk = %ldHz\n", _get_rate("arm_clk"));
pr_info("exynos5440 clock initialization complete\n");
}
CLK_OF_DECLARE(exynos5440_clk, "samsung,exynos5440-clock", exynos5440_clk_init);
......@@ -708,6 +708,7 @@ static const struct omap_clkctrl_reg_data dra7_wkupaon_clkctrl_regs[] __initcons
{ DRA7_COUNTER_32K_CLKCTRL, NULL, 0, "wkupaon_iclk_mux" },
{ DRA7_UART10_CLKCTRL, dra7_uart10_bit_data, CLKF_SW_SUP, "wkupaon_cm:clk:0060:24" },
{ DRA7_DCAN1_CLKCTRL, dra7_dcan1_bit_data, CLKF_SW_SUP, "wkupaon_cm:clk:0068:24" },
{ DRA7_ADC_CLKCTRL, NULL, CLKF_SW_SUP, "mcan_clk"},
{ 0 },
};
......
......@@ -71,20 +71,6 @@ config ARM_BRCMSTB_AVS_CPUFREQ
Say Y, if you have a Broadcom SoC with AVS support for DFS or DVFS.
config ARM_EXYNOS5440_CPUFREQ
tristate "SAMSUNG EXYNOS5440"
depends on SOC_EXYNOS5440
depends on HAVE_CLK && OF
select PM_OPP
default y
help
This adds the CPUFreq driver for Samsung EXYNOS5440
SoC. The nature of exynos5440 clock controller is
different than previous exynos controllers so not using
the common exynos framework.
If in doubt, say N.
config ARM_HIGHBANK_CPUFREQ
tristate "Calxeda Highbank-based"
depends on ARCH_HIGHBANK && CPUFREQ_DT && REGULATOR
......
......@@ -56,7 +56,6 @@ obj-$(CONFIG_ARM_ARMADA_37XX_CPUFREQ) += armada-37xx-cpufreq.o
obj-$(CONFIG_ARM_BRCMSTB_AVS_CPUFREQ) += brcmstb-avs-cpufreq.o
obj-$(CONFIG_ACPI_CPPC_CPUFREQ) += cppc_cpufreq.o
obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o
obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ) += exynos5440-cpufreq.o
obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o
obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o
......
/*
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Amit Daniel Kachhap <amit.daniel@samsung.com>
*
* EXYNOS5440 - CPU frequency scaling support
*
* 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.
*/
#include <linux/clk.h>
#include <linux/cpu.h>
#include <linux/cpufreq.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/pm_opp.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
/* Register definitions */
#define XMU_DVFS_CTRL 0x0060
#define XMU_PMU_P0_7 0x0064
#define XMU_C0_3_PSTATE 0x0090
#define XMU_P_LIMIT 0x00a0
#define XMU_P_STATUS 0x00a4
#define XMU_PMUEVTEN 0x00d0
#define XMU_PMUIRQEN 0x00d4
#define XMU_PMUIRQ 0x00d8
/* PMU mask and shift definations */
#define P_VALUE_MASK 0x7
#define XMU_DVFS_CTRL_EN_SHIFT 0
#define P0_7_CPUCLKDEV_SHIFT 21
#define P0_7_CPUCLKDEV_MASK 0x7
#define P0_7_ATBCLKDEV_SHIFT 18
#define P0_7_ATBCLKDEV_MASK 0x7
#define P0_7_CSCLKDEV_SHIFT 15
#define P0_7_CSCLKDEV_MASK 0x7
#define P0_7_CPUEMA_SHIFT 28
#define P0_7_CPUEMA_MASK 0xf
#define P0_7_L2EMA_SHIFT 24
#define P0_7_L2EMA_MASK 0xf
#define P0_7_VDD_SHIFT 8
#define P0_7_VDD_MASK 0x7f
#define P0_7_FREQ_SHIFT 0
#define P0_7_FREQ_MASK 0xff
#define C0_3_PSTATE_VALID_SHIFT 8
#define C0_3_PSTATE_CURR_SHIFT 4
#define C0_3_PSTATE_NEW_SHIFT 0
#define PSTATE_CHANGED_EVTEN_SHIFT 0
#define PSTATE_CHANGED_IRQEN_SHIFT 0
#define PSTATE_CHANGED_SHIFT 0
/* some constant values for clock divider calculation */
#define CPU_DIV_FREQ_MAX 500
#define CPU_DBG_FREQ_MAX 375
#define CPU_ATB_FREQ_MAX 500
#define PMIC_LOW_VOLT 0x30
#define PMIC_HIGH_VOLT 0x28
#define CPUEMA_HIGH 0x2
#define CPUEMA_MID 0x4
#define CPUEMA_LOW 0x7
#define L2EMA_HIGH 0x1
#define L2EMA_MID 0x3
#define L2EMA_LOW 0x4
#define DIV_TAB_MAX 2
/* frequency unit is 20MHZ */
#define FREQ_UNIT 20
#define MAX_VOLTAGE 1550000 /* In microvolt */
#define VOLTAGE_STEP 12500 /* In microvolt */
#define CPUFREQ_NAME "exynos5440_dvfs"
#define DEF_TRANS_LATENCY 100000
enum cpufreq_level_index {
L0, L1, L2, L3, L4,
L5, L6, L7, L8, L9,
};
#define CPUFREQ_LEVEL_END (L7 + 1)
struct exynos_dvfs_data {
void __iomem *base;
struct resource *mem;
int irq;
struct clk *cpu_clk;
unsigned int latency;
struct cpufreq_frequency_table *freq_table;
unsigned int freq_count;
struct device *dev;
bool dvfs_enabled;
struct work_struct irq_work;
};
static struct exynos_dvfs_data *dvfs_info;
static DEFINE_MUTEX(cpufreq_lock);
static struct cpufreq_freqs freqs;
static int init_div_table(void)
{
struct cpufreq_frequency_table *pos, *freq_tbl = dvfs_info->freq_table;
unsigned int tmp, clk_div, ema_div, freq, volt_id, idx;
struct dev_pm_opp *opp;
cpufreq_for_each_entry_idx(pos, freq_tbl, idx) {
opp = dev_pm_opp_find_freq_exact(dvfs_info->dev,
pos->frequency * 1000, true);
if (IS_ERR(opp)) {
dev_err(dvfs_info->dev,
"failed to find valid OPP for %u KHZ\n",
pos->frequency);
return PTR_ERR(opp);
}
freq = pos->frequency / 1000; /* In MHZ */
clk_div = ((freq / CPU_DIV_FREQ_MAX) & P0_7_CPUCLKDEV_MASK)
<< P0_7_CPUCLKDEV_SHIFT;
clk_div |= ((freq / CPU_ATB_FREQ_MAX) & P0_7_ATBCLKDEV_MASK)
<< P0_7_ATBCLKDEV_SHIFT;
clk_div |= ((freq / CPU_DBG_FREQ_MAX) & P0_7_CSCLKDEV_MASK)
<< P0_7_CSCLKDEV_SHIFT;
/* Calculate EMA */
volt_id = dev_pm_opp_get_voltage(opp);
volt_id = (MAX_VOLTAGE - volt_id) / VOLTAGE_STEP;
if (volt_id < PMIC_HIGH_VOLT) {
ema_div = (CPUEMA_HIGH << P0_7_CPUEMA_SHIFT) |
(L2EMA_HIGH << P0_7_L2EMA_SHIFT);
} else if (volt_id > PMIC_LOW_VOLT) {
ema_div = (CPUEMA_LOW << P0_7_CPUEMA_SHIFT) |
(L2EMA_LOW << P0_7_L2EMA_SHIFT);
} else {
ema_div = (CPUEMA_MID << P0_7_CPUEMA_SHIFT) |
(L2EMA_MID << P0_7_L2EMA_SHIFT);
}
tmp = (clk_div | ema_div | (volt_id << P0_7_VDD_SHIFT)
| ((freq / FREQ_UNIT) << P0_7_FREQ_SHIFT));
__raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 * idx);
dev_pm_opp_put(opp);
}
return 0;
}
static void exynos_enable_dvfs(unsigned int cur_frequency)
{
unsigned int tmp, cpu;
struct cpufreq_frequency_table *freq_table = dvfs_info->freq_table;
struct cpufreq_frequency_table *pos;
/* Disable DVFS */
__raw_writel(0, dvfs_info->base + XMU_DVFS_CTRL);
/* Enable PSTATE Change Event */
tmp = __raw_readl(dvfs_info->base + XMU_PMUEVTEN);
tmp |= (1 << PSTATE_CHANGED_EVTEN_SHIFT);
__raw_writel(tmp, dvfs_info->base + XMU_PMUEVTEN);
/* Enable PSTATE Change IRQ */
tmp = __raw_readl(dvfs_info->base + XMU_PMUIRQEN);
tmp |= (1 << PSTATE_CHANGED_IRQEN_SHIFT);
__raw_writel(tmp, dvfs_info->base + XMU_PMUIRQEN);
/* Set initial performance index */
cpufreq_for_each_entry(pos, freq_table)
if (pos->frequency == cur_frequency)
break;
if (pos->frequency == CPUFREQ_TABLE_END) {
dev_crit(dvfs_info->dev, "Boot up frequency not supported\n");
/* Assign the highest frequency */
pos = freq_table;
cur_frequency = pos->frequency;
}
dev_info(dvfs_info->dev, "Setting dvfs initial frequency = %uKHZ",
cur_frequency);
for (cpu = 0; cpu < CONFIG_NR_CPUS; cpu++) {
tmp = __raw_readl(dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4);
tmp &= ~(P_VALUE_MASK << C0_3_PSTATE_NEW_SHIFT);
tmp |= ((pos - freq_table) << C0_3_PSTATE_NEW_SHIFT);
__raw_writel(tmp, dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4);
}
/* Enable DVFS */
__raw_writel(1 << XMU_DVFS_CTRL_EN_SHIFT,
dvfs_info->base + XMU_DVFS_CTRL);
}
static int exynos_target(struct cpufreq_policy *policy, unsigned int index)
{
unsigned int tmp;
int i;
struct cpufreq_frequency_table *freq_table = dvfs_info->freq_table;
mutex_lock(&cpufreq_lock);
freqs.old = policy->cur;
freqs.new = freq_table[index].frequency;
cpufreq_freq_transition_begin(policy, &freqs);
/* Set the target frequency in all C0_3_PSTATE register */
for_each_cpu(i, policy->cpus) {
tmp = __raw_readl(dvfs_info->base + XMU_C0_3_PSTATE + i * 4);
tmp &= ~(P_VALUE_MASK << C0_3_PSTATE_NEW_SHIFT);
tmp |= (index << C0_3_PSTATE_NEW_SHIFT);
__raw_writel(tmp, dvfs_info->base + XMU_C0_3_PSTATE + i * 4);
}
mutex_unlock(&cpufreq_lock);
return 0;
}
static void exynos_cpufreq_work(struct work_struct *work)
{
unsigned int cur_pstate, index;
struct cpufreq_policy *policy = cpufreq_cpu_get(0); /* boot CPU */
struct cpufreq_frequency_table *freq_table = dvfs_info->freq_table;
/* Ensure we can access cpufreq structures */
if (unlikely(dvfs_info->dvfs_enabled == false))
goto skip_work;
mutex_lock(&cpufreq_lock);
freqs.old = policy->cur;
cur_pstate = __raw_readl(dvfs_info->base + XMU_P_STATUS);
if (cur_pstate >> C0_3_PSTATE_VALID_SHIFT & 0x1)
index = (cur_pstate >> C0_3_PSTATE_CURR_SHIFT) & P_VALUE_MASK;
else
index = (cur_pstate >> C0_3_PSTATE_NEW_SHIFT) & P_VALUE_MASK;
if (likely(index < dvfs_info->freq_count)) {
freqs.new = freq_table[index].frequency;
} else {
dev_crit(dvfs_info->dev, "New frequency out of range\n");
freqs.new = freqs.old;
}
cpufreq_freq_transition_end(policy, &freqs, 0);
cpufreq_cpu_put(policy);
mutex_unlock(&cpufreq_lock);
skip_work:
enable_irq(dvfs_info->irq);
}
static irqreturn_t exynos_cpufreq_irq(int irq, void *id)
{
unsigned int tmp;
tmp = __raw_readl(dvfs_info->base + XMU_PMUIRQ);
if (tmp >> PSTATE_CHANGED_SHIFT & 0x1) {
__raw_writel(tmp, dvfs_info->base + XMU_PMUIRQ);
disable_irq_nosync(irq);
schedule_work(&dvfs_info->irq_work);
}
return IRQ_HANDLED;
}
static void exynos_sort_descend_freq_table(void)
{
struct cpufreq_frequency_table *freq_tbl = dvfs_info->freq_table;
int i = 0, index;
unsigned int tmp_freq;
/*
* Exynos5440 clock controller state logic expects the cpufreq table to
* be in descending order. But the OPP library constructs the table in
* ascending order. So to make the table descending we just need to
* swap the i element with the N - i element.
*/
for (i = 0; i < dvfs_info->freq_count / 2; i++) {
index = dvfs_info->freq_count - i - 1;
tmp_freq = freq_tbl[i].frequency;
freq_tbl[i].frequency = freq_tbl[index].frequency;
freq_tbl[index].frequency = tmp_freq;
}
}
static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
policy->clk = dvfs_info->cpu_clk;
return cpufreq_generic_init(policy, dvfs_info->freq_table,
dvfs_info->latency);
}
static struct cpufreq_driver exynos_driver = {
.flags = CPUFREQ_STICKY | CPUFREQ_ASYNC_NOTIFICATION |
CPUFREQ_NEED_INITIAL_FREQ_CHECK,
.verify = cpufreq_generic_frequency_table_verify,
.target_index = exynos_target,
.get = cpufreq_generic_get,
.init = exynos_cpufreq_cpu_init,
.name = CPUFREQ_NAME,
.attr = cpufreq_generic_attr,
};
static const struct of_device_id exynos_cpufreq_match[] = {
{
.compatible = "samsung,exynos5440-cpufreq",
},
{},
};
MODULE_DEVICE_TABLE(of, exynos_cpufreq_match);
static int exynos_cpufreq_probe(struct platform_device *pdev)
{
int ret = -EINVAL;
struct device_node *np;
struct resource res;
unsigned int cur_frequency;
np = pdev->dev.of_node;
if (!np)
return -ENODEV;
dvfs_info = devm_kzalloc(&pdev->dev, sizeof(*dvfs_info), GFP_KERNEL);
if (!dvfs_info) {
ret = -ENOMEM;
goto err_put_node;
}
dvfs_info->dev = &pdev->dev;
ret = of_address_to_resource(np, 0, &res);
if (ret)
goto err_put_node;
dvfs_info->base = devm_ioremap_resource(dvfs_info->dev, &res);
if (IS_ERR(dvfs_info->base)) {
ret = PTR_ERR(dvfs_info->base);
goto err_put_node;
}
dvfs_info->irq = irq_of_parse_and_map(np, 0);
if (!dvfs_info->irq) {
dev_err(dvfs_info->dev, "No cpufreq irq found\n");
ret = -ENODEV;
goto err_put_node;
}
ret = dev_pm_opp_of_add_table(dvfs_info->dev);
if (ret) {
dev_err(dvfs_info->dev, "failed to init OPP table: %d\n", ret);
goto err_put_node;
}
ret = dev_pm_opp_init_cpufreq_table(dvfs_info->dev,
&dvfs_info->freq_table);
if (ret) {
dev_err(dvfs_info->dev,
"failed to init cpufreq table: %d\n", ret);
goto err_free_opp;
}
dvfs_info->freq_count = dev_pm_opp_get_opp_count(dvfs_info->dev);
exynos_sort_descend_freq_table();
if (of_property_read_u32(np, "clock-latency", &dvfs_info->latency))
dvfs_info->latency = DEF_TRANS_LATENCY;
dvfs_info->cpu_clk = devm_clk_get(dvfs_info->dev, "armclk");
if (IS_ERR(dvfs_info->cpu_clk)) {
dev_err(dvfs_info->dev, "Failed to get cpu clock\n");
ret = PTR_ERR(dvfs_info->cpu_clk);
goto err_free_table;
}
cur_frequency = clk_get_rate(dvfs_info->cpu_clk);
if (!cur_frequency) {
dev_err(dvfs_info->dev, "Failed to get clock rate\n");
ret = -EINVAL;
goto err_free_table;
}
cur_frequency /= 1000;
INIT_WORK(&dvfs_info->irq_work, exynos_cpufreq_work);
ret = devm_request_irq(dvfs_info->dev, dvfs_info->irq,
exynos_cpufreq_irq, IRQF_TRIGGER_NONE,
CPUFREQ_NAME, dvfs_info);
if (ret) {
dev_err(dvfs_info->dev, "Failed to register IRQ\n");
goto err_free_table;
}
ret = init_div_table();
if (ret) {
dev_err(dvfs_info->dev, "Failed to initialise div table\n");
goto err_free_table;
}
exynos_enable_dvfs(cur_frequency);
ret = cpufreq_register_driver(&exynos_driver);
if (ret) {
dev_err(dvfs_info->dev,
"%s: failed to register cpufreq driver\n", __func__);
goto err_free_table;
}
of_node_put(np);
dvfs_info->dvfs_enabled = true;
return 0;
err_free_table:
dev_pm_opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table);
err_free_opp:
dev_pm_opp_of_remove_table(dvfs_info->dev);
err_put_node:
of_node_put(np);
dev_err(&pdev->dev, "%s: failed initialization\n", __func__);
return ret;
}
static int exynos_cpufreq_remove(struct platform_device *pdev)
{
cpufreq_unregister_driver(&exynos_driver);
dev_pm_opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table);
dev_pm_opp_of_remove_table(dvfs_info->dev);
return 0;
}
static struct platform_driver exynos_cpufreq_platdrv = {
.driver = {
.name = "exynos5440-cpufreq",
.of_match_table = exynos_cpufreq_match,
},
.probe = exynos_cpufreq_probe,
.remove = exynos_cpufreq_remove,
};
module_platform_driver(exynos_cpufreq_platdrv);
MODULE_AUTHOR("Amit Daniel Kachhap <amit.daniel@samsung.com>");
MODULE_DESCRIPTION("Exynos5440 cpufreq driver");
MODULE_LICENSE("GPL");
......@@ -35,7 +35,7 @@
#ifndef _SG_SW_QM2_H_
#define _SG_SW_QM2_H_
#include "../../../drivers/staging/fsl-mc/include/dpaa2-fd.h"
#include <soc/fsl/dpaa2-fd.h>
static inline void dma_to_qm_sg_one(struct dpaa2_sg_entry *qm_sg_ptr,
dma_addr_t dma, u32 len, u16 offset)
......
......@@ -12,7 +12,7 @@
#include "ctrl.h"
#include "regs.h"
#include "sg_sw_qm2.h"
#include "../../../drivers/staging/fsl-mc/include/dpaa2-fd.h"
#include <soc/fsl/dpaa2-fd.h>
struct sec4_sg_entry {
u64 ptr;
......
......@@ -363,8 +363,6 @@ static int scmi_dvfs_device_opps_add(const struct scmi_handle *handle,
return domain;
dom = pi->dom_info + domain;
if (!dom)
return -EIO;
for (opp = dom->opp, idx = 0; idx < dom->opp_count; idx++, opp++) {
freq = opp->perf * dom->mult_factor;
......@@ -394,9 +392,6 @@ static int scmi_dvfs_transition_latency_get(const struct scmi_handle *handle,
return domain;
dom = pi->dom_info + domain;
if (!dom)
return -EIO;
/* uS to nS */
return dom->opp[dom->opp_count - 1].trans_latency_us * 1000;
}
......
......@@ -77,28 +77,6 @@ static int psci_ops_check(void)
return 0;
}
static int find_cpu_groups(const struct cpumask *cpus,
const struct cpumask **cpu_groups)
{
unsigned int nb = 0;
cpumask_var_t tmp;
if (!alloc_cpumask_var(&tmp, GFP_KERNEL))
return -ENOMEM;
cpumask_copy(tmp, cpus);
while (!cpumask_empty(tmp)) {
const struct cpumask *cpu_group =
topology_core_cpumask(cpumask_any(tmp));
cpu_groups[nb++] = cpu_group;
cpumask_andnot(tmp, tmp, cpu_group);
}
free_cpumask_var(tmp);
return nb;
}
/*
* offlined_cpus is a temporary array but passing it as an argument avoids
* multiple allocations.
......@@ -166,29 +144,66 @@ static unsigned int down_and_up_cpus(const struct cpumask *cpus,
return err;
}
static void free_cpu_groups(int num, cpumask_var_t **pcpu_groups)
{
int i;
cpumask_var_t *cpu_groups = *pcpu_groups;
for (i = 0; i < num; ++i)
free_cpumask_var(cpu_groups[i]);
kfree(cpu_groups);
}
static int alloc_init_cpu_groups(cpumask_var_t **pcpu_groups)
{
int num_groups = 0;
cpumask_var_t tmp, *cpu_groups;
if (!alloc_cpumask_var(&tmp, GFP_KERNEL))
return -ENOMEM;
cpu_groups = kcalloc(nb_available_cpus, sizeof(cpu_groups),
GFP_KERNEL);
if (!cpu_groups)
return -ENOMEM;
cpumask_copy(tmp, cpu_online_mask);
while (!cpumask_empty(tmp)) {
const struct cpumask *cpu_group =
topology_core_cpumask(cpumask_any(tmp));
if (!alloc_cpumask_var(&cpu_groups[num_groups], GFP_KERNEL)) {
free_cpu_groups(num_groups, &cpu_groups);
return -ENOMEM;
}
cpumask_copy(cpu_groups[num_groups++], cpu_group);
cpumask_andnot(tmp, tmp, cpu_group);
}
free_cpumask_var(tmp);
*pcpu_groups = cpu_groups;
return num_groups;
}
static int hotplug_tests(void)
{
int err;
cpumask_var_t offlined_cpus;
int i, nb_cpu_group;
const struct cpumask **cpu_groups;
int i, nb_cpu_group, err = -ENOMEM;
cpumask_var_t offlined_cpus, *cpu_groups;
char *page_buf;
err = -ENOMEM;
if (!alloc_cpumask_var(&offlined_cpus, GFP_KERNEL))
return err;
/* We may have up to nb_available_cpus cpu_groups. */
cpu_groups = kmalloc_array(nb_available_cpus, sizeof(*cpu_groups),
GFP_KERNEL);
if (!cpu_groups)
nb_cpu_group = alloc_init_cpu_groups(&cpu_groups);
if (nb_cpu_group < 0)
goto out_free_cpus;
page_buf = (char *)__get_free_page(GFP_KERNEL);
if (!page_buf)
goto out_free_cpu_groups;
err = 0;
nb_cpu_group = find_cpu_groups(cpu_online_mask, cpu_groups);
/*
* Of course the last CPU cannot be powered down and cpu_down() should
* refuse doing that.
......@@ -212,7 +227,7 @@ static int hotplug_tests(void)
free_page((unsigned long)page_buf);
out_free_cpu_groups:
kfree(cpu_groups);
free_cpu_groups(nb_cpu_group, &cpu_groups);
out_free_cpus:
free_cpumask_var(offlined_cpus);
return err;
......
......@@ -21,6 +21,10 @@
#define MBOX_DATA28(msg) ((msg) & ~0xf)
#define MBOX_CHAN_PROPERTY 8
#define MAX_RPI_FW_PROP_BUF_SIZE 32
static struct platform_device *rpi_hwmon;
struct rpi_firmware {
struct mbox_client cl;
struct mbox_chan *chan; /* The property channel. */
......@@ -143,18 +147,22 @@ int rpi_firmware_property(struct rpi_firmware *fw,
/* Single tags are very small (generally 8 bytes), so the
* stack should be safe.
*/
u8 data[buf_size + sizeof(struct rpi_firmware_property_tag_header)];
u8 data[sizeof(struct rpi_firmware_property_tag_header) +
MAX_RPI_FW_PROP_BUF_SIZE];
struct rpi_firmware_property_tag_header *header =
(struct rpi_firmware_property_tag_header *)data;
int ret;
if (WARN_ON(buf_size > sizeof(data) - sizeof(*header)))
return -EINVAL;
header->tag = tag;
header->buf_size = buf_size;
header->req_resp_size = 0;
memcpy(data + sizeof(struct rpi_firmware_property_tag_header),
tag_data, buf_size);
ret = rpi_firmware_property_list(fw, &data, sizeof(data));
ret = rpi_firmware_property_list(fw, &data, buf_size + sizeof(*header));
memcpy(tag_data,
data + sizeof(struct rpi_firmware_property_tag_header),
buf_size);
......@@ -183,6 +191,20 @@ rpi_firmware_print_firmware_revision(struct rpi_firmware *fw)
}
}
static void
rpi_register_hwmon_driver(struct device *dev, struct rpi_firmware *fw)
{
u32 packet;
int ret = rpi_firmware_property(fw, RPI_FIRMWARE_GET_THROTTLED,
&packet, sizeof(packet));
if (ret)
return;
rpi_hwmon = platform_device_register_data(dev, "raspberrypi-hwmon",
-1, NULL, 0);
}
static int rpi_firmware_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
......@@ -209,6 +231,7 @@ static int rpi_firmware_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, fw);
rpi_firmware_print_firmware_revision(fw);
rpi_register_hwmon_driver(dev, fw);
return 0;
}
......@@ -217,6 +240,8 @@ static int rpi_firmware_remove(struct platform_device *pdev)
{
struct rpi_firmware *fw = platform_get_drvdata(pdev);
platform_device_unregister(rpi_hwmon);
rpi_hwmon = NULL;
mbox_free_channel(fw->chan);
return 0;
......
......@@ -1320,6 +1320,16 @@ config SENSORS_PWM_FAN
This driver can also be built as a module. If so, the module
will be called pwm-fan.
config SENSORS_RASPBERRYPI_HWMON
tristate "Raspberry Pi voltage monitor"
depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE)
help
If you say yes here you get support for voltage sensor on the
Raspberry Pi.
This driver can also be built as a module. If so, the module
will be called raspberrypi-hwmon.
config SENSORS_SHT15
tristate "Sensiron humidity and temperature sensors. SHT15 and compat."
depends on GPIOLIB || COMPILE_TEST
......
......@@ -143,6 +143,7 @@ obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o
obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o
obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o
obj-$(CONFIG_SENSORS_S3C) += s3c-hwmon.o
obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o
obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Raspberry Pi voltage sensor driver
*
* Based on firmware/raspberrypi.c by Noralf Trønnes
*
* Copyright (C) 2018 Stefan Wahren <stefan.wahren@i2se.com>
*/
#include <linux/device.h>
#include <linux/err.h>
#include <linux/hwmon.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <soc/bcm2835/raspberrypi-firmware.h>
#define UNDERVOLTAGE_STICKY_BIT BIT(16)
struct rpi_hwmon_data {
struct device *hwmon_dev;
struct rpi_firmware *fw;
u32 last_throttled;
struct delayed_work get_values_poll_work;
};
static void rpi_firmware_get_throttled(struct rpi_hwmon_data *data)
{
u32 new_uv, old_uv, value;
int ret;
/* Request firmware to clear sticky bits */
value = 0xffff;
ret = rpi_firmware_property(data->fw, RPI_FIRMWARE_GET_THROTTLED,
&value, sizeof(value));
if (ret) {
dev_err_once(data->hwmon_dev, "Failed to get throttled (%d)\n",
ret);
return;
}
new_uv = value & UNDERVOLTAGE_STICKY_BIT;
old_uv = data->last_throttled & UNDERVOLTAGE_STICKY_BIT;
data->last_throttled = value;
if (new_uv == old_uv)
return;
if (new_uv)
dev_crit(data->hwmon_dev, "Undervoltage detected!\n");
else
dev_info(data->hwmon_dev, "Voltage normalised\n");
sysfs_notify(&data->hwmon_dev->kobj, NULL, "in0_lcrit_alarm");
}
static void get_values_poll(struct work_struct *work)
{
struct rpi_hwmon_data *data;
data = container_of(work, struct rpi_hwmon_data,
get_values_poll_work.work);
rpi_firmware_get_throttled(data);
/*
* We can't run faster than the sticky shift (100ms) since we get
* flipping in the sticky bits that are cleared.
*/
schedule_delayed_work(&data->get_values_poll_work, 2 * HZ);
}
static int rpi_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
struct rpi_hwmon_data *data = dev_get_drvdata(dev);
*val = !!(data->last_throttled & UNDERVOLTAGE_STICKY_BIT);
return 0;
}
static umode_t rpi_is_visible(const void *_data, enum hwmon_sensor_types type,
u32 attr, int channel)
{
return 0444;
}
static const u32 rpi_in_config[] = {
HWMON_I_LCRIT_ALARM,
0
};
static const struct hwmon_channel_info rpi_in = {
.type = hwmon_in,
.config = rpi_in_config,
};
static const struct hwmon_channel_info *rpi_info[] = {
&rpi_in,
NULL
};
static const struct hwmon_ops rpi_hwmon_ops = {
.is_visible = rpi_is_visible,
.read = rpi_read,
};
static const struct hwmon_chip_info rpi_chip_info = {
.ops = &rpi_hwmon_ops,
.info = rpi_info,
};
static int rpi_hwmon_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct rpi_hwmon_data *data;
int ret;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
/* Parent driver assure that firmware is correct */
data->fw = dev_get_drvdata(dev->parent);
/* Init throttled */
ret = rpi_firmware_property(data->fw, RPI_FIRMWARE_GET_THROTTLED,
&data->last_throttled,
sizeof(data->last_throttled));
data->hwmon_dev = devm_hwmon_device_register_with_info(dev, "rpi_volt",
data,
&rpi_chip_info,
NULL);
INIT_DELAYED_WORK(&data->get_values_poll_work, get_values_poll);
platform_set_drvdata(pdev, data);
if (!PTR_ERR_OR_ZERO(data->hwmon_dev))
schedule_delayed_work(&data->get_values_poll_work, 2 * HZ);
return PTR_ERR_OR_ZERO(data->hwmon_dev);
}
static int rpi_hwmon_remove(struct platform_device *pdev)
{
struct rpi_hwmon_data *data = platform_get_drvdata(pdev);
cancel_delayed_work_sync(&data->get_values_poll_work);
return 0;
}
static struct platform_driver rpi_hwmon_driver = {
.probe = rpi_hwmon_probe,
.remove = rpi_hwmon_remove,
.driver = {
.name = "raspberrypi-hwmon",
},
};
module_platform_driver(rpi_hwmon_driver);
MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>");
MODULE_DESCRIPTION("Raspberry Pi voltage sensor driver");
MODULE_LICENSE("GPL v2");
......@@ -672,13 +672,6 @@ static int tegra_mc_probe(struct platform_device *pdev)
return err;
}
err = tegra_mc_reset_setup(mc);
if (err < 0) {
dev_err(&pdev->dev, "failed to register reset controller: %d\n",
err);
return err;
}
mc->irq = platform_get_irq(pdev, 0);
if (mc->irq < 0) {
dev_err(&pdev->dev, "interrupt not specified\n");
......@@ -697,13 +690,16 @@ static int tegra_mc_probe(struct platform_device *pdev)
return err;
}
err = tegra_mc_reset_setup(mc);
if (err < 0)
dev_err(&pdev->dev, "failed to register reset controller: %d\n",
err);
if (IS_ENABLED(CONFIG_TEGRA_IOMMU_SMMU)) {
mc->smmu = tegra_smmu_probe(&pdev->dev, mc->soc->smmu, mc);
if (IS_ERR(mc->smmu)) {
if (IS_ERR(mc->smmu))
dev_err(&pdev->dev, "failed to probe SMMU: %ld\n",
PTR_ERR(mc->smmu));
return PTR_ERR(mc->smmu);
}
}
return 0;
......
......@@ -249,6 +249,34 @@ static const struct of_device_id ti_emif_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ti_emif_of_match);
#ifdef CONFIG_PM_SLEEP
static int ti_emif_resume(struct device *dev)
{
unsigned long tmp =
__raw_readl((void *)emif_instance->ti_emif_sram_virt);
/*
* Check to see if what we are copying is already present in the
* first byte at the destination, only copy if it is not which
* indicates we have lost context and sram no longer contains
* the PM code
*/
if (tmp != ti_emif_sram)
ti_emif_push_sram(dev, emif_instance);
return 0;
}
static int ti_emif_suspend(struct device *dev)
{
/*
* The contents will be present in DDR hence no need to
* explicitly save
*/
return 0;
}
#endif /* CONFIG_PM_SLEEP */
static int ti_emif_probe(struct platform_device *pdev)
{
int ret;
......@@ -308,12 +336,17 @@ static int ti_emif_remove(struct platform_device *pdev)
return 0;
}
static const struct dev_pm_ops ti_emif_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(ti_emif_suspend, ti_emif_resume)
};
static struct platform_driver ti_emif_driver = {
.probe = ti_emif_probe,
.remove = ti_emif_remove,
.driver = {
.name = KBUILD_MODNAME,
.of_match_table = of_match_ptr(ti_emif_of_match),
.pm = &ti_emif_pm_ops,
},
};
module_platform_driver(ti_emif_driver);
......
......@@ -82,6 +82,15 @@ config RESET_PISTACHIO
help
This enables the reset driver for ImgTec Pistachio SoCs.
config RESET_QCOM_AOSS
bool "Qcom AOSS Reset Driver"
depends on ARCH_QCOM || COMPILE_TEST
help
This enables the AOSS (always on subsystem) reset driver
for Qualcomm SDM845 SoCs. Say Y if you want to control
reset signals provided by AOSS for Modem, Venus, ADSP,
GPU, Camera, Wireless, Display subsystem. Otherwise, say N.
config RESET_SIMPLE
bool "Simple Reset Controller Driver" if COMPILE_TEST
default ARCH_SOCFPGA || ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARCH_ASPEED
......@@ -138,6 +147,16 @@ config RESET_UNIPHIER
Say Y if you want to control reset signals provided by System Control
block, Media I/O block, Peripheral Block.
config RESET_UNIPHIER_USB3
tristate "USB3 reset driver for UniPhier SoCs"
depends on (ARCH_UNIPHIER || COMPILE_TEST) && OF
default ARCH_UNIPHIER
select RESET_SIMPLE
help
Support for the USB3 core reset on UniPhier SoCs.
Say Y if you want to control reset signals provided by
USB3 glue layer.
config RESET_ZYNQ
bool "ZYNQ Reset Driver" if COMPILE_TEST
default ARCH_ZYNQ
......
......@@ -14,11 +14,13 @@ obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o
obj-$(CONFIG_RESET_MESON) += reset-meson.o
obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o
obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o
obj-$(CONFIG_RESET_QCOM_AOSS) += reset-qcom-aoss.o
obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
obj-$(CONFIG_RESET_STM32MP157) += reset-stm32mp1.o
obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o
obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o
obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
obj-$(CONFIG_RESET_UNIPHIER_USB3) += reset-uniphier-usb3.o
obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2018 The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/of_device.h>
#include <dt-bindings/reset/qcom,sdm845-aoss.h>
struct qcom_aoss_reset_map {
unsigned int reg;
};
struct qcom_aoss_desc {
const struct qcom_aoss_reset_map *resets;
size_t num_resets;
};
struct qcom_aoss_reset_data {
struct reset_controller_dev rcdev;
void __iomem *base;
const struct qcom_aoss_desc *desc;
};
static const struct qcom_aoss_reset_map sdm845_aoss_resets[] = {
[AOSS_CC_MSS_RESTART] = {0x10000},
[AOSS_CC_CAMSS_RESTART] = {0x11000},
[AOSS_CC_VENUS_RESTART] = {0x12000},
[AOSS_CC_GPU_RESTART] = {0x13000},
[AOSS_CC_DISPSS_RESTART] = {0x14000},
[AOSS_CC_WCSS_RESTART] = {0x20000},
[AOSS_CC_LPASS_RESTART] = {0x30000},
};
static const struct qcom_aoss_desc sdm845_aoss_desc = {
.resets = sdm845_aoss_resets,
.num_resets = ARRAY_SIZE(sdm845_aoss_resets),
};
static inline struct qcom_aoss_reset_data *to_qcom_aoss_reset_data(
struct reset_controller_dev *rcdev)
{
return container_of(rcdev, struct qcom_aoss_reset_data, rcdev);
}
static int qcom_aoss_control_assert(struct reset_controller_dev *rcdev,
unsigned long idx)
{
struct qcom_aoss_reset_data *data = to_qcom_aoss_reset_data(rcdev);
const struct qcom_aoss_reset_map *map = &data->desc->resets[idx];
writel(1, data->base + map->reg);
/* Wait 6 32kHz sleep cycles for reset */
usleep_range(200, 300);
return 0;
}
static int qcom_aoss_control_deassert(struct reset_controller_dev *rcdev,
unsigned long idx)
{
struct qcom_aoss_reset_data *data = to_qcom_aoss_reset_data(rcdev);
const struct qcom_aoss_reset_map *map = &data->desc->resets[idx];
writel(0, data->base + map->reg);
/* Wait 6 32kHz sleep cycles for reset */
usleep_range(200, 300);
return 0;
}
static int qcom_aoss_control_reset(struct reset_controller_dev *rcdev,
unsigned long idx)
{
qcom_aoss_control_assert(rcdev, idx);
return qcom_aoss_control_deassert(rcdev, idx);
}
static const struct reset_control_ops qcom_aoss_reset_ops = {
.reset = qcom_aoss_control_reset,
.assert = qcom_aoss_control_assert,
.deassert = qcom_aoss_control_deassert,
};
static int qcom_aoss_reset_probe(struct platform_device *pdev)
{
struct qcom_aoss_reset_data *data;
struct device *dev = &pdev->dev;
const struct qcom_aoss_desc *desc;
struct resource *res;
desc = of_device_get_match_data(dev);
if (!desc)
return -EINVAL;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->desc = desc;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
data->base = devm_ioremap_resource(dev, res);
if (IS_ERR(data->base))
return PTR_ERR(data->base);
data->rcdev.owner = THIS_MODULE;
data->rcdev.ops = &qcom_aoss_reset_ops;
data->rcdev.nr_resets = desc->num_resets;
data->rcdev.of_node = dev->of_node;
return devm_reset_controller_register(dev, &data->rcdev);
}
static const struct of_device_id qcom_aoss_reset_of_match[] = {
{ .compatible = "qcom,sdm845-aoss-cc", .data = &sdm845_aoss_desc },
{}
};
static struct platform_driver qcom_aoss_reset_driver = {
.probe = qcom_aoss_reset_probe,
.driver = {
.name = "qcom_aoss_reset",
.of_match_table = qcom_aoss_reset_of_match,
},
};
builtin_platform_driver(qcom_aoss_reset_driver);
MODULE_DESCRIPTION("Qualcomm AOSS Reset Driver");
MODULE_LICENSE("GPL v2");
......@@ -87,6 +87,7 @@ const struct reset_control_ops reset_simple_ops = {
.deassert = reset_simple_deassert,
.status = reset_simple_status,
};
EXPORT_SYMBOL_GPL(reset_simple_ops);
/**
* struct reset_simple_devdata - simple reset controller properties
......
// SPDX-License-Identifier: GPL-2.0
//
// reset-uniphier-usb3.c - USB3 reset driver for UniPhier
// Copyright 2018 Socionext Inc.
// Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include "reset-simple.h"
#define MAX_CLKS 2
#define MAX_RSTS 2
struct uniphier_usb3_reset_soc_data {
int nclks;
const char * const *clock_names;
int nrsts;
const char * const *reset_names;
};
struct uniphier_usb3_reset_priv {
struct clk_bulk_data clk[MAX_CLKS];
struct reset_control *rst[MAX_RSTS];
struct reset_simple_data rdata;
const struct uniphier_usb3_reset_soc_data *data;
};
static int uniphier_usb3_reset_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct uniphier_usb3_reset_priv *priv;
struct resource *res;
resource_size_t size;
const char *name;
int i, ret, nr;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->data = of_device_get_match_data(dev);
if (WARN_ON(!priv->data || priv->data->nclks > MAX_CLKS ||
priv->data->nrsts > MAX_RSTS))
return -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
size = resource_size(res);
priv->rdata.membase = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->rdata.membase))
return PTR_ERR(priv->rdata.membase);
for (i = 0; i < priv->data->nclks; i++)
priv->clk[i].id = priv->data->clock_names[i];
ret = devm_clk_bulk_get(dev, priv->data->nclks, priv->clk);
if (ret)
return ret;
for (i = 0; i < priv->data->nrsts; i++) {
name = priv->data->reset_names[i];
priv->rst[i] = devm_reset_control_get_shared(dev, name);
if (IS_ERR(priv->rst[i]))
return PTR_ERR(priv->rst[i]);
}
ret = clk_bulk_prepare_enable(priv->data->nclks, priv->clk);
if (ret)
return ret;
for (nr = 0; nr < priv->data->nrsts; nr++) {
ret = reset_control_deassert(priv->rst[nr]);
if (ret)
goto out_rst_assert;
}
spin_lock_init(&priv->rdata.lock);
priv->rdata.rcdev.owner = THIS_MODULE;
priv->rdata.rcdev.nr_resets = size * BITS_PER_BYTE;
priv->rdata.rcdev.ops = &reset_simple_ops;
priv->rdata.rcdev.of_node = dev->of_node;
priv->rdata.active_low = true;
platform_set_drvdata(pdev, priv);
ret = devm_reset_controller_register(dev, &priv->rdata.rcdev);
if (ret)
goto out_rst_assert;
return 0;
out_rst_assert:
while (nr--)
reset_control_assert(priv->rst[nr]);
clk_bulk_disable_unprepare(priv->data->nclks, priv->clk);
return ret;
}
static int uniphier_usb3_reset_remove(struct platform_device *pdev)
{
struct uniphier_usb3_reset_priv *priv = platform_get_drvdata(pdev);
int i;
for (i = 0; i < priv->data->nrsts; i++)
reset_control_assert(priv->rst[i]);
clk_bulk_disable_unprepare(priv->data->nclks, priv->clk);
return 0;
}
static const char * const uniphier_pro4_clock_reset_names[] = {
"gio", "link",
};
static const struct uniphier_usb3_reset_soc_data uniphier_pro4_data = {
.nclks = ARRAY_SIZE(uniphier_pro4_clock_reset_names),
.clock_names = uniphier_pro4_clock_reset_names,
.nrsts = ARRAY_SIZE(uniphier_pro4_clock_reset_names),
.reset_names = uniphier_pro4_clock_reset_names,
};
static const char * const uniphier_pxs2_clock_reset_names[] = {
"link",
};
static const struct uniphier_usb3_reset_soc_data uniphier_pxs2_data = {
.nclks = ARRAY_SIZE(uniphier_pxs2_clock_reset_names),
.clock_names = uniphier_pxs2_clock_reset_names,
.nrsts = ARRAY_SIZE(uniphier_pxs2_clock_reset_names),
.reset_names = uniphier_pxs2_clock_reset_names,
};
static const struct of_device_id uniphier_usb3_reset_match[] = {
{
.compatible = "socionext,uniphier-pro4-usb3-reset",
.data = &uniphier_pro4_data,
},
{
.compatible = "socionext,uniphier-pxs2-usb3-reset",
.data = &uniphier_pxs2_data,
},
{
.compatible = "socionext,uniphier-ld20-usb3-reset",
.data = &uniphier_pxs2_data,
},
{
.compatible = "socionext,uniphier-pxs3-usb3-reset",
.data = &uniphier_pxs2_data,
},
{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, uniphier_usb3_reset_match);
static struct platform_driver uniphier_usb3_reset_driver = {
.probe = uniphier_usb3_reset_probe,
.remove = uniphier_usb3_reset_remove,
.driver = {
.name = "uniphier-usb3-reset",
.of_match_table = uniphier_usb3_reset_match,
},
};
module_platform_driver(uniphier_usb3_reset_driver);
MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
MODULE_DESCRIPTION("UniPhier USB3 Reset Driver");
MODULE_LICENSE("GPL");
......@@ -202,6 +202,12 @@ static const struct uniphier_reset_data uniphier_pro5_sd_reset_data[] = {
#define UNIPHIER_PERI_RESET_FI2C(id, ch) \
UNIPHIER_RESETX((id), 0x114, 24 + (ch))
#define UNIPHIER_PERI_RESET_SCSSI(id) \
UNIPHIER_RESETX((id), 0x110, 17)
#define UNIPHIER_PERI_RESET_MCSSI(id) \
UNIPHIER_RESETX((id), 0x114, 14)
static const struct uniphier_reset_data uniphier_ld4_peri_reset_data[] = {
UNIPHIER_PERI_RESET_UART(0, 0),
UNIPHIER_PERI_RESET_UART(1, 1),
......@@ -212,6 +218,7 @@ static const struct uniphier_reset_data uniphier_ld4_peri_reset_data[] = {
UNIPHIER_PERI_RESET_I2C(6, 2),
UNIPHIER_PERI_RESET_I2C(7, 3),
UNIPHIER_PERI_RESET_I2C(8, 4),
UNIPHIER_PERI_RESET_SCSSI(11),
UNIPHIER_RESET_END,
};
......@@ -227,6 +234,8 @@ static const struct uniphier_reset_data uniphier_pro4_peri_reset_data[] = {
UNIPHIER_PERI_RESET_FI2C(8, 4),
UNIPHIER_PERI_RESET_FI2C(9, 5),
UNIPHIER_PERI_RESET_FI2C(10, 6),
UNIPHIER_PERI_RESET_SCSSI(11),
UNIPHIER_PERI_RESET_MCSSI(12),
UNIPHIER_RESET_END,
};
......
......@@ -627,10 +627,26 @@ static const struct of_device_id ddr_shimphy_dt_ids[] = {
};
static const struct of_device_id brcmstb_memc_of_match[] = {
{
.compatible = "brcm,brcmstb-memc-ddr-rev-b.2.1",
.data = &ddr_seq,
},
{
.compatible = "brcm,brcmstb-memc-ddr-rev-b.2.2",
.data = &ddr_seq_b22,
},
{
.compatible = "brcm,brcmstb-memc-ddr-rev-b.2.3",
.data = &ddr_seq_b22,
},
{
.compatible = "brcm,brcmstb-memc-ddr-rev-b.3.0",
.data = &ddr_seq_b22,
},
{
.compatible = "brcm,brcmstb-memc-ddr-rev-b.3.1",
.data = &ddr_seq_b22,
},
{
.compatible = "brcm,brcmstb-memc-ddr",
.data = &ddr_seq,
......
#
# Freescale SOC drivers
# NXP/Freescale QorIQ series SOC drivers
#
menu "NXP/Freescale QorIQ SoC drivers"
source "drivers/soc/fsl/qbman/Kconfig"
source "drivers/soc/fsl/qe/Kconfig"
......@@ -16,3 +18,14 @@ config FSL_GUTS
Initially only reading SVR and registering soc device are supported.
Other guts accesses, such as reading RCW, should eventually be moved
into this driver as well.
config FSL_MC_DPIO
tristate "QorIQ DPAA2 DPIO driver"
depends on FSL_MC_BUS
help
Driver for the DPAA2 DPIO object. A DPIO provides queue and
buffer management facilities for software to interact with
other DPAA2 objects. This driver does not expose the DPIO
objects individually, but groups them under a service layer
API.
endmenu
......@@ -6,3 +6,4 @@ obj-$(CONFIG_FSL_DPAA) += qbman/
obj-$(CONFIG_QUICC_ENGINE) += qe/
obj-$(CONFIG_CPM) += qe/
obj-$(CONFIG_FSL_GUTS) += guts.o
obj-$(CONFIG_FSL_MC_DPIO) += dpio/
......@@ -16,7 +16,7 @@
#include <linux/io.h>
#include <linux/fsl/mc.h>
#include "../../include/dpaa2-io.h"
#include <soc/fsl/dpaa2-io.h>
#include "qbman-portal.h"
#include "dpio.h"
......
......@@ -6,7 +6,7 @@
*/
#include <linux/types.h>
#include <linux/fsl/mc.h>
#include "../../include/dpaa2-io.h"
#include <soc/fsl/dpaa2-io.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
......
......@@ -8,7 +8,7 @@
#include <asm/cacheflush.h>
#include <linux/io.h>
#include <linux/slab.h>
#include "../../include/dpaa2-global.h"
#include <soc/fsl/dpaa2-global.h>
#include "qbman-portal.h"
......
......@@ -7,7 +7,7 @@
#ifndef __FSL_QBMAN_PORTAL_H
#define __FSL_QBMAN_PORTAL_H
#include "../../include/dpaa2-fd.h"
#include <soc/fsl/dpaa2-fd.h>
struct dpaa2_dq;
struct qbman_swp;
......
menuconfig FSL_DPAA
bool "Freescale DPAA 1.x support"
bool "QorIQ DPAA1 framework support"
depends on (FSL_SOC_BOOKE || ARCH_LAYERSCAPE)
select GENERIC_ALLOCATOR
help
......
......@@ -3,7 +3,7 @@
#
config QUICC_ENGINE
bool "Freescale QUICC Engine (QE) Support"
bool "QUICC Engine (QE) framework support"
depends on FSL_SOC && PPC32
select GENERIC_ALLOCATOR
select CRC32
......
......@@ -83,6 +83,33 @@ static void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
spin_unlock_irqrestore(&qe_gc->lock, flags);
}
static void qe_gpio_set_multiple(struct gpio_chip *gc,
unsigned long *mask, unsigned long *bits)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct qe_gpio_chip *qe_gc = gpiochip_get_data(gc);
struct qe_pio_regs __iomem *regs = mm_gc->regs;
unsigned long flags;
int i;
spin_lock_irqsave(&qe_gc->lock, flags);
for (i = 0; i < gc->ngpio; i++) {
if (*mask == 0)
break;
if (__test_and_clear_bit(i, mask)) {
if (test_bit(i, bits))
qe_gc->cpdata |= (1U << (QE_PIO_PINS - 1 - i));
else
qe_gc->cpdata &= ~(1U << (QE_PIO_PINS - 1 - i));
}
}
out_be32(&regs->cpdata, qe_gc->cpdata);
spin_unlock_irqrestore(&qe_gc->lock, flags);
}
static int qe_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
......@@ -298,6 +325,7 @@ static int __init qe_add_gpiochips(void)
gc->direction_output = qe_gpio_dir_out;
gc->get = qe_gpio_get;
gc->set = qe_gpio_set;
gc->set_multiple = qe_gpio_set_multiple;
ret = of_mm_gpiochip_add_data(np, mm_gc, qe_gc);
if (ret)
......
......@@ -54,7 +54,6 @@ struct imx_pm_domain {
unsigned int reg_offs;
signed char cntr_pdn_bit;
unsigned int ipg_rate_mhz;
unsigned int flags;
};
static inline struct imx_pm_domain *
......@@ -69,9 +68,6 @@ static int imx6_pm_domain_power_off(struct generic_pm_domain *genpd)
int iso, iso2sw;
u32 val;
if (pd->flags & PGC_DOMAIN_FLAG_NO_PD)
return -EBUSY;
/* Read ISO and ISO2SW power down delays */
regmap_read(pd->regmap, pd->reg_offs + GPC_PGC_PUPSCR_OFFS, &val);
iso = val & 0x3f;
......@@ -295,26 +291,31 @@ static struct imx_pm_domain imx_gpc_domains[] = {
struct imx_gpc_dt_data {
int num_domains;
bool err009619_present;
bool err006287_present;
};
static const struct imx_gpc_dt_data imx6q_dt_data = {
.num_domains = 2,
.err009619_present = false,
.err006287_present = false,
};
static const struct imx_gpc_dt_data imx6qp_dt_data = {
.num_domains = 2,
.err009619_present = true,
.err006287_present = false,
};
static const struct imx_gpc_dt_data imx6sl_dt_data = {
.num_domains = 3,
.err009619_present = false,
.err006287_present = true,
};
static const struct imx_gpc_dt_data imx6sx_dt_data = {
.num_domains = 4,
.err009619_present = false,
.err006287_present = false,
};
static const struct of_device_id imx_gpc_dt_ids[] = {
......@@ -434,8 +435,13 @@ static int imx_gpc_probe(struct platform_device *pdev)
/* Disable PU power down in normal operation if ERR009619 is present */
if (of_id_data->err009619_present)
imx_gpc_domains[GPC_PGC_DOMAIN_PU].flags |=
PGC_DOMAIN_FLAG_NO_PD;
imx_gpc_domains[GPC_PGC_DOMAIN_PU].base.flags |=
GENPD_FLAG_ALWAYS_ON;
/* Keep DISP always on if ERR006287 is present */
if (of_id_data->err006287_present)
imx_gpc_domains[GPC_PGC_DOMAIN_DISPLAY].base.flags |=
GENPD_FLAG_ALWAYS_ON;
if (!pgc_node) {
ret = imx_gpc_old_dt_init(&pdev->dev, regmap,
......
......@@ -146,6 +146,21 @@ static const u32 mt6397_regs[] = {
[PWRAP_DEW_CIPHER_SWRST] = 0xbc24,
};
static const u32 mt6351_regs[] = {
[PWRAP_DEW_DIO_EN] = 0x02F2,
[PWRAP_DEW_READ_TEST] = 0x02F4,
[PWRAP_DEW_WRITE_TEST] = 0x02F6,
[PWRAP_DEW_CRC_EN] = 0x02FA,
[PWRAP_DEW_CRC_VAL] = 0x02FC,
[PWRAP_DEW_CIPHER_KEY_SEL] = 0x0300,
[PWRAP_DEW_CIPHER_IV_SEL] = 0x0302,
[PWRAP_DEW_CIPHER_EN] = 0x0304,
[PWRAP_DEW_CIPHER_RDY] = 0x0306,
[PWRAP_DEW_CIPHER_MODE] = 0x0308,
[PWRAP_DEW_CIPHER_SWRST] = 0x030A,
[PWRAP_DEW_RDDMY_NO] = 0x030C,
};
enum pwrap_regs {
PWRAP_MUX_SEL,
PWRAP_WRAP_EN,
......@@ -366,6 +381,39 @@ static int mt2701_regs[] = {
[PWRAP_ADC_RDATA_ADDR2] = 0x154,
};
static int mt6797_regs[] = {
[PWRAP_MUX_SEL] = 0x0,
[PWRAP_WRAP_EN] = 0x4,
[PWRAP_DIO_EN] = 0x8,
[PWRAP_SIDLY] = 0xC,
[PWRAP_RDDMY] = 0x10,
[PWRAP_CSHEXT_WRITE] = 0x18,
[PWRAP_CSHEXT_READ] = 0x1C,
[PWRAP_CSLEXT_START] = 0x20,
[PWRAP_CSLEXT_END] = 0x24,
[PWRAP_STAUPD_PRD] = 0x28,
[PWRAP_HARB_HPRIO] = 0x50,
[PWRAP_HIPRIO_ARB_EN] = 0x54,
[PWRAP_MAN_EN] = 0x60,
[PWRAP_MAN_CMD] = 0x64,
[PWRAP_WACS0_EN] = 0x70,
[PWRAP_WACS1_EN] = 0x84,
[PWRAP_WACS2_EN] = 0x98,
[PWRAP_INIT_DONE2] = 0x9C,
[PWRAP_WACS2_CMD] = 0xA0,
[PWRAP_WACS2_RDATA] = 0xA4,
[PWRAP_WACS2_VLDCLR] = 0xA8,
[PWRAP_INT_EN] = 0xC0,
[PWRAP_INT_FLG_RAW] = 0xC4,
[PWRAP_INT_FLG] = 0xC8,
[PWRAP_INT_CLR] = 0xCC,
[PWRAP_TIMER_EN] = 0xF4,
[PWRAP_WDT_UNIT] = 0xFC,
[PWRAP_WDT_SRC_EN] = 0x100,
[PWRAP_DCM_EN] = 0x1CC,
[PWRAP_DCM_DBC_PRD] = 0x1D4,
};
static int mt7622_regs[] = {
[PWRAP_MUX_SEL] = 0x0,
[PWRAP_WRAP_EN] = 0x4,
......@@ -635,12 +683,14 @@ static int mt8135_regs[] = {
enum pmic_type {
PMIC_MT6323,
PMIC_MT6351,
PMIC_MT6380,
PMIC_MT6397,
};
enum pwrap_type {
PWRAP_MT2701,
PWRAP_MT6797,
PWRAP_MT7622,
PWRAP_MT8135,
PWRAP_MT8173,
......@@ -1067,6 +1117,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
pwrap_writel(wrp, 1, PWRAP_CIPHER_START);
break;
case PWRAP_MT2701:
case PWRAP_MT6797:
case PWRAP_MT8173:
pwrap_writel(wrp, 1, PWRAP_CIPHER_EN);
break;
......@@ -1080,8 +1131,6 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_SWRST], 0x0);
pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_KEY_SEL], 0x1);
pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_IV_SEL], 0x2);
pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_LOAD], 0x1);
pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_START], 0x1);
switch (wrp->slave->type) {
case PMIC_MT6397:
......@@ -1091,6 +1140,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
0x1);
break;
case PMIC_MT6323:
case PMIC_MT6351:
pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_EN],
0x1);
break;
......@@ -1367,6 +1417,15 @@ static const struct pwrap_slv_type pmic_mt6397 = {
.pwrap_write = pwrap_write16,
};
static const struct pwrap_slv_type pmic_mt6351 = {
.dew_regs = mt6351_regs,
.type = PMIC_MT6351,
.regmap = &pwrap_regmap_config16,
.caps = 0,
.pwrap_read = pwrap_read16,
.pwrap_write = pwrap_write16,
};
static const struct of_device_id of_slave_match_tbl[] = {
{
.compatible = "mediatek,mt6323",
......@@ -1380,6 +1439,9 @@ static const struct of_device_id of_slave_match_tbl[] = {
}, {
.compatible = "mediatek,mt6397",
.data = &pmic_mt6397,
}, {
.compatible = "mediatek,mt6351",
.data = &pmic_mt6351,
}, {
/* sentinel */
}
......@@ -1398,6 +1460,18 @@ static const struct pmic_wrapper_type pwrap_mt2701 = {
.init_soc_specific = pwrap_mt2701_init_soc_specific,
};
static const struct pmic_wrapper_type pwrap_mt6797 = {
.regs = mt6797_regs,
.type = PWRAP_MT6797,
.arb_en_all = 0x01fff,
.int_en_all = 0xffffffc6,
.spi_w = PWRAP_MAN_CMD_SPI_WRITE,
.wdt_src = PWRAP_WDT_SRC_MASK_ALL,
.has_bridge = 0,
.init_reg_clock = pwrap_common_init_reg_clock,
.init_soc_specific = NULL,
};
static const struct pmic_wrapper_type pwrap_mt7622 = {
.regs = mt7622_regs,
.type = PWRAP_MT7622,
......@@ -1438,6 +1512,9 @@ static const struct of_device_id of_pwrap_match_tbl[] = {
{
.compatible = "mediatek,mt2701-pwrap",
.data = &pwrap_mt2701,
}, {
.compatible = "mediatek,mt6797-pwrap",
.data = &pwrap_mt6797,
}, {
.compatible = "mediatek,mt7622-pwrap",
.data = &pwrap_mt7622,
......
......@@ -17,6 +17,7 @@
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/soc/sunxi/sunxi_sram.h>
......@@ -63,6 +64,12 @@ static struct sunxi_sram_desc sun4i_a10_sram_a3_a4 = {
SUNXI_SRAM_MAP(1, 1, "emac")),
};
static struct sunxi_sram_desc sun4i_a10_sram_c1 = {
.data = SUNXI_SRAM_DATA("C1", 0x0, 0x0, 31,
SUNXI_SRAM_MAP(0, 0, "cpu"),
SUNXI_SRAM_MAP(0x7fffffff, 1, "ve")),
};
static struct sunxi_sram_desc sun4i_a10_sram_d = {
.data = SUNXI_SRAM_DATA("D", 0x4, 0x0, 1,
SUNXI_SRAM_MAP(0, 0, "cpu"),
......@@ -80,6 +87,10 @@ static const struct of_device_id sunxi_sram_dt_ids[] = {
.compatible = "allwinner,sun4i-a10-sram-a3-a4",
.data = &sun4i_a10_sram_a3_a4.data,
},
{
.compatible = "allwinner,sun4i-a10-sram-c1",
.data = &sun4i_a10_sram_c1.data,
},
{
.compatible = "allwinner,sun4i-a10-sram-d",
.data = &sun4i_a10_sram_d.data,
......@@ -281,13 +292,51 @@ int sunxi_sram_release(struct device *dev)
}
EXPORT_SYMBOL(sunxi_sram_release);
struct sunxi_sramc_variant {
bool has_emac_clock;
};
static const struct sunxi_sramc_variant sun4i_a10_sramc_variant = {
/* Nothing special */
};
static const struct sunxi_sramc_variant sun50i_a64_sramc_variant = {
.has_emac_clock = true,
};
#define SUNXI_SRAM_EMAC_CLOCK_REG 0x30
static bool sunxi_sram_regmap_accessible_reg(struct device *dev,
unsigned int reg)
{
if (reg == SUNXI_SRAM_EMAC_CLOCK_REG)
return true;
return false;
}
static struct regmap_config sunxi_sram_emac_clock_regmap = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
/* last defined register */
.max_register = SUNXI_SRAM_EMAC_CLOCK_REG,
/* other devices have no business accessing other registers */
.readable_reg = sunxi_sram_regmap_accessible_reg,
.writeable_reg = sunxi_sram_regmap_accessible_reg,
};
static int sunxi_sram_probe(struct platform_device *pdev)
{
struct resource *res;
struct dentry *d;
struct regmap *emac_clock;
const struct sunxi_sramc_variant *variant;
sram_dev = &pdev->dev;
variant = of_device_get_match_data(&pdev->dev);
if (!variant)
return -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
......@@ -300,12 +349,46 @@ static int sunxi_sram_probe(struct platform_device *pdev)
if (!d)
return -ENOMEM;
if (variant->has_emac_clock) {
emac_clock = devm_regmap_init_mmio(&pdev->dev, base,
&sunxi_sram_emac_clock_regmap);
if (IS_ERR(emac_clock))
return PTR_ERR(emac_clock);
}
return 0;
}
static const struct of_device_id sunxi_sram_dt_match[] = {
{ .compatible = "allwinner,sun4i-a10-sram-controller" },
{ .compatible = "allwinner,sun50i-a64-sram-controller" },
{
.compatible = "allwinner,sun4i-a10-sram-controller",
.data = &sun4i_a10_sramc_variant,
},
{
.compatible = "allwinner,sun4i-a10-system-control",
.data = &sun4i_a10_sramc_variant,
},
{
.compatible = "allwinner,sun5i-a13-system-control",
.data = &sun4i_a10_sramc_variant,
},
{
.compatible = "allwinner,sun8i-a23-system-control",
.data = &sun4i_a10_sramc_variant,
},
{
.compatible = "allwinner,sun8i-h3-system-control",
.data = &sun4i_a10_sramc_variant,
},
{
.compatible = "allwinner,sun50i-a64-sram-controller",
.data = &sun50i_a64_sramc_variant,
},
{
.compatible = "allwinner,sun50i-a64-system-control",
.data = &sun50i_a64_sramc_variant,
},
{ },
};
MODULE_DEVICE_TABLE(of, sunxi_sram_dt_match);
......
......@@ -46,6 +46,7 @@
#define M3_BASELINE_VERSION 0x191
#define M3_STATUS_RESP_MASK (0xffff << 16)
#define M3_FW_VERSION_MASK 0xffff
#define M3_WAKE_SRC_MASK 0xff
#define M3_STATE_UNKNOWN 0
#define M3_STATE_RESET 1
......@@ -55,6 +56,23 @@
static struct wkup_m3_ipc *m3_ipc_state;
static const struct wkup_m3_wakeup_src wakeups[] = {
{.irq_nr = 35, .src = "USB0_PHY"},
{.irq_nr = 36, .src = "USB1_PHY"},
{.irq_nr = 40, .src = "I2C0"},
{.irq_nr = 41, .src = "RTC Timer"},
{.irq_nr = 42, .src = "RTC Alarm"},
{.irq_nr = 43, .src = "Timer0"},
{.irq_nr = 44, .src = "Timer1"},
{.irq_nr = 45, .src = "UART"},
{.irq_nr = 46, .src = "GPIO0"},
{.irq_nr = 48, .src = "MPU_WAKE"},
{.irq_nr = 49, .src = "WDT0"},
{.irq_nr = 50, .src = "WDT1"},
{.irq_nr = 51, .src = "ADC_TSC"},
{.irq_nr = 0, .src = "Unknown"},
};
static void am33xx_txev_eoi(struct wkup_m3_ipc *m3_ipc)
{
writel(AM33XX_M3_TXEV_ACK,
......@@ -329,12 +347,45 @@ static int wkup_m3_finish_low_power(struct wkup_m3_ipc *m3_ipc)
return 0;
}
/**
* wkup_m3_request_wake_src - Get the wakeup source info passed from wkup_m3
* @m3_ipc: Pointer to wkup_m3_ipc context
*/
static const char *wkup_m3_request_wake_src(struct wkup_m3_ipc *m3_ipc)
{
unsigned int wakeup_src_idx;
int j, val;
val = wkup_m3_ctrl_ipc_read(m3_ipc, 6);
wakeup_src_idx = val & M3_WAKE_SRC_MASK;
for (j = 0; j < ARRAY_SIZE(wakeups) - 1; j++) {
if (wakeups[j].irq_nr == wakeup_src_idx)
return wakeups[j].src;
}
return wakeups[j].src;
}
/**
* wkup_m3_set_rtc_only - Set the rtc_only flag
* @wkup_m3_wakeup: struct wkup_m3_wakeup_src * gets assigned the
* wakeup src value
*/
static void wkup_m3_set_rtc_only(struct wkup_m3_ipc *m3_ipc)
{
if (m3_ipc_state)
m3_ipc_state->is_rtc_only = true;
}
static struct wkup_m3_ipc_ops ipc_ops = {
.set_mem_type = wkup_m3_set_mem_type,
.set_resume_address = wkup_m3_set_resume_address,
.prepare_low_power = wkup_m3_prepare_low_power,
.finish_low_power = wkup_m3_finish_low_power,
.request_pm_status = wkup_m3_request_pm_status,
.request_wake_src = wkup_m3_request_wake_src,
.set_rtc_only = wkup_m3_set_rtc_only,
};
/**
......@@ -484,6 +535,30 @@ static int wkup_m3_ipc_remove(struct platform_device *pdev)
return 0;
}
static int __maybe_unused wkup_m3_ipc_suspend(struct device *dev)
{
/*
* Nothing needs to be done on suspend even with rtc_only flag set
*/
return 0;
}
static int __maybe_unused wkup_m3_ipc_resume(struct device *dev)
{
if (m3_ipc_state->is_rtc_only) {
rproc_shutdown(m3_ipc_state->rproc);
rproc_boot(m3_ipc_state->rproc);
}
m3_ipc_state->is_rtc_only = false;
return 0;
}
static const struct dev_pm_ops wkup_m3_ipc_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(wkup_m3_ipc_suspend, wkup_m3_ipc_resume)
};
static const struct of_device_id wkup_m3_ipc_of_match[] = {
{ .compatible = "ti,am3352-wkup-m3-ipc", },
{ .compatible = "ti,am4372-wkup-m3-ipc", },
......@@ -497,6 +572,7 @@ static struct platform_driver wkup_m3_ipc_driver = {
.driver = {
.name = "wkup_m3_ipc",
.of_match_table = wkup_m3_ipc_of_match,
.pm = &wkup_m3_ipc_pm_ops,
},
};
......
......@@ -90,8 +90,6 @@ source "drivers/staging/clocking-wizard/Kconfig"
source "drivers/staging/fbtft/Kconfig"
source "drivers/staging/fsl-mc/Kconfig"
source "drivers/staging/fsl-dpaa2/Kconfig"
source "drivers/staging/wilc1000/Kconfig"
......
......@@ -35,7 +35,6 @@ obj-$(CONFIG_GS_FPGABOOT) += gs_fpgaboot/
obj-$(CONFIG_UNISYSSPAR) += unisys/
obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clocking-wizard/
obj-$(CONFIG_FB_TFT) += fbtft/
obj-$(CONFIG_FSL_MC_BUS) += fsl-mc/
obj-$(CONFIG_FSL_DPAA2) += fsl-dpaa2/
obj-$(CONFIG_WILC1000) += wilc1000/
obj-$(CONFIG_MOST) += most/
......
......@@ -426,7 +426,7 @@ static int build_sg_fd(struct dpaa2_eth_priv *priv,
dpaa2_fd_set_format(fd, dpaa2_fd_sg);
dpaa2_fd_set_addr(fd, addr);
dpaa2_fd_set_len(fd, skb->len);
dpaa2_fd_set_ctrl(fd, DPAA2_FD_CTRL_PTA | DPAA2_FD_CTRL_PTV1);
dpaa2_fd_set_ctrl(fd, FD_CTRL_PTA | FD_CTRL_PTV1);
if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)
enable_tx_tstamp(fd, sgt_buf);
......@@ -479,7 +479,7 @@ static int build_single_fd(struct dpaa2_eth_priv *priv,
dpaa2_fd_set_offset(fd, (u16)(skb->data - buffer_start));
dpaa2_fd_set_len(fd, skb->len);
dpaa2_fd_set_format(fd, dpaa2_fd_single);
dpaa2_fd_set_ctrl(fd, DPAA2_FD_CTRL_PTA | DPAA2_FD_CTRL_PTV1);
dpaa2_fd_set_ctrl(fd, FD_CTRL_PTA | FD_CTRL_PTV1);
if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)
enable_tx_tstamp(fd, buffer_start);
......
......@@ -10,8 +10,8 @@
#include <linux/if_vlan.h>
#include <linux/fsl/mc.h>
#include "../../fsl-mc/include/dpaa2-io.h"
#include "../../fsl-mc/include/dpaa2-fd.h"
#include <soc/fsl/dpaa2-io.h>
#include <soc/fsl/dpaa2-fd.h>
#include "dpni.h"
#include "dpni-cmd.h"
......@@ -97,21 +97,13 @@ struct dpaa2_eth_swa {
#define DPAA2_FD_FRC_FAICFDV 0x0400
/* Error bits in FD CTRL */
#define DPAA2_FD_CTRL_UFD 0x00000004
#define DPAA2_FD_CTRL_SBE 0x00000008
#define DPAA2_FD_CTRL_FSE 0x00000020
#define DPAA2_FD_CTRL_FAERR 0x00000040
#define DPAA2_FD_RX_ERR_MASK (DPAA2_FD_CTRL_SBE | \
DPAA2_FD_CTRL_FAERR)
#define DPAA2_FD_TX_ERR_MASK (DPAA2_FD_CTRL_UFD | \
DPAA2_FD_CTRL_SBE | \
DPAA2_FD_CTRL_FSE | \
DPAA2_FD_CTRL_FAERR)
#define DPAA2_FD_RX_ERR_MASK (FD_CTRL_SBE | FD_CTRL_FAERR)
#define DPAA2_FD_TX_ERR_MASK (FD_CTRL_UFD | \
FD_CTRL_SBE | \
FD_CTRL_FSE | \
FD_CTRL_FAERR)
/* Annotation bits in FD CTRL */
#define DPAA2_FD_CTRL_PTA 0x00800000
#define DPAA2_FD_CTRL_PTV1 0x00400000
#define DPAA2_FD_CTRL_ASAL 0x00020000 /* ASAL = 128B */
/* Frame annotation status */
......
# SPDX-License-Identifier: GPL-2.0
source "drivers/staging/fsl-mc/bus/Kconfig"
# SPDX-License-Identifier: GPL-2.0
# Freescale Management Complex (MC) bus drivers
obj-$(CONFIG_FSL_MC_BUS) += bus/
# SPDX-License-Identifier: GPL-2.0
#
# DPAA2 fsl-mc bus
#
# Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
#
config FSL_MC_DPIO
tristate "QorIQ DPAA2 DPIO driver"
depends on FSL_MC_BUS
help
Driver for the DPAA2 DPIO object. A DPIO provides queue and
buffer management facilities for software to interact with
other DPAA2 objects. This driver does not expose the DPIO
objects individually, but groups them under a service layer
API.
# SPDX-License-Identifier: GPL-2.0
#
# Freescale Management Complex (MC) bus drivers
#
# Copyright (C) 2014 Freescale Semiconductor, Inc.
#
# MC DPIO driver
obj-$(CONFIG_FSL_MC_DPIO) += dpio/
......@@ -5,3 +5,11 @@ config OPTEE
help
This implements the OP-TEE Trusted Execution Environment (TEE)
driver.
config OPTEE_SHM_NUM_PRIV_PAGES
int "Private Shared Memory Pages"
default 1
depends on OPTEE
help
This sets the number of private shared memory pages to be
used by OP-TEE TEE driver.
......@@ -32,7 +32,7 @@
#define DRIVER_NAME "optee"
#define OPTEE_SHM_NUM_PRIV_PAGES 1
#define OPTEE_SHM_NUM_PRIV_PAGES CONFIG_OPTEE_SHM_NUM_PRIV_PAGES
/**
* optee_from_msg_param() - convert from OPTEE_MSG parameters to
......
......@@ -48,7 +48,7 @@ static void handle_rpc_func_cmd_get_time(struct optee_msg_arg *arg)
OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT)
goto bad;
getnstimeofday64(&ts);
ktime_get_real_ts64(&ts);
arg->params[0].u.value.a = ts.tv_sec;
arg->params[0].u.value.b = ts.tv_nsec;
......
......@@ -161,16 +161,10 @@ static int exynos_ehci_probe(struct platform_device *pdev)
}
exynos_ehci = to_exynos_ehci(hcd);
if (of_device_is_compatible(pdev->dev.of_node,
"samsung,exynos5440-ehci"))
goto skip_phy;
err = exynos_ehci_get_phy(&pdev->dev, exynos_ehci);
if (err)
goto fail_clk;
skip_phy:
exynos_ehci->clk = devm_clk_get(&pdev->dev, "usbhost");
if (IS_ERR(exynos_ehci->clk)) {
......@@ -304,7 +298,6 @@ static const struct dev_pm_ops exynos_ehci_pm_ops = {
#ifdef CONFIG_OF
static const struct of_device_id exynos_ehci_match[] = {
{ .compatible = "samsung,exynos4210-ehci" },
{ .compatible = "samsung,exynos5440-ehci" },
{},
};
MODULE_DEVICE_TABLE(of, exynos_ehci_match);
......
......@@ -130,15 +130,10 @@ static int exynos_ohci_probe(struct platform_device *pdev)
exynos_ohci = to_exynos_ohci(hcd);
if (of_device_is_compatible(pdev->dev.of_node,
"samsung,exynos5440-ohci"))
goto skip_phy;
err = exynos_ohci_get_phy(&pdev->dev, exynos_ohci);
if (err)
goto fail_clk;
skip_phy:
exynos_ohci->clk = devm_clk_get(&pdev->dev, "usbhost");
if (IS_ERR(exynos_ohci->clk)) {
......@@ -270,7 +265,6 @@ static const struct dev_pm_ops exynos_ohci_pm_ops = {
#ifdef CONFIG_OF
static const struct of_device_id exynos_ohci_match[] = {
{ .compatible = "samsung,exynos4210-ohci" },
{ .compatible = "samsung,exynos5440-ohci" },
{},
};
MODULE_DEVICE_TABLE(of, exynos_ohci_match);
......
......@@ -15,6 +15,8 @@
/* SmartReflex sysc found on 36xx and later */
#define SYSC_OMAP3_SR_ENAWAKEUP (1 << 26)
#define SYSC_DRA7_MCAN_ENAWAKEUP (1 << 4)
/* SYSCONFIG STANDBYMODE/MIDLEMODE/SIDLEMODE supported by hardware */
#define SYSC_IDLE_FORCE 0
#define SYSC_IDLE_NO 1
......
......@@ -168,5 +168,6 @@
#define DRA7_COUNTER_32K_CLKCTRL DRA7_CLKCTRL_INDEX(0x50)
#define DRA7_UART10_CLKCTRL DRA7_CLKCTRL_INDEX(0x80)
#define DRA7_DCAN1_CLKCTRL DRA7_CLKCTRL_INDEX(0x88)
#define DRA7_ADC_CLKCTRL DRA7_CLKCTRL_INDEX(0xa0)
#endif
/*
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* Author: Andrzej Hajda <a.hajda@samsung.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.
*
* Device Tree binding constants for Exynos5440 clock controller.
*/
#ifndef _DT_BINDINGS_CLOCK_EXYNOS_5440_H
#define _DT_BINDINGS_CLOCK_EXYNOS_5440_H
#define CLK_XTAL 1
#define CLK_ARM_CLK 2
#define CLK_CPLLA 3
#define CLK_CPLLB 4
#define CLK_SPI_BAUD 16
#define CLK_PB0_250 17
#define CLK_PR0_250 18
#define CLK_PR1_250 19
#define CLK_B_250 20
#define CLK_B_125 21
#define CLK_B_200 22
#define CLK_SATA 23
#define CLK_USB 24
#define CLK_GMAC0 25
#define CLK_CS250 26
#define CLK_PB0_250_O 27
#define CLK_PR0_250_O 28
#define CLK_PR1_250_O 29
#define CLK_B_250_O 30
#define CLK_B_125_O 31
#define CLK_B_200_O 32
#define CLK_SATA_O 33
#define CLK_USB_O 34
#define CLK_GMAC0_O 35
#define CLK_CS250_O 36
/* must be greater than maximal clock id */
#define CLK_NR_CLKS 37
#endif /* _DT_BINDINGS_CLOCK_EXYNOS_5440_H */
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2018 The Linux Foundation. All rights reserved.
*/
#ifndef _DT_BINDINGS_RESET_AOSS_SDM_845_H
#define _DT_BINDINGS_RESET_AOSS_SDM_845_H
#define AOSS_CC_MSS_RESTART 0
#define AOSS_CC_CAMSS_RESTART 1
#define AOSS_CC_VENUS_RESTART 2
#define AOSS_CC_GPU_RESTART 3
#define AOSS_CC_DISPSS_RESTART 4
#define AOSS_CC_WCSS_RESTART 5
#define AOSS_CC_LPASS_RESTART 6
#endif
......@@ -14,6 +14,7 @@ enum ti_sysc_module_type {
TI_SYSC_OMAP4_SR,
TI_SYSC_OMAP4_MCASP,
TI_SYSC_OMAP4_USB_HOST_FS,
TI_SYSC_DRA7_MCAN,
};
struct ti_sysc_cookie {
......
......@@ -40,6 +40,12 @@ struct wkup_m3_ipc {
struct mbox_chan *mbox;
struct wkup_m3_ipc_ops *ops;
int is_rtc_only;
};
struct wkup_m3_wakeup_src {
int irq_nr;
char src[10];
};
struct wkup_m3_ipc_ops {
......@@ -48,8 +54,11 @@ struct wkup_m3_ipc_ops {
int (*prepare_low_power)(struct wkup_m3_ipc *m3_ipc, int state);
int (*finish_low_power)(struct wkup_m3_ipc *m3_ipc);
int (*request_pm_status)(struct wkup_m3_ipc *m3_ipc);
const char *(*request_wake_src)(struct wkup_m3_ipc *m3_ipc);
void (*set_rtc_only)(struct wkup_m3_ipc *m3_ipc);
};
struct wkup_m3_ipc *wkup_m3_ipc_get(void);
void wkup_m3_ipc_put(struct wkup_m3_ipc *m3_ipc);
void wkup_m3_set_rtc_only_mode(void);
#endif /* _LINUX_WKUP_M3_IPC_H */
......@@ -75,6 +75,7 @@ enum rpi_firmware_property_tag {
RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020,
RPI_FIRMWARE_GET_CUSTOMER_OTP = 0x00030021,
RPI_FIRMWARE_GET_DOMAIN_STATE = 0x00030030,
RPI_FIRMWARE_GET_THROTTLED = 0x00030046,
RPI_FIRMWARE_SET_CLOCK_STATE = 0x00038001,
RPI_FIRMWARE_SET_CLOCK_RATE = 0x00038002,
RPI_FIRMWARE_SET_VOLTAGE = 0x00038003,
......
......@@ -67,6 +67,18 @@ struct dpaa2_fd {
#define SG_FINAL_FLAG_MASK 0x1
#define SG_FINAL_FLAG_SHIFT 15
/* Error bits in FD CTRL */
#define FD_CTRL_ERR_MASK 0x000000FF
#define FD_CTRL_UFD 0x00000004
#define FD_CTRL_SBE 0x00000008
#define FD_CTRL_FLC 0x00000010
#define FD_CTRL_FSE 0x00000020
#define FD_CTRL_FAERR 0x00000040
/* Annotation bits in FD CTRL */
#define FD_CTRL_PTA 0x00800000
#define FD_CTRL_PTV1 0x00400000
enum dpaa2_fd_format {
dpaa2_fd_single = 0,
dpaa2_fd_list,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment