Commit c9235d99 authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

Merge tag 'imx-drivers-5.1' of...

Merge tag 'imx-drivers-5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux into arm/drivers

i.MX drivers update for 5.1:
 - Do not get GPCv2 driver depend on SOC_IMX8MQ since the driver is
   going to be used on more SoCs than just i.MX8MQ.
 - Add power domain information into SCU bindings document.
 - Add support of start/stop a CPU into imx firmware driver.
 - Support multiple address ranges per child node for imx-weim bus
   driver.

* tag 'imx-drivers-5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux

:
  firmware: imx: Add support to start/stop a CPU
  soc: imx: Break dependency on SOC_IMX8MQ for GPCv2
  firmware: imx: scu-pd: add fallback compatible string support
  dt-bindings: fsl: scu: add imx8qm scu power domain support
  dt-bindings: fsl: scu: add fallback compatible string for power domain
  bus: imx-weim: guard against timing configuration conflicts
  bus: imx-weim: support multiple address ranges per child node
  dt-bindings: bus: imx-weim: document multiple address ranges per child node
  soc: imx: gpcv2: handle reset clocks
  soc: imx: gpcv2: handle additional power-down bits in handshake register

Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents 59f527dd d90bf296
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -58,7 +58,11 @@ This binding for the SCU power domain providers uses the generic power
domain binding[2].

Required properties:
- compatible:		Should be "fsl,imx8qxp-scu-pd".
- compatible:		Should be one of:
			  "fsl,imx8qm-scu-pd",
			  "fsl,imx8qxp-scu-pd"
			followed by "fsl,scu-pd"

- #power-domain-cells:	Must be 1. Contains the Resource ID used by
			SCU commands.
			See detailed Resource ID list from:
@@ -154,7 +158,7 @@ firmware {
		};

		pd: imx8qx-pd {
			compatible = "fsl,imx8qxp-scu-pd";
			compatible = "fsl,imx8qxp-scu-pd", "fsl,scu-pd";
			#power-domain-cells = <1>;
		};

+29 −3
Original line number Diff line number Diff line
@@ -47,9 +47,9 @@ Optional properties:
Timing property for child nodes. It is mandatory, not optional.

 - fsl,weim-cs-timing:	The timing array, contains timing values for the
			child node. We can get the CS index from the child
			node's "reg" property. The number of registers depends
			on the selected chip.
			child node. We get the CS indexes from the address
			ranges in the child node's "reg" property.
			The number of registers depends on the selected chip:
			For i.MX1, i.MX21 ("fsl,imx1-weim") there are two
			registers: CSxU, CSxL.
			For i.MX25, i.MX27, i.MX31 and i.MX35 ("fsl,imx27-weim")
@@ -80,3 +80,29 @@ Example for an imx6q-sabreauto board, the NOR flash connected to the WEIM:
					0x0000c000 0x1404a38e 0x00000000>;
		};
	};

Example for an imx6q-based board, a multi-chipselect device connected to WEIM:

In this case, both chip select 0 and 1 will be configured with the same timing
array values.

	weim: weim@21b8000 {
		compatible = "fsl,imx6q-weim";
		reg = <0x021b8000 0x4000>;
		clocks = <&clks 196>;
		#address-cells = <2>;
		#size-cells = <1>;
		ranges = <0 0 0x08000000 0x02000000
			  1 0 0x0a000000 0x02000000
			  2 0 0x0c000000 0x02000000
			  3 0 0x0e000000 0x02000000>;
		fsl,weim-cs-gpr = <&gpr>;

		acme@0 {
			compatible = "acme,whatever";
			reg = <0 0 0x100>, <0 0x400000 0x800>,
				<1 0x400000 0x800>;
			fsl,weim-cs-timing = <0x024400b1 0x00001010 0x20081100
				0x00000000 0xa0000240 0x00000000>;
		};
	};
+3 −0
Original line number Diff line number Diff line
@@ -32,6 +32,9 @@ Required properties:
Optional properties:

- power-supply: Power supply used to power the domain
- clocks: a number of phandles to clocks that need to be enabled during
  domain power-up sequencing to ensure reset propagation into devices
  located inside this power domain

Example:

+57 −13
Original line number Diff line number Diff line
@@ -46,6 +46,17 @@ static const struct imx_weim_devtype imx51_weim_devtype = {
};

#define MAX_CS_REGS_COUNT	6
#define MAX_CS_COUNT		6
#define OF_REG_SIZE		3

struct cs_timing {
	bool is_applied;
	u32 regs[MAX_CS_REGS_COUNT];
};

struct cs_timing_state {
	struct cs_timing cs[MAX_CS_COUNT];
};

static const struct of_device_id weim_id_table[] = {
	/* i.MX1/21 */
@@ -111,31 +122,63 @@ err:
}

/* Parse and set the timing for this device. */
static int __init weim_timing_setup(struct device_node *np, void __iomem *base,
				    const struct imx_weim_devtype *devtype)
static int __init weim_timing_setup(struct device *dev,
				    struct device_node *np, void __iomem *base,
				    const struct imx_weim_devtype *devtype,
				    struct cs_timing_state *ts)
{
	u32 cs_idx, value[MAX_CS_REGS_COUNT];
	int i, ret;
	int reg_idx, num_regs;
	struct cs_timing *cst;

	if (WARN_ON(devtype->cs_regs_count > MAX_CS_REGS_COUNT))
		return -EINVAL;
	if (WARN_ON(devtype->cs_count > MAX_CS_COUNT))
		return -EINVAL;

	/* get the CS index from this child node's "reg" property. */
	ret = of_property_read_u32(np, "reg", &cs_idx);
	ret = of_property_read_u32_array(np, "fsl,weim-cs-timing",
					 value, devtype->cs_regs_count);
	if (ret)
		return ret;

	/*
	 * the child node's "reg" property may contain multiple address ranges,
	 * extract the chip select for each.
	 */
	num_regs = of_property_count_elems_of_size(np, "reg", OF_REG_SIZE);
	if (num_regs < 0)
		return num_regs;
	if (!num_regs)
		return -EINVAL;
	for (reg_idx = 0; reg_idx < num_regs; reg_idx++) {
		/* get the CS index from this child node's "reg" property. */
		ret = of_property_read_u32_index(np, "reg",
					reg_idx * OF_REG_SIZE, &cs_idx);
		if (ret)
			break;

		if (cs_idx >= devtype->cs_count)
			return -EINVAL;

	ret = of_property_read_u32_array(np, "fsl,weim-cs-timing",
					 value, devtype->cs_regs_count);
	if (ret)
		return ret;
		/* prevent re-configuring a CS that's already been configured */
		cst = &ts->cs[cs_idx];
		if (cst->is_applied && memcmp(value, cst->regs,
					devtype->cs_regs_count * sizeof(u32))) {
			dev_err(dev, "fsl,weim-cs-timing conflict on %pOF", np);
			return -EINVAL;
		}

		/* set the timing for WEIM */
		for (i = 0; i < devtype->cs_regs_count; i++)
		writel(value[i], base + cs_idx * devtype->cs_stride + i * 4);
			writel(value[i],
				base + cs_idx * devtype->cs_stride + i * 4);
		if (!cst->is_applied) {
			cst->is_applied = true;
			memcpy(cst->regs, value,
				devtype->cs_regs_count * sizeof(u32));
		}
	}

	return 0;
}
@@ -148,6 +191,7 @@ static int __init weim_parse_dt(struct platform_device *pdev,
	const struct imx_weim_devtype *devtype = of_id->data;
	struct device_node *child;
	int ret, have_child = 0;
	struct cs_timing_state ts = {};

	if (devtype == &imx50_weim_devtype) {
		ret = imx_weim_gpr_setup(pdev);
@@ -156,7 +200,7 @@ static int __init weim_parse_dt(struct platform_device *pdev,
	}

	for_each_available_child_of_node(pdev->dev.of_node, child) {
		ret = weim_timing_setup(child, base, devtype);
		ret = weim_timing_setup(&pdev->dev, child, base, devtype, &ts);
		if (ret)
			dev_warn(&pdev->dev, "%pOF set timing failed.\n",
				child);
+38 −0
Original line number Diff line number Diff line
@@ -18,6 +18,14 @@ struct imx_sc_msg_req_misc_set_ctrl {
	u16 resource;
} __packed;

struct imx_sc_msg_req_cpu_start {
	struct imx_sc_rpc_msg hdr;
	u32 address_hi;
	u32 address_lo;
	u16 resource;
	u8 enable;
} __packed;

struct imx_sc_msg_req_misc_get_ctrl {
	struct imx_sc_rpc_msg hdr;
	u32 ctrl;
@@ -97,3 +105,33 @@ int imx_sc_misc_get_control(struct imx_sc_ipc *ipc, u32 resource,
	return 0;
}
EXPORT_SYMBOL(imx_sc_misc_get_control);

/*
 * This function starts/stops a CPU identified by @resource
 *
 * @param[in]     ipc         IPC handle
 * @param[in]     resource    resource the control is associated with
 * @param[in]     enable      true for start, false for stop
 * @param[in]     phys_addr   initial instruction address to be executed
 *
 * @return Returns 0 for success and < 0 for errors.
 */
int imx_sc_pm_cpu_start(struct imx_sc_ipc *ipc, u32 resource,
			bool enable, u64 phys_addr)
{
	struct imx_sc_msg_req_cpu_start msg;
	struct imx_sc_rpc_msg *hdr = &msg.hdr;

	hdr->ver = IMX_SC_RPC_VERSION;
	hdr->svc = IMX_SC_RPC_SVC_PM;
	hdr->func = IMX_SC_PM_FUNC_CPU_START;
	hdr->size = 4;

	msg.address_hi = phys_addr >> 32;
	msg.address_lo = phys_addr;
	msg.resource = resource;
	msg.enable = enable;

	return imx_scu_call_rpc(ipc, &msg, true);
}
EXPORT_SYMBOL(imx_sc_pm_cpu_start);
Loading