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

Pull ARM SoC driver updates from Arnd Bergmann:
 "Driver updates for ARM SoCs, including a couple of newly added
  drivers:

   - A new driver for the power management controller on TI Keystone

   - Support for the prerelease "SCPI" firmware protocol that ended up
     being shipped by Amlogic in their GXBB SoC.

   - A soc_device can now be matched using a glob from inside the
     kernel, when another driver wants to know the specific chip it is
     running on and cannot find out from DT, firmware or hardware.

   - Renesas SoCs now support identification through the soc_device
     interface, both in user space and kernel.

   - Renesas r8a7743 and r8a7745 gain support for their system
     controller

   - A new checking module for the ARM "PSCI" (not to be confused with
     "SCPI" mentioned above) firmware interface.

   - A new driver for the Tegra GMI memory interface

   - Support for the Tegra firmware interfaces with their power
     management controllers

  As usual, the updates for the reset controller framework are merged
  here, as they tend to touch multiple SoCs as well, including a new
  driver for the Oxford (now Broadcom) OX820 chip and the Tegra bpmp
  interface.

  The existing drivers for Atmel, Qualcomm, NVIDIA, TI Davinci, and
  Rockchips SoCs see some further updates"

* tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (76 commits)
  misc: sram: remove useless #ifdef
  drivers: psci: Allow PSCI node to be disabled
  drivers: psci: PSCI checker module
  soc: renesas: Identify SoC and register with the SoC bus
  firmware: qcom: scm: Return PTR_ERR when devm_clk_get fails
  firmware: qcom: scm: Remove core, iface and bus clocks dependency
  dt-bindings: firmware: scm: Add MSM8996 DT bindings
  memory: da8xx-ddrctl: drop the call to of_flat_dt_get_machine_name()
  bus: da8xx-mstpri: drop the call to of_flat_dt_get_machine_name()
  ARM: shmobile: Document DT bindings for Product Register
  soc: renesas: rcar-sysc: add R8A7745 support
  reset: Add Tegra BPMP reset driver
  dt-bindings: firmware: Allow child nodes inside the Tegra BPMP
  dt-bindings: Add power domains to Tegra BPMP firmware
  firmware: tegra: Add BPMP support
  firmware: tegra: Add IVC library
  dt-bindings: firmware: Add bindings for Tegra BPMP
  mailbox: tegra-hsp: Use after free in tegra_hsp_remove_doorbells()
  mailbox: Add Tegra HSP driver
  firmware: arm_scpi: add support for pre-v1.0 SCPI compatible
  ...
This commit is contained in:
Linus Torvalds
2016-12-15 16:03:25 -08:00
86 changed files with 11443 additions and 737 deletions

View File

@@ -150,6 +150,13 @@ config TEGRA_ACONNECT
Driver for the Tegra ACONNECT bus which is used to interface with
the devices inside the Audio Processing Engine (APE) for Tegra210.
config TEGRA_GMI
tristate "Tegra Generic Memory Interface bus driver"
depends on ARCH_TEGRA
help
Driver for the Tegra Generic Memory Interface bus which can be used
to attach devices such as NOR, UART, FPGA and more.
config UNIPHIER_SYSTEM_BUS
tristate "UniPhier System Bus driver"
depends on ARCH_UNIPHIER && OF
@@ -167,4 +174,13 @@ config VEXPRESS_CONFIG
help
Platform configuration infrastructure for the ARM Ltd.
Versatile Express.
config DA8XX_MSTPRI
bool "TI da8xx master peripheral priority driver"
depends on ARCH_DAVINCI_DA8XX
help
Driver for Texas Instruments da8xx master peripheral priority
configuration. Allows to adjust the priorities of all master
peripherals.
endmenu

View File

@@ -19,5 +19,8 @@ obj-$(CONFIG_QCOM_EBI2) += qcom-ebi2.o
obj-$(CONFIG_SUNXI_RSB) += sunxi-rsb.o
obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o
obj-$(CONFIG_TEGRA_ACONNECT) += tegra-aconnect.o
obj-$(CONFIG_TEGRA_GMI) += tegra-gmi.o
obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o
obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o
obj-$(CONFIG_DA8XX_MSTPRI) += da8xx-mstpri.o

267
drivers/bus/da8xx-mstpri.c Normal file
View File

@@ -0,0 +1,267 @@
/*
* TI da8xx master peripheral priority driver
*
* Copyright (C) 2016 BayLibre SAS
*
* Author:
* Bartosz Golaszewski <bgolaszewski@baylibre.com.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.
*/
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/regmap.h>
/*
* REVISIT: Linux doesn't have a good framework for the kind of performance
* knobs this driver controls. We can't use device tree properties as it deals
* with hardware configuration rather than description. We also don't want to
* commit to maintaining some random sysfs attributes.
*
* For now we just hardcode the register values for the boards that need
* some changes (as is the case for the LCD controller on da850-lcdk - the
* first board we support here). When linux gets an appropriate framework,
* we'll easily convert the driver to it.
*/
#define DA8XX_MSTPRI0_OFFSET 0
#define DA8XX_MSTPRI1_OFFSET 4
#define DA8XX_MSTPRI2_OFFSET 8
enum {
DA8XX_MSTPRI_ARM_I = 0,
DA8XX_MSTPRI_ARM_D,
DA8XX_MSTPRI_UPP,
DA8XX_MSTPRI_SATA,
DA8XX_MSTPRI_PRU0,
DA8XX_MSTPRI_PRU1,
DA8XX_MSTPRI_EDMA30TC0,
DA8XX_MSTPRI_EDMA30TC1,
DA8XX_MSTPRI_EDMA31TC0,
DA8XX_MSTPRI_VPIF_DMA_0,
DA8XX_MSTPRI_VPIF_DMA_1,
DA8XX_MSTPRI_EMAC,
DA8XX_MSTPRI_USB0CFG,
DA8XX_MSTPRI_USB0CDMA,
DA8XX_MSTPRI_UHPI,
DA8XX_MSTPRI_USB1,
DA8XX_MSTPRI_LCDC,
};
struct da8xx_mstpri_descr {
int reg;
int shift;
int mask;
};
static const struct da8xx_mstpri_descr da8xx_mstpri_priority_list[] = {
[DA8XX_MSTPRI_ARM_I] = {
.reg = DA8XX_MSTPRI0_OFFSET,
.shift = 0,
.mask = 0x0000000f,
},
[DA8XX_MSTPRI_ARM_D] = {
.reg = DA8XX_MSTPRI0_OFFSET,
.shift = 4,
.mask = 0x000000f0,
},
[DA8XX_MSTPRI_UPP] = {
.reg = DA8XX_MSTPRI0_OFFSET,
.shift = 16,
.mask = 0x000f0000,
},
[DA8XX_MSTPRI_SATA] = {
.reg = DA8XX_MSTPRI0_OFFSET,
.shift = 20,
.mask = 0x00f00000,
},
[DA8XX_MSTPRI_PRU0] = {
.reg = DA8XX_MSTPRI1_OFFSET,
.shift = 0,
.mask = 0x0000000f,
},
[DA8XX_MSTPRI_PRU1] = {
.reg = DA8XX_MSTPRI1_OFFSET,
.shift = 4,
.mask = 0x000000f0,
},
[DA8XX_MSTPRI_EDMA30TC0] = {
.reg = DA8XX_MSTPRI1_OFFSET,
.shift = 8,
.mask = 0x00000f00,
},
[DA8XX_MSTPRI_EDMA30TC1] = {
.reg = DA8XX_MSTPRI1_OFFSET,
.shift = 12,
.mask = 0x0000f000,
},
[DA8XX_MSTPRI_EDMA31TC0] = {
.reg = DA8XX_MSTPRI1_OFFSET,
.shift = 16,
.mask = 0x000f0000,
},
[DA8XX_MSTPRI_VPIF_DMA_0] = {
.reg = DA8XX_MSTPRI1_OFFSET,
.shift = 24,
.mask = 0x0f000000,
},
[DA8XX_MSTPRI_VPIF_DMA_1] = {
.reg = DA8XX_MSTPRI1_OFFSET,
.shift = 28,
.mask = 0xf0000000,
},
[DA8XX_MSTPRI_EMAC] = {
.reg = DA8XX_MSTPRI2_OFFSET,
.shift = 0,
.mask = 0x0000000f,
},
[DA8XX_MSTPRI_USB0CFG] = {
.reg = DA8XX_MSTPRI2_OFFSET,
.shift = 8,
.mask = 0x00000f00,
},
[DA8XX_MSTPRI_USB0CDMA] = {
.reg = DA8XX_MSTPRI2_OFFSET,
.shift = 12,
.mask = 0x0000f000,
},
[DA8XX_MSTPRI_UHPI] = {
.reg = DA8XX_MSTPRI2_OFFSET,
.shift = 20,
.mask = 0x00f00000,
},
[DA8XX_MSTPRI_USB1] = {
.reg = DA8XX_MSTPRI2_OFFSET,
.shift = 24,
.mask = 0x0f000000,
},
[DA8XX_MSTPRI_LCDC] = {
.reg = DA8XX_MSTPRI2_OFFSET,
.shift = 28,
.mask = 0xf0000000,
},
};
struct da8xx_mstpri_priority {
int which;
u32 val;
};
struct da8xx_mstpri_board_priorities {
const char *board;
const struct da8xx_mstpri_priority *priorities;
size_t numprio;
};
/*
* Default memory settings of da850 do not meet the throughput/latency
* requirements of tilcdc. This results in the image displayed being
* incorrect and the following warning being displayed by the LCDC
* drm driver:
*
* tilcdc da8xx_lcdc.0: tilcdc_crtc_irq(0x00000020): FIFO underfow
*/
static const struct da8xx_mstpri_priority da850_lcdk_priorities[] = {
{
.which = DA8XX_MSTPRI_LCDC,
.val = 0,
},
{
.which = DA8XX_MSTPRI_EDMA30TC1,
.val = 0,
},
{
.which = DA8XX_MSTPRI_EDMA30TC0,
.val = 1,
},
};
static const struct da8xx_mstpri_board_priorities da8xx_mstpri_board_confs[] = {
{
.board = "ti,da850-lcdk",
.priorities = da850_lcdk_priorities,
.numprio = ARRAY_SIZE(da850_lcdk_priorities),
},
};
static const struct da8xx_mstpri_board_priorities *
da8xx_mstpri_get_board_prio(void)
{
const struct da8xx_mstpri_board_priorities *board_prio;
int i;
for (i = 0; i < ARRAY_SIZE(da8xx_mstpri_board_confs); i++) {
board_prio = &da8xx_mstpri_board_confs[i];
if (of_machine_is_compatible(board_prio->board))
return board_prio;
}
return NULL;
}
static int da8xx_mstpri_probe(struct platform_device *pdev)
{
const struct da8xx_mstpri_board_priorities *prio_list;
const struct da8xx_mstpri_descr *prio_descr;
const struct da8xx_mstpri_priority *prio;
struct device *dev = &pdev->dev;
struct resource *res;
void __iomem *mstpri;
u32 reg;
int i;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mstpri = devm_ioremap_resource(dev, res);
if (IS_ERR(mstpri)) {
dev_err(dev, "unable to map MSTPRI registers\n");
return PTR_ERR(mstpri);
}
prio_list = da8xx_mstpri_get_board_prio();
if (!prio_list) {
dev_err(dev, "no master priorities defined for this board\n");
return -EINVAL;
}
for (i = 0; i < prio_list->numprio; i++) {
prio = &prio_list->priorities[i];
prio_descr = &da8xx_mstpri_priority_list[prio->which];
if (prio_descr->reg + sizeof(u32) > resource_size(res)) {
dev_warn(dev, "register offset out of range\n");
continue;
}
reg = readl(mstpri + prio_descr->reg);
reg &= ~prio_descr->mask;
reg |= prio->val << prio_descr->shift;
writel(reg, mstpri + prio_descr->reg);
}
return 0;
}
static const struct of_device_id da8xx_mstpri_of_match[] = {
{ .compatible = "ti,da850-mstpri", },
{ },
};
static struct platform_driver da8xx_mstpri_driver = {
.probe = da8xx_mstpri_probe,
.driver = {
.name = "da8xx-mstpri",
.of_match_table = da8xx_mstpri_of_match,
},
};
module_platform_driver(da8xx_mstpri_driver);
MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
MODULE_DESCRIPTION("TI da8xx master peripheral priority driver");
MODULE_LICENSE("GPL v2");

284
drivers/bus/tegra-gmi.c Normal file
View File

@@ -0,0 +1,284 @@
/*
* Driver for NVIDIA Generic Memory Interface
*
* Copyright (C) 2016 Host Mobility AB. All rights reserved.
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/reset.h>
#define TEGRA_GMI_CONFIG 0x00
#define TEGRA_GMI_CONFIG_GO BIT(31)
#define TEGRA_GMI_BUS_WIDTH_32BIT BIT(30)
#define TEGRA_GMI_MUX_MODE BIT(28)
#define TEGRA_GMI_RDY_BEFORE_DATA BIT(24)
#define TEGRA_GMI_RDY_ACTIVE_HIGH BIT(23)
#define TEGRA_GMI_ADV_ACTIVE_HIGH BIT(22)
#define TEGRA_GMI_OE_ACTIVE_HIGH BIT(21)
#define TEGRA_GMI_CS_ACTIVE_HIGH BIT(20)
#define TEGRA_GMI_CS_SELECT(x) ((x & 0x7) << 4)
#define TEGRA_GMI_TIMING0 0x10
#define TEGRA_GMI_MUXED_WIDTH(x) ((x & 0xf) << 12)
#define TEGRA_GMI_HOLD_WIDTH(x) ((x & 0xf) << 8)
#define TEGRA_GMI_ADV_WIDTH(x) ((x & 0xf) << 4)
#define TEGRA_GMI_CE_WIDTH(x) (x & 0xf)
#define TEGRA_GMI_TIMING1 0x14
#define TEGRA_GMI_WE_WIDTH(x) ((x & 0xff) << 16)
#define TEGRA_GMI_OE_WIDTH(x) ((x & 0xff) << 8)
#define TEGRA_GMI_WAIT_WIDTH(x) (x & 0xff)
#define TEGRA_GMI_MAX_CHIP_SELECT 8
struct tegra_gmi {
struct device *dev;
void __iomem *base;
struct clk *clk;
struct reset_control *rst;
u32 snor_config;
u32 snor_timing0;
u32 snor_timing1;
};
static int tegra_gmi_enable(struct tegra_gmi *gmi)
{
int err;
err = clk_prepare_enable(gmi->clk);
if (err < 0) {
dev_err(gmi->dev, "failed to enable clock: %d\n", err);
return err;
}
reset_control_assert(gmi->rst);
usleep_range(2000, 4000);
reset_control_deassert(gmi->rst);
writel(gmi->snor_timing0, gmi->base + TEGRA_GMI_TIMING0);
writel(gmi->snor_timing1, gmi->base + TEGRA_GMI_TIMING1);
gmi->snor_config |= TEGRA_GMI_CONFIG_GO;
writel(gmi->snor_config, gmi->base + TEGRA_GMI_CONFIG);
return 0;
}
static void tegra_gmi_disable(struct tegra_gmi *gmi)
{
u32 config;
/* stop GMI operation */
config = readl(gmi->base + TEGRA_GMI_CONFIG);
config &= ~TEGRA_GMI_CONFIG_GO;
writel(config, gmi->base + TEGRA_GMI_CONFIG);
reset_control_assert(gmi->rst);
clk_disable_unprepare(gmi->clk);
}
static int tegra_gmi_parse_dt(struct tegra_gmi *gmi)
{
struct device_node *child;
u32 property, ranges[4];
int err;
child = of_get_next_available_child(gmi->dev->of_node, NULL);
if (!child) {
dev_err(gmi->dev, "no child nodes found\n");
return -ENODEV;
}
/*
* We currently only support one child device due to lack of
* chip-select address decoding. Which means that we only have one
* chip-select line from the GMI controller.
*/
if (of_get_child_count(gmi->dev->of_node) > 1)
dev_warn(gmi->dev, "only one child device is supported.");
if (of_property_read_bool(child, "nvidia,snor-data-width-32bit"))
gmi->snor_config |= TEGRA_GMI_BUS_WIDTH_32BIT;
if (of_property_read_bool(child, "nvidia,snor-mux-mode"))
gmi->snor_config |= TEGRA_GMI_MUX_MODE;
if (of_property_read_bool(child, "nvidia,snor-rdy-active-before-data"))
gmi->snor_config |= TEGRA_GMI_RDY_BEFORE_DATA;
if (of_property_read_bool(child, "nvidia,snor-rdy-active-high"))
gmi->snor_config |= TEGRA_GMI_RDY_ACTIVE_HIGH;
if (of_property_read_bool(child, "nvidia,snor-adv-active-high"))
gmi->snor_config |= TEGRA_GMI_ADV_ACTIVE_HIGH;
if (of_property_read_bool(child, "nvidia,snor-oe-active-high"))
gmi->snor_config |= TEGRA_GMI_OE_ACTIVE_HIGH;
if (of_property_read_bool(child, "nvidia,snor-cs-active-high"))
gmi->snor_config |= TEGRA_GMI_CS_ACTIVE_HIGH;
/* Decode the CS# */
err = of_property_read_u32_array(child, "ranges", ranges, 4);
if (err < 0) {
/* Invalid binding */
if (err == -EOVERFLOW) {
dev_err(gmi->dev,
"failed to decode CS: invalid ranges length\n");
goto error_cs;
}
/*
* If we reach here it means that the child node has an empty
* ranges or it does not exist at all. Attempt to decode the
* CS# from the reg property instead.
*/
err = of_property_read_u32(child, "reg", &property);
if (err < 0) {
dev_err(gmi->dev,
"failed to decode CS: no reg property found\n");
goto error_cs;
}
} else {
property = ranges[1];
}
/* Valid chip selects are CS0-CS7 */
if (property >= TEGRA_GMI_MAX_CHIP_SELECT) {
dev_err(gmi->dev, "invalid chip select: %d", property);
err = -EINVAL;
goto error_cs;
}
gmi->snor_config |= TEGRA_GMI_CS_SELECT(property);
/* The default values that are provided below are reset values */
if (!of_property_read_u32(child, "nvidia,snor-muxed-width", &property))
gmi->snor_timing0 |= TEGRA_GMI_MUXED_WIDTH(property);
else
gmi->snor_timing0 |= TEGRA_GMI_MUXED_WIDTH(1);
if (!of_property_read_u32(child, "nvidia,snor-hold-width", &property))
gmi->snor_timing0 |= TEGRA_GMI_HOLD_WIDTH(property);
else
gmi->snor_timing0 |= TEGRA_GMI_HOLD_WIDTH(1);
if (!of_property_read_u32(child, "nvidia,snor-adv-width", &property))
gmi->snor_timing0 |= TEGRA_GMI_ADV_WIDTH(property);
else
gmi->snor_timing0 |= TEGRA_GMI_ADV_WIDTH(1);
if (!of_property_read_u32(child, "nvidia,snor-ce-width", &property))
gmi->snor_timing0 |= TEGRA_GMI_CE_WIDTH(property);
else
gmi->snor_timing0 |= TEGRA_GMI_CE_WIDTH(4);
if (!of_property_read_u32(child, "nvidia,snor-we-width", &property))
gmi->snor_timing1 |= TEGRA_GMI_WE_WIDTH(property);
else
gmi->snor_timing1 |= TEGRA_GMI_WE_WIDTH(1);
if (!of_property_read_u32(child, "nvidia,snor-oe-width", &property))
gmi->snor_timing1 |= TEGRA_GMI_OE_WIDTH(property);
else
gmi->snor_timing1 |= TEGRA_GMI_OE_WIDTH(1);
if (!of_property_read_u32(child, "nvidia,snor-wait-width", &property))
gmi->snor_timing1 |= TEGRA_GMI_WAIT_WIDTH(property);
else
gmi->snor_timing1 |= TEGRA_GMI_WAIT_WIDTH(3);
error_cs:
of_node_put(child);
return err;
}
static int tegra_gmi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct tegra_gmi *gmi;
struct resource *res;
int err;
gmi = devm_kzalloc(dev, sizeof(*gmi), GFP_KERNEL);
if (!gmi)
return -ENOMEM;
gmi->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
gmi->base = devm_ioremap_resource(dev, res);
if (IS_ERR(gmi->base))
return PTR_ERR(gmi->base);
gmi->clk = devm_clk_get(dev, "gmi");
if (IS_ERR(gmi->clk)) {
dev_err(dev, "can not get clock\n");
return PTR_ERR(gmi->clk);
}
gmi->rst = devm_reset_control_get(dev, "gmi");
if (IS_ERR(gmi->rst)) {
dev_err(dev, "can not get reset\n");
return PTR_ERR(gmi->rst);
}
err = tegra_gmi_parse_dt(gmi);
if (err)
return err;
err = tegra_gmi_enable(gmi);
if (err < 0)
return err;
err = of_platform_default_populate(dev->of_node, NULL, dev);
if (err < 0) {
dev_err(dev, "fail to create devices.\n");
tegra_gmi_disable(gmi);
return err;
}
platform_set_drvdata(pdev, gmi);
return 0;
}
static int tegra_gmi_remove(struct platform_device *pdev)
{
struct tegra_gmi *gmi = platform_get_drvdata(pdev);
of_platform_depopulate(gmi->dev);
tegra_gmi_disable(gmi);
return 0;
}
static const struct of_device_id tegra_gmi_id_table[] = {
{ .compatible = "nvidia,tegra20-gmi", },
{ .compatible = "nvidia,tegra30-gmi", },
{ }
};
MODULE_DEVICE_TABLE(of, tegra_gmi_id_table);
static struct platform_driver tegra_gmi_driver = {
.probe = tegra_gmi_probe,
.remove = tegra_gmi_remove,
.driver = {
.name = "tegra-gmi",
.of_match_table = tegra_gmi_id_table,
},
};
module_platform_driver(tegra_gmi_driver);
MODULE_AUTHOR("Mirza Krak <mirza.krak@gmail.com");
MODULE_DESCRIPTION("NVIDIA Tegra GMI Bus Driver");
MODULE_LICENSE("GPL v2");