Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V4 1/6] clk: tegra: add TEGRA20_CLK_NOR to init table
From: Thierry Reding @ 2016-11-07 11:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478507405-13204-2-git-send-email-mirza.krak@gmail.com>

On Mon, Nov 07, 2016 at 09:30:00AM +0100, Mirza Krak wrote:
> From: Mirza Krak <mirza.krak@gmail.com>
> 
> Add TEGRA20_CLK_NOR to init table and set default rate to 92 MHz which
> is max rate.
> 
> The maximum rate value of 92 MHz is pulled from the downstream L4T
> kernel.
> 
> Signed-off-by: Mirza Krak <mirza.krak@gmail.com>
> Tested-by: Marcel Ziswiler <marcel.ziswiler@toradex.com>
> Tested-on: Colibri T20/T30 on EvalBoard V3.x and GMI-Memory Board
> Acked-by: Jon Hunter <jonathanh@nvidia.com>
> ---
> 
> Changes in v2:
> - no changes
> 
> Changes in v3:
> - Added comment in commit message where I got the maximum rates from.
> 
> Changes in V4:
> - no changes

Applied, thanks.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161107/14d088fa/attachment.sig>

^ permalink raw reply

* [PATCH V4 2/6] clk: tegra: add TEGRA30_CLK_NOR to init table
From: Thierry Reding @ 2016-11-07 11:28 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478507405-13204-3-git-send-email-mirza.krak@gmail.com>

On Mon, Nov 07, 2016 at 09:30:01AM +0100, Mirza Krak wrote:
> From: Mirza Krak <mirza.krak@gmail.com>
> 
> Add TEGRA30_CLK_NOR to init table and set default rate to 127 MHz which
> is max rate.
> 
> The maximum rate value of 127 MHz is pulled from the downstream L4T
> kernel.
> 
> Signed-off-by: Mirza Krak <mirza.krak@gmail.com>
> Tested-by: Marcel Ziswiler <marcel.ziswiler@toradex.com>
> Tested-on: Colibri T20/T30 on EvalBoard V3.x and GMI-Memory Board
> Acked-by: Jon Hunter <jonathanh@nvidia.com>
> ---
> 
> Changes in v2:
> - no changes
> 
> Changes in v3:
> - Added comment in commit message where I got the maximum rates from.
> 
> Changes in V4:
> - no changes
> 
>  drivers/clk/tegra/clk-tegra30.c | 1 +
>  1 file changed, 1 insertion(+)

Applied, thanks.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161107/c0620109/attachment-0001.sig>

^ permalink raw reply

* [PATCH/RESEND V4 3/3] ARM64 LPC: LPC driver implementation on Hip06
From: Mark Rutland @ 2016-11-07 11:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478006926-240933-4-git-send-email-yuanzhichang@hisilicon.com>

Hi,

I received an off-list v5 of this for some reason.

I have several concerns with this, but given there's evidently a v5, I
intend to wait until that is posted before I reply with my comments.

Thanks,
Mark.

On Tue, Nov 01, 2016 at 09:28:46PM +0800, zhichang.yuan wrote:
> On Hip06, the accesses to LPC peripherals work in an indirect way. A
> corresponding LPC driver configure some registers in LPC master at first, then
> the real accesses on LPC slave devices are finished by the LPC master, which
> is transparent to LPC driver.
> This patch implement the relevant driver for Hip06 LPC. Cooperating with
> indirect-IO, ipmi messages is in service without any changes on ipmi driver.
> 
> Cc: Mark Rutland <mark.rutland@arm.com>
> Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> ---
>  .../arm/hisilicon/hisilicon-low-pin-count.txt      |  31 ++
>  MAINTAINERS                                        |   8 +
>  drivers/bus/Kconfig                                |   8 +
>  drivers/bus/Makefile                               |   1 +
>  drivers/bus/hisi_lpc.c                             | 501 +++++++++++++++++++++
>  5 files changed, 549 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
>  create mode 100644 drivers/bus/hisi_lpc.c
> 
> diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
> new file mode 100644
> index 0000000..e681419
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
> @@ -0,0 +1,31 @@
> +Hisilicon Hip06 low-pin-count device
> +  Usually LPC controller is part of PCI host bridge, so the legacy ISA ports
> +  locate on LPC bus can be accessed direclty. But some SoCs have independent
> +  LPC controller, and access the legacy ports by triggering LPC I/O cycles.
> +  Hisilicon Hip06 implements this LPC device.
> +
> +Required properties:
> +- compatible: should be "hisilicon,low-pin-count"
> +- #address-cells: must be 2 which stick to the ISA/EISA binding doc.
> +- #size-cells: must be 1 which stick to the ISA/EISA binding doc.
> +- reg: base memory range where the register set for this device is mapped.
> +
> +Note:
> +  The node name before '@' must be "isa" to represent the binding stick to the
> +  ISA/EISA binding specification.
> +
> +Example:
> +
> +isa at a01b0000 {
> +	compatible = "hisilicom,low-pin-count";
> +	#address-cells = <2>;
> +	#size-cells = <1>;
> +	reg = <0x0 0xa01b0000 0x0 0x1000>;
> +
> +	ipmi0: bt at e4 {
> +		compatible = "ipmi-bt";
> +		device_type = "ipmi";
> +		reg = <0x01 0xe4 0x04>;
> +		status = "disabled";
> +	};
> +};
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 1cd38a7..7c69410 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -5716,6 +5716,14 @@ F:	include/uapi/linux/if_hippi.h
>  F:	net/802/hippi.c
>  F:	drivers/net/hippi/
>  
> +HISILICON LPC BUS DRIVER
> +M:	Zhichang Yuan <yuanzhichang@hisilicon.com>
> +L:	linux-arm-kernel at lists.infradead.org
> +W:	http://www.hisilicon.com
> +S:	Maintained
> +F:	drivers/bus/hisi_lpc.c
> +F:	Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
> +
>  HISILICON NETWORK SUBSYSTEM DRIVER
>  M:	Yisen Zhuang <yisen.zhuang@huawei.com>
>  M:	Salil Mehta <salil.mehta@huawei.com>
> diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
> index 7010dca..a108abc 100644
> --- a/drivers/bus/Kconfig
> +++ b/drivers/bus/Kconfig
> @@ -64,6 +64,14 @@ config BRCMSTB_GISB_ARB
>  	  arbiter. This driver provides timeout and target abort error handling
>  	  and internal bus master decoding.
>  
> +config HISILICON_LPC
> +	bool "Workaround for nonstandard ISA I/O space on Hisilicon Hip0X"
> +	depends on (ARCH_HISI || COMPILE_TEST) && ARM64
> +	select ARM64_INDIRECT_PIO
> +	help
> +	  Driver needed for some legacy ISA devices attached to Low-Pin-Count
> +	  on Hisilicon Hip0X SoC.
> +
>  config IMX_WEIM
>  	bool "Freescale EIM DRIVER"
>  	depends on ARCH_MXC
> diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
> index c6cfa6b..10b4983 100644
> --- a/drivers/bus/Makefile
> +++ b/drivers/bus/Makefile
> @@ -7,6 +7,7 @@ obj-$(CONFIG_ARM_CCI)		+= arm-cci.o
>  obj-$(CONFIG_ARM_CCN)		+= arm-ccn.o
>  
>  obj-$(CONFIG_BRCMSTB_GISB_ARB)	+= brcmstb_gisb.o
> +obj-$(CONFIG_HISILICON_LPC)	+= hisi_lpc.o
>  obj-$(CONFIG_IMX_WEIM)		+= imx-weim.o
>  obj-$(CONFIG_MIPS_CDMM)		+= mips_cdmm.o
>  obj-$(CONFIG_MVEBU_MBUS) 	+= mvebu-mbus.o
> diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c
> new file mode 100644
> index 0000000..9f48a1a
> --- /dev/null
> +++ b/drivers/bus/hisi_lpc.c
> @@ -0,0 +1,501 @@
> +/*
> + * Copyright (C) 2016 Hisilicon Limited, All Rights Reserved.
> + * Author: Zhichang Yuan <yuanzhichang@hisilicon.com>
> + * Author: Zou Rongrong <zourongrong@huawei.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.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/console.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_platform.h>
> +#include <linux/pci.h>
> +#include <linux/serial_8250.h>
> +#include <linux/slab.h>
> +
> +/*
> + * this bit set means each IO operation will target to different port address;
> + * 0 means repeatly IO operations will be sticked on the same port, such as BT;
> + */
> +#define FG_INCRADDR_LPC		0x02
> +
> +struct lpc_cycle_para {
> +	unsigned int opflags;
> +	unsigned int csize;/* the data length of each operation */
> +};
> +
> +struct hisilpc_dev {
> +	spinlock_t cycle_lock;
> +	void __iomem  *membase;
> +	struct extio_ops io_ops;
> +};
> +
> +
> +/* The maximum continous operations*/
> +#define LPC_MAX_OPCNT	16
> +/* only support IO data unit length is four at maximum */
> +#define LPC_MAX_DULEN	4
> +#if LPC_MAX_DULEN > LPC_MAX_OPCNT
> +#error "LPC.. MAX_DULEN must be not bigger than MAX_OPCNT!"
> +#endif
> +
> +#define LPC_REG_START		0x00/* start a new LPC cycle */
> +#define LPC_REG_OP_STATUS	0x04/* the current LPC status */
> +#define LPC_REG_IRQ_ST		0x08/* interrupt enable&status */
> +#define LPC_REG_OP_LEN		0x10/* how many LPC cycles each start */
> +#define LPC_REG_CMD		0x14/* command for the required LPC cycle */
> +#define LPC_REG_ADDR		0x20/* LPC target address */
> +#define LPC_REG_WDATA		0x24/* data to be written */
> +#define LPC_REG_RDATA		0x28/* data coming from peer */
> +
> +
> +/* The command register fields*/
> +#define LPC_CMD_SAMEADDR	0x08
> +#define LPC_CMD_TYPE_IO		0x00
> +#define LPC_CMD_WRITE		0x01
> +#define LPC_CMD_READ		0x00
> +/* the bit attribute is W1C. 1 represents OK. */
> +#define LPC_STAT_BYIRQ		0x02
> +
> +#define LPC_STATUS_IDLE		0x01
> +#define LPC_OP_FINISHED		0x02
> +
> +#define START_WORK		0x01
> +
> +/*
> + * The minimal waiting interval... Suggest it is not less than 10.
> + * Bigger value probably will lower the performance.
> + */
> +#define LPC_NSEC_PERWAIT	100
> +/*
> + * The maximum waiting time is about 128us.
> + * The fastest IO cycle time is about 390ns, but the worst case will wait
> + * for extra 256 lpc clocks, so (256 + 13) * 30ns = 8 us. The maximum
> + * burst cycles is 16. So, the maximum waiting time is about 128us under
> + * worst case.
> + * choose 1300 as the maximum.
> + */
> +#define LPC_MAX_WAITCNT		1300
> +/* About 10us. This is specfic for single IO operation, such as inb. */
> +#define LPC_PEROP_WAITCNT	100
> +
> +
> +static inline int wait_lpc_idle(unsigned char *mbase,
> +				unsigned int waitcnt) {
> +	u32 opstatus;
> +
> +	while (waitcnt--) {
> +		ndelay(LPC_NSEC_PERWAIT);
> +		opstatus = readl(mbase + LPC_REG_OP_STATUS);
> +		if (opstatus & LPC_STATUS_IDLE)
> +			return (opstatus & LPC_OP_FINISHED) ? 0 : (-EIO);
> +	}
> +	return -ETIME;
> +}
> +
> +
> +/**
> + * hisilpc_target_in - trigger a series of lpc cycles to read required data
> + *		  from target periperal.
> + * @pdev: pointer to hisi lpc device
> + * @para: some paramerters used to control the lpc I/O operations
> + * @ptaddr: the lpc I/O target port address
> + * @buf: where the read back data is stored
> + * @opcnt: how many I/O operations required in this calling
> + *
> + * only one byte data is read each I/O operation.
> + *
> + * Returns 0 on success, non-zero on fail.
> + *
> + */
> +static int hisilpc_target_in(struct hisilpc_dev *pdev,
> +				struct lpc_cycle_para *para,
> +				unsigned long ptaddr, unsigned char *buf,
> +				unsigned long opcnt)
> +{
> +	unsigned int cmd_word;
> +	unsigned int waitcnt;
> +	int retval;
> +	unsigned long flags;
> +	unsigned long cnt_per_trans;
> +
> +	if (!buf || !opcnt || !para || !para->csize || !pdev)
> +		return -EINVAL;
> +
> +	if (opcnt  > LPC_MAX_OPCNT)
> +		return -EINVAL;
> +
> +	cmd_word = LPC_CMD_TYPE_IO | LPC_CMD_READ;
> +	waitcnt = (LPC_PEROP_WAITCNT);
> +	if (!(para->opflags & FG_INCRADDR_LPC)) {
> +		cmd_word |= LPC_CMD_SAMEADDR;
> +		waitcnt = LPC_MAX_WAITCNT;
> +	}
> +
> +	retval = 0;
> +	cnt_per_trans = (para->csize == 1) ? opcnt : para->csize;
> +	for (; opcnt && !retval; cnt_per_trans = para->csize) {
> +		/* whole operation must be atomic */
> +		spin_lock_irqsave(&pdev->cycle_lock, flags);
> +
> +		writel(cnt_per_trans, pdev->membase + LPC_REG_OP_LEN);
> +
> +		writel(cmd_word, pdev->membase + LPC_REG_CMD);
> +
> +		writel(ptaddr, pdev->membase + LPC_REG_ADDR);
> +
> +		writel(START_WORK, pdev->membase + LPC_REG_START);
> +
> +		/* whether the operation is finished */
> +		retval = wait_lpc_idle(pdev->membase, waitcnt);
> +		if (!retval) {
> +			opcnt -= cnt_per_trans;
> +			for (; cnt_per_trans--; buf++)
> +				*buf = readl(pdev->membase + LPC_REG_RDATA);
> +		}
> +
> +		spin_unlock_irqrestore(&pdev->cycle_lock, flags);
> +	}
> +
> +	return retval;
> +}
> +
> +/**
> + * hisilpc_target_out - trigger a series of lpc cycles to write required data
> + *		  to target periperal.
> + * @pdev: pointer to hisi lpc device
> + * @para: some paramerters used to control the lpc I/O operations
> + * @ptaddr: the lpc I/O target port address
> + * @buf: where the data to be written is stored
> + * @opcnt: how many I/O operations required
> + *
> + * only one byte data is read each I/O operation.
> + *
> + * Returns 0 on success, non-zero on fail.
> + *
> + */
> +static int hisilpc_target_out(struct hisilpc_dev *pdev,
> +				struct lpc_cycle_para *para,
> +				unsigned long ptaddr,
> +				const unsigned char *buf,
> +				unsigned long opcnt)
> +{
> +	unsigned int cmd_word;
> +	unsigned int waitcnt;
> +	int retval;
> +	unsigned long flags;
> +	unsigned long cnt_per_trans;
> +
> +	if (!buf || !opcnt || !para || !pdev)
> +		return -EINVAL;
> +
> +	if (opcnt > LPC_MAX_OPCNT)
> +		return -EINVAL;
> +	/* default is increasing address */
> +	cmd_word = LPC_CMD_TYPE_IO | LPC_CMD_WRITE;
> +	waitcnt = (LPC_PEROP_WAITCNT);
> +	if (!(para->opflags & FG_INCRADDR_LPC)) {
> +		cmd_word |= LPC_CMD_SAMEADDR;
> +		waitcnt = LPC_MAX_WAITCNT;
> +	}
> +
> +	retval = 0;
> +	cnt_per_trans = (para->csize == 1) ? opcnt : para->csize;
> +	for (; opcnt && !retval; cnt_per_trans = para->csize) {
> +		spin_lock_irqsave(&pdev->cycle_lock, flags);
> +
> +		writel(cnt_per_trans, pdev->membase + LPC_REG_OP_LEN);
> +		opcnt -= cnt_per_trans;
> +		for (; cnt_per_trans--; buf++)
> +			writel(*buf, pdev->membase + LPC_REG_WDATA);
> +
> +		writel(cmd_word, pdev->membase + LPC_REG_CMD);
> +
> +		writel(ptaddr, pdev->membase + LPC_REG_ADDR);
> +
> +		writel(START_WORK, pdev->membase + LPC_REG_START);
> +
> +		/* whether the operation is finished */
> +		retval = wait_lpc_idle(pdev->membase, waitcnt);
> +
> +		spin_unlock_irqrestore(&pdev->cycle_lock, flags);
> +	}
> +
> +	return retval;
> +}
> +
> +
> +/**
> + * hisilpc_comm_in - read/input the data from the I/O peripheral through LPC.
> + * @devobj: pointer to the device information relevant to LPC controller.
> + * @ptaddr: the target I/O port address.
> + * @dlen: the data length required to read from the target I/O port.
> + *
> + * when succeed, the data read back is stored in buffer pointed by inbuf.
> + * For inb, return the data read from I/O or -1 when error occur.
> + */
> +static u64 hisilpc_comm_in(void *devobj, unsigned long ptaddr, size_t dlen)
> +{
> +	struct hisilpc_dev *lpcdev;
> +	struct lpc_cycle_para iopara;
> +	u32 rd_data;
> +	unsigned char *newbuf;
> +	int ret = 0;
> +
> +	if (!devobj || !dlen || dlen > LPC_MAX_DULEN ||	(dlen & (dlen - 1)))
> +		return -1;
> +
> +	/* the local buffer must be enough for one data unit */
> +	if (sizeof(rd_data) < dlen)
> +		return -1;
> +
> +	newbuf = (unsigned char *)&rd_data;
> +
> +	lpcdev = (struct hisilpc_dev *)devobj;
> +
> +	iopara.opflags = FG_INCRADDR_LPC;
> +	iopara.csize = dlen;
> +
> +	ret = hisilpc_target_in(lpcdev, &iopara, ptaddr, newbuf, dlen);
> +	if (ret)
> +		return -1;
> +
> +	return le32_to_cpu(rd_data);
> +}
> +
> +/**
> + * hisilpc_comm_out - write/output the data whose maximal length is four bytes to
> + *		the I/O peripheral through LPC.
> + * @devobj: pointer to the device information relevant to LPC controller.
> + * @outval: a value to be outputed from caller, maximum is four bytes.
> + * @ptaddr: the target I/O port address.
> + * @dlen: the data length required writing to the target I/O port .
> + *
> + * This function is corresponding to out(b,w,l) only
> + *
> + */
> +static void hisilpc_comm_out(void *devobj, unsigned long ptaddr,
> +				u32 outval, size_t dlen)
> +{
> +	struct hisilpc_dev *lpcdev;
> +	struct lpc_cycle_para iopara;
> +	const unsigned char *newbuf;
> +
> +	if (!devobj || !dlen || dlen > LPC_MAX_DULEN)
> +		return;
> +
> +	if (sizeof(outval) < dlen)
> +		return;
> +
> +	outval = cpu_to_le32(outval);
> +
> +	newbuf = (const unsigned char *)&outval;
> +	lpcdev = (struct hisilpc_dev *)devobj;
> +
> +	iopara.opflags = FG_INCRADDR_LPC;
> +	iopara.csize = dlen;
> +
> +	hisilpc_target_out(lpcdev, &iopara, ptaddr, newbuf, dlen);
> +}
> +
> +
> +/**
> + * hisilpc_comm_ins - read/input the data in buffer to the I/O peripheral
> + *		    through LPC, it corresponds to ins(b,w,l)
> + * @devobj: pointer to the device information relevant to LPC controller.
> + * @ptaddr: the target I/O port address.
> + * @inbuf: a buffer where read/input data bytes are stored.
> + * @dlen: the data length required writing to the target I/O port .
> + * @count: how many data units whose length is dlen will be read.
> + *
> + */
> +static u64 hisilpc_comm_ins(void *devobj, unsigned long ptaddr,
> +			void *inbuf, size_t dlen, unsigned int count)
> +{
> +	struct hisilpc_dev *lpcdev;
> +	struct lpc_cycle_para iopara;
> +	unsigned char *newbuf;
> +	unsigned int loopcnt, cntleft;
> +	unsigned int max_perburst;
> +	int ret = 0;
> +
> +	if (!devobj || !inbuf || !count || !dlen ||
> +			dlen > LPC_MAX_DULEN || (dlen & (dlen - 1)))
> +		return -1;
> +
> +	iopara.opflags = 0;
> +	if (dlen > 1)
> +		iopara.opflags |= FG_INCRADDR_LPC;
> +	iopara.csize = dlen;
> +
> +	lpcdev = (struct hisilpc_dev *)devobj;
> +	newbuf = (unsigned char *)inbuf;
> +	/*
> +	 * ensure data stream whose lenght is multiple of dlen to be processed
> +	 * each IO input
> +	 */
> +	max_perburst = LPC_MAX_OPCNT & (~(dlen - 1));
> +	cntleft = count * dlen;
> +	do {
> +		loopcnt = (cntleft >= max_perburst) ? max_perburst : cntleft;
> +		ret = hisilpc_target_in(lpcdev, &iopara, ptaddr, newbuf,
> +						loopcnt);
> +		if (ret)
> +			break;
> +		newbuf += loopcnt;
> +		cntleft -= loopcnt;
> +	} while (cntleft);
> +
> +	return ret;
> +}
> +
> +/**
> + * hisilpc_comm_outs - write/output the data in buffer to the I/O peripheral
> + *		    through LPC, it corresponds to outs(b,w,l)
> + * @devobj: pointer to the device information relevant to LPC controller.
> + * @ptaddr: the target I/O port address.
> + * @outbuf: a buffer where write/output data bytes are stored.
> + * @dlen: the data length required writing to the target I/O port .
> + * @count: how many data units whose length is dlen will be written.
> + *
> + */
> +static void hisilpc_comm_outs(void *devobj, unsigned long ptaddr,
> +			const void *outbuf, size_t dlen, unsigned int count)
> +{
> +	struct hisilpc_dev *lpcdev;
> +	struct lpc_cycle_para iopara;
> +	const unsigned char *newbuf;
> +	unsigned int loopcnt, cntleft;
> +	unsigned int max_perburst;
> +	int ret = 0;
> +
> +	if (!devobj || !outbuf || !count || !dlen ||
> +			dlen > LPC_MAX_DULEN || (dlen & (dlen - 1)))
> +		return;
> +
> +	iopara.opflags = 0;
> +	if (dlen > 1)
> +		iopara.opflags |= FG_INCRADDR_LPC;
> +	iopara.csize = dlen;
> +
> +	lpcdev = (struct hisilpc_dev *)devobj;
> +	newbuf = (unsigned char *)outbuf;
> +	/*
> +	 * ensure data stream whose lenght is multiple of dlen to be processed
> +	 * each IO input
> +	 */
> +	max_perburst = LPC_MAX_OPCNT & (~(dlen - 1));
> +	cntleft = count * dlen;
> +	do {
> +		loopcnt = (cntleft >= max_perburst) ? max_perburst : cntleft;
> +		ret = hisilpc_target_out(lpcdev, &iopara, ptaddr, newbuf,
> +						loopcnt);
> +		if (ret)
> +			break;
> +		newbuf += loopcnt;
> +		cntleft -= loopcnt;
> +	} while (cntleft);
> +}
> +
> +
> +/**
> + * hisilpc_probe - the probe callback function for hisi lpc device,
> + *		will finish all the intialization.
> + * @pdev: the platform device corresponding to hisi lpc
> + *
> + * Returns 0 on success, non-zero on fail.
> + *
> + */
> +static int hisilpc_probe(struct platform_device *pdev)
> +{
> +	struct resource *iores;
> +	struct hisilpc_dev *lpcdev;
> +	int ret;
> +
> +	dev_info(&pdev->dev, "hslpc start probing...\n");
> +
> +	lpcdev = devm_kzalloc(&pdev->dev,
> +				sizeof(struct hisilpc_dev), GFP_KERNEL);
> +	if (!lpcdev)
> +		return -ENOMEM;
> +
> +	spin_lock_init(&lpcdev->cycle_lock);
> +	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	lpcdev->membase = devm_ioremap_resource(&pdev->dev, iores);
> +	if (IS_ERR(lpcdev->membase)) {
> +		dev_err(&pdev->dev, "No mem resource for memory mapping!\n");
> +		return PTR_ERR(lpcdev->membase);
> +	}
> +	/*
> +	 * The first PCIBIOS_MIN_IO is reserved specific for indirectIO.
> +	 * It will separate indirectIO range from pci host bridge to
> +	 * avoid the possible PIO conflict.
> +	 * Set the indirectIO range directly here.
> +	 */
> +	lpcdev->io_ops.start = 0;
> +	lpcdev->io_ops.end = PCIBIOS_MIN_IO - 1;
> +	lpcdev->io_ops.devpara = lpcdev;
> +	lpcdev->io_ops.pfin = hisilpc_comm_in;
> +	lpcdev->io_ops.pfout = hisilpc_comm_out;
> +	lpcdev->io_ops.pfins = hisilpc_comm_ins;
> +	lpcdev->io_ops.pfouts = hisilpc_comm_outs;
> +
> +	platform_set_drvdata(pdev, lpcdev);
> +
> +	arm64_set_extops(&lpcdev->io_ops);
> +
> +	/*
> +	 * The children scanning is only for dts mode. For ACPI children,
> +	 * the corresponding devices had be created during acpi scanning.
> +	 */
> +	ret = 0;
> +	if (!has_acpi_companion(&pdev->dev))
> +		ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
> +
> +	if (!ret)
> +		dev_info(&pdev->dev, "hslpc end probing. range[0x%lx - %lx]\n",
> +			arm64_extio_ops->start, arm64_extio_ops->end);
> +	else
> +		dev_info(&pdev->dev, "hslpc probing is fail(%d)\n", ret);
> +
> +	return ret;
> +}
> +
> +static const struct of_device_id hisilpc_of_match[] = {
> +	{
> +		.compatible = "hisilicon,low-pin-count",
> +	},
> +	{},
> +};
> +
> +static const struct acpi_device_id hisilpc_acpi_match[] = {
> +	{"HISI0191", },
> +	{},
> +};
> +
> +static struct platform_driver hisilpc_driver = {
> +	.driver = {
> +		.name           = "hisi_lpc",
> +		.of_match_table = hisilpc_of_match,
> +		.acpi_match_table = hisilpc_acpi_match,
> +	},
> +	.probe = hisilpc_probe,
> +};
> +
> +
> +builtin_platform_driver(hisilpc_driver);
> -- 
> 1.9.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH] ARM: avoid cache flushing in flush_dcache_page()
From: Catalin Marinas @ 2016-11-07 11:35 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478514624-30910-1-git-send-email-rabin.vincent@axis.com>

On Mon, Nov 07, 2016 at 11:30:24AM +0100, Rabin Vincent wrote:
> diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
> index 3cced84..f1e6190 100644
> --- a/arch/arm/mm/flush.c
> +++ b/arch/arm/mm/flush.c
> @@ -327,6 +327,12 @@ void flush_dcache_page(struct page *page)
>  	if (page == ZERO_PAGE(0))
>  		return;
>  
> +	if (!cache_ops_need_broadcast() && cache_is_vipt_nonaliasing()) {
> +		if (test_bit(PG_dcache_clean, &page->flags))
> +			clear_bit(PG_dcache_clean, &page->flags);
> +		return;
> +	}
> +
>  	mapping = page_mapping(page);
>  
>  	if (!cache_ops_need_broadcast() &&

I'm ok with the logic in this patch but is there a way to combine the
two 'if' blocks together, just to keep the function shorter?

-- 
Catalin

^ permalink raw reply

* [PATCH V4 3/6] dt/bindings: Add bindings for Tegra GMI controller
From: Thierry Reding @ 2016-11-07 11:35 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478507405-13204-4-git-send-email-mirza.krak@gmail.com>

On Mon, Nov 07, 2016 at 09:30:02AM +0100, Mirza Krak wrote:
> From: Mirza Krak <mirza.krak@gmail.com>
> 
> Document the devicetree bindings for the Generic Memory Interface (GMI)
> bus driver found on Tegra SOCs.
> 
> Signed-off-by: Mirza Krak <mirza.krak@gmail.com>
> Tested-by: Marcel Ziswiler <marcel.ziswiler@toradex.com>
> Tested-on: Colibri T20/T30 on EvalBoard V3.x and GMI-Memory Board
> Acked-by: Rob Herring <robh@kernel.org>
> ---
> 
> Changes in v2:
> - Updated examples and some information based on comments from Jon Hunter.
> 
> Changes in v3:
> - Updates ranges description based on comments from Rob Herring
> 
> Changes in v4:
> - renamed snor-*-inv to snor-*-active-high
> 
>  .../devicetree/bindings/bus/nvidia,tegra20-gmi.txt | 132 +++++++++++++++++++++
>  1 file changed, 132 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/bus/nvidia,tegra20-gmi.txt

Applied, thanks.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161107/42611e92/attachment-0001.sig>

^ permalink raw reply

* [PATCH v6 09/16] drivers: acpi: iort: add support for ARM SMMU platform devices creation
From: Lorenzo Pieralisi @ 2016-11-07 11:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161101223022.GA1234@xora-yoga13>

On Tue, Nov 01, 2016 at 04:30:22PM -0600, Graeme Gregory wrote:
> On Fri, Oct 28, 2016 at 04:50:07PM +0100, Lorenzo Pieralisi wrote:
> > On Tue, Oct 18, 2016 at 05:04:07PM +0100, Lorenzo Pieralisi wrote:
> > > In ARM ACPI systems, IOMMU components are specified through static
> > > IORT table entries. In order to create platform devices for the
> > > corresponding ARM SMMU components, IORT kernel code should be made
> > > able to parse IORT table entries and create platform devices
> > > dynamically.
> > > 
> > > This patch adds the generic IORT infrastructure required to create
> > > platform devices for ARM SMMUs.
> > > 
> > > ARM SMMU versions have different resources requirement therefore this
> > > patch also introduces an IORT specific structure (ie iort_iommu_config)
> > > that contains hooks (to be defined when the corresponding ARM SMMU
> > > driver support is added to the kernel) to be used to define the
> > > platform devices names, init the IOMMUs, count their resources and
> > > finally initialize them.
> > > 
> > > Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> > > Cc: Hanjun Guo <hanjun.guo@linaro.org>
> > > Cc: Tomasz Nowicki <tn@semihalf.com>
> > > Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
> > > ---
> > >  drivers/acpi/arm64/iort.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++
> > >  1 file changed, 151 insertions(+)
> > > 
> > > diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
> > > index 1433de3..2eda2f5 100644
> > > --- a/drivers/acpi/arm64/iort.c
> > > +++ b/drivers/acpi/arm64/iort.c
> > > @@ -19,9 +19,11 @@
> > >  #define pr_fmt(fmt)	"ACPI: IORT: " fmt
> > >  
> > >  #include <linux/acpi_iort.h>
> > > +#include <linux/iommu.h>
> > >  #include <linux/kernel.h>
> > >  #include <linux/list.h>
> > >  #include <linux/pci.h>
> > > +#include <linux/platform_device.h>
> > >  #include <linux/slab.h>
> > >  
> > >  struct iort_its_msi_chip {
> > > @@ -457,6 +459,153 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
> > >  	return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
> > >  }
> > >  
> > > +struct iort_iommu_config {
> > > +	const char *name;
> > > +	int (*iommu_init)(struct acpi_iort_node *node);
> > > +	bool (*iommu_is_coherent)(struct acpi_iort_node *node);
> > > +	int (*iommu_count_resources)(struct acpi_iort_node *node);
> > > +	void (*iommu_init_resources)(struct resource *res,
> > > +				     struct acpi_iort_node *node);
> > > +};
> > > +
> > > +static __init
> > > +const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
> > > +{
> > > +	return NULL;
> > > +}
> > > +
> > > +/**
> > > + * iort_add_smmu_platform_device() - Allocate a platform device for SMMU
> > > + * @node: Pointer to SMMU ACPI IORT node
> > > + *
> > > + * Returns: 0 on success, <0 failure
> > > + */
> > > +static int __init iort_add_smmu_platform_device(struct acpi_iort_node *node)
> > > +{
> > > +	struct fwnode_handle *fwnode;
> > > +	struct platform_device *pdev;
> > > +	struct resource *r;
> > > +	enum dev_dma_attr attr;
> > > +	int ret, count;
> > > +	const struct iort_iommu_config *ops = iort_get_iommu_cfg(node);
> > > +
> > > +	if (!ops)
> > > +		return -ENODEV;
> > > +
> > > +	pdev = platform_device_alloc(ops->name, PLATFORM_DEVID_AUTO);
> > > +	if (!pdev)
> > > +		return PTR_ERR(pdev);
> > > +
> > > +	count = ops->iommu_count_resources(node);
> > > +
> > > +	r = kcalloc(count, sizeof(*r), GFP_KERNEL);
> > > +	if (!r) {
> > > +		ret = -ENOMEM;
> > > +		goto dev_put;
> > > +	}
> > > +
> > > +	ops->iommu_init_resources(r, node);
> > > +
> > > +	ret = platform_device_add_resources(pdev, r, count);
> > > +	/*
> > > +	 * Resources are duplicated in platform_device_add_resources,
> > > +	 * free their allocated memory
> > > +	 */
> > > +	kfree(r);
> > > +
> > > +	if (ret)
> > > +		goto dev_put;
> > > +
> > > +	/*
> > > +	 * Add a copy of IORT node pointer to platform_data to
> > > +	 * be used to retrieve IORT data information.
> > > +	 */
> > > +	ret = platform_device_add_data(pdev, &node, sizeof(node));
> > > +	if (ret)
> > > +		goto dev_put;
> > > +
> > > +	/*
> > > +	 * We expect the dma masks to be equivalent for
> > > +	 * all SMMUs set-ups
> > > +	 */
> > > +	pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
> > > +
> > > +	fwnode = iort_get_fwnode(node);
> > > +
> > > +	if (!fwnode) {
> > > +		ret = -ENODEV;
> > > +		goto dev_put;
> > > +	}
> > > +
> > > +	pdev->dev.fwnode = fwnode;
> > > +
> > > +	attr = ops->iommu_is_coherent(node) ?
> > > +			     DEV_DMA_COHERENT : DEV_DMA_NON_COHERENT;
> > > +
> > > +	/* Configure DMA for the page table walker */
> > > +	acpi_dma_configure(&pdev->dev, attr);
> > > +
> > > +	ret = platform_device_add(pdev);
> > > +	if (ret)
> > > +		goto dma_deconfigure;
> > > +
> > > +	return 0;
> > > +
> > > +dma_deconfigure:
> > > +	acpi_dma_deconfigure(&pdev->dev);
> > > +dev_put:
> > > +	platform_device_put(pdev);
> > > +
> > > +	return ret;
> > > +}
> > > +
> > > +static void __init iort_init_platform_devices(void)
> > > +{
> > > +	struct acpi_iort_node *iort_node, *iort_end;
> > > +	struct acpi_table_iort *iort;
> > > +	struct fwnode_handle *fwnode;
> > > +	int i, ret;
> > > +
> > > +	/*
> > > +	 * iort_table and iort both point to the start of IORT table, but
> > > +	 * have different struct types
> > > +	 */
> > > +	iort = (struct acpi_table_iort *)iort_table;
> > > +
> > > +	/* Get the first IORT node */
> > > +	iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort,
> > > +				 iort->node_offset);
> > > +	iort_end = ACPI_ADD_PTR(struct acpi_iort_node, iort,
> > > +				iort_table->length);
> > > +
> > > +	for (i = 0; i < iort->node_count; i++) {
> > > +		if (iort_node >= iort_end) {
> > > +			pr_err("iort node pointer overflows, bad table\n");
> > > +			return;
> > > +		}
> > > +
> > > +		if ((iort_node->type == ACPI_IORT_NODE_SMMU) ||
> > > +			(iort_node->type == ACPI_IORT_NODE_SMMU_V3)) {
> > > +
> > > +			fwnode = acpi_alloc_fwnode_static();
> > > +			if (!fwnode)
> > > +				return;
> > > +
> > > +			iort_set_fwnode(iort_node, fwnode);
> > > +
> > > +			ret = iort_add_smmu_platform_device(iort_node);
> > > +			if (ret) {
> > > +				iort_delete_fwnode(iort_node);
> > > +				acpi_free_fwnode_static(fwnode);
> > > +				return;
> > > +			}
> > > +		}
> > > +
> > > +		iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
> > > +					 iort_node->length);
> > > +	}
> > > +}
> > > +
> > >  void __init acpi_iort_init(void)
> > >  {
> > >  	acpi_status status;
> > > @@ -468,5 +617,7 @@ void __init acpi_iort_init(void)
> > >  		return;
> > >  	}
> > >  
> > 
> > Slipped through the cracks while rebasing v6, I should add code that
> > returns if no IORT table found here to prevent calling:
> > 
> > iort_init_platform_devices()
> > 
> > I will update the next version, it is just a heads-up for testers,
> > I can push an updated/fixed branch if needed.
> > 
> 
> I could do with the updated branch.

Done, please find it here, I will post a v7 this week with updates.

git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/linux.git acpi/iort-smmu-v6

Lorenzo

^ permalink raw reply

* [PATCH V3 0/6] ARM64: Uprobe support added
From: Catalin Marinas @ 2016-11-07 11:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <e1593d0d-b63c-cc7b-fcee-753b5bd8f0de@redhat.com>

On Sat, Nov 05, 2016 at 11:01:31AM +0530, Pratyush Anand wrote:
> On Saturday 05 November 2016 12:16 AM, Catalin Marinas wrote:
> > On Fri, Nov 04, 2016 at 11:49:51AM -0600, Catalin Marinas wrote:
> > > On Wed, Nov 02, 2016 at 02:40:40PM +0530, Pratyush Anand wrote:
> > > > Pratyush Anand (6):
> > > >   arm64: kprobe: protect/rename few definitions to be reused by uprobe
> > > >   arm64: kgdb_step_brk_fn: ignore other's exception
> > > >   arm64: Handle TRAP_TRACE for user mode as well
> > > >   arm64: Handle TRAP_BRKPT for user mode as well
> > > >   arm64: introduce mm context flag to keep 32 bit task information
> > > >   arm64: Add uprobe support
> > > 
> > > I queued the patches for 4.10. I will push them into -next sometime next
> > > week once I do some testing (I'm currently at the LPC).
> > 
> > I spoke too soon. With these patches on top of 4.9-rc3, defconfig
> > together with FTRACE and UPROBE_EVENT enabled I get:
> > 
> > In file included from /work/Linux/linux-2.6-aarch64/arch/arm64/kernel/probes/decode-insn.c:20:0:
> > /work/Linux/linux-2.6-aarch64/arch/arm64/include/asm/kprobes.h:52:5: error: conflicting types for 'kprobe_fault_handler'
> >  int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr);
> >      ^~~~~~~~~~~~~~~~~~~~
> > In file included from /work/Linux/linux-2.6-aarch64/arch/arm64/kernel/probes/decode-insn.c:17:0:
> > /work/Linux/linux-2.6-aarch64/include/linux/kprobes.h:398:90: note: previous definition of 'kprobe_fault_handler' was here
> >  static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
> >                                                                                           ^
> > /work/Linux/linux-2.6-aarch64/scripts/Makefile.build:290: recipe for target 'arch/arm64/kernel/probes/decode-insn.o' failed
> 
> Hummmm...CONFIG_KPROBE was defined in my setup and did not notice it :( . We
> need to remove #include <asm/kprobes.h> from
> /arch/arm64/kernel/probes/decode-insn.c.
> <asm/kprobes.h> is already included from <linux/kprobes.h> under #ifdef
> CONFIG_KPROBE.
> 
> diff --git a/arch/arm64/kernel/probes/decode-insn.c
> b/arch/arm64/kernel/probes/decode-insn.c
> index 8a29d29..6bf6657 100644
> --- a/arch/arm64/kernel/probes/decode-insn.c
> +++ b/arch/arm64/kernel/probes/decode-insn.c
> @@ -17,7 +17,6 @@
>  #include <linux/kprobes.h>
>  #include <linux/module.h>
>  #include <linux/kallsyms.h>
> -#include <asm/kprobes.h>
>  #include <asm/insn.h>
>  #include <asm/sections.h>
> 
> So, do you want me to send V4 or a separate topup fixup patch. Please let me
> know, will do accordingly.

Just a separate patch on top of your series would do. Also please test
your series with CONFIG_KPROBE disabled and I assume this wasn't done
(just in case there is an interaction we were not aware of).

Thanks.

-- 
Catalin

^ permalink raw reply

* [PATCH] ARM: avoid cache flushing in flush_dcache_page()
From: Russell King - ARM Linux @ 2016-11-07 11:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161107113525.GA28876@MBP.local>

On Mon, Nov 07, 2016 at 11:35:27AM +0000, Catalin Marinas wrote:
> On Mon, Nov 07, 2016 at 11:30:24AM +0100, Rabin Vincent wrote:
> > diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
> > index 3cced84..f1e6190 100644
> > --- a/arch/arm/mm/flush.c
> > +++ b/arch/arm/mm/flush.c
> > @@ -327,6 +327,12 @@ void flush_dcache_page(struct page *page)
> >  	if (page == ZERO_PAGE(0))
> >  		return;
> >  
> > +	if (!cache_ops_need_broadcast() && cache_is_vipt_nonaliasing()) {
> > +		if (test_bit(PG_dcache_clean, &page->flags))
> > +			clear_bit(PG_dcache_clean, &page->flags);
> > +		return;
> > +	}
> > +
> >  	mapping = page_mapping(page);
> >  
> >  	if (!cache_ops_need_broadcast() &&
> 
> I'm ok with the logic in this patch but is there a way to combine the
> two 'if' blocks together, just to keep the function shorter?

Probably not without reducing code readability, or moving
page_mapping() before this new if() block (which may introduce
extra code into the path.)

As this path gets used for filesystem read/write, it would be a
good idea to keep it as efficient as possible.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply

* [PATCH V4 6/6] bus: Add support for Tegra Generic Memory Interface
From: Thierry Reding @ 2016-11-07 11:49 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478507405-13204-7-git-send-email-mirza.krak@gmail.com>

On Mon, Nov 07, 2016 at 09:30:05AM +0100, Mirza Krak wrote:
> From: Mirza Krak <mirza.krak@gmail.com>
> 
> The Generic Memory Interface bus can be used to connect high-speed
> devices such as NOR flash, FPGAs, DSPs...
> 
> Signed-off-by: Mirza Krak <mirza.krak@gmail.com>
> Tested-by: Marcel Ziswiler <marcel.ziswiler@toradex.com>
> Tested-on: Colibri T20/T30 on EvalBoard V3.x and GMI-Memory Board
> ---
> 
> Changes in v2:
>  - Fixed some checkpatch errors
>  - Re-ordered probe to get rid of local variables
>  - Moved of_platform_default_populate call to the end of probe
>  - Use the timing and configuration properties from the child device
>  - Added warning if more then 1 child device exist
> 
> Changes in v3:
>  - added helper function to disable the controller which is used in remove and
>  on error.
>  - Added logic to parse CS# from "ranges" property with fallback to "reg"
>  property
> 
> Changes in v4:
> - added sanity check of chip-select property (fail if invalid)
> - adjusted for device tree binding property name changes
> - fail probe if there are no child nodes
> - removed superfluous error message
> - removed superfluous newline in Kconfig
> 
>  drivers/bus/Kconfig     |   7 ++
>  drivers/bus/Makefile    |   1 +
>  drivers/bus/tegra-gmi.c | 275 ++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 283 insertions(+)
>  create mode 100644 drivers/bus/tegra-gmi.c

Applied with a bit of code reshuffling to make things more symmetric as
well as a couple of pedantic cleanups because I couldn't resist.

Thanks,
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161107/e087bf16/attachment-0001.sig>

^ permalink raw reply

* Tegra baseline test results for v4.9-rc4
From: Jon Hunter @ 2016-11-07 11:51 UTC (permalink / raw)
  To: linux-arm-kernel

Here are some basic Tegra test results for Linux v4.9-rc4.
Logs and other details at:

    https://nvtb.github.io//linux/test_v4.9-rc4/20161107030103/


Test summary
------------

Build: zImage:
    Pass: ( 2/ 2): multi_v7_defconfig, tegra_defconfig

Build: Image:
    Pass: ( 1/ 1): defconfig

Boot to userspace: defconfig:
    Pass: ( 4/ 4): qemu-vexpress64, tegra132-norrin,
		   tegra210-p2371-0000, tegra210-smaug

Boot to userspace: multi_v7_defconfig:
    Pass: ( 5/ 5): tegra114-dalmore-a04, tegra124-jetson-tk1,
		   tegra124-nyan-big, tegra20-trimslice, tegra30-beaver

Boot to userspace: tegra_defconfig:
    Pass: ( 5/ 5): tegra114-dalmore-a04, tegra124-jetson-tk1,
		   tegra124-nyan-big, tegra20-trimslice, tegra30-beaver

PM: System suspend: multi_v7_defconfig:
    Pass: ( 5/ 5): tegra114-dalmore-a04, tegra124-jetson-tk1,
		   tegra124-nyan-big, tegra20-trimslice, tegra30-beaver

PM: System suspend: tegra_defconfig:
    Pass: ( 5/ 5): tegra114-dalmore-a04, tegra124-jetson-tk1,
		   tegra124-nyan-big, tegra20-trimslice, tegra30-beaver


vmlinux object size
(delta in bytes from test_v4.9-rc3 (a909d3e636995ba7c349e2ca5dbb528154d4ac30)):
   text     data      bss    total  kernel
  +4122      -32        0    +4090  defconfig
  +1138        0        0    +1138  multi_v7_defconfig
  +1573        0        0    +1573  tegra_defconfig


Boot-time memory difference
(delta in bytes from test_v4.9-rc3 (a909d3e636995ba7c349e2ca5dbb528154d4ac30))
    avail    rsrvd     high    freed                board              kconfig                  dtb
        .        .        .        .      qemu-vexpress64            defconfig           __internal
        .        .        .        . tegra114-dalmore-a04   multi_v7_defconfig     tegra114-dalmore
        .        .        .        . tegra114-dalmore-a04      tegra_defconfig     tegra114-dalmore
        .        .        .        .  tegra124-jetson-tk1   multi_v7_defconfig  tegra124-jetson-tk1
        .        .        .        .  tegra124-jetson-tk1      tegra_defconfig  tegra124-jetson-tk1
        .        .        .        .    tegra124-nyan-big   multi_v7_defconfig    tegra124-nyan-big
        .        .        .        .    tegra124-nyan-big      tegra_defconfig    tegra124-nyan-big
        .        .        .        .      tegra132-norrin            defconfig      tegra132-norrin
        .        .        .        .    tegra20-trimslice   multi_v7_defconfig    tegra20-trimslice
        .        .        .        .    tegra20-trimslice      tegra_defconfig    tegra20-trimslice
        .        .        .        .  tegra210-p2371-0000            defconfig  tegra210-p2371-0000
        .        .        .        .       tegra210-smaug            defconfig       tegra210-smaug
        .        .        .        .       tegra30-beaver   multi_v7_defconfig       tegra30-beaver
        .        .        .        .       tegra30-beaver      tegra_defconfig       tegra30-beaver

--
nvpublic

^ permalink raw reply

* [PATCH] ARM: avoid cache flushing in flush_dcache_page()
From: Catalin Marinas @ 2016-11-07 12:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161107114845.GF1041@n2100.armlinux.org.uk>

On Mon, Nov 07, 2016 at 11:48:45AM +0000, Russell King - ARM Linux wrote:
> On Mon, Nov 07, 2016 at 11:35:27AM +0000, Catalin Marinas wrote:
> > On Mon, Nov 07, 2016 at 11:30:24AM +0100, Rabin Vincent wrote:
> > > diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
> > > index 3cced84..f1e6190 100644
> > > --- a/arch/arm/mm/flush.c
> > > +++ b/arch/arm/mm/flush.c
> > > @@ -327,6 +327,12 @@ void flush_dcache_page(struct page *page)
> > >  	if (page == ZERO_PAGE(0))
> > >  		return;
> > >  
> > > +	if (!cache_ops_need_broadcast() && cache_is_vipt_nonaliasing()) {
> > > +		if (test_bit(PG_dcache_clean, &page->flags))
> > > +			clear_bit(PG_dcache_clean, &page->flags);
> > > +		return;
> > > +	}
> > > +
> > >  	mapping = page_mapping(page);
> > >  
> > >  	if (!cache_ops_need_broadcast() &&
> > 
> > I'm ok with the logic in this patch but is there a way to combine the
> > two 'if' blocks together, just to keep the function shorter?
> 
> Probably not without reducing code readability, or moving
> page_mapping() before this new if() block (which may introduce
> extra code into the path.)

You are right, we would need 'mapping' in the subsequent checks, so I
don't think the code would be more readable if we are to keep it
efficient. In this case:

Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>

^ permalink raw reply

* [PATCH v3 0/2] support USB2 PHY OTG port for rk3399
From: William Wu @ 2016-11-07 12:08 UTC (permalink / raw)
  To: linux-arm-kernel

This series add support for rk3399 USB2 PHY0 and PHY1 OTG port.
rk3399 has two USB2 PHYs, and each USB2 PHY is comprised of one
Host port and one OTG port. We have supported Host port before,
and try to support OTG port now.

Test on rk3399-evb board.

William Wu (2):
  phy: rockchip-inno-usb2: support otg-port for rk3399
  arm64: dts: rockchip: add usb2-phy otg-port support for rk3399

 arch/arm64/boot/dts/rockchip/rk3399.dtsi |  21 ++
 drivers/phy/phy-rockchip-inno-usb2.c     | 591 +++++++++++++++++++++++++++++--
 2 files changed, 582 insertions(+), 30 deletions(-)

-- 
2.0.0

^ permalink raw reply

* [PATCH v3 1/2] phy: rockchip-inno-usb2: support otg-port for rk3399
From: William Wu @ 2016-11-07 12:08 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478520529-8869-1-git-send-email-wulf@rock-chips.com>

The rk3399 SoC USB2 PHY is comprised of one Host port and
one OTG port. And OTG port is for USB2.0 part of USB3.0 OTG
controller, as a part to construct a fully feature Type-C
subsystem.

With this patch, we can support OTG port with the following
functions:
- Support BC1.2 charger detect, and use extcon notifier to
  send USB charger types to power driver.
- Support PHY suspend for power management.
- Support OTG Host only mode.

Signed-off-by: William Wu <wulf@rock-chips.com>
---
Changes in v3:
- split the clock fix into a separate patch 

Changes in v2:
- remove wakelock

 drivers/phy/phy-rockchip-inno-usb2.c | 591 +++++++++++++++++++++++++++++++++--
 1 file changed, 561 insertions(+), 30 deletions(-)

diff --git a/drivers/phy/phy-rockchip-inno-usb2.c b/drivers/phy/phy-rockchip-inno-usb2.c
index ac20310..ecfd7d1 100644
--- a/drivers/phy/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/phy-rockchip-inno-usb2.c
@@ -17,6 +17,7 @@
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
+#include <linux/extcon.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/gpio/consumer.h>
@@ -30,11 +31,15 @@
 #include <linux/of_platform.h>
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
+#include <linux/power_supply.h>
 #include <linux/regmap.h>
 #include <linux/mfd/syscon.h>
+#include <linux/usb/of.h>
+#include <linux/usb/otg.h>
 
 #define BIT_WRITEABLE_SHIFT	16
-#define SCHEDULE_DELAY	(60 * HZ)
+#define SCHEDULE_DELAY		(60 * HZ)
+#define OTG_SCHEDULE_DELAY	(2 * HZ)
 
 enum rockchip_usb2phy_port_id {
 	USB2PHY_PORT_OTG,
@@ -49,6 +54,37 @@ enum rockchip_usb2phy_host_state {
 	PHY_STATE_FS_LS_ONLINE	= 4,
 };
 
+/**
+ * Different states involved in USB charger detection.
+ * USB_CHG_STATE_UNDEFINED	USB charger is not connected or detection
+ *				process is not yet started.
+ * USB_CHG_STATE_WAIT_FOR_DCD	Waiting for Data pins contact.
+ * USB_CHG_STATE_DCD_DONE	Data pin contact is detected.
+ * USB_CHG_STATE_PRIMARY_DONE	Primary detection is completed (Detects
+ *				between SDP and DCP/CDP).
+ * USB_CHG_STATE_SECONDARY_DONE	Secondary detection is completed (Detects
+ *				between DCP and CDP).
+ * USB_CHG_STATE_DETECTED	USB charger type is determined.
+ */
+enum usb_chg_state {
+	USB_CHG_STATE_UNDEFINED = 0,
+	USB_CHG_STATE_WAIT_FOR_DCD,
+	USB_CHG_STATE_DCD_DONE,
+	USB_CHG_STATE_PRIMARY_DONE,
+	USB_CHG_STATE_SECONDARY_DONE,
+	USB_CHG_STATE_DETECTED,
+};
+
+static const unsigned int rockchip_usb2phy_extcon_cable[] = {
+	EXTCON_USB,
+	EXTCON_USB_HOST,
+	EXTCON_CHG_USB_SDP,
+	EXTCON_CHG_USB_CDP,
+	EXTCON_CHG_USB_DCP,
+	EXTCON_CHG_USB_SLOW,
+	EXTCON_NONE,
+};
+
 struct usb2phy_reg {
 	unsigned int	offset;
 	unsigned int	bitend;
@@ -58,19 +94,55 @@ struct usb2phy_reg {
 };
 
 /**
+ * struct rockchip_chg_det_reg: usb charger detect registers
+ * @cp_det: charging port detected successfully.
+ * @dcp_det: dedicated charging port detected successfully.
+ * @dp_det: assert data pin connect successfully.
+ * @idm_sink_en: open dm sink curren.
+ * @idp_sink_en: open dp sink current.
+ * @idp_src_en: open dm source current.
+ * @rdm_pdwn_en: open dm pull down resistor.
+ * @vdm_src_en: open dm voltage source.
+ * @vdp_src_en: open dp voltage source.
+ * @opmode: utmi operational mode.
+ */
+struct rockchip_chg_det_reg {
+	struct usb2phy_reg	cp_det;
+	struct usb2phy_reg	dcp_det;
+	struct usb2phy_reg	dp_det;
+	struct usb2phy_reg	idm_sink_en;
+	struct usb2phy_reg	idp_sink_en;
+	struct usb2phy_reg	idp_src_en;
+	struct usb2phy_reg	rdm_pdwn_en;
+	struct usb2phy_reg	vdm_src_en;
+	struct usb2phy_reg	vdp_src_en;
+	struct usb2phy_reg	opmode;
+};
+
+/**
  * struct rockchip_usb2phy_port_cfg: usb-phy port configuration.
  * @phy_sus: phy suspend register.
+ * @bvalid_det_en: vbus valid rise detection enable register.
+ * @bvalid_det_st: vbus valid rise detection status register.
+ * @bvalid_det_clr: vbus valid rise detection clear register.
  * @ls_det_en: linestate detection enable register.
  * @ls_det_st: linestate detection state register.
  * @ls_det_clr: linestate detection clear register.
+ * @utmi_avalid: utmi vbus avalid status register.
+ * @utmi_bvalid: utmi vbus bvalid status register.
  * @utmi_ls: utmi linestate state register.
  * @utmi_hstdet: utmi host disconnect register.
  */
 struct rockchip_usb2phy_port_cfg {
 	struct usb2phy_reg	phy_sus;
+	struct usb2phy_reg	bvalid_det_en;
+	struct usb2phy_reg	bvalid_det_st;
+	struct usb2phy_reg	bvalid_det_clr;
 	struct usb2phy_reg	ls_det_en;
 	struct usb2phy_reg	ls_det_st;
 	struct usb2phy_reg	ls_det_clr;
+	struct usb2phy_reg	utmi_avalid;
+	struct usb2phy_reg	utmi_bvalid;
 	struct usb2phy_reg	utmi_ls;
 	struct usb2phy_reg	utmi_hstdet;
 };
@@ -80,31 +152,51 @@ struct rockchip_usb2phy_port_cfg {
  * @reg: the address offset of grf for usb-phy config.
  * @num_ports: specify how many ports that the phy has.
  * @clkout_ctl: keep on/turn off output clk of phy.
+ * @chg_det: charger detection registers.
  */
 struct rockchip_usb2phy_cfg {
 	unsigned int	reg;
 	unsigned int	num_ports;
 	struct usb2phy_reg	clkout_ctl;
 	const struct rockchip_usb2phy_port_cfg	port_cfgs[USB2PHY_NUM_PORTS];
+	const struct rockchip_chg_det_reg	chg_det;
 };
 
 /**
  * struct rockchip_usb2phy_port: usb-phy port data.
  * @port_id: flag for otg port or host port.
  * @suspended: phy suspended flag.
+ * @utmi_avalid: utmi avalid status usage flag.
+ *	true	- use avalid to get vbus status
+ *	flase	- use bvalid to get vbus status
+ * @vbus_attached: otg device vbus status.
+ * @bvalid_irq: IRQ number assigned for vbus valid rise detection.
  * @ls_irq: IRQ number assigned for linestate detection.
  * @mutex: for register updating in sm_work.
- * @sm_work: OTG state machine work.
+ * @chg_work: charge detect work.
+ * @otg_sm_work: OTG state machine work.
+ * @sm_work: HOST state machine work.
  * @phy_cfg: port register configuration, assigned by driver data.
+ * @event_nb: hold event notification callback.
+ * @state: define OTG enumeration states before device reset.
+ * @mode: the dr_mode of the controller.
  */
 struct rockchip_usb2phy_port {
 	struct phy	*phy;
 	unsigned int	port_id;
 	bool		suspended;
+	bool		utmi_avalid;
+	bool		vbus_attached;
+	int		bvalid_irq;
 	int		ls_irq;
 	struct mutex	mutex;
+	struct		delayed_work chg_work;
+	struct		delayed_work otg_sm_work;
 	struct		delayed_work sm_work;
 	const struct	rockchip_usb2phy_port_cfg *port_cfg;
+	struct notifier_block	event_nb;
+	enum usb_otg_state	state;
+	enum usb_dr_mode	mode;
 };
 
 /**
@@ -113,6 +205,11 @@ struct rockchip_usb2phy_port {
  * @clk: clock struct of phy input clk.
  * @clk480m: clock struct of phy output clk.
  * @clk_hw: clock struct of phy output clk management.
+ * @chg_state: states involved in USB charger detection.
+ * @chg_type: USB charger types.
+ * @dcd_retries: The retry count used to track Data contact
+ *		 detection process.
+ * @edev: extcon device for notification registration
  * @phy_cfg: phy register configuration, assigned by driver data.
  * @ports: phy port instance.
  */
@@ -122,6 +219,10 @@ struct rockchip_usb2phy {
 	struct clk	*clk;
 	struct clk	*clk480m;
 	struct clk_hw	clk480m_hw;
+	enum usb_chg_state	chg_state;
+	enum power_supply_type	chg_type;
+	u8			dcd_retries;
+	struct extcon_dev	*edev;
 	const struct rockchip_usb2phy_cfg	*phy_cfg;
 	struct rockchip_usb2phy_port	ports[USB2PHY_NUM_PORTS];
 };
@@ -263,33 +364,84 @@ rockchip_usb2phy_clk480m_register(struct rockchip_usb2phy *rphy)
 	return ret;
 }
 
-static int rockchip_usb2phy_init(struct phy *phy)
+static int rockchip_usb2phy_extcon_register(struct rockchip_usb2phy *rphy)
 {
-	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
-	struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent);
 	int ret;
+	struct device_node *node = rphy->dev->of_node;
+	struct extcon_dev *edev;
+
+	if (of_property_read_bool(node, "extcon")) {
+		edev = extcon_get_edev_by_phandle(rphy->dev, 0);
+		if (IS_ERR(edev)) {
+			if (PTR_ERR(edev) != -EPROBE_DEFER)
+				dev_err(rphy->dev, "Invalid or missing extcon\n");
+			return PTR_ERR(edev);
+		}
+	} else {
+		/* Initialize extcon device */
+		edev = devm_extcon_dev_allocate(rphy->dev,
+						rockchip_usb2phy_extcon_cable);
 
-	if (rport->port_id == USB2PHY_PORT_HOST) {
-		/* clear linestate and enable linestate detect irq */
-		mutex_lock(&rport->mutex);
+		if (IS_ERR(edev))
+			return -ENOMEM;
 
-		ret = property_enable(rphy, &rport->port_cfg->ls_det_clr, true);
+		ret = devm_extcon_dev_register(rphy->dev, edev);
 		if (ret) {
-			mutex_unlock(&rport->mutex);
+			dev_err(rphy->dev, "failed to register extcon device\n");
 			return ret;
 		}
+	}
 
-		ret = property_enable(rphy, &rport->port_cfg->ls_det_en, true);
-		if (ret) {
-			mutex_unlock(&rport->mutex);
-			return ret;
+	rphy->edev = edev;
+
+	return 0;
+}
+
+static int rockchip_usb2phy_init(struct phy *phy)
+{
+	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
+	struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent);
+	int ret = 0;
+
+	mutex_lock(&rport->mutex);
+
+	if (rport->port_id == USB2PHY_PORT_OTG) {
+		if (rport->mode != USB_DR_MODE_HOST) {
+			/* clear bvalid status and enable bvalid detect irq */
+			ret = property_enable(rphy,
+					      &rport->port_cfg->bvalid_det_clr,
+					      true);
+			if (ret)
+				goto out;
+
+			ret = property_enable(rphy,
+					      &rport->port_cfg->bvalid_det_en,
+					      true);
+			if (ret)
+				goto out;
+
+			schedule_delayed_work(&rport->otg_sm_work,
+					      OTG_SCHEDULE_DELAY);
+		} else {
+			/* If OTG works in host only mode, do nothing. */
+			dev_dbg(&rport->phy->dev, "mode %d\n", rport->mode);
 		}
+	} else if (rport->port_id == USB2PHY_PORT_HOST) {
+		/* clear linestate and enable linestate detect irq */
+		ret = property_enable(rphy, &rport->port_cfg->ls_det_clr, true);
+		if (ret)
+			goto out;
+
+		ret = property_enable(rphy, &rport->port_cfg->ls_det_en, true);
+		if (ret)
+			goto out;
 
-		mutex_unlock(&rport->mutex);
 		schedule_delayed_work(&rport->sm_work, SCHEDULE_DELAY);
 	}
 
-	return 0;
+out:
+	mutex_unlock(&rport->mutex);
+	return ret;
 }
 
 static int rockchip_usb2phy_power_on(struct phy *phy)
@@ -340,7 +492,11 @@ static int rockchip_usb2phy_exit(struct phy *phy)
 {
 	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
 
-	if (rport->port_id == USB2PHY_PORT_HOST)
+	if (rport->port_id == USB2PHY_PORT_OTG &&
+	    rport->mode != USB_DR_MODE_HOST) {
+		cancel_delayed_work_sync(&rport->otg_sm_work);
+		cancel_delayed_work_sync(&rport->chg_work);
+	} else if (rport->port_id == USB2PHY_PORT_HOST)
 		cancel_delayed_work_sync(&rport->sm_work);
 
 	return 0;
@@ -354,6 +510,249 @@ static const struct phy_ops rockchip_usb2phy_ops = {
 	.owner		= THIS_MODULE,
 };
 
+static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
+{
+	struct rockchip_usb2phy_port *rport =
+		container_of(work, struct rockchip_usb2phy_port,
+			     otg_sm_work.work);
+	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
+	static unsigned int cable;
+	unsigned long delay;
+	bool vbus_attach, sch_work, notify_charger;
+
+	if (rport->utmi_avalid)
+		vbus_attach =
+			property_enabled(rphy, &rport->port_cfg->utmi_avalid);
+	else
+		vbus_attach =
+			property_enabled(rphy, &rport->port_cfg->utmi_bvalid);
+
+	sch_work = false;
+	notify_charger = false;
+	delay = OTG_SCHEDULE_DELAY;
+	dev_dbg(&rport->phy->dev, "%s otg sm work\n",
+		usb_otg_state_string(rport->state));
+
+	switch (rport->state) {
+	case OTG_STATE_UNDEFINED:
+		rport->state = OTG_STATE_B_IDLE;
+		if (!vbus_attach)
+			rockchip_usb2phy_power_off(rport->phy);
+		/* fall through */
+	case OTG_STATE_B_IDLE:
+		if (extcon_get_cable_state_(rphy->edev, EXTCON_USB_HOST) > 0) {
+			dev_dbg(&rport->phy->dev, "usb otg host connect\n");
+			rport->state = OTG_STATE_A_HOST;
+			rockchip_usb2phy_power_on(rport->phy);
+			return;
+		} else if (vbus_attach) {
+			dev_dbg(&rport->phy->dev, "vbus_attach\n");
+			switch (rphy->chg_state) {
+			case USB_CHG_STATE_UNDEFINED:
+				schedule_delayed_work(&rport->chg_work, 0);
+				return;
+			case USB_CHG_STATE_DETECTED:
+				switch (rphy->chg_type) {
+				case POWER_SUPPLY_TYPE_USB:
+					dev_dbg(&rport->phy->dev,
+						"sdp cable is connecetd\n");
+					rockchip_usb2phy_power_on(rport->phy);
+					rport->state = OTG_STATE_B_PERIPHERAL;
+					notify_charger = true;
+					sch_work = true;
+					cable = EXTCON_CHG_USB_SDP;
+					break;
+				case POWER_SUPPLY_TYPE_USB_DCP:
+					dev_dbg(&rport->phy->dev,
+						"dcp cable is connecetd\n");
+					rockchip_usb2phy_power_off(rport->phy);
+					notify_charger = true;
+					sch_work = true;
+					cable = EXTCON_CHG_USB_DCP;
+					break;
+				case POWER_SUPPLY_TYPE_USB_CDP:
+					dev_dbg(&rport->phy->dev,
+						"cdp cable is connecetd\n");
+					rockchip_usb2phy_power_on(rport->phy);
+					rport->state = OTG_STATE_B_PERIPHERAL;
+					notify_charger = true;
+					sch_work = true;
+					cable = EXTCON_CHG_USB_CDP;
+					break;
+				default:
+					break;
+				}
+				break;
+			default:
+				break;
+			}
+		} else {
+			notify_charger = true;
+			rphy->chg_state = USB_CHG_STATE_UNDEFINED;
+			rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN;
+		}
+
+		if (rport->vbus_attached != vbus_attach) {
+			rport->vbus_attached = vbus_attach;
+
+			if (notify_charger && rphy->edev)
+				extcon_set_cable_state_(rphy->edev,
+							cable, vbus_attach);
+		}
+		break;
+	case OTG_STATE_B_PERIPHERAL:
+		if (!vbus_attach) {
+			dev_dbg(&rport->phy->dev, "usb disconnect\n");
+			rphy->chg_state = USB_CHG_STATE_UNDEFINED;
+			rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN;
+			rport->state = OTG_STATE_B_IDLE;
+			delay = 0;
+			rockchip_usb2phy_power_off(rport->phy);
+		}
+		sch_work = true;
+		break;
+	case OTG_STATE_A_HOST:
+		if (extcon_get_cable_state_(rphy->edev, EXTCON_USB_HOST) == 0) {
+			dev_dbg(&rport->phy->dev, "usb otg host disconnect\n");
+			rport->state = OTG_STATE_B_IDLE;
+			rockchip_usb2phy_power_off(rport->phy);
+		}
+		break;
+	default:
+		break;
+	}
+
+	if (sch_work)
+		schedule_delayed_work(&rport->otg_sm_work, delay);
+}
+
+static const char *chg_to_string(enum power_supply_type chg_type)
+{
+	switch (chg_type) {
+	case POWER_SUPPLY_TYPE_USB:
+		return "USB_SDP_CHARGER";
+	case POWER_SUPPLY_TYPE_USB_DCP:
+		return "USB_DCP_CHARGER";
+	case POWER_SUPPLY_TYPE_USB_CDP:
+		return "USB_CDP_CHARGER";
+	default:
+		return "INVALID_CHARGER";
+	}
+}
+
+static void rockchip_chg_enable_dcd(struct rockchip_usb2phy *rphy,
+				    bool en)
+{
+	property_enable(rphy, &rphy->phy_cfg->chg_det.rdm_pdwn_en, en);
+	property_enable(rphy, &rphy->phy_cfg->chg_det.idp_src_en, en);
+}
+
+static void rockchip_chg_enable_primary_det(struct rockchip_usb2phy *rphy,
+					    bool en)
+{
+	property_enable(rphy, &rphy->phy_cfg->chg_det.vdp_src_en, en);
+	property_enable(rphy, &rphy->phy_cfg->chg_det.idm_sink_en, en);
+}
+
+static void rockchip_chg_enable_secondary_det(struct rockchip_usb2phy *rphy,
+					      bool en)
+{
+	property_enable(rphy, &rphy->phy_cfg->chg_det.vdm_src_en, en);
+	property_enable(rphy, &rphy->phy_cfg->chg_det.idp_sink_en, en);
+}
+
+#define CHG_DCD_POLL_TIME	(100 * HZ / 1000)
+#define CHG_DCD_MAX_RETRIES	6
+#define CHG_PRIMARY_DET_TIME	(40 * HZ / 1000)
+#define CHG_SECONDARY_DET_TIME	(40 * HZ / 1000)
+static void rockchip_chg_detect_work(struct work_struct *work)
+{
+	struct rockchip_usb2phy_port *rport =
+		container_of(work, struct rockchip_usb2phy_port, chg_work.work);
+	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
+	bool is_dcd, tmout, vout;
+	unsigned long delay;
+
+	dev_dbg(&rport->phy->dev, "chg detection work state = %d\n",
+		rphy->chg_state);
+	switch (rphy->chg_state) {
+	case USB_CHG_STATE_UNDEFINED:
+		if (!rport->suspended)
+			rockchip_usb2phy_power_off(rport->phy);
+		/* put the controller in non-driving mode */
+		property_enable(rphy, &rphy->phy_cfg->chg_det.opmode, false);
+		/* Start DCD processing stage 1 */
+		rockchip_chg_enable_dcd(rphy, true);
+		rphy->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
+		rphy->dcd_retries = 0;
+		delay = CHG_DCD_POLL_TIME;
+		break;
+	case USB_CHG_STATE_WAIT_FOR_DCD:
+		/* get data contact detection status */
+		is_dcd = property_enabled(rphy, &rphy->phy_cfg->chg_det.dp_det);
+		tmout = ++rphy->dcd_retries == CHG_DCD_MAX_RETRIES;
+		/* stage 2 */
+		if (is_dcd || tmout) {
+			/* stage 4 */
+			/* Turn off DCD circuitry */
+			rockchip_chg_enable_dcd(rphy, false);
+			/* Voltage Source on DP, Probe on DM */
+			rockchip_chg_enable_primary_det(rphy, true);
+			delay = CHG_PRIMARY_DET_TIME;
+			rphy->chg_state = USB_CHG_STATE_DCD_DONE;
+		} else {
+			/* stage 3 */
+			delay = CHG_DCD_POLL_TIME;
+		}
+		break;
+	case USB_CHG_STATE_DCD_DONE:
+		vout = property_enabled(rphy, &rphy->phy_cfg->chg_det.cp_det);
+		rockchip_chg_enable_primary_det(rphy, false);
+		if (vout) {
+			/* Voltage Source on DM, Probe on DP  */
+			rockchip_chg_enable_secondary_det(rphy, true);
+			delay = CHG_SECONDARY_DET_TIME;
+			rphy->chg_state = USB_CHG_STATE_PRIMARY_DONE;
+		} else {
+			if (tmout) {
+				/* floating charger found */
+				rphy->chg_type = POWER_SUPPLY_TYPE_USB_DCP;
+				rphy->chg_state = USB_CHG_STATE_DETECTED;
+				delay = 0;
+			} else {
+				rphy->chg_type = POWER_SUPPLY_TYPE_USB;
+				rphy->chg_state = USB_CHG_STATE_DETECTED;
+				delay = 0;
+			}
+		}
+		break;
+	case USB_CHG_STATE_PRIMARY_DONE:
+		vout = property_enabled(rphy, &rphy->phy_cfg->chg_det.dcp_det);
+		/* Turn off voltage source */
+		rockchip_chg_enable_secondary_det(rphy, false);
+		if (vout)
+			rphy->chg_type = POWER_SUPPLY_TYPE_USB_DCP;
+		else
+			rphy->chg_type = POWER_SUPPLY_TYPE_USB_CDP;
+		/* fall through */
+	case USB_CHG_STATE_SECONDARY_DONE:
+		rphy->chg_state = USB_CHG_STATE_DETECTED;
+		delay = 0;
+		/* fall through */
+	case USB_CHG_STATE_DETECTED:
+		/* put the controller in normal mode */
+		property_enable(rphy, &rphy->phy_cfg->chg_det.opmode, true);
+		rockchip_usb2phy_otg_sm_work(&rport->otg_sm_work.work);
+		dev_info(&rport->phy->dev, "charger = %s\n",
+			 chg_to_string(rphy->chg_type));
+		return;
+	default:
+		return;
+	}
+
+	schedule_delayed_work(&rport->chg_work, delay);
+}
+
 /*
  * The function manage host-phy port state and suspend/resume phy port
  * to save power.
@@ -485,6 +884,26 @@ static irqreturn_t rockchip_usb2phy_linestate_irq(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t rockchip_usb2phy_bvalid_irq(int irq, void *data)
+{
+	struct rockchip_usb2phy_port *rport = data;
+	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
+
+	if (!property_enabled(rphy, &rport->port_cfg->bvalid_det_st))
+		return IRQ_NONE;
+
+	mutex_lock(&rport->mutex);
+
+	/* clear bvalid detect irq pending status */
+	property_enable(rphy, &rport->port_cfg->bvalid_det_clr, true);
+
+	mutex_unlock(&rport->mutex);
+
+	rockchip_usb2phy_otg_sm_work(&rport->otg_sm_work.work);
+
+	return IRQ_HANDLED;
+}
+
 static int rockchip_usb2phy_host_port_init(struct rockchip_usb2phy *rphy,
 					   struct rockchip_usb2phy_port *rport,
 					   struct device_node *child_np)
@@ -509,13 +928,86 @@ static int rockchip_usb2phy_host_port_init(struct rockchip_usb2phy *rphy,
 					IRQF_ONESHOT,
 					"rockchip_usb2phy", rport);
 	if (ret) {
-		dev_err(rphy->dev, "failed to request irq handle\n");
+		dev_err(rphy->dev, "failed to request linestate irq handle\n");
 		return ret;
 	}
 
 	return 0;
 }
 
+static int rockchip_otg_event(struct notifier_block *nb,
+			      unsigned long event, void *ptr)
+{
+	struct rockchip_usb2phy_port *rport =
+		container_of(nb, struct rockchip_usb2phy_port, event_nb);
+
+	schedule_delayed_work(&rport->otg_sm_work, OTG_SCHEDULE_DELAY);
+
+	return NOTIFY_DONE;
+}
+
+static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy,
+					  struct rockchip_usb2phy_port *rport,
+					  struct device_node *child_np)
+{
+	int ret;
+
+	rport->port_id = USB2PHY_PORT_OTG;
+	rport->port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_OTG];
+	rport->state = OTG_STATE_UNDEFINED;
+
+	/*
+	 * set suspended flag to true, but actually don't
+	 * put phy in suspend mode, it aims to enable usb
+	 * phy and clock in power_on() called by usb controller
+	 * driver during probe.
+	 */
+	rport->suspended = true;
+	rport->vbus_attached = false;
+
+	mutex_init(&rport->mutex);
+
+	rport->mode = of_usb_get_dr_mode_by_phy(child_np, -1);
+	if (rport->mode == USB_DR_MODE_HOST) {
+		ret = 0;
+		goto out;
+	}
+
+	INIT_DELAYED_WORK(&rport->chg_work, rockchip_chg_detect_work);
+	INIT_DELAYED_WORK(&rport->otg_sm_work, rockchip_usb2phy_otg_sm_work);
+
+	rport->utmi_avalid =
+		of_property_read_bool(child_np, "rockchip,utmi-avalid");
+
+	rport->bvalid_irq = of_irq_get_byname(child_np, "otg-bvalid");
+	if (rport->bvalid_irq < 0) {
+		dev_err(rphy->dev, "no vbus valid irq provided\n");
+		ret = rport->bvalid_irq;
+		goto out;
+	}
+
+	ret = devm_request_threaded_irq(rphy->dev, rport->bvalid_irq, NULL,
+					rockchip_usb2phy_bvalid_irq,
+					IRQF_ONESHOT,
+					"rockchip_usb2phy_bvalid", rport);
+	if (ret) {
+		dev_err(rphy->dev, "failed to request otg-bvalid irq handle\n");
+		goto out;
+	}
+
+	if (!IS_ERR(rphy->edev)) {
+		rport->event_nb.notifier_call = rockchip_otg_event;
+
+		ret = extcon_register_notifier(rphy->edev, EXTCON_USB_HOST,
+					       &rport->event_nb);
+		if (ret)
+			dev_err(rphy->dev, "register USB HOST notifier failed\n");
+	}
+
+out:
+	return ret;
+}
+
 static int rockchip_usb2phy_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -553,8 +1045,14 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev)
 
 	rphy->dev = dev;
 	phy_cfgs = match->data;
+	rphy->chg_state = USB_CHG_STATE_UNDEFINED;
+	rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN;
 	platform_set_drvdata(pdev, rphy);
 
+	ret = rockchip_usb2phy_extcon_register(rphy);
+	if (ret)
+		return ret;
+
 	/* find out a proper config which can be matched with dt. */
 	index = 0;
 	while (phy_cfgs[index].reg) {
@@ -591,13 +1089,9 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev)
 		struct rockchip_usb2phy_port *rport = &rphy->ports[index];
 		struct phy *phy;
 
-		/*
-		 * This driver aim to support both otg-port and host-port,
-		 * but unfortunately, the otg part is not ready in current,
-		 * so this comments and below codes are interim, which should
-		 * be changed after otg-port is supplied soon.
-		 */
-		if (of_node_cmp(child_np->name, "host-port"))
+		/* This driver aims to support both otg-port and host-port */
+		if (of_node_cmp(child_np->name, "host-port") &&
+		    of_node_cmp(child_np->name, "otg-port"))
 			goto next_child;
 
 		phy = devm_phy_create(dev, child_np, &rockchip_usb2phy_ops);
@@ -610,9 +1104,18 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev)
 		rport->phy = phy;
 		phy_set_drvdata(rport->phy, rport);
 
-		ret = rockchip_usb2phy_host_port_init(rphy, rport, child_np);
-		if (ret)
-			goto put_child;
+		/* initialize otg/host port separately */
+		if (!of_node_cmp(child_np->name, "host-port")) {
+			ret = rockchip_usb2phy_host_port_init(rphy, rport,
+							      child_np);
+			if (ret)
+				goto put_child;
+		} else {
+			ret = rockchip_usb2phy_otg_port_init(rphy, rport,
+							     child_np);
+			if (ret)
+				goto put_child;
+		}
 
 next_child:
 		/* to prevent out of boundary */
@@ -654,10 +1157,18 @@ static const struct rockchip_usb2phy_cfg rk3366_phy_cfgs[] = {
 
 static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = {
 	{
-		.reg = 0xe450,
+		.reg		= 0xe450,
 		.num_ports	= 2,
 		.clkout_ctl	= { 0xe450, 4, 4, 1, 0 },
 		.port_cfgs	= {
+			[USB2PHY_PORT_OTG] = {
+				.phy_sus	= { 0xe454, 1, 0, 2, 1 },
+				.bvalid_det_en	= { 0xe3c0, 3, 3, 0, 1 },
+				.bvalid_det_st	= { 0xe3e0, 3, 3, 0, 1 },
+				.bvalid_det_clr	= { 0xe3d0, 3, 3, 0, 1 },
+				.utmi_avalid	= { 0xe2ac, 7, 7, 0, 1 },
+				.utmi_bvalid	= { 0xe2ac, 12, 12, 0, 1 },
+			},
 			[USB2PHY_PORT_HOST] = {
 				.phy_sus	= { 0xe458, 1, 0, 0x2, 0x1 },
 				.ls_det_en	= { 0xe3c0, 6, 6, 0, 1 },
@@ -667,12 +1178,32 @@ static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = {
 				.utmi_hstdet	= { 0xe2ac, 23, 23, 0, 1 }
 			}
 		},
+		.chg_det = {
+			.opmode		= { 0xe454, 3, 0, 5, 1 },
+			.cp_det		= { 0xe2ac, 2, 2, 0, 1 },
+			.dcp_det	= { 0xe2ac, 1, 1, 0, 1 },
+			.dp_det		= { 0xe2ac, 0, 0, 0, 1 },
+			.idm_sink_en	= { 0xe450, 8, 8, 0, 1 },
+			.idp_sink_en	= { 0xe450, 7, 7, 0, 1 },
+			.idp_src_en	= { 0xe450, 9, 9, 0, 1 },
+			.rdm_pdwn_en	= { 0xe450, 10, 10, 0, 1 },
+			.vdm_src_en	= { 0xe450, 12, 12, 0, 1 },
+			.vdp_src_en	= { 0xe450, 11, 11, 0, 1 },
+		},
 	},
 	{
-		.reg = 0xe460,
+		.reg		= 0xe460,
 		.num_ports	= 2,
 		.clkout_ctl	= { 0xe460, 4, 4, 1, 0 },
 		.port_cfgs	= {
+			[USB2PHY_PORT_OTG] = {
+				.phy_sus        = { 0xe464, 1, 0, 2, 1 },
+				.bvalid_det_en  = { 0xe3c0, 8, 8, 0, 1 },
+				.bvalid_det_st  = { 0xe3e0, 8, 8, 0, 1 },
+				.bvalid_det_clr = { 0xe3d0, 8, 8, 0, 1 },
+				.utmi_avalid	= { 0xe2ac, 10, 10, 0, 1 },
+				.utmi_bvalid    = { 0xe2ac, 16, 16, 0, 1 },
+			},
 			[USB2PHY_PORT_HOST] = {
 				.phy_sus	= { 0xe468, 1, 0, 0x2, 0x1 },
 				.ls_det_en	= { 0xe3c0, 11, 11, 0, 1 },
-- 
2.0.0

^ permalink raw reply related

* [PATCH v3 2/2] arm64: dts: rockchip: add usb2-phy otg-port support for rk3399
From: William Wu @ 2016-11-07 12:08 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478520529-8869-1-git-send-email-wulf@rock-chips.com>

Add otg-port nodes for both u2phy0 and u2phy1. The otg-port can
be used for USB2.0 part of USB3.0 OTG controller.

Signed-off-by: William Wu <wulf@rock-chips.com>
---
Changes in v3:
- None

Changes in v2:
- None

 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index b65c193..ea2df51 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -1095,6 +1095,17 @@
 			clock-output-names = "clk_usbphy0_480m";
 			status = "disabled";
 
+			u2phy0_otg: otg-port {
+				#phy-cells = <0>;
+				interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH 0>,
+					     <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH 0>,
+					     <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH 0>;
+				interrupt-names = "otg-bvalid", "otg-id",
+						  "linestate";
+				status = "disabled";
+			};
+
+
 			u2phy0_host: host-port {
 				#phy-cells = <0>;
 				interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH 0>;
@@ -1112,6 +1123,16 @@
 			clock-output-names = "clk_usbphy1_480m";
 			status = "disabled";
 
+			u2phy1_otg: otg-port {
+				#phy-cells = <0>;
+				interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH 0>,
+					     <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH 0>,
+					     <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH 0>;
+				interrupt-names = "otg-bvalid", "otg-id",
+						  "linestate";
+				status = "disabled";
+			};
+
 			u2phy1_host: host-port {
 				#phy-cells = <0>;
 				interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH 0>;
-- 
2.0.0

^ permalink raw reply related

* [PATCH v2 0/2] mmc: sdhci-iproc: Add byte register access support
From: Ulf Hansson @ 2016-11-07 12:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478018277-10097-1-git-send-email-scott.branden@broadcom.com>

On 1 November 2016 at 17:37, Scott Branden <scott.branden@broadcom.com> wrote:
> Add brcm,sdhci-iproc compat string and code for support of newer versions of
> sdhci-iproc controller that allow byte-wise register accesses.
>
> Changes from v1:
> - added details to bindings documentation to clarify usage of brcm,sdhci-iproc
> compatibility string
>
> Scott Branden (2):
>   mmc: sdhci-iproc: Add brcm,sdhci-iproc compat string in bindings
>     document
>   mmc: sdhci-iproc: support standard byte register accesses
>
>  .../devicetree/bindings/mmc/brcm,sdhci-iproc.txt   |  9 ++++++
>  drivers/mmc/host/sdhci-iproc.c                     | 35 ++++++++++++++++++++--
>  2 files changed, 42 insertions(+), 2 deletions(-)
>
> --
> 2.5.0
>

It seems I had already applied v1 of this series. I have dropped those
now, waiting to receive an ack from Rob first.

Kind regards
Uffe

^ permalink raw reply

* imx6: PCIe imx6_pcie_assert_core_reset() hangs after watchdog reset
From: Fabio Estevam @ 2016-11-07 12:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478514883.12872.2.camel@pengutronix.de>

Hi Lucas,

On Mon, Nov 7, 2016 at 8:34 AM, Lucas Stach <l.stach@pengutronix.de> wrote:

> The problem is definitely present in current mainline Linux. I intent to
> remove this workaround from the kernel, but we need to make sure that
> the bootloader properly disables PCIe before jumping to the kernel
> image.
>
> I don't know what the status of this is in U-Boot, but Barebox already
> does this correctly.
>
> Fabio, would you mind to port this coed to U-Boot, or at least check if
> it does the right thing?

Sure, could you point me to the Barebox fix so I can take a look?

Thanks

^ permalink raw reply

* [PATCH v7 03/11] arm64: dts: r8a7795: salvator-x: Enable UHS-I SDR-104
From: Simon Horman @ 2016-11-07 12:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAMuHMdW8WMFMWzjr+KnrifbOgvJV3dZWxC3zVYMfSvd=L6KAsw@mail.gmail.com>

On Tue, Oct 25, 2016 at 12:48:40PM +0200, Geert Uytterhoeven wrote:
> On Tue, Sep 13, 2016 at 12:57 PM, Simon Horman
> <horms+renesas@verge.net.au> wrote:
> > Add the sd-uhs-sdr104 property to SDHI0 and SDHI1.
> 
> SDHI0 and SDHI3?

Thanks, I will fix that.

^ permalink raw reply

* [PATCH v7 11/11] arm64: dts: r8a7796: salvator-x: Enable UHS-I SDR-104
From: Simon Horman @ 2016-11-07 12:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAMuHMdVLAK0TKLoB07_U1XNW9kCOyen80gPrkaXOLqAq0=BA+Q@mail.gmail.com>

On Tue, Oct 25, 2016 at 12:49:42PM +0200, Geert Uytterhoeven wrote:
> On Tue, Sep 13, 2016 at 12:57 PM, Simon Horman
> <horms+renesas@verge.net.au> wrote:
> > Add the sd-uhs-sdr104 property to SDHI0 and SDHI1.
> 
> SDHI0 and SDHI3.

Thanks, I will fix that.

^ permalink raw reply

* [PATCH v2] ARM: DTS: r8a7794: alt: Fix PFC names for DU
From: Simon Horman @ 2016-11-07 12:40 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <c0a3c44b-545c-7af3-feed-857cb20ef698@cogentembedded.com>

On Fri, Nov 04, 2016 at 02:43:18PM +0300, Sergei Shtylyov wrote:
> Hello.
> 
> On 11/3/2016 10:34 PM, Jacopo Mondi wrote:
> 
> >Update the PFC pin groups and function names of DU interface for
> >r8a7794 ALT board.
> >
> >The currently specified pin groups and function names prevented PFC and
> >DU interfaces from being correctly configured:
> >
> >sh-pfc e6060000.pin-controller: function 'du' not supported
> >sh-pfc e6060000.pin-controller: invalid function du in map table
> >sh-pfc e6060000.pin-controller: function 'du' not supported
> >sh-pfc e6060000.pin-controller: invalid function du in map table
> >sh-pfc e6060000.pin-controller: function 'du' not supported
> >sh-pfc e6060000.pin-controller: invalid function du in map table
> >sh-pfc e6060000.pin-controller: function 'du' not supported
> >sh-pfc e6060000.pin-controller: invalid function du in map table
> >rcar-du: probe of feb00000.display failed with error -22
> >
> >Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> 
> Acked-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>

Thanks, I have queued this up.

^ permalink raw reply

* [PATCH] media: mtk-mdp: allocate video_device dynamically
From: Minghsiu Tsai @ 2016-11-07 12:42 UTC (permalink / raw)
  To: linux-arm-kernel

v4l2-compliance test output:
v4l2-compliance SHA   : abc1453dfe89f244dccd3460d8e1a2e3091cbadb

Driver Info:
        Driver name   : mtk-mdp
        Card type     : soc:mdp
        Bus info      : platform:mt8173
        Driver version: 4.9.0
        Capabilities  : 0x84204000
                Video Memory-to-Memory Multiplanar
                Streaming
                Extended Pix Format
                Device Capabilities
        Device Caps   : 0x04204000
                Video Memory-to-Memory Multiplanar
                Streaming
                Extended Pix Format

Compliance test for device /dev/image-proc0 (not using libv4l2):

Required ioctls:
        test VIDIOC_QUERYCAP: OK

Allow for multiple opens:
        test second video open: OK
        test VIDIOC_QUERYCAP: OK
        test VIDIOC_G/S_PRIORITY: OK
        test for unlimited opens: OK

Debug ioctls:
        test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
        test VIDIOC_LOG_STATUS: OK (Not Supported)

Input ioctls:
        test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
        test VIDIOC_ENUMAUDIO: OK (Not Supported)
        test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDIO: OK (Not Supported)
        Inputs: 0 Audio Inputs: 0 Tuners: 0

Output ioctls:
        test VIDIOC_G/S_MODULATOR: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_ENUMAUDOUT: OK (Not Supported)
        test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDOUT: OK (Not Supported)
        Outputs: 0 Audio Outputs: 0 Modulators: 0

Input/Output configuration ioctls:
        test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
        test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
        test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
        test VIDIOC_G/S_EDID: OK (Not Supported)

        Control ioctls:
                test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
                test VIDIOC_QUERYCTRL: OK
                test VIDIOC_G/S_CTRL: OK
                test VIDIOC_G/S/TRY_EXT_CTRLS: OK
                test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK
                test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
                Standard Controls: 5 Private Controls: 0

        Format ioctls:
                test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
                test VIDIOC_G/S_PARM: OK (Not Supported)
                test VIDIOC_G_FBUF: OK (Not Supported)
                test VIDIOC_G_FMT: OK
                test VIDIOC_TRY_FMT: OK
                test VIDIOC_S_FMT: OK
                test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
                test Cropping: OK
                test Composing: OK
                test Scaling: OK

        Codec ioctls:
                test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
                test VIDIOC_G_ENC_INDEX: OK (Not Supported)
                test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

        Buffer ioctls:
                test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
                test VIDIOC_EXPBUF: OK

Test input 0:


Total: 43, Succeeded: 43, Failed: 0, Warnings: 0

Minghsiu Tsai (1):
  [media] mtk-mdp: allocate video_device dynamically

 drivers/media/platform/mtk-mdp/mtk_mdp_core.h |  2 +-
 drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c  | 33 ++++++++++++++++-----------
 2 files changed, 21 insertions(+), 14 deletions(-)

-- 
1.9.1

^ permalink raw reply

* [PATCH] [media] mtk-mdp: allocate video_device dynamically
From: Minghsiu Tsai @ 2016-11-07 12:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478522529-57129-1-git-send-email-minghsiu.tsai@mediatek.com>

It can fix known problems with embedded video_device structs.

Signed-off-by: Minghsiu Tsai <minghsiu.tsai@mediatek.com>
---
 drivers/media/platform/mtk-mdp/mtk_mdp_core.h |  2 +-
 drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c  | 33 ++++++++++++++++-----------
 2 files changed, 21 insertions(+), 14 deletions(-)

diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.h b/drivers/media/platform/mtk-mdp/mtk_mdp_core.h
index 848569d..ad1cff3 100644
--- a/drivers/media/platform/mtk-mdp/mtk_mdp_core.h
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.h
@@ -167,7 +167,7 @@ struct mtk_mdp_dev {
 	struct mtk_mdp_comp		*comp[MTK_MDP_COMP_ID_MAX];
 	struct v4l2_m2m_dev		*m2m_dev;
 	struct list_head		ctx_list;
-	struct video_device		vdev;
+	struct video_device		*vdev;
 	struct v4l2_device		v4l2_dev;
 	struct workqueue_struct		*job_wq;
 	struct platform_device		*vpu_dev;
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
index 9a747e7..b8dee1c 100644
--- a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
@@ -1236,16 +1236,22 @@ int mtk_mdp_register_m2m_device(struct mtk_mdp_dev *mdp)
 	int ret;
 
 	mdp->variant = &mtk_mdp_default_variant;
-	mdp->vdev.device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
-	mdp->vdev.fops = &mtk_mdp_m2m_fops;
-	mdp->vdev.ioctl_ops = &mtk_mdp_m2m_ioctl_ops;
-	mdp->vdev.release = video_device_release_empty;
-	mdp->vdev.lock = &mdp->lock;
-	mdp->vdev.vfl_dir = VFL_DIR_M2M;
-	mdp->vdev.v4l2_dev = &mdp->v4l2_dev;
-	snprintf(mdp->vdev.name, sizeof(mdp->vdev.name), "%s:m2m",
+	mdp->vdev = video_device_alloc();
+	if (!mdp->vdev) {
+		dev_err(dev, "failed to allocate video device\n");
+		ret = -ENOMEM;
+		goto err_video_alloc;
+	}
+	mdp->vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
+	mdp->vdev->fops = &mtk_mdp_m2m_fops;
+	mdp->vdev->ioctl_ops = &mtk_mdp_m2m_ioctl_ops;
+	mdp->vdev->release = video_device_release;
+	mdp->vdev->lock = &mdp->lock;
+	mdp->vdev->vfl_dir = VFL_DIR_M2M;
+	mdp->vdev->v4l2_dev = &mdp->v4l2_dev;
+	snprintf(mdp->vdev->name, sizeof(mdp->vdev->name), "%s:m2m",
 		 MTK_MDP_MODULE_NAME);
-	video_set_drvdata(&mdp->vdev, mdp);
+	video_set_drvdata(mdp->vdev, mdp);
 
 	mdp->m2m_dev = v4l2_m2m_init(&mtk_mdp_m2m_ops);
 	if (IS_ERR(mdp->m2m_dev)) {
@@ -1254,26 +1260,27 @@ int mtk_mdp_register_m2m_device(struct mtk_mdp_dev *mdp)
 		goto err_m2m_init;
 	}
 
-	ret = video_register_device(&mdp->vdev, VFL_TYPE_GRABBER, 2);
+	ret = video_register_device(mdp->vdev, VFL_TYPE_GRABBER, 2);
 	if (ret) {
 		dev_err(dev, "failed to register video device\n");
 		goto err_vdev_register;
 	}
 
 	v4l2_info(&mdp->v4l2_dev, "driver registered as /dev/video%d",
-		  mdp->vdev.num);
+		  mdp->vdev->num);
 	return 0;
 
 err_vdev_register:
 	v4l2_m2m_release(mdp->m2m_dev);
 err_m2m_init:
-	video_device_release(&mdp->vdev);
+	video_unregister_device(mdp->vdev);
+err_video_alloc:
 
 	return ret;
 }
 
 void mtk_mdp_unregister_m2m_device(struct mtk_mdp_dev *mdp)
 {
-	video_device_release(&mdp->vdev);
+	video_unregister_device(mdp->vdev);
 	v4l2_m2m_release(mdp->m2m_dev);
 }
-- 
1.9.1

^ permalink raw reply related

* [PATCH 1/3 v2] mmc: mmci: clean up header defines
From: Ulf Hansson @ 2016-11-07 12:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1477386367-18514-1-git-send-email-linus.walleij@linaro.org>

On 25 October 2016 at 11:06, Linus Walleij <linus.walleij@linaro.org> wrote:
> There was some confusion in the CPSM (Command Path State Machine)
> and DPSM (Data Path State Machine) regarding the naming of the
> registers, clarify the meaning of this acronym so the naming is
> understandable, and consistently use BIT() to define these fields.
>
> Consequently name the register bit defines MCI_[C|D]PSM_* and
> adjust the driver as well.
>
> Include new definitions for a few bits found in a patch from
> Srinivas Kandagatla.
>
> Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

Thanks, applied for next!

Kind regards
Uffe

> ---
> ChangeLog v1->v2:
> - Use more consequent register naming.
> ---
>  drivers/mmc/host/mmci.c | 16 ++++++------
>  drivers/mmc/host/mmci.h | 69 +++++++++++++++++++++++++++----------------------
>  2 files changed, 46 insertions(+), 39 deletions(-)
>
> diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
> index df990bb8c873..6a8ea9c633d4 100644
> --- a/drivers/mmc/host/mmci.c
> +++ b/drivers/mmc/host/mmci.c
> @@ -137,7 +137,7 @@ static struct variant_data variant_u300 = {
>         .clkreg_enable          = MCI_ST_U300_HWFCEN,
>         .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
>         .datalength_bits        = 16,
> -       .datactrl_mask_sdio     = MCI_ST_DPSM_SDIOEN,
> +       .datactrl_mask_sdio     = MCI_DPSM_ST_SDIOEN,
>         .st_sdio                        = true,
>         .pwrreg_powerup         = MCI_PWR_ON,
>         .f_max                  = 100000000,
> @@ -152,7 +152,7 @@ static struct variant_data variant_nomadik = {
>         .clkreg                 = MCI_CLK_ENABLE,
>         .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
>         .datalength_bits        = 24,
> -       .datactrl_mask_sdio     = MCI_ST_DPSM_SDIOEN,
> +       .datactrl_mask_sdio     = MCI_DPSM_ST_SDIOEN,
>         .st_sdio                = true,
>         .st_clkdiv              = true,
>         .pwrreg_powerup         = MCI_PWR_ON,
> @@ -170,7 +170,7 @@ static struct variant_data variant_ux500 = {
>         .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
>         .clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE,
>         .datalength_bits        = 24,
> -       .datactrl_mask_sdio     = MCI_ST_DPSM_SDIOEN,
> +       .datactrl_mask_sdio     = MCI_DPSM_ST_SDIOEN,
>         .st_sdio                = true,
>         .st_clkdiv              = true,
>         .pwrreg_powerup         = MCI_PWR_ON,
> @@ -188,9 +188,9 @@ static struct variant_data variant_ux500v2 = {
>         .clkreg_enable          = MCI_ST_UX500_HWFCEN,
>         .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
>         .clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE,
> -       .datactrl_mask_ddrmode  = MCI_ST_DPSM_DDRMODE,
> +       .datactrl_mask_ddrmode  = MCI_DPSM_ST_DDRMODE,
>         .datalength_bits        = 24,
> -       .datactrl_mask_sdio     = MCI_ST_DPSM_SDIOEN,
> +       .datactrl_mask_sdio     = MCI_DPSM_ST_SDIOEN,
>         .st_sdio                = true,
>         .st_clkdiv              = true,
>         .blksz_datactrl16       = true,
> @@ -210,7 +210,7 @@ static struct variant_data variant_qcom = {
>                                   MCI_QCOM_CLK_SELECT_IN_FBCLK,
>         .clkreg_8bit_bus_enable = MCI_QCOM_CLK_WIDEBUS_8,
>         .datactrl_mask_ddrmode  = MCI_QCOM_CLK_SELECT_IN_DDR_MODE,
> -       .data_cmd_enable        = MCI_QCOM_CSPM_DATCMD,
> +       .data_cmd_enable        = MCI_CPSM_QCOM_DATCMD,
>         .blksz_datactrl4        = true,
>         .datalength_bits        = 24,
>         .pwrreg_powerup         = MCI_PWR_UP,
> @@ -295,7 +295,7 @@ static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr)
>  static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl)
>  {
>         /* Keep ST Micro busy mode if enabled */
> -       datactrl |= host->datactrl_reg & MCI_ST_DPSM_BUSYMODE;
> +       datactrl |= host->datactrl_reg & MCI_DPSM_ST_BUSYMODE;
>
>         if (host->datactrl_reg != datactrl) {
>                 host->datactrl_reg = datactrl;
> @@ -1614,7 +1614,7 @@ static int mmci_probe(struct amba_device *dev,
>
>         if (variant->busy_detect) {
>                 mmci_ops.card_busy = mmci_card_busy;
> -               mmci_write_datactrlreg(host, MCI_ST_DPSM_BUSYMODE);
> +               mmci_write_datactrlreg(host, MCI_DPSM_ST_BUSYMODE);
>                 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
>                 mmc->max_busy_timeout = 0;
>         }
> diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
> index a1f5e4f49e2a..7cabf270050b 100644
> --- a/drivers/mmc/host/mmci.h
> +++ b/drivers/mmc/host/mmci.h
> @@ -51,25 +51,27 @@
>  #define MCI_QCOM_CLK_SELECT_IN_DDR_MODE        (BIT(14) | BIT(15))
>
>  #define MMCIARGUMENT           0x008
> -#define MMCICOMMAND            0x00c
> -#define MCI_CPSM_RESPONSE      (1 << 6)
> -#define MCI_CPSM_LONGRSP       (1 << 7)
> -#define MCI_CPSM_INTERRUPT     (1 << 8)
> -#define MCI_CPSM_PENDING       (1 << 9)
> -#define MCI_CPSM_ENABLE                (1 << 10)
> -/* Argument flag extenstions in the ST Micro versions */
> -#define MCI_ST_SDIO_SUSP       (1 << 11)
> -#define MCI_ST_ENCMD_COMPL     (1 << 12)
> -#define MCI_ST_NIEN            (1 << 13)
> -#define MCI_ST_CE_ATACMD       (1 << 14)
>
> -/* Modified on Qualcomm Integrations */
> -#define MCI_QCOM_CSPM_DATCMD           BIT(12)
> -#define MCI_QCOM_CSPM_MCIABORT         BIT(13)
> -#define MCI_QCOM_CSPM_CCSENABLE                BIT(14)
> -#define MCI_QCOM_CSPM_CCSDISABLE       BIT(15)
> -#define MCI_QCOM_CSPM_AUTO_CMD19       BIT(16)
> -#define MCI_QCOM_CSPM_AUTO_CMD21       BIT(21)
> +/* The command register controls the Command Path State Machine (CPSM) */
> +#define MMCICOMMAND            0x00c
> +#define MCI_CPSM_RESPONSE      BIT(6)
> +#define MCI_CPSM_LONGRSP       BIT(7)
> +#define MCI_CPSM_INTERRUPT     BIT(8)
> +#define MCI_CPSM_PENDING       BIT(9)
> +#define MCI_CPSM_ENABLE                BIT(10)
> +/* Command register flag extenstions in the ST Micro versions */
> +#define MCI_CPSM_ST_SDIO_SUSP          BIT(11)
> +#define MCI_CPSM_ST_ENCMD_COMPL                BIT(12)
> +#define MCI_CPSM_ST_NIEN               BIT(13)
> +#define MCI_CPSM_ST_CE_ATACMD          BIT(14)
> +/* Command register flag extensions in the Qualcomm versions */
> +#define MCI_CPSM_QCOM_PROGENA          BIT(11)
> +#define MCI_CPSM_QCOM_DATCMD           BIT(12)
> +#define MCI_CPSM_QCOM_MCIABORT         BIT(13)
> +#define MCI_CPSM_QCOM_CCSENABLE                BIT(14)
> +#define MCI_CPSM_QCOM_CCSDISABLE       BIT(15)
> +#define MCI_CPSM_QCOM_AUTO_CMD19       BIT(16)
> +#define MCI_CPSM_QCOM_AUTO_CMD21       BIT(21)
>
>  #define MMCIRESPCMD            0x010
>  #define MMCIRESPONSE0          0x014
> @@ -78,22 +80,27 @@
>  #define MMCIRESPONSE3          0x020
>  #define MMCIDATATIMER          0x024
>  #define MMCIDATALENGTH         0x028
> +
> +/* The data control register controls the Data Path State Machine (DPSM) */
>  #define MMCIDATACTRL           0x02c
> -#define MCI_DPSM_ENABLE                (1 << 0)
> -#define MCI_DPSM_DIRECTION     (1 << 1)
> -#define MCI_DPSM_MODE          (1 << 2)
> -#define MCI_DPSM_DMAENABLE     (1 << 3)
> -#define MCI_DPSM_BLOCKSIZE     (1 << 4)
> +#define MCI_DPSM_ENABLE                BIT(0)
> +#define MCI_DPSM_DIRECTION     BIT(1)
> +#define MCI_DPSM_MODE          BIT(2)
> +#define MCI_DPSM_DMAENABLE     BIT(3)
> +#define MCI_DPSM_BLOCKSIZE     BIT(4)
>  /* Control register extensions in the ST Micro U300 and Ux500 versions */
> -#define MCI_ST_DPSM_RWSTART    (1 << 8)
> -#define MCI_ST_DPSM_RWSTOP     (1 << 9)
> -#define MCI_ST_DPSM_RWMOD      (1 << 10)
> -#define MCI_ST_DPSM_SDIOEN     (1 << 11)
> +#define MCI_DPSM_ST_RWSTART    BIT(8)
> +#define MCI_DPSM_ST_RWSTOP     BIT(9)
> +#define MCI_DPSM_ST_RWMOD      BIT(10)
> +#define MCI_DPSM_ST_SDIOEN     BIT(11)
>  /* Control register extensions in the ST Micro Ux500 versions */
> -#define MCI_ST_DPSM_DMAREQCTL  (1 << 12)
> -#define MCI_ST_DPSM_DBOOTMODEEN        (1 << 13)
> -#define MCI_ST_DPSM_BUSYMODE   (1 << 14)
> -#define MCI_ST_DPSM_DDRMODE    (1 << 15)
> +#define MCI_DPSM_ST_DMAREQCTL  BIT(12)
> +#define MCI_DPSM_ST_DBOOTMODEEN        BIT(13)
> +#define MCI_DPSM_ST_BUSYMODE   BIT(14)
> +#define MCI_DPSM_ST_DDRMODE    BIT(15)
> +/* Control register extensions in the Qualcomm versions */
> +#define MCI_DPSM_QCOM_DATA_PEND        BIT(17)
> +#define MCI_DPSM_QCOM_RX_DATA_PEND BIT(20)
>
>  #define MMCIDATACNT            0x030
>  #define MMCISTATUS             0x034
> --
> 2.7.4
>

^ permalink raw reply

* [PATCH 2/3 v2] mmc: mmci: refactor ST Micro busy detection
From: Ulf Hansson @ 2016-11-07 12:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1477386367-18514-2-git-send-email-linus.walleij@linaro.org>

On 25 October 2016 at 11:06, Linus Walleij <linus.walleij@linaro.org> wrote:
> The ST Micro-specific busy detection was made after the assumption
> that only this variant supports busy detection. So when doing busy
> detection, the host immediately tries to use some ST-specific
> register bits.
>
> Since the qualcomm variant also supports some busy detection
> schemes, encapsulate the variant flags better in the variant struct
> and prepare to add more variants by just providing some bitmasks
> to the logic.
>
> Put the entire busy detection logic within an if()-clause in the
> mmci_cmd_irq() function so the code is only executed when busy
> detection is enabled, and so that it is kept in (almost) one
> place, and add comments describing what is going on so the
> code can be understood.
>
> Tested on the Ux500 by introducing some prints in the busy
> detection path and noticing how the IRQ is enabled, used and
> disabled successfully.
>
> Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

Thanks, applied for next!

Kind regards
Uffe

> ---
> ChangeLog v1->v2:
> - Rebase on new register naming.
> ---
>  drivers/mmc/host/mmci.c | 113 +++++++++++++++++++++++++++++++++++-------------
>  drivers/mmc/host/mmci.h |   2 +-
>  2 files changed, 85 insertions(+), 30 deletions(-)
>
> diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
> index 6a8ea9c633d4..7f68fa7a961e 100644
> --- a/drivers/mmc/host/mmci.c
> +++ b/drivers/mmc/host/mmci.c
> @@ -71,7 +71,12 @@ static unsigned int fmax = 515633;
>   * @f_max: maximum clk frequency supported by the controller.
>   * @signal_direction: input/out direction of bus signals can be indicated
>   * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
> - * @busy_detect: true if busy detection on dat0 is supported
> + * @busy_detect: true if the variant supports busy detection on DAT0.
> + * @busy_dpsm_flag: bitmask enabling busy detection in the DPSM
> + * @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register
> + *                   indicating that the card is busy
> + * @busy_detect_mask: bitmask identifying the bit in the MMCIMASK0 to mask for
> + *                   getting busy end detection interrupts
>   * @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply
>   * @explicit_mclk_control: enable explicit mclk control in driver.
>   * @qcom_fifo: enables qcom specific fifo pio read logic.
> @@ -98,6 +103,9 @@ struct variant_data {
>         bool                    signal_direction;
>         bool                    pwrreg_clkgate;
>         bool                    busy_detect;
> +       u32                     busy_dpsm_flag;
> +       u32                     busy_detect_flag;
> +       u32                     busy_detect_mask;
>         bool                    pwrreg_nopower;
>         bool                    explicit_mclk_control;
>         bool                    qcom_fifo;
> @@ -178,6 +186,9 @@ static struct variant_data variant_ux500 = {
>         .signal_direction       = true,
>         .pwrreg_clkgate         = true,
>         .busy_detect            = true,
> +       .busy_dpsm_flag         = MCI_DPSM_ST_BUSYMODE,
> +       .busy_detect_flag       = MCI_ST_CARDBUSY,
> +       .busy_detect_mask       = MCI_ST_BUSYENDMASK,
>         .pwrreg_nopower         = true,
>  };
>
> @@ -199,6 +210,9 @@ static struct variant_data variant_ux500v2 = {
>         .signal_direction       = true,
>         .pwrreg_clkgate         = true,
>         .busy_detect            = true,
> +       .busy_dpsm_flag         = MCI_DPSM_ST_BUSYMODE,
> +       .busy_detect_flag       = MCI_ST_CARDBUSY,
> +       .busy_detect_mask       = MCI_ST_BUSYENDMASK,
>         .pwrreg_nopower         = true,
>  };
>
> @@ -220,6 +234,7 @@ static struct variant_data variant_qcom = {
>         .qcom_dml               = true,
>  };
>
> +/* Busy detection for the ST Micro variant */
>  static int mmci_card_busy(struct mmc_host *mmc)
>  {
>         struct mmci_host *host = mmc_priv(mmc);
> @@ -227,7 +242,7 @@ static int mmci_card_busy(struct mmc_host *mmc)
>         int busy = 0;
>
>         spin_lock_irqsave(&host->lock, flags);
> -       if (readl(host->base + MMCISTATUS) & MCI_ST_CARDBUSY)
> +       if (readl(host->base + MMCISTATUS) & host->variant->busy_detect_flag)
>                 busy = 1;
>         spin_unlock_irqrestore(&host->lock, flags);
>
> @@ -294,8 +309,8 @@ static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr)
>   */
>  static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl)
>  {
> -       /* Keep ST Micro busy mode if enabled */
> -       datactrl |= host->datactrl_reg & MCI_DPSM_ST_BUSYMODE;
> +       /* Keep busy mode in DPSM if enabled */
> +       datactrl |= host->datactrl_reg & host->variant->busy_dpsm_flag;
>
>         if (host->datactrl_reg != datactrl) {
>                 host->datactrl_reg = datactrl;
> @@ -973,37 +988,66 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
>              unsigned int status)
>  {
>         void __iomem *base = host->base;
> -       bool sbc, busy_resp;
> +       bool sbc;
>
>         if (!cmd)
>                 return;
>
>         sbc = (cmd == host->mrq->sbc);
> -       busy_resp = host->variant->busy_detect && (cmd->flags & MMC_RSP_BUSY);
>
> -       if (!((status|host->busy_status) & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|
> -               MCI_CMDSENT|MCI_CMDRESPEND)))
> +       /*
> +        * We need to be one of these interrupts to be considered worth
> +        * handling. Note that we tag on any latent IRQs postponed
> +        * due to waiting for busy status.
> +        */
> +       if (!((status|host->busy_status) &
> +             (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND)))
>                 return;
>
> -       /* Check if we need to wait for busy completion. */
> -       if (host->busy_status && (status & MCI_ST_CARDBUSY))
> -               return;
> +       /*
> +        * ST Micro variant: handle busy detection.
> +        */
> +       if (host->variant->busy_detect) {
> +               bool busy_resp = !!(cmd->flags & MMC_RSP_BUSY);
>
> -       /* Enable busy completion if needed and supported. */
> -       if (!host->busy_status && busy_resp &&
> -               !(status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT)) &&
> -               (readl(base + MMCISTATUS) & MCI_ST_CARDBUSY)) {
> -               writel(readl(base + MMCIMASK0) | MCI_ST_BUSYEND,
> -                       base + MMCIMASK0);
> -               host->busy_status = status & (MCI_CMDSENT|MCI_CMDRESPEND);
> -               return;
> -       }
> +               /* We are busy with a command, return */
> +               if (host->busy_status &&
> +                   (status & host->variant->busy_detect_flag))
> +                       return;
> +
> +               /*
> +                * We were not busy, but we now got a busy response on
> +                * something that was not an error, and we double-check
> +                * that the special busy status bit is still set before
> +                * proceeding.
> +                */
> +               if (!host->busy_status && busy_resp &&
> +                   !(status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT)) &&
> +                   (readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) {
> +                       /* Unmask the busy IRQ */
> +                       writel(readl(base + MMCIMASK0) |
> +                              host->variant->busy_detect_mask,
> +                              base + MMCIMASK0);
> +                       /*
> +                        * Now cache the last response status code (until
> +                        * the busy bit goes low), and return.
> +                        */
> +                       host->busy_status =
> +                               status & (MCI_CMDSENT|MCI_CMDRESPEND);
> +                       return;
> +               }
>
> -       /* At busy completion, mask the IRQ and complete the request. */
> -       if (host->busy_status) {
> -               writel(readl(base + MMCIMASK0) & ~MCI_ST_BUSYEND,
> -                       base + MMCIMASK0);
> -               host->busy_status = 0;
> +               /*
> +                * At this point we are not busy with a command, we have
> +                * not recieved a new busy request, mask the busy IRQ and
> +                * fall through to process the IRQ.
> +                */
> +               if (host->busy_status) {
> +                       writel(readl(base + MMCIMASK0) &
> +                              ~host->variant->busy_detect_mask,
> +                              base + MMCIMASK0);
> +                       host->busy_status = 0;
> +               }
>         }
>
>         host->cmd = NULL;
> @@ -1257,9 +1301,11 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
>                         mmci_data_irq(host, host->data, status);
>                 }
>
> -               /* Don't poll for busy completion in irq context. */
> -               if (host->busy_status)
> -                       status &= ~MCI_ST_CARDBUSY;
> +               /*
> +                * Don't poll for busy completion in irq context.
> +                */
> +               if (host->variant->busy_detect && host->busy_status)
> +                       status &= ~host->variant->busy_detect_flag;
>
>                 ret = 1;
>         } while (status);
> @@ -1612,9 +1658,18 @@ static int mmci_probe(struct amba_device *dev,
>         /* We support these capabilities. */
>         mmc->caps |= MMC_CAP_CMD23;
>
> +       /*
> +        * Enable busy detection.
> +        */
>         if (variant->busy_detect) {
>                 mmci_ops.card_busy = mmci_card_busy;
> -               mmci_write_datactrlreg(host, MCI_DPSM_ST_BUSYMODE);
> +               /*
> +                * Not all variants have a flag to enable busy detection
> +                * in the DPSM, but if they do, set it here.
> +                */
> +               if (variant->busy_dpsm_flag)
> +                       mmci_write_datactrlreg(host,
> +                                              host->variant->busy_dpsm_flag);
>                 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
>                 mmc->max_busy_timeout = 0;
>         }
> diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
> index 7cabf270050b..56322c6afba4 100644
> --- a/drivers/mmc/host/mmci.h
> +++ b/drivers/mmc/host/mmci.h
> @@ -174,7 +174,7 @@
>  /* Extended status bits for the ST Micro variants */
>  #define MCI_ST_SDIOITMASK      (1 << 22)
>  #define MCI_ST_CEATAENDMASK    (1 << 23)
> -#define MCI_ST_BUSYEND         (1 << 24)
> +#define MCI_ST_BUSYENDMASK     (1 << 24)
>
>  #define MMCIMASK1              0x040
>  #define MMCIFIFOCNT            0x048
> --
> 2.7.4
>

^ permalink raw reply

* [PATCH next 1/2] media: mtk-mdp: fix video_device_release argument
From: Minghsiu Tsai @ 2016-11-07 12:47 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <dbaa8b70-ea72-7d9b-176c-6c0a816aaae8@xs4all.nl>

On Thu, 2016-11-03 at 13:47 +0100, Hans Verkuil wrote:
> Hi Vincent,
> 
> On 28/10/16 09:52, Vincent Stehl? wrote:
> > On Thu, Oct 27, 2016 at 10:23:24PM +0200, Vincent Stehl? wrote:
> >> video_device_release() takes a pointer to struct video_device as argument.
> >> Fix two call sites where the address of the pointer is passed instead.
> >
> > Sorry, I messed up: please ignore that "fix". The 0day robot made me
> > realize this is indeed not a proper fix.
> >
> > The issue remains, though: we cannot call video_device_release() on the
> > vdev structure member, as this will in turn call kfree(). Most probably,
> > vdev needs to be dynamically allocated, or the call to
> > video_device_release() dropped completely.
> 
> I prefer that vdev is dynamically allocated. There are known problems with
> embedded video_device structs, so allocating it is preferred.
> 
> Minghsiu, can you do that?
> 

Hi Hans,

I just send the patch for this.
https://patchwork.kernel.org/patch/9415007/


> Regards,
> 
> 	Hans
> 
> >
> > Sorry for the bad patch.
> >
> > Best regards,
> >
> > Vincent.
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-media" in
> > the body of a message to majordomo at vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >

^ permalink raw reply

* [PATCH] ARM: tegra: nyan: Enable GPU node and related supply
From: Alexandre Courbot @ 2016-11-07 12:51 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <e95335ae-ad19-b8cd-634b-63c6a0b88e01@nvidia.com>

On Wed, Sep 21, 2016 at 4:57 PM, Jon Hunter <jonathanh@nvidia.com> wrote:
>
> On 20/09/16 19:17, Paul Kocialkowski wrote:
>> * PGP Signed by an unknown key
>>
>> Le mardi 20 septembre 2016 ? 13:24 +0100, Jon Hunter a ?crit :
>>> On 18/09/16 15:13, Paul Kocialkowski wrote:
>>>>
>>>> This enables the GPU node for tegra124 nyan boards, which is required to
>>>> get graphics acceleration with nouveau on these devices.
>>>>
>>>> Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
>>>> ---
>>>>  arch/arm/boot/dts/tegra124-nyan.dtsi | 8 +++++++-
>>>>  1 file changed, 7 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/arch/arm/boot/dts/tegra124-nyan.dtsi
>>>> b/arch/arm/boot/dts/tegra124-nyan.dtsi
>>>> index dab9509..225ca77 100644
>>>> --- a/arch/arm/boot/dts/tegra124-nyan.dtsi
>>>> +++ b/arch/arm/boot/dts/tegra124-nyan.dtsi
>>>> @@ -42,6 +42,12 @@
>>>>             };
>>>>     };
>>>>
>>>> +   gpu at 0,57000000 {
>>>> +           status = "okay";
>>>> +
>>>> +           vdd-supply = <&vdd_gpu>;
>>>> +   };
>>>> +
>>>>     serial at 70006000 {
>>>>             /* Debug connector on the bottom of the board near SD card.
>>>> */
>>>>             status = "okay";
>>>> @@ -214,7 +220,7 @@
>>>>                                     regulator-always-on;
>>>>                             };
>>>>
>>>> -                           sd6 {
>>>> +                           vdd_gpu: sd6 {
>>>>                                     regulator-name = "+VDD_GPU_AP";
>>>>                                     regulator-min-microvolt = <650000>;
>>>>                                     regulator-max-microvolt =
>>>> <1200000>;
>>>>
>>>
>>> Looks good to me. I see the following error when booting but looking at the
>>> code appears to be benign. Thierry, Alex, is this normal/okay?
>>
>> I have the same messages and asked Alexandre about them the other day. He told
>> me that it looks normal.
>
> Ok great. Hopefully, Alex can ACK then.

Apologies for the (very) delayed reply.

Yes, the messages you are seeing are part of the normal probe sequence
on Tegra. So this looks good to me.

Acked-by: Alexandre Courbot <acourbot@nvidia.com>

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox