From hverkuil at xs4all.nl  Fri Jul  1 03:11:51 2016
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Fri, 1 Jul 2016 12:11:51 +0200
Subject: [PATCH v3 0/9] Add MT8173 Video Decoder Driver
In-Reply-To: <20160616075428.0fde4aaa@recife.lan>
References: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
 <20160607112235.475c2e4c@recife.lan> <575746EE.3030706@cisco.com>
 <1465902488.27938.7.camel@mtksdaap41> <20160616075428.0fde4aaa@recife.lan>
Message-ID: <8a46c1e7-1f27-1e67-8c05-b133598b6a66@xs4all.nl>

On 06/16/2016 12:54 PM, Mauro Carvalho Chehab wrote:
> Em Tue, 14 Jun 2016 19:08:08 +0800
> tiffany lin <tiffany.lin at mediatek.com> escreveu:
> 
>> Hi Mauro,
>>
>>
>> On Wed, 2016-06-08 at 07:13 +0900, Hans Verkuil wrote:
>>>
>>> On 06/07/2016 11:22 PM, Mauro Carvalho Chehab wrote:  
>>>> Em Mon, 30 May 2016 20:29:14 +0800
>>>> Tiffany Lin <tiffany.lin at mediatek.com> escreveu:
>>>>  
>>>>> ==============
>>>>>   Introduction
>>>>> ==============
>>>>>
>>>>> The purpose of this series is to add the driver for video codec hw embedded in the Mediatek's MT8173 SoCs.
>>>>> Mediatek Video Codec is able to handle video decoding of in a range of formats.
>>>>>
>>>>> This patch series add Mediatek block format V4L2_PIX_FMT_MT21, the decoder driver will decoded bitstream to
>>>>> V4L2_PIX_FMT_MT21 format.
>>>>>
>>>>> This patch series rely on MTK VPU driver in patch series "Add MT8173 Video Encoder Driver and VPU Driver"[1]
>>>>> and patch "CHROMIUM: v4l: Add V4L2_PIX_FMT_VP9 definition"[2] for VP9 support.
>>>>> Mediatek Video Decoder driver rely on VPU driver to load, communicate with VPU.
>>>>>
>>>>> Internally the driver uses videobuf2 framework and MTK IOMMU and MTK SMI both have been merged in v4.6-rc1.
>>>>>
>>>>> [1]https://patchwork.linuxtv.org/patch/33734/
>>>>> [2]https://chromium-review.googlesource.com/#/c/245241/  
>>>>
>>>> Hmm... I'm not seeing the firmware for this driver at the
>>>> linux-firmware tree:
>>>> 	https://git.kernel.org/cgit/linux/kernel/git/firmware/linux-firmware.git/log/
>>>>
>>>> Nor I'm seeing any pull request for them. Did you send it?
>>>> I'll only merge the driver upstream after seeing such pull request.  
>>>   
>> Sorry, I am not familiar with how to upstream firmware.
>> Do you mean we need to upstream vpu firmware first before merge encoder
>> driver upstream?
> 
> Please look at this page:
> 	https://linuxtv.org/wiki/index.php/Development:_How_to_submit_patches#Firmware_submission
> 
> The information here can also be useful:
> 	https://www.kernel.org/doc/readme/firmware-README.AddingFirmware
> 
> In summary, you need to provide redistribution rights for the
> firmware blob. You can either submit it to me or directly to
> linux-firmware. In the latter, please c/c me on such patch.

Tiffany, what is the status of the firmware submission?

Regards,

	Hans


From wuchengli at chromium.org  Fri Jul  1 03:47:40 2016
From: wuchengli at chromium.org (=?UTF-8?B?V3UtQ2hlbmcgTGkgKOadjuWLmeiqoCk=?=)
Date: Fri, 1 Jul 2016 18:47:40 +0800
Subject: [PATCH v3 0/9] Add MT8173 Video Decoder Driver
In-Reply-To: <8a46c1e7-1f27-1e67-8c05-b133598b6a66@xs4all.nl>
References: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
 <20160607112235.475c2e4c@recife.lan> <575746EE.3030706@cisco.com>
 <1465902488.27938.7.camel@mtksdaap41> <20160616075428.0fde4aaa@recife.lan>
 <8a46c1e7-1f27-1e67-8c05-b133598b6a66@xs4all.nl>
Message-ID: <CAOMLVLgsB8mGdTZdn7dNQATFodqFPqmPH_yCn2+PKMYD2B+kYw@mail.gmail.com>

+Andrew. Last I heard the license was ready and Andrew was preparing
the VPU firmware. Andrew. Is the firmware ready to submit?

On Fri, Jul 1, 2016 at 6:11 PM, Hans Verkuil <hverkuil at xs4all.nl> wrote:
> On 06/16/2016 12:54 PM, Mauro Carvalho Chehab wrote:
>> Em Tue, 14 Jun 2016 19:08:08 +0800
>> tiffany lin <tiffany.lin at mediatek.com> escreveu:
>>
>>> Hi Mauro,
>>>
>>>
>>> On Wed, 2016-06-08 at 07:13 +0900, Hans Verkuil wrote:
>>>>
>>>> On 06/07/2016 11:22 PM, Mauro Carvalho Chehab wrote:
>>>>> Em Mon, 30 May 2016 20:29:14 +0800
>>>>> Tiffany Lin <tiffany.lin at mediatek.com> escreveu:
>>>>>
>>>>>> ==============
>>>>>>   Introduction
>>>>>> ==============
>>>>>>
>>>>>> The purpose of this series is to add the driver for video codec hw embedded in the Mediatek's MT8173 SoCs.
>>>>>> Mediatek Video Codec is able to handle video decoding of in a range of formats.
>>>>>>
>>>>>> This patch series add Mediatek block format V4L2_PIX_FMT_MT21, the decoder driver will decoded bitstream to
>>>>>> V4L2_PIX_FMT_MT21 format.
>>>>>>
>>>>>> This patch series rely on MTK VPU driver in patch series "Add MT8173 Video Encoder Driver and VPU Driver"[1]
>>>>>> and patch "CHROMIUM: v4l: Add V4L2_PIX_FMT_VP9 definition"[2] for VP9 support.
>>>>>> Mediatek Video Decoder driver rely on VPU driver to load, communicate with VPU.
>>>>>>
>>>>>> Internally the driver uses videobuf2 framework and MTK IOMMU and MTK SMI both have been merged in v4.6-rc1.
>>>>>>
>>>>>> [1]https://patchwork.linuxtv.org/patch/33734/
>>>>>> [2]https://chromium-review.googlesource.com/#/c/245241/
>>>>>
>>>>> Hmm... I'm not seeing the firmware for this driver at the
>>>>> linux-firmware tree:
>>>>>    https://git.kernel.org/cgit/linux/kernel/git/firmware/linux-firmware.git/log/
>>>>>
>>>>> Nor I'm seeing any pull request for them. Did you send it?
>>>>> I'll only merge the driver upstream after seeing such pull request.
>>>>
>>> Sorry, I am not familiar with how to upstream firmware.
>>> Do you mean we need to upstream vpu firmware first before merge encoder
>>> driver upstream?
>>
>> Please look at this page:
>>       https://linuxtv.org/wiki/index.php/Development:_How_to_submit_patches#Firmware_submission
>>
>> The information here can also be useful:
>>       https://www.kernel.org/doc/readme/firmware-README.AddingFirmware
>>
>> In summary, you need to provide redistribution rights for the
>> firmware blob. You can either submit it to me or directly to
>> linux-firmware. In the latter, please c/c me on such patch.
>
> Tiffany, what is the status of the firmware submission?
>
> Regards,
>
>         Hans
> --
> 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


From andrew-ct.chen at mediatek.com  Fri Jul  1 04:53:15 2016
From: andrew-ct.chen at mediatek.com (andrew-ct chen)
Date: Fri, 1 Jul 2016 19:53:15 +0800
Subject: [PATCH v3 0/9] Add MT8173 Video Decoder Driver
In-Reply-To: <8a46c1e7-1f27-1e67-8c05-b133598b6a66@xs4all.nl>
References: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
 <20160607112235.475c2e4c@recife.lan> <575746EE.3030706@cisco.com>
 <1465902488.27938.7.camel@mtksdaap41> <20160616075428.0fde4aaa@recife.lan>
 <8a46c1e7-1f27-1e67-8c05-b133598b6a66@xs4all.nl>
Message-ID: <1467373995.17297.2.camel@mtksdaap41>

On Fri, 2016-07-01 at 12:11 +0200, Hans Verkuil wrote:
> On 06/16/2016 12:54 PM, Mauro Carvalho Chehab wrote:
> > Em Tue, 14 Jun 2016 19:08:08 +0800
> > tiffany lin <tiffany.lin at mediatek.com> escreveu:
> > 
> >> Hi Mauro,
> >>
> >>
> >> On Wed, 2016-06-08 at 07:13 +0900, Hans Verkuil wrote:
> >>>
> >>> On 06/07/2016 11:22 PM, Mauro Carvalho Chehab wrote:  
> >>>> Em Mon, 30 May 2016 20:29:14 +0800
> >>>> Tiffany Lin <tiffany.lin at mediatek.com> escreveu:
> >>>>  
> >>>>> ==============
> >>>>>   Introduction
> >>>>> ==============
> >>>>>
> >>>>> The purpose of this series is to add the driver for video codec hw embedded in the Mediatek's MT8173 SoCs.
> >>>>> Mediatek Video Codec is able to handle video decoding of in a range of formats.
> >>>>>
> >>>>> This patch series add Mediatek block format V4L2_PIX_FMT_MT21, the decoder driver will decoded bitstream to
> >>>>> V4L2_PIX_FMT_MT21 format.
> >>>>>
> >>>>> This patch series rely on MTK VPU driver in patch series "Add MT8173 Video Encoder Driver and VPU Driver"[1]
> >>>>> and patch "CHROMIUM: v4l: Add V4L2_PIX_FMT_VP9 definition"[2] for VP9 support.
> >>>>> Mediatek Video Decoder driver rely on VPU driver to load, communicate with VPU.
> >>>>>
> >>>>> Internally the driver uses videobuf2 framework and MTK IOMMU and MTK SMI both have been merged in v4.6-rc1.
> >>>>>
> >>>>> [1]https://patchwork.linuxtv.org/patch/33734/
> >>>>> [2]https://chromium-review.googlesource.com/#/c/245241/  
> >>>>
> >>>> Hmm... I'm not seeing the firmware for this driver at the
> >>>> linux-firmware tree:
> >>>> 	https://git.kernel.org/cgit/linux/kernel/git/firmware/linux-firmware.git/log/
> >>>>
> >>>> Nor I'm seeing any pull request for them. Did you send it?
> >>>> I'll only merge the driver upstream after seeing such pull request.  
> >>>   
> >> Sorry, I am not familiar with how to upstream firmware.
> >> Do you mean we need to upstream vpu firmware first before merge encoder
> >> driver upstream?
> > 
> > Please look at this page:
> > 	https://linuxtv.org/wiki/index.php/Development:_How_to_submit_patches#Firmware_submission
> > 
> > The information here can also be useful:
> > 	https://www.kernel.org/doc/readme/firmware-README.AddingFirmware
> > 
> > In summary, you need to provide redistribution rights for the
> > firmware blob. You can either submit it to me or directly to
> > linux-firmware. In the latter, please c/c me on such patch.
> 
> Tiffany, what is the status of the firmware submission?
> 
> Regards,
> 
> 	Hans

Hi Hans,
We are working on firmware test to make sure that both decoder and
encoder work well. Hopes it can be ready (firmware submission) on July 4
or July 5.

Thanks.
Andrew

> 
> _______________________________________________
> Linux-mediatek mailing list
> Linux-mediatek at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-mediatek




From hverkuil at xs4all.nl  Fri Jul  1 05:00:54 2016
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Fri, 1 Jul 2016 14:00:54 +0200
Subject: [PATCH v3 0/9] Add MT8173 Video Decoder Driver
In-Reply-To: <1467373995.17297.2.camel@mtksdaap41>
References: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
 <20160607112235.475c2e4c@recife.lan> <575746EE.3030706@cisco.com>
 <1465902488.27938.7.camel@mtksdaap41> <20160616075428.0fde4aaa@recife.lan>
 <8a46c1e7-1f27-1e67-8c05-b133598b6a66@xs4all.nl>
 <1467373995.17297.2.camel@mtksdaap41>
Message-ID: <7ee128a2-f026-5404-bbac-6b5c1bee51e7@xs4all.nl>

On 07/01/2016 01:53 PM, andrew-ct chen wrote:
> On Fri, 2016-07-01 at 12:11 +0200, Hans Verkuil wrote:
>> On 06/16/2016 12:54 PM, Mauro Carvalho Chehab wrote:
>>> Em Tue, 14 Jun 2016 19:08:08 +0800
>>> tiffany lin <tiffany.lin at mediatek.com> escreveu:
>>>
>>>> Hi Mauro,
>>>>
>>>>
>>>> On Wed, 2016-06-08 at 07:13 +0900, Hans Verkuil wrote:
>>>>>
>>>>> On 06/07/2016 11:22 PM, Mauro Carvalho Chehab wrote:  
>>>>>> Em Mon, 30 May 2016 20:29:14 +0800
>>>>>> Tiffany Lin <tiffany.lin at mediatek.com> escreveu:
>>>>>>  
>>>>>>> ==============
>>>>>>>   Introduction
>>>>>>> ==============
>>>>>>>
>>>>>>> The purpose of this series is to add the driver for video codec hw embedded in the Mediatek's MT8173 SoCs.
>>>>>>> Mediatek Video Codec is able to handle video decoding of in a range of formats.
>>>>>>>
>>>>>>> This patch series add Mediatek block format V4L2_PIX_FMT_MT21, the decoder driver will decoded bitstream to
>>>>>>> V4L2_PIX_FMT_MT21 format.
>>>>>>>
>>>>>>> This patch series rely on MTK VPU driver in patch series "Add MT8173 Video Encoder Driver and VPU Driver"[1]
>>>>>>> and patch "CHROMIUM: v4l: Add V4L2_PIX_FMT_VP9 definition"[2] for VP9 support.
>>>>>>> Mediatek Video Decoder driver rely on VPU driver to load, communicate with VPU.
>>>>>>>
>>>>>>> Internally the driver uses videobuf2 framework and MTK IOMMU and MTK SMI both have been merged in v4.6-rc1.
>>>>>>>
>>>>>>> [1]https://patchwork.linuxtv.org/patch/33734/
>>>>>>> [2]https://chromium-review.googlesource.com/#/c/245241/  
>>>>>>
>>>>>> Hmm... I'm not seeing the firmware for this driver at the
>>>>>> linux-firmware tree:
>>>>>> 	https://git.kernel.org/cgit/linux/kernel/git/firmware/linux-firmware.git/log/
>>>>>>
>>>>>> Nor I'm seeing any pull request for them. Did you send it?
>>>>>> I'll only merge the driver upstream after seeing such pull request.  
>>>>>   
>>>> Sorry, I am not familiar with how to upstream firmware.
>>>> Do you mean we need to upstream vpu firmware first before merge encoder
>>>> driver upstream?
>>>
>>> Please look at this page:
>>> 	https://linuxtv.org/wiki/index.php/Development:_How_to_submit_patches#Firmware_submission
>>>
>>> The information here can also be useful:
>>> 	https://www.kernel.org/doc/readme/firmware-README.AddingFirmware
>>>
>>> In summary, you need to provide redistribution rights for the
>>> firmware blob. You can either submit it to me or directly to
>>> linux-firmware. In the latter, please c/c me on such patch.
>>
>> Tiffany, what is the status of the firmware submission?
>>
>> Regards,
>>
>> 	Hans
> 
> Hi Hans,
> We are working on firmware test to make sure that both decoder and
> encoder work well. Hopes it can be ready (firmware submission) on July 4
> or July 5.

OK, great! Just wanted to make sure that this work was progressing and not stalled.

Thanks!

	Hans


From dan.carpenter at oracle.com  Fri Jul  1 06:59:34 2016
From: dan.carpenter at oracle.com (Dan Carpenter)
Date: Fri, 1 Jul 2016 16:59:34 +0300
Subject: [patch] drm/mediatek/mtk_mipi_tx: checking the wrong variable
Message-ID: <20160701135934.GA15723@mwanda>

We should be checking "phy_provider" here not "phy".

Fixes: 2e54c14e310f ('drm/mediatek: Add DSI sub driver')
Signed-off-by: Dan Carpenter <dan.carpenter at oracle.com>

diff --git a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
index cf8f38d..1c366f8 100644
--- a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
+++ b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
@@ -431,7 +431,7 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev)
 	phy_set_drvdata(phy, mipi_tx);
 
 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
-	if (IS_ERR(phy)) {
+	if (IS_ERR(phy_provider)) {
 		ret = PTR_ERR(phy_provider);
 		return ret;
 	}


From tj at kernel.org  Fri Jul  1 09:09:42 2016
From: tj at kernel.org (Tejun Heo)
Date: Fri, 1 Jul 2016 11:09:42 -0500
Subject: [PATCH v2] PM / suspend: show workqueue state in suspend flow
In-Reply-To: <1467342302-16129-1-git-send-email-roger.lu@mediatek.com>
References: <1467342302-16129-1-git-send-email-roger.lu@mediatek.com>
Message-ID: <20160701160942.GC28719@htj.duckdns.org>

On Fri, Jul 01, 2016 at 11:05:02AM +0800, Roger Lu wrote:
> If freezable workqueue aborts suspend flow, show
> workqueue state for debug purpose.
> 
> Signed-off-by: Roger Lu <roger.lu at mediatek.com>

Acked-by: Tejun Heo <tj at kernel.org>

Rafael, can you please pick this on up?

Thanks.

-- 
tejun


From broonie at kernel.org  Fri Jul  1 09:11:05 2016
From: broonie at kernel.org (Mark Brown)
Date: Fri, 1 Jul 2016 18:11:05 +0200
Subject: [alsa-devel] [PATCH v5 7/9] ASoC: bt-sco: extend rate and add a
 general compatible string
In-Reply-To: <1467341386.21689.6.camel@mtksdaap41>
References: <1466149440-23889-1-git-send-email-garlic.tseng@mediatek.com>
 <1466149440-23889-8-git-send-email-garlic.tseng@mediatek.com>
 <20160629191500.GU6247@sirena.org.uk>
 <1467291345.11091.16.camel@mtksdaap41>
 <1467341386.21689.6.camel@mtksdaap41>
Message-ID: <20160701161105.GY6247@sirena.org.uk>

On Fri, Jul 01, 2016 at 10:49:46AM +0800, Garlic Tseng wrote:
> On Thu, 2016-06-30 at 20:55 +0800, Garlic Tseng wrote:

> > If you worry about some potential risk (I don't see any) maybe we have
> > to develop another dummy bt-sco codec driver which support both 8k and
> > 16k?

> Ah! If someone whose bluetooth modules only support 8k use the driver,
> they might be broken, right? Maybe we can add another snd_soc_dai_driver
> which can support both 8k and 16k.
> (Actually I found the issue is discussed before
> http://mailman.alsa-project.org/pipermail/alsa-devel/2014-November/084687.html )

Yes, that'd be fine - it could be the same driver and register different
parameters depending on config/compatible.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mediatek/attachments/20160701/c7971a12/attachment.sig>

From rjw at rjwysocki.net  Fri Jul  1 14:09:31 2016
From: rjw at rjwysocki.net (Rafael J. Wysocki)
Date: Fri, 01 Jul 2016 23:09:31 +0200
Subject: [PATCH v2] PM / suspend: show workqueue state in suspend flow
In-Reply-To: <20160701160942.GC28719@htj.duckdns.org>
References: <1467342302-16129-1-git-send-email-roger.lu@mediatek.com>
 <20160701160942.GC28719@htj.duckdns.org>
Message-ID: <2215954.JsBGX7yoLs@vostro.rjw.lan>

On Friday, July 01, 2016 11:09:42 AM Tejun Heo wrote:
> On Fri, Jul 01, 2016 at 11:05:02AM +0800, Roger Lu wrote:
> > If freezable workqueue aborts suspend flow, show
> > workqueue state for debug purpose.
> > 
> > Signed-off-by: Roger Lu <roger.lu at mediatek.com>
> 
> Acked-by: Tejun Heo <tj at kernel.org>
> 
> Rafael, can you please pick this on up?

I will.

Thanks,
Rafael



From sboyd at codeaurora.org  Fri Jul  1 18:21:40 2016
From: sboyd at codeaurora.org (Stephen Boyd)
Date: Fri, 1 Jul 2016 18:21:40 -0700
Subject: [PATCH v9 01/10] clk: fix initial state of critical clock's
 parents
In-Reply-To: <1466581229-2342-2-git-send-email-erin.lo@mediatek.com>
References: <1466581229-2342-1-git-send-email-erin.lo@mediatek.com>
 <1466581229-2342-2-git-send-email-erin.lo@mediatek.com>
Message-ID: <20160702012140.GB17071@codeaurora.org>

(Resending to everyone)

On 06/22, Erin Lo wrote:
> From: James Liao <jamesjj.liao at mediatek.com>
> 
> This patch fixed wrong state of parent clocks if they are registered
> after critical clocks.
> 
> Signed-off-by: James Liao <jamesjj.liao at mediatek.com>
> Signed-off-by: Erin Lo <erin.lo at mediatek.com>

It would be nice if you included the information about the
problem from James' previous mail. This says what it does, but
doesn't explain what the problem is and how it is fixing it.

> ---
>  drivers/clk/clk.c | 9 ++++++++-
>  1 file changed, 8 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index d584004..e9f5f89 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -2388,8 +2388,15 @@ static int __clk_core_init(struct clk_core *core)
>  	hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) {
>  		struct clk_core *parent = __clk_init_parent(orphan);
>  
> -		if (parent)
> +		if (parent) {
>  			clk_core_reparent(orphan, parent);
> +
> +			if (orphan->prepare_count)
> +				clk_core_prepare(parent);
> +
> +			if (orphan->enable_count)
> +				clk_core_enable(parent);
> +		}
>  	}

I'm pretty sure I pointed this problem out to Mike when the
critical clk patches were being pushed. I can't recall what the
plan was though to fix the problem. I'm pretty sure he said that
clk_core_reparent() would take care of it, but obviously it is
not doing that. Or perhaps it was that clk handoff should figure
out that the parents of a critical clk are also on and thus keep
them on.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


From john at phrozen.org  Fri Jul  1 23:00:50 2016
From: john at phrozen.org (John Crispin)
Date: Sat,  2 Jul 2016 08:00:50 +0200
Subject: [PATCH] net-next: mediatek: fix compile error inside
 mtk_poll_controller()
Message-ID: <1467439250-48222-1-git-send-email-john@phrozen.org>

commit 8067302973a1 ("net-next: mediatek: add support for IRQ grouping")
failed to properly update the irq handling inside mtk_poll_controller()
causing compile errors if netconsole was enabled. Fix this by updating
the code to use the new separated irq handler function for RX.

Signed-off-by: John Crispin <john at phrozen.org>

---

Hi Dave,

ideally you could fold this into the following patch inside net-next.git

commit 8067302973a1 ("net-next: mediatek: add support for IRQ grouping")

	John
---
 drivers/net/ethernet/mediatek/mtk_eth_soc.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 7056a37..fbab9b2 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -1297,7 +1297,7 @@ static void mtk_poll_controller(struct net_device *dev)
 	u32 int_mask = MTK_TX_DONE_INT | MTK_RX_DONE_INT;
 
 	mtk_irq_disable(eth, int_mask);
-	mtk_handle_irq(dev->irq[0], dev);
+	mtk_handle_irq_rx(eth->irq[2], dev);
 	mtk_irq_enable(eth, int_mask);
 }
 #endif
-- 
1.7.10.4



From wens at csie.org  Sat Jul  2 02:05:21 2016
From: wens at csie.org (Chen-Yu Tsai)
Date: Sat, 2 Jul 2016 17:05:21 +0800
Subject: [alsa-devel] [PATCH v5 7/9] ASoC: bt-sco: extend rate and add a
 general compatible string
In-Reply-To: <20160701161105.GY6247@sirena.org.uk>
References: <1466149440-23889-1-git-send-email-garlic.tseng@mediatek.com>
 <1466149440-23889-8-git-send-email-garlic.tseng@mediatek.com>
 <20160629191500.GU6247@sirena.org.uk> <1467291345.11091.16.camel@mtksdaap41>
 <1467341386.21689.6.camel@mtksdaap41> <20160701161105.GY6247@sirena.org.uk>
Message-ID: <CAGb2v67rgj4efyTZpZ-79NnCRM=KLJCJedte594qgSjMMB5xsQ@mail.gmail.com>

Hi,

On Sat, Jul 2, 2016 at 12:11 AM, Mark Brown <broonie at kernel.org> wrote:
> On Fri, Jul 01, 2016 at 10:49:46AM +0800, Garlic Tseng wrote:
>> On Thu, 2016-06-30 at 20:55 +0800, Garlic Tseng wrote:
>
>> > If you worry about some potential risk (I don't see any) maybe we have
>> > to develop another dummy bt-sco codec driver which support both 8k and
>> > 16k?
>
>> Ah! If someone whose bluetooth modules only support 8k use the driver,
>> they might be broken, right? Maybe we can add another snd_soc_dai_driver
>> which can support both 8k and 16k.
>> (Actually I found the issue is discussed before
>> http://mailman.alsa-project.org/pipermail/alsa-devel/2014-November/084687.html )
>
> Yes, that'd be fine - it could be the same driver and register different
> parameters depending on config/compatible.

Could we also make this driver directly configurable from Kconfig,
and not just selected by platforms (currently Samsung) or by building
all coddecs?

Thanks
ChenYu


From matthias.bgg at gmail.com  Sat Jul  2 09:33:35 2016
From: matthias.bgg at gmail.com (Matthias Brugger)
Date: Sat, 2 Jul 2016 18:33:35 +0200
Subject: [PATCH v7 1/4] soc: mediatek: Refine scpsys to support multiple
 platform
In-Reply-To: <1463390894-32062-2-git-send-email-jamesjj.liao@mediatek.com>
References: <1463390894-32062-1-git-send-email-jamesjj.liao@mediatek.com>
 <1463390894-32062-2-git-send-email-jamesjj.liao@mediatek.com>
Message-ID: <6762e420-0d68-0376-b584-bfc878b5e95f@gmail.com>



On 05/16/2016 11:28 AM, James Liao wrote:
> Refine scpsys driver common code to support multiple SoC / platform.
>
> Signed-off-by: James Liao <jamesjj.liao at mediatek.com>
> Reviewed-by: Kevin Hilman <khilman at baylibre.com>
> ---
>  drivers/soc/mediatek/mtk-scpsys.c | 363 +++++++++++++++++++++++---------------
>  1 file changed, 220 insertions(+), 143 deletions(-)
>
> diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
> index 57e781c..5870a24 100644
> --- a/drivers/soc/mediatek/mtk-scpsys.c
> +++ b/drivers/soc/mediatek/mtk-scpsys.c
> @@ -11,17 +11,15 @@
>   * GNU General Public License for more details.
>   */
>  #include <linux/clk.h>
> -#include <linux/delay.h>
> +#include <linux/init.h>
>  #include <linux/io.h>
> -#include <linux/kernel.h>
>  #include <linux/mfd/syscon.h>
> -#include <linux/init.h>
>  #include <linux/of_device.h>
>  #include <linux/platform_device.h>
>  #include <linux/pm_domain.h>
> -#include <linux/regmap.h>
> -#include <linux/soc/mediatek/infracfg.h>
>  #include <linux/regulator/consumer.h>
> +#include <linux/soc/mediatek/infracfg.h>
> +
>  #include <dt-bindings/power/mt8173-power.h>
>
>  #define SPM_VDE_PWR_CON			0x0210
> @@ -34,6 +32,7 @@
>  #define SPM_MFG_2D_PWR_CON		0x02c0
>  #define SPM_MFG_ASYNC_PWR_CON		0x02c4
>  #define SPM_USB_PWR_CON			0x02cc
> +
>  #define SPM_PWR_STATUS			0x060c
>  #define SPM_PWR_STATUS_2ND		0x0610
>
> @@ -55,12 +54,12 @@
>  #define PWR_STATUS_USB			BIT(25)
>
>  enum clk_id {
> -	MT8173_CLK_NONE,
> -	MT8173_CLK_MM,
> -	MT8173_CLK_MFG,
> -	MT8173_CLK_VENC,
> -	MT8173_CLK_VENC_LT,
> -	MT8173_CLK_MAX,
> +	CLK_NONE,
> +	CLK_MM,
> +	CLK_MFG,
> +	CLK_VENC,
> +	CLK_VENC_LT,
> +	CLK_MAX,
>  };
>
>  #define MAX_CLKS	2
> @@ -76,98 +75,6 @@ struct scp_domain_data {
>  	bool active_wakeup;
>  };
>
> -static const struct scp_domain_data scp_domain_data[] = {
> -	[MT8173_POWER_DOMAIN_VDEC] = {
> -		.name = "vdec",
> -		.sta_mask = PWR_STATUS_VDEC,
> -		.ctl_offs = SPM_VDE_PWR_CON,
> -		.sram_pdn_bits = GENMASK(11, 8),
> -		.sram_pdn_ack_bits = GENMASK(12, 12),
> -		.clk_id = {MT8173_CLK_MM},
> -	},
> -	[MT8173_POWER_DOMAIN_VENC] = {
> -		.name = "venc",
> -		.sta_mask = PWR_STATUS_VENC,
> -		.ctl_offs = SPM_VEN_PWR_CON,
> -		.sram_pdn_bits = GENMASK(11, 8),
> -		.sram_pdn_ack_bits = GENMASK(15, 12),
> -		.clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC},
> -	},
> -	[MT8173_POWER_DOMAIN_ISP] = {
> -		.name = "isp",
> -		.sta_mask = PWR_STATUS_ISP,
> -		.ctl_offs = SPM_ISP_PWR_CON,
> -		.sram_pdn_bits = GENMASK(11, 8),
> -		.sram_pdn_ack_bits = GENMASK(13, 12),
> -		.clk_id = {MT8173_CLK_MM},
> -	},
> -	[MT8173_POWER_DOMAIN_MM] = {
> -		.name = "mm",
> -		.sta_mask = PWR_STATUS_DISP,
> -		.ctl_offs = SPM_DIS_PWR_CON,
> -		.sram_pdn_bits = GENMASK(11, 8),
> -		.sram_pdn_ack_bits = GENMASK(12, 12),
> -		.clk_id = {MT8173_CLK_MM},
> -		.bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
> -			MT8173_TOP_AXI_PROT_EN_MM_M1,
> -	},
> -	[MT8173_POWER_DOMAIN_VENC_LT] = {
> -		.name = "venc_lt",
> -		.sta_mask = PWR_STATUS_VENC_LT,
> -		.ctl_offs = SPM_VEN2_PWR_CON,
> -		.sram_pdn_bits = GENMASK(11, 8),
> -		.sram_pdn_ack_bits = GENMASK(15, 12),
> -		.clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC_LT},
> -	},
> -	[MT8173_POWER_DOMAIN_AUDIO] = {
> -		.name = "audio",
> -		.sta_mask = PWR_STATUS_AUDIO,
> -		.ctl_offs = SPM_AUDIO_PWR_CON,
> -		.sram_pdn_bits = GENMASK(11, 8),
> -		.sram_pdn_ack_bits = GENMASK(15, 12),
> -		.clk_id = {MT8173_CLK_NONE},
> -	},
> -	[MT8173_POWER_DOMAIN_USB] = {
> -		.name = "usb",
> -		.sta_mask = PWR_STATUS_USB,
> -		.ctl_offs = SPM_USB_PWR_CON,
> -		.sram_pdn_bits = GENMASK(11, 8),
> -		.sram_pdn_ack_bits = GENMASK(15, 12),
> -		.clk_id = {MT8173_CLK_NONE},
> -		.active_wakeup = true,
> -	},
> -	[MT8173_POWER_DOMAIN_MFG_ASYNC] = {
> -		.name = "mfg_async",
> -		.sta_mask = PWR_STATUS_MFG_ASYNC,
> -		.ctl_offs = SPM_MFG_ASYNC_PWR_CON,
> -		.sram_pdn_bits = GENMASK(11, 8),
> -		.sram_pdn_ack_bits = 0,
> -		.clk_id = {MT8173_CLK_MFG},
> -	},
> -	[MT8173_POWER_DOMAIN_MFG_2D] = {
> -		.name = "mfg_2d",
> -		.sta_mask = PWR_STATUS_MFG_2D,
> -		.ctl_offs = SPM_MFG_2D_PWR_CON,
> -		.sram_pdn_bits = GENMASK(11, 8),
> -		.sram_pdn_ack_bits = GENMASK(13, 12),
> -		.clk_id = {MT8173_CLK_NONE},
> -	},
> -	[MT8173_POWER_DOMAIN_MFG] = {
> -		.name = "mfg",
> -		.sta_mask = PWR_STATUS_MFG,
> -		.ctl_offs = SPM_MFG_PWR_CON,
> -		.sram_pdn_bits = GENMASK(13, 8),
> -		.sram_pdn_ack_bits = GENMASK(21, 16),
> -		.clk_id = {MT8173_CLK_NONE},
> -		.bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
> -			MT8173_TOP_AXI_PROT_EN_MFG_M0 |
> -			MT8173_TOP_AXI_PROT_EN_MFG_M1 |
> -			MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT,
> -	},
> -};
> -
> -#define NUM_DOMAINS	ARRAY_SIZE(scp_domain_data)
> -
>  struct scp;
>
>  struct scp_domain {
> @@ -179,7 +86,7 @@ struct scp_domain {
>  };
>
>  struct scp {
> -	struct scp_domain domains[NUM_DOMAINS];
> +	struct scp_domain *domains;
>  	struct genpd_onecell_data pd_data;
>  	struct device *dev;
>  	void __iomem *base;
> @@ -408,57 +315,69 @@ static bool scpsys_active_wakeup(struct device *dev)
>  	return scpd->data->active_wakeup;
>  }
>
> -static int scpsys_probe(struct platform_device *pdev)
> +static void init_clks(struct platform_device *pdev, struct clk *clk[CLK_MAX])
> +{
> +	enum clk_id clk_ids[] = {
> +		CLK_MM,
> +		CLK_MFG,
> +		CLK_VENC,
> +		CLK_VENC_LT
> +	};
> +
> +	static const char * const clk_names[] = {
> +		"mm",
> +		"mfg",
> +		"venc",
> +		"venc_lt",
> +	};
> +
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(clk_ids); i++)
> +		clk[clk_ids[i]] = devm_clk_get(&pdev->dev, clk_names[i]);

We can use the global enum clk_id and stat with i = 1, right?

> +}
> +
> +static struct scp *init_scp(struct platform_device *pdev,
> +			const struct scp_domain_data *scp_domain_data, int num)
>  {
>  	struct genpd_onecell_data *pd_data;
>  	struct resource *res;
> -	int i, j, ret;
> +	int i, j;
>  	struct scp *scp;
> -	struct clk *clk[MT8173_CLK_MAX];
> +	struct clk *clk[CLK_MAX];
>
>  	scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL);
>  	if (!scp)
> -		return -ENOMEM;
> +		return ERR_PTR(-ENOMEM);
>
>  	scp->dev = &pdev->dev;
>
>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	scp->base = devm_ioremap_resource(&pdev->dev, res);
>  	if (IS_ERR(scp->base))
> -		return PTR_ERR(scp->base);
> -
> -	pd_data = &scp->pd_data;
> -
> -	pd_data->domains = devm_kzalloc(&pdev->dev,
> -			sizeof(*pd_data->domains) * NUM_DOMAINS, GFP_KERNEL);
> -	if (!pd_data->domains)
> -		return -ENOMEM;
> -
> -	clk[MT8173_CLK_MM] = devm_clk_get(&pdev->dev, "mm");
> -	if (IS_ERR(clk[MT8173_CLK_MM]))
> -		return PTR_ERR(clk[MT8173_CLK_MM]);
> -
> -	clk[MT8173_CLK_MFG] = devm_clk_get(&pdev->dev, "mfg");
> -	if (IS_ERR(clk[MT8173_CLK_MFG]))
> -		return PTR_ERR(clk[MT8173_CLK_MFG]);
> -
> -	clk[MT8173_CLK_VENC] = devm_clk_get(&pdev->dev, "venc");
> -	if (IS_ERR(clk[MT8173_CLK_VENC]))
> -		return PTR_ERR(clk[MT8173_CLK_VENC]);
> -
> -	clk[MT8173_CLK_VENC_LT] = devm_clk_get(&pdev->dev, "venc_lt");
> -	if (IS_ERR(clk[MT8173_CLK_VENC_LT]))
> -		return PTR_ERR(clk[MT8173_CLK_VENC_LT]);
> +		return ERR_CAST(scp->base);
>
>  	scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
>  			"infracfg");
>  	if (IS_ERR(scp->infracfg)) {
>  		dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n",
>  				PTR_ERR(scp->infracfg));
> -		return PTR_ERR(scp->infracfg);
> +		return ERR_CAST(scp->infracfg);
>  	}
>
> -	for (i = 0; i < NUM_DOMAINS; i++) {
> +	scp->domains = devm_kzalloc(&pdev->dev,
> +				sizeof(*scp->domains) * num, GFP_KERNEL);
> +	if (!scp->domains)
> +		return ERR_PTR(-ENOMEM);
> +
> +	pd_data = &scp->pd_data;
> +
> +	pd_data->domains = devm_kzalloc(&pdev->dev,
> +			sizeof(*pd_data->domains) * num, GFP_KERNEL);
> +	if (!pd_data->domains)
> +		return ERR_PTR(-ENOMEM);
> +
> +	for (i = 0; i < num; i++) {
>  		struct scp_domain *scpd = &scp->domains[i];
>  		const struct scp_domain_data *data = &scp_domain_data[i];
>
> @@ -467,28 +386,54 @@ static int scpsys_probe(struct platform_device *pdev)
>  			if (PTR_ERR(scpd->supply) == -ENODEV)
>  				scpd->supply = NULL;
>  			else
> -				return PTR_ERR(scpd->supply);
> +				return ERR_CAST(scpd->supply);
>  		}
>  	}
>
> -	pd_data->num_domains = NUM_DOMAINS;
> +	pd_data->num_domains = num;
>
> -	for (i = 0; i < NUM_DOMAINS; i++) {
> +	init_clks(pdev, clk);
> +
> +	for (i = 0; i < num; i++) {
>  		struct scp_domain *scpd = &scp->domains[i];
>  		struct generic_pm_domain *genpd = &scpd->genpd;
>  		const struct scp_domain_data *data = &scp_domain_data[i];
>
> +		for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
> +			struct clk *c = clk[data->clk_id[j]];
> +
> +			if (IS_ERR(c)) {
> +				dev_err(&pdev->dev, "%s: clk unavailable\n",
> +					data->name);
> +				return ERR_CAST(c);
> +			}
> +
> +			scpd->clk[j] = c;

Put this in the else branch. Apart from that is there any reason you 
moved the for up in the function? If not, I would prefer not to move it, 
to make it easier to read the diff.

Apart from that, the patch looks good to me.
Sorry for the delay in responding.

Matthias


From matthias.bgg at gmail.com  Sat Jul  2 09:35:41 2016
From: matthias.bgg at gmail.com (Matthias Brugger)
Date: Sat, 2 Jul 2016 18:35:41 +0200
Subject: [PATCH v7 2/4] soc: mediatek: Init MT8173 scpsys driver earlier
In-Reply-To: <1463390894-32062-3-git-send-email-jamesjj.liao@mediatek.com>
References: <1463390894-32062-1-git-send-email-jamesjj.liao@mediatek.com>
 <1463390894-32062-3-git-send-email-jamesjj.liao@mediatek.com>
Message-ID: <34025ec4-19d3-8b25-d669-50c6f19159cd@gmail.com>



On 05/16/2016 11:28 AM, James Liao wrote:
> Some power domain comsumers may init before module_init.
> So the power domain provider (scpsys) need to be initialized
> earlier too.
>
> Take an example for our IOMMU (M4U) and SMI. SMI is a bridge
> between IOMMU and multimedia HW. SMI is responsible to
> enable/disable iommu and help transfer data for each multimedia
> HW. Both of them have to wait until the power and clocks are
> enabled.
>
> So scpsys driver should be initialized before SMI, and SMI should
> be initialized before IOMMU, and then init IOMMU consumers
> (display/vdec/venc/camera etc.).
>
> IOMMU is subsys_init by default. So we need to init scpsys driver
> before subsys_init.
>
> Signed-off-by: James Liao <jamesjj.liao at mediatek.com>
> Reviewed-by: Kevin Hilman <khilman at baylibre.com>
> ---
>  drivers/soc/mediatek/mtk-scpsys.c | 19 ++++++++++++++++++-
>  1 file changed, 18 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
> index 5870a24..00c0adb 100644
> --- a/drivers/soc/mediatek/mtk-scpsys.c
> +++ b/drivers/soc/mediatek/mtk-scpsys.c
> @@ -617,4 +617,21 @@ static struct platform_driver scpsys_drv = {
>  		.of_match_table = of_match_ptr(of_scpsys_match_tbl),
>  	},
>  };
> -builtin_platform_driver(scpsys_drv);
> +
> +static int __init scpsys_drv_init(void)
> +{
> +	return platform_driver_register(&scpsys_drv);
> +}
> +
> +/*
> + * There are some Mediatek drivers which depend on the power domain driver need
> + * to probe in earlier initcall levels. So scpsys driver also need to probe
> + * earlier.
> + *
> + * IOMMU(M4U) and SMI drivers for example. SMI is a bridge between IOMMU and
> + * multimedia HW. IOMMU depends on SMI, and SMI is a power domain consumer,
> + * so the proper probe sequence should be scpsys -> SMI -> IOMMU driver.
> + * IOMMU drivers are initialized during subsys_init by default, so we need to
> + * move SMI and scpsys drivers to subsys_init or earlier init levels.
> + */
> +subsys_initcall(scpsys_drv_init);
>

Can't we achieve this with probe deferring? I'm not really keen on 
coding the order of the different drivers like this.

Regards,
Matthias


From matthias.bgg at gmail.com  Sat Jul  2 09:41:28 2016
From: matthias.bgg at gmail.com (Matthias Brugger)
Date: Sat, 2 Jul 2016 18:41:28 +0200
Subject: [PATCH v7 4/4] soc: mediatek: Add MT2701 scpsys driver
In-Reply-To: <1463390894-32062-5-git-send-email-jamesjj.liao@mediatek.com>
References: <1463390894-32062-1-git-send-email-jamesjj.liao@mediatek.com>
 <1463390894-32062-5-git-send-email-jamesjj.liao@mediatek.com>
Message-ID: <0ed4df8f-334a-e32d-e378-2ebdd80038e7@gmail.com>



On 05/16/2016 11:28 AM, James Liao wrote:
> From: Shunli Wang <shunli.wang at mediatek.com>
>
> Add scpsys driver for MT2701.
>
> mtk-scpsys now supports MT8173 (arm64) and MT2701 (arm). So it should
> be enabled on both arm64 and arm platforms.
>
> Signed-off-by: Shunli Wang <shunli.wang at mediatek.com>
> Signed-off-by: James Liao <jamesjj.liao at mediatek.com>
> Reviewed-by: Kevin Hilman <khilman at baylibre.com>
> ---
>  drivers/soc/mediatek/Kconfig      |   2 +-
>  drivers/soc/mediatek/mtk-scpsys.c | 117 +++++++++++++++++++++++++++++++++++++-
>  2 files changed, 116 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
> index 0a4ea80..609bb34 100644
> --- a/drivers/soc/mediatek/Kconfig
> +++ b/drivers/soc/mediatek/Kconfig
> @@ -23,7 +23,7 @@ config MTK_PMIC_WRAP
>  config MTK_SCPSYS
>  	bool "MediaTek SCPSYS Support"
>  	depends on ARCH_MEDIATEK || COMPILE_TEST
> -	default ARM64 && ARCH_MEDIATEK
> +	default ARCH_MEDIATEK
>  	select REGMAP
>  	select MTK_INFRACFG
>  	select PM_GENERIC_DOMAINS if PM
> diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
> index 00c0adb..f4d1230 100644
> --- a/drivers/soc/mediatek/mtk-scpsys.c
> +++ b/drivers/soc/mediatek/mtk-scpsys.c
> @@ -20,6 +20,7 @@
>  #include <linux/regulator/consumer.h>
>  #include <linux/soc/mediatek/infracfg.h>
>
> +#include <dt-bindings/power/mt2701-power.h>
>  #include <dt-bindings/power/mt8173-power.h>
>
>  #define SPM_VDE_PWR_CON			0x0210
> @@ -27,8 +28,13 @@
>  #define SPM_VEN_PWR_CON			0x0230
>  #define SPM_ISP_PWR_CON			0x0238
>  #define SPM_DIS_PWR_CON			0x023c
> +#define SPM_CONN_PWR_CON		0x0280
>  #define SPM_VEN2_PWR_CON		0x0298
> -#define SPM_AUDIO_PWR_CON		0x029c
> +#define SPM_AUDIO_PWR_CON		0x029c	/* MT8173 */
> +#define SPM_BDP_PWR_CON			0x029c	/* MT2701 */
> +#define SPM_ETH_PWR_CON			0x02a0
> +#define SPM_HIF_PWR_CON			0x02a4
> +#define SPM_IFR_MSC_PWR_CON		0x02a8
>  #define SPM_MFG_2D_PWR_CON		0x02c0
>  #define SPM_MFG_ASYNC_PWR_CON		0x02c4
>  #define SPM_USB_PWR_CON			0x02cc
> @@ -42,10 +48,15 @@
>  #define PWR_ON_2ND_BIT			BIT(3)
>  #define PWR_CLK_DIS_BIT			BIT(4)
>
> +#define PWR_STATUS_CONN			BIT(1)
>  #define PWR_STATUS_DISP			BIT(3)
>  #define PWR_STATUS_MFG			BIT(4)
>  #define PWR_STATUS_ISP			BIT(5)
>  #define PWR_STATUS_VDEC			BIT(7)
> +#define PWR_STATUS_BDP			BIT(14)
> +#define PWR_STATUS_ETH			BIT(15)
> +#define PWR_STATUS_HIF			BIT(16)
> +#define PWR_STATUS_IFR_MSC		BIT(17)
>  #define PWR_STATUS_VENC_LT		BIT(20)
>  #define PWR_STATUS_VENC			BIT(21)
>  #define PWR_STATUS_MFG_2D		BIT(22)
> @@ -59,6 +70,7 @@ enum clk_id {
>  	CLK_MFG,
>  	CLK_VENC,
>  	CLK_VENC_LT,
> +	CLK_ETHIF,
>  	CLK_MAX,
>  };
>
> @@ -321,7 +333,8 @@ static void init_clks(struct platform_device *pdev, struct clk *clk[CLK_MAX])
>  		CLK_MM,
>  		CLK_MFG,
>  		CLK_VENC,
> -		CLK_VENC_LT
> +		CLK_VENC_LT,
> +		CLK_ETHIF
>  	};
>
>  	static const char * const clk_names[] = {
> @@ -329,6 +342,7 @@ static void init_clks(struct platform_device *pdev, struct clk *clk[CLK_MAX])
>  		"mfg",
>  		"venc",
>  		"venc_lt",
> +		"ethif",
>  	};
>
>  	int i;
> @@ -459,6 +473,102 @@ static void mtk_register_power_domains(struct platform_device *pdev,
>  }
>
>  /*
> + * MT2701 power domain support
> + */
> +
> +static const struct scp_domain_data scp_domain_data_mt2701[] = {
> +	[MT2701_POWER_DOMAIN_CONN] = {
> +		.name = "conn",
> +		.sta_mask = PWR_STATUS_CONN,
> +		.ctl_offs = SPM_CONN_PWR_CON,
> +		.bus_prot_mask = 0x0104,
> +		.active_wakeup = true,

.clk_id = {CLK_NONE},

> +	},
> +	[MT2701_POWER_DOMAIN_DISP] = {
> +		.name = "disp",
> +		.sta_mask = PWR_STATUS_DISP,
> +		.ctl_offs = SPM_DIS_PWR_CON,
> +		.sram_pdn_bits = GENMASK(11, 8),
> +		.clk_id = {CLK_MM},
> +		.bus_prot_mask = 0x0002,
> +		.active_wakeup = true,
> +	},
> +	[MT2701_POWER_DOMAIN_MFG] = {
> +		.name = "mfg",
> +		.sta_mask = PWR_STATUS_MFG,
> +		.ctl_offs = SPM_MFG_PWR_CON,
> +		.sram_pdn_bits = GENMASK(11, 8),
> +		.sram_pdn_ack_bits = GENMASK(12, 12),
> +		.clk_id = {CLK_MFG},
> +		.active_wakeup = true,
> +	},
> +	[MT2701_POWER_DOMAIN_VDEC] = {
> +		.name = "vdec",
> +		.sta_mask = PWR_STATUS_VDEC,
> +		.ctl_offs = SPM_VDE_PWR_CON,
> +		.sram_pdn_bits = GENMASK(11, 8),
> +		.sram_pdn_ack_bits = GENMASK(12, 12),
> +		.clk_id = {CLK_MM},
> +		.active_wakeup = true,
> +	},
> +	[MT2701_POWER_DOMAIN_ISP] = {
> +		.name = "isp",
> +		.sta_mask = PWR_STATUS_ISP,
> +		.ctl_offs = SPM_ISP_PWR_CON,
> +		.sram_pdn_bits = GENMASK(11, 8),
> +		.sram_pdn_ack_bits = GENMASK(13, 12),
> +		.clk_id = {CLK_MM},
> +		.active_wakeup = true,
> +	},
> +	[MT2701_POWER_DOMAIN_BDP] = {
> +		.name = "bdp",
> +		.sta_mask = PWR_STATUS_BDP,
> +		.ctl_offs = SPM_BDP_PWR_CON,
> +		.sram_pdn_bits = GENMASK(11, 8),
> +		.active_wakeup = true,

same here.

> +	},
> +	[MT2701_POWER_DOMAIN_ETH] = {
> +		.name = "eth",
> +		.sta_mask = PWR_STATUS_ETH,
> +		.ctl_offs = SPM_ETH_PWR_CON,
> +		.sram_pdn_bits = GENMASK(11, 8),
> +		.sram_pdn_ack_bits = GENMASK(15, 12),
> +		.clk_id = {CLK_ETHIF},
> +		.active_wakeup = true,
> +	},
> +	[MT2701_POWER_DOMAIN_HIF] = {
> +		.name = "hif",
> +		.sta_mask = PWR_STATUS_HIF,
> +		.ctl_offs = SPM_HIF_PWR_CON,
> +		.sram_pdn_bits = GENMASK(11, 8),
> +		.sram_pdn_ack_bits = GENMASK(15, 12),
> +		.clk_id = {CLK_ETHIF},
> +		.active_wakeup = true,
> +	},
> +	[MT2701_POWER_DOMAIN_IFR_MSC] = {
> +		.name = "ifr_msc",
> +		.sta_mask = PWR_STATUS_IFR_MSC,
> +		.ctl_offs = SPM_IFR_MSC_PWR_CON,
> +		.active_wakeup = true,

same here.

regards,
Matthias

> +	},
> +};
> +
> +#define NUM_DOMAINS_MT2701	ARRAY_SIZE(scp_domain_data_mt2701)
> +
> +static int __init scpsys_probe_mt2701(struct platform_device *pdev)
> +{
> +	struct scp *scp;
> +
> +	scp = init_scp(pdev, scp_domain_data_mt2701, NUM_DOMAINS_MT2701);
> +	if (IS_ERR(scp))
> +		return PTR_ERR(scp);
> +
> +	mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT2701);
> +
> +	return 0;
> +}
> +
> +/*
>   * MT8173 power domain support
>   */
>
> @@ -587,6 +697,9 @@ static int __init scpsys_probe_mt8173(struct platform_device *pdev)
>
>  static const struct of_device_id of_scpsys_match_tbl[] = {
>  	{
> +		.compatible = "mediatek,mt2701-scpsys",
> +		.data = scpsys_probe_mt2701,
> +	}, {
>  		.compatible = "mediatek,mt8173-scpsys",
>  		.data = scpsys_probe_mt8173,
>  	}, {
>


From matthias.bgg at gmail.com  Sat Jul  2 09:44:13 2016
From: matthias.bgg at gmail.com (Matthias Brugger)
Date: Sat, 2 Jul 2016 18:44:13 +0200
Subject: [patch] drm/mediatek/mtk_mipi_tx: checking the wrong variable
In-Reply-To: <20160701135934.GA15723@mwanda>
References: <20160701135934.GA15723@mwanda>
Message-ID: <f665b4b4-c7b3-f07a-4185-fe551d334623@gmail.com>



On 07/01/2016 03:59 PM, Dan Carpenter wrote:
> We should be checking "phy_provider" here not "phy".
>
> Fixes: 2e54c14e310f ('drm/mediatek: Add DSI sub driver')
> Signed-off-by: Dan Carpenter <dan.carpenter at oracle.com>
>

Reviewed-by: Matthias Brugger <matthias.bgg at gmail.com>

> diff --git a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
> index cf8f38d..1c366f8 100644
> --- a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
> +++ b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
> @@ -431,7 +431,7 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev)
>  	phy_set_drvdata(phy, mipi_tx);
>
>  	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
> -	if (IS_ERR(phy)) {
> +	if (IS_ERR(phy_provider)) {
>  		ret = PTR_ERR(phy_provider);
>  		return ret;
>  	}
>


From davem at davemloft.net  Sat Jul  2 13:39:03 2016
From: davem at davemloft.net (David Miller)
Date: Sat, 02 Jul 2016 16:39:03 -0400 (EDT)
Subject: [PATCH] net-next: mediatek: fix compile error inside
 mtk_poll_controller()
In-Reply-To: <1467439250-48222-1-git-send-email-john@phrozen.org>
References: <1467439250-48222-1-git-send-email-john@phrozen.org>
Message-ID: <20160702.163903.1756164632554941051.davem@davemloft.net>

From: John Crispin <john at phrozen.org>
Date: Sat,  2 Jul 2016 08:00:50 +0200

> commit 8067302973a1 ("net-next: mediatek: add support for IRQ grouping")
> failed to properly update the irq handling inside mtk_poll_controller()
> causing compile errors if netconsole was enabled. Fix this by updating
> the code to use the new separated irq handler function for RX.
> 
> Signed-off-by: John Crispin <john at phrozen.org>

Applied.

> ideally you could fold this into the following patch inside net-next.git

There is no "folding" in my tree, commits are forever and history is
never changed or modified ever.


From christophe.jaillet at wanadoo.fr  Sat Jul  2 22:37:08 2016
From: christophe.jaillet at wanadoo.fr (Christophe JAILLET)
Date: Sun,  3 Jul 2016 07:37:08 +0200
Subject: [PATCH] drm/mediatek: fix error handling
Message-ID: <1467524228-12546-1-git-send-email-christophe.jaillet@wanadoo.fr>

This is likely that checking 'phy_provider' instead of 'phy' is
expected here.

Signed-off-by: Christophe JAILLET <christophe.jaillet at wanadoo.fr>
---
 drivers/gpu/drm/mediatek/mtk_mipi_tx.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
index cf8f38d..1c366f8 100644
--- a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
+++ b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
@@ -431,7 +431,7 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev)
 	phy_set_drvdata(phy, mipi_tx);
 
 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
-	if (IS_ERR(phy)) {
+	if (IS_ERR(phy_provider)) {
 		ret = PTR_ERR(phy_provider);
 		return ret;
 	}
-- 
2.7.4



From matthias.bgg at gmail.com  Sat Jul  2 22:51:31 2016
From: matthias.bgg at gmail.com (Matthias Brugger)
Date: Sun, 3 Jul 2016 07:51:31 +0200
Subject: [PATCH] drm/mediatek: fix error handling
In-Reply-To: <1467524228-12546-1-git-send-email-christophe.jaillet@wanadoo.fr>
References: <1467524228-12546-1-git-send-email-christophe.jaillet@wanadoo.fr>
Message-ID: <d49277ce-e45c-a706-0f3a-e0d6e5fc8891@gmail.com>



On 07/03/2016 07:37 AM, Christophe JAILLET wrote:
> This is likely that checking 'phy_provider' instead of 'phy' is
> expected here.
>
> Signed-off-by: Christophe JAILLET <christophe.jaillet at wanadoo.fr>
> ---
>  drivers/gpu/drm/mediatek/mtk_mipi_tx.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
> index cf8f38d..1c366f8 100644
> --- a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
> +++ b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
> @@ -431,7 +431,7 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev)
>  	phy_set_drvdata(phy, mipi_tx);
>
>  	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
> -	if (IS_ERR(phy)) {
> +	if (IS_ERR(phy_provider)) {

Dan already send a patch for that:
http://www.spinics.net/lists/dri-devel/msg112031.html

Regards,
Matthias

>  		ret = PTR_ERR(phy_provider);
>  		return ret;
>  	}
>


From matthias.bgg at gmail.com  Sat Jul  2 22:59:46 2016
From: matthias.bgg at gmail.com (Matthias Brugger)
Date: Sun, 3 Jul 2016 07:59:46 +0200
Subject: [PATCH v3 0/2] Add mt6755 basic chip support
In-Reply-To: <1467166173-9029-1-git-send-email-mars.cheng@mediatek.com>
References: <1467166173-9029-1-git-send-email-mars.cheng@mediatek.com>
Message-ID: <6516278a-4a21-3d67-bda2-ad861d56dd89@gmail.com>



On 06/29/2016 04:09 AM, Mars Cheng wrote:
> This patch adds basic support for Mediatek's new 8-core chip, mt6755.
> Based on 4.7-rc1
>
> Changes in v3:
> 1. use evb as project suffix
> 2. add "disable" property for uart dts nodes
> 3. only alias uart0 as serial0, since we don't enable uart1
> 4. confirm all acks are added
>
> Mars Cheng (2):
>   Document: DT: Add bindings for mediatek MT6755 SoC Platform
>   arm64: dts: mediatek: add mt6755 support
>

Applied, thanks.

Matthias

> Mars Cheng (2):
>   Document: DT: Add bindings for mediatek MT6755 SoC Platform
>   arm64: dts: mediatek: add mt6755 support
>
>  Documentation/devicetree/bindings/arm/mediatek.txt |    4 +
>  .../interrupt-controller/mediatek,sysirq.txt       |    1 +
>  .../devicetree/bindings/serial/mtk-uart.txt        |    1 +
>  arch/arm64/boot/dts/mediatek/Makefile              |    1 +
>  arch/arm64/boot/dts/mediatek/mt6755-evb.dts        |   38 +++++
>  arch/arm64/boot/dts/mediatek/mt6755.dtsi           |  145 ++++++++++++++++++++
>  6 files changed, 190 insertions(+)
>  create mode 100644 arch/arm64/boot/dts/mediatek/mt6755-evb.dts
>  create mode 100644 arch/arm64/boot/dts/mediatek/mt6755.dtsi
>
> --
> 1.7.9.5
>


From matthias.bgg at gmail.com  Sat Jul  2 23:24:30 2016
From: matthias.bgg at gmail.com (Matthias Brugger)
Date: Sun, 3 Jul 2016 08:24:30 +0200
Subject: [PATCH v4 5/5] ARM: dts: mt2701: add iommu/smi dtsi node for
 mt2701
In-Reply-To: <1465379461-14757-6-git-send-email-honghui.zhang@mediatek.com>
References: <1465379461-14757-1-git-send-email-honghui.zhang@mediatek.com>
 <1465379461-14757-6-git-send-email-honghui.zhang@mediatek.com>
Message-ID: <09eaf7a5-2b18-1ea6-5699-2e968c6b79a4@gmail.com>



On 06/08/2016 11:51 AM, honghui.zhang at mediatek.com wrote:
> From: Honghui Zhang <honghui.zhang at mediatek.com>
>
> Add the dtsi node of iommu and smi for mt2701.
>
> Signed-off-by: Honghui Zhang <honghui.zhang at mediatek.com>
> ---
>  arch/arm/boot/dts/mt2701.dtsi | 51 +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 51 insertions(+)
>

Applied,

Thanks.

> diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
> index 42d5a37..363de0d 100644
> --- a/arch/arm/boot/dts/mt2701.dtsi
> +++ b/arch/arm/boot/dts/mt2701.dtsi
> @@ -16,6 +16,7 @@
>  #include <dt-bindings/power/mt2701-power.h>
>  #include <dt-bindings/interrupt-controller/irq.h>
>  #include <dt-bindings/interrupt-controller/arm-gic.h>
> +#include <dt-bindings/memory/mt2701-larb-port.h>
>  #include "skeleton64.dtsi"
>  #include "mt2701-pinfunc.h"
>
> @@ -160,6 +161,16 @@
>  		clock-names = "system-clk", "rtc-clk";
>  	};
>
> +	smi_common: smi at 1000c000 {
> +		compatible = "mediatek,mt2701-smi-common";
> +		reg = <0 0x1000c000 0 0x1000>;
> +		clocks = <&infracfg CLK_INFRA_SMI>,
> +			 <&mmsys CLK_MM_SMI_COMMON>,
> +			 <&infracfg CLK_INFRA_SMI>;
> +		clock-names = "apb", "smi", "async";
> +		power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>;
> +	};
> +
>  	sysirq: interrupt-controller at 10200100 {
>  		compatible = "mediatek,mt2701-sysirq",
>  			     "mediatek,mt6577-sysirq";
> @@ -169,6 +180,16 @@
>  		reg = <0 0x10200100 0 0x1c>;
>  	};
>
> +	iommu: mmsys_iommu at 10205000 {
> +		compatible = "mediatek,mt2701-m4u";
> +		reg = <0 0x10205000 0 0x1000>;
> +		interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_LOW>;
> +		clocks = <&infracfg CLK_INFRA_M4U>;
> +		clock-names = "bclk";
> +		mediatek,larbs = <&larb0 &larb1 &larb2>;
> +		#iommu-cells = <1>;
> +	};
> +
>  	apmixedsys: syscon at 10209000 {
>  		compatible = "mediatek,mt2701-apmixedsys", "syscon";
>  		reg = <0 0x10209000 0 0x1000>;
> @@ -234,6 +255,16 @@
>  		status = "disabled";
>  	};
>
> +	larb0: larb at 14010000 {
> +		compatible = "mediatek,mt2701-smi-larb";
> +		reg = <0 0x14010000 0 0x1000>;
> +		mediatek,smi = <&smi_common>;
> +		clocks = <&mmsys CLK_MM_SMI_LARB0>,
> +			 <&mmsys CLK_MM_SMI_LARB0>;
> +		clock-names = "apb", "smi";
> +		power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>;
> +	};
> +
>  	imgsys: syscon at 15000000 {
>  		compatible = "mediatek,mt2701-imgsys", "syscon";
>  		reg = <0 0x15000000 0 0x1000>;
> @@ -241,6 +272,16 @@
>  		status = "disabled";
>  	};
>
> +	larb2: larb at 15001000 {
> +		compatible = "mediatek,mt2701-smi-larb";
> +		reg = <0 0x15001000 0 0x1000>;
> +		mediatek,smi = <&smi_common>;
> +		clocks = <&imgsys CLK_IMG_SMI_COMM>,
> +			 <&imgsys CLK_IMG_SMI_COMM>;
> +		clock-names = "apb", "smi";
> +		power-domains = <&scpsys MT2701_POWER_DOMAIN_ISP>;
> +	};
> +
>  	vdecsys: syscon at 16000000 {
>  		compatible = "mediatek,mt2701-vdecsys", "syscon";
>  		reg = <0 0x16000000 0 0x1000>;
> @@ -248,6 +289,16 @@
>  		status = "disabled";
>  	};
>
> +	larb1: larb at 16010000 {
> +		compatible = "mediatek,mt2701-smi-larb";
> +		reg = <0 0x16010000 0 0x1000>;
> +		mediatek,smi = <&smi_common>;
> +		clocks = <&vdecsys CLK_VDEC_CKGEN>,
> +			 <&vdecsys CLK_VDEC_LARB>;
> +		clock-names = "apb", "smi";
> +		power-domains = <&scpsys MT2701_POWER_DOMAIN_VDEC>;
> +	};
> +
>  	hifsys: syscon at 1a000000 {
>  		compatible = "mediatek,mt2701-hifsys", "syscon";
>  		reg = <0 0x1a000000 0 0x1000>;
>


From matthias.bgg at gmail.com  Sat Jul  2 23:47:19 2016
From: matthias.bgg at gmail.com (Matthias Brugger)
Date: Sun, 3 Jul 2016 08:47:19 +0200
Subject: ARM: mediatek: dts 64 bit updates for v4.8
Message-ID: <8e60cf93-062d-368a-f2e0-58c747bb34ca@gmail.com>

Hi all,

Please merge the following updates for arm64 device tree branch.

Thanks,
Matthias

---

The following changes since commit 1a695a905c18548062509178b98bc91e67510864:

   Linux 4.7-rc1 (2016-05-29 09:29:24 -0700)

are available in the git repository at:

   https://github.com/mbgg/linux-mediatek.git tags/v4.7-next-dts

for you to fetch changes up to aea1c315b6395920bbeb69804e0355e57c67e086:

   arm64: dts: mediatek: add mt6755 support (2016-07-03 07:57:21 +0200)

----------------------------------------------------------------
- Add nodes for the DISP function ports
- Add dt-bindings for mt6755
- Add basic support for mt6755 SoC

----------------------------------------------------------------
CK Hu (1):
       arm64: dts: mt8173: Add display subsystem related nodes

Mars Cheng (2):
       Document: DT: Add bindings for mediatek MT6755 SoC Platform
       arm64: dts: mediatek: add mt6755 support

  Documentation/devicetree/bindings/arm/mediatek.txt |   4 +
  .../interrupt-controller/mediatek,sysirq.txt       |   1 +
  .../devicetree/bindings/serial/mtk-uart.txt        |   1 +
  arch/arm64/boot/dts/mediatek/Makefile              |   1 +
  arch/arm64/boot/dts/mediatek/mt6755-evb.dts        |  38 ++++
  arch/arm64/boot/dts/mediatek/mt6755.dtsi           | 145 ++++++++++++++
  arch/arm64/boot/dts/mediatek/mt8173.dtsi           | 223 
+++++++++++++++++++++
  7 files changed, 413 insertions(+)
  create mode 100644 arch/arm64/boot/dts/mediatek/mt6755-evb.dts
  create mode 100644 arch/arm64/boot/dts/mediatek/mt6755.dtsi


From matthias.bgg at gmail.com  Sat Jul  2 23:49:29 2016
From: matthias.bgg at gmail.com (Matthias Brugger)
Date: Sun, 3 Jul 2016 08:49:29 +0200
Subject: ARM: mediatek: dts 32 bits updates for v4.8
Message-ID: <94a90d0c-f459-296c-4290-739515b4ac5b@gmail.com>

Hi all,

Please take into account the following dts patch for arm 32 bits.

Thanks,
Matthias

---

The following changes since commit 1a695a905c18548062509178b98bc91e67510864:

   Linux 4.7-rc1 (2016-05-29 09:29:24 -0700)

are available in the git repository at:

   https://github.com/mbgg/linux-mediatek.git tags/v4.7-next-dts32

for you to fetch changes up to 6f108172f13c311ce2175fab25fbd50940a3622b:

   ARM: dts: mt2701: add iommu/smi dtsi node for mt2701 (2016-07-03 
08:25:08 +0200)

----------------------------------------------------------------
- Add dtsi parts for iommu support

----------------------------------------------------------------
Honghui Zhang (1):
       ARM: dts: mt2701: add iommu/smi dtsi node for mt2701

  arch/arm/boot/dts/mt2701.dtsi | 50 
+++++++++++++++++++++++++++++++++++++++++++
  1 file changed, 50 insertions(+)


From matthias.bgg at gmail.com  Sun Jul  3 12:08:40 2016
From: matthias.bgg at gmail.com (Matthias Brugger)
Date: Sun, 3 Jul 2016 21:08:40 +0200
Subject: ARM: mediatek: dts 32 bits updates for v4.8
In-Reply-To: <94a90d0c-f459-296c-4290-739515b4ac5b@gmail.com>
References: <94a90d0c-f459-296c-4290-739515b4ac5b@gmail.com>
Message-ID: <98233d90-47ef-88f7-e474-c1fa04a65c04@gmail.com>



On 07/03/2016 08:49 AM, Matthias Brugger wrote:
> Hi all,
>
> Please take into account the following dts patch for arm 32 bits.
>

The patch causes a compilation error, please don't pull this branch.

Sorry for the noise,
Matthias

> Thanks,
> Matthias
>
> ---
>
> The following changes since commit
> 1a695a905c18548062509178b98bc91e67510864:
>
>   Linux 4.7-rc1 (2016-05-29 09:29:24 -0700)
>
> are available in the git repository at:
>
>   https://github.com/mbgg/linux-mediatek.git tags/v4.7-next-dts32
>
> for you to fetch changes up to 6f108172f13c311ce2175fab25fbd50940a3622b:
>
>   ARM: dts: mt2701: add iommu/smi dtsi node for mt2701 (2016-07-03
> 08:25:08 +0200)
>
> ----------------------------------------------------------------
> - Add dtsi parts for iommu support
>
> ----------------------------------------------------------------
> Honghui Zhang (1):
>       ARM: dts: mt2701: add iommu/smi dtsi node for mt2701
>
>  arch/arm/boot/dts/mt2701.dtsi | 50
> +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 50 insertions(+)


From matthias.bgg at gmail.com  Sun Jul  3 12:12:11 2016
From: matthias.bgg at gmail.com (Matthias Brugger)
Date: Sun, 3 Jul 2016 21:12:11 +0200
Subject: [PATCH v4 5/5] ARM: dts: mt2701: add iommu/smi dtsi node for
 mt2701
In-Reply-To: <09eaf7a5-2b18-1ea6-5699-2e968c6b79a4@gmail.com>
References: <1465379461-14757-1-git-send-email-honghui.zhang@mediatek.com>
 <1465379461-14757-6-git-send-email-honghui.zhang@mediatek.com>
 <09eaf7a5-2b18-1ea6-5699-2e968c6b79a4@gmail.com>
Message-ID: <51441f39-e5b5-2cce-63ab-47bd3cf298b3@gmail.com>



On 07/03/2016 08:24 AM, Matthias Brugger wrote:
>
>
> On 06/08/2016 11:51 AM, honghui.zhang at mediatek.com wrote:
>> From: Honghui Zhang <honghui.zhang at mediatek.com>
>>
>> Add the dtsi node of iommu and smi for mt2701.
>>
>> Signed-off-by: Honghui Zhang <honghui.zhang at mediatek.com>
>> ---
>>  arch/arm/boot/dts/mt2701.dtsi | 51
>> +++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 51 insertions(+)
>>
>
> Applied,

Please resend the patch including the infracfg and mmsys node.

Regards,
Matthias

>
> Thanks.
>
>> diff --git a/arch/arm/boot/dts/mt2701.dtsi
>> b/arch/arm/boot/dts/mt2701.dtsi
>> index 42d5a37..363de0d 100644
>> --- a/arch/arm/boot/dts/mt2701.dtsi
>> +++ b/arch/arm/boot/dts/mt2701.dtsi
>> @@ -16,6 +16,7 @@
>>  #include <dt-bindings/power/mt2701-power.h>
>>  #include <dt-bindings/interrupt-controller/irq.h>
>>  #include <dt-bindings/interrupt-controller/arm-gic.h>
>> +#include <dt-bindings/memory/mt2701-larb-port.h>
>>  #include "skeleton64.dtsi"
>>  #include "mt2701-pinfunc.h"
>>
>> @@ -160,6 +161,16 @@
>>          clock-names = "system-clk", "rtc-clk";
>>      };
>>
>> +    smi_common: smi at 1000c000 {
>> +        compatible = "mediatek,mt2701-smi-common";
>> +        reg = <0 0x1000c000 0 0x1000>;
>> +        clocks = <&infracfg CLK_INFRA_SMI>,
>> +             <&mmsys CLK_MM_SMI_COMMON>,
>> +             <&infracfg CLK_INFRA_SMI>;
>> +        clock-names = "apb", "smi", "async";
>> +        power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>;
>> +    };
>> +
>>      sysirq: interrupt-controller at 10200100 {
>>          compatible = "mediatek,mt2701-sysirq",
>>                   "mediatek,mt6577-sysirq";
>> @@ -169,6 +180,16 @@
>>          reg = <0 0x10200100 0 0x1c>;
>>      };
>>
>> +    iommu: mmsys_iommu at 10205000 {
>> +        compatible = "mediatek,mt2701-m4u";
>> +        reg = <0 0x10205000 0 0x1000>;
>> +        interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_LOW>;
>> +        clocks = <&infracfg CLK_INFRA_M4U>;
>> +        clock-names = "bclk";
>> +        mediatek,larbs = <&larb0 &larb1 &larb2>;
>> +        #iommu-cells = <1>;
>> +    };
>> +
>>      apmixedsys: syscon at 10209000 {
>>          compatible = "mediatek,mt2701-apmixedsys", "syscon";
>>          reg = <0 0x10209000 0 0x1000>;
>> @@ -234,6 +255,16 @@
>>          status = "disabled";
>>      };
>>
>> +    larb0: larb at 14010000 {
>> +        compatible = "mediatek,mt2701-smi-larb";
>> +        reg = <0 0x14010000 0 0x1000>;
>> +        mediatek,smi = <&smi_common>;
>> +        clocks = <&mmsys CLK_MM_SMI_LARB0>,
>> +             <&mmsys CLK_MM_SMI_LARB0>;
>> +        clock-names = "apb", "smi";
>> +        power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>;
>> +    };
>> +
>>      imgsys: syscon at 15000000 {
>>          compatible = "mediatek,mt2701-imgsys", "syscon";
>>          reg = <0 0x15000000 0 0x1000>;
>> @@ -241,6 +272,16 @@
>>          status = "disabled";
>>      };
>>
>> +    larb2: larb at 15001000 {
>> +        compatible = "mediatek,mt2701-smi-larb";
>> +        reg = <0 0x15001000 0 0x1000>;
>> +        mediatek,smi = <&smi_common>;
>> +        clocks = <&imgsys CLK_IMG_SMI_COMM>,
>> +             <&imgsys CLK_IMG_SMI_COMM>;
>> +        clock-names = "apb", "smi";
>> +        power-domains = <&scpsys MT2701_POWER_DOMAIN_ISP>;
>> +    };
>> +
>>      vdecsys: syscon at 16000000 {
>>          compatible = "mediatek,mt2701-vdecsys", "syscon";
>>          reg = <0 0x16000000 0 0x1000>;
>> @@ -248,6 +289,16 @@
>>          status = "disabled";
>>      };
>>
>> +    larb1: larb at 16010000 {
>> +        compatible = "mediatek,mt2701-smi-larb";
>> +        reg = <0 0x16010000 0 0x1000>;
>> +        mediatek,smi = <&smi_common>;
>> +        clocks = <&vdecsys CLK_VDEC_CKGEN>,
>> +             <&vdecsys CLK_VDEC_LARB>;
>> +        clock-names = "apb", "smi";
>> +        power-domains = <&scpsys MT2701_POWER_DOMAIN_VDEC>;
>> +    };
>> +
>>      hifsys: syscon at 1a000000 {
>>          compatible = "mediatek,mt2701-hifsys", "syscon";
>>          reg = <0 0x1a000000 0 0x1000>;
>>


From emil.l.velikov at gmail.com  Sun Jul  3 15:43:46 2016
From: emil.l.velikov at gmail.com (Emil Velikov)
Date: Sun, 3 Jul 2016 23:43:46 +0100
Subject: [GIT PULL] drm/mediatek: MT8173 gamma & dither support
In-Reply-To: <1467026970.23883.16.camel@mtksdaap41>
References: <1466753238-17216-1-git-send-email-bibby.hsieh@mediatek.com>
 <558c9efc-d197-a6c3-cf7e-f9fcac60ca64@gmail.com>
 <1467026970.23883.16.camel@mtksdaap41>
Message-ID: <CACvgo52YgRat8Uqhd9qh_ppvk0h=krxYLHL6Cjqs9+EzQaogUg@mail.gmail.com>

Hi Bibby,

On 27 June 2016 at 12:29, Bibby Hsieh <bibby.hsieh at mediatek.com> wrote:
> On Mon, 2016-06-27 at 12:20 +0200, Matthias Brugger wrote:
>>
>> On 06/24/2016 09:27 AM, Bibby Hsieh wrote:
>> > Hi Dave,
>> >
>> > Please consider merging this tag, which contains the v2 MT8173 gamma & dither function patches I sent on 2016-06-17, rebased onto v4.7-rc1. There have been no further comments.
>> >
>> > Thanks
>> > Bibby
>> >
>> > The following changes since commit 1a695a905c18548062509178b98bc91e67510864:
>> >
>> >   Linux 4.7-rc1 (2016-05-29 16:29:24 GMT)
>> >
>> > are available in the git repository at:
>> >
>> >   git at github.com:BibbyHsieh/linux4.7-rc1.git
>> >
>> > for you to fetch changes up to dd0eb773bc125f5e6bca735d19c08500dc3730f9:
>> >
>> >   drm/mediatek: Add gamma correction
>> >
>> > -------------------------------------------------------------------------
>>
>> As far as I can see, your branch has 3 patches on top from Eddie. It
>> seems to me as if you didn't send your patches to the mailinglist before?
>> Anyway this branch does not fulfill the rules to get merged into the
>> linux kernel.
>>
>> Why do you send a pull request? The normal process is to send the
>> patches via email and if the maintainer wants you can send a pull
>> request once the patches are ready to be merged.
>>
>> Regards,
>> Matthias
>>
>
> I sent v1 and v2 on 2016-06-14 and 06-17 respectively [0-8].
> After I made some modifications according to Daniel Vetter's comments,
> there had been no further comments and I sent the pull request as the
> other sub-sys.
>
> I'm sorry for my mistake, I will re-arrange the tree for upstream.
> Next time, I will check with maintainer by email first, and sent the
> pull request.
>
It might be a bit hard to find out who's the maintainer considering
MAINTAINERS has no entry for this driver.

Looking at how things are going Philipp Zabel will be the more likely
person for the task, yet I would be nice if someone from the Mediatek
squad is helping him out - CK Hu perhaps ?

Regards,
Emil


From honghui.zhang at mediatek.com  Sun Jul  3 18:32:30 2016
From: honghui.zhang at mediatek.com (Honghui Zhang)
Date: Mon, 4 Jul 2016 09:32:30 +0800
Subject: [PATCH v4 5/5] ARM: dts: mt2701: add iommu/smi dtsi node for
 mt2701
In-Reply-To: <51441f39-e5b5-2cce-63ab-47bd3cf298b3@gmail.com>
References: <1465379461-14757-1-git-send-email-honghui.zhang@mediatek.com>
 <1465379461-14757-6-git-send-email-honghui.zhang@mediatek.com>
 <09eaf7a5-2b18-1ea6-5699-2e968c6b79a4@gmail.com>
 <51441f39-e5b5-2cce-63ab-47bd3cf298b3@gmail.com>
Message-ID: <1467595950.8420.2.camel@mtksdaap41>

On Sun, 2016-07-03 at 21:12 +0200, Matthias Brugger wrote:
> 
> On 07/03/2016 08:24 AM, Matthias Brugger wrote:
> >
> >
> > On 06/08/2016 11:51 AM, honghui.zhang at mediatek.com wrote:
> >> From: Honghui Zhang <honghui.zhang at mediatek.com>
> >>
> >> Add the dtsi node of iommu and smi for mt2701.
> >>
> >> Signed-off-by: Honghui Zhang <honghui.zhang at mediatek.com>
> >> ---
> >>  arch/arm/boot/dts/mt2701.dtsi | 51
> >> +++++++++++++++++++++++++++++++++++++++++++
> >>  1 file changed, 51 insertions(+)
> >>
> >
> > Applied,
> 
> Please resend the patch including the infracfg and mmsys node.
> 

Hi, Matthias,

Please hold this one.
This one is based on CCF "arm: dts: mt2701: Add clock controller device
nodes"[1] and power domain patch "Mediatek MT2701 SCPSYS power domain
support v7"[2],
But these two patchset are still being reviewed now.

Do you think it's better that I send this one later after ccf and power
domain patch got merged? I will send this patch later if it's OK with
you.

Thanks.
[1] https://patchwork.kernel.org/patch/9109081
[2]
http://lists.infradead.org/pipermail/linux-mediatek/2016-May/005429.html

> Regards,
> Matthias
> 
> >
> > Thanks.
> >
> >> diff --git a/arch/arm/boot/dts/mt2701.dtsi
> >> b/arch/arm/boot/dts/mt2701.dtsi
> >> index 42d5a37..363de0d 100644
> >> --- a/arch/arm/boot/dts/mt2701.dtsi
> >> +++ b/arch/arm/boot/dts/mt2701.dtsi
> >> @@ -16,6 +16,7 @@
> >>  #include <dt-bindings/power/mt2701-power.h>
> >>  #include <dt-bindings/interrupt-controller/irq.h>
> >>  #include <dt-bindings/interrupt-controller/arm-gic.h>
> >> +#include <dt-bindings/memory/mt2701-larb-port.h>
> >>  #include "skeleton64.dtsi"
> >>  #include "mt2701-pinfunc.h"
> >>
> >> @@ -160,6 +161,16 @@
> >>          clock-names = "system-clk", "rtc-clk";
> >>      };
> >>
> >> +    smi_common: smi at 1000c000 {
> >> +        compatible = "mediatek,mt2701-smi-common";
> >> +        reg = <0 0x1000c000 0 0x1000>;
> >> +        clocks = <&infracfg CLK_INFRA_SMI>,
> >> +             <&mmsys CLK_MM_SMI_COMMON>,
> >> +             <&infracfg CLK_INFRA_SMI>;
> >> +        clock-names = "apb", "smi", "async";
> >> +        power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>;
> >> +    };
> >> +
> >>      sysirq: interrupt-controller at 10200100 {
> >>          compatible = "mediatek,mt2701-sysirq",
> >>                   "mediatek,mt6577-sysirq";
> >> @@ -169,6 +180,16 @@
> >>          reg = <0 0x10200100 0 0x1c>;
> >>      };
> >>
> >> +    iommu: mmsys_iommu at 10205000 {
> >> +        compatible = "mediatek,mt2701-m4u";
> >> +        reg = <0 0x10205000 0 0x1000>;
> >> +        interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_LOW>;
> >> +        clocks = <&infracfg CLK_INFRA_M4U>;
> >> +        clock-names = "bclk";
> >> +        mediatek,larbs = <&larb0 &larb1 &larb2>;
> >> +        #iommu-cells = <1>;
> >> +    };
> >> +
> >>      apmixedsys: syscon at 10209000 {
> >>          compatible = "mediatek,mt2701-apmixedsys", "syscon";
> >>          reg = <0 0x10209000 0 0x1000>;
> >> @@ -234,6 +255,16 @@
> >>          status = "disabled";
> >>      };
> >>
> >> +    larb0: larb at 14010000 {
> >> +        compatible = "mediatek,mt2701-smi-larb";
> >> +        reg = <0 0x14010000 0 0x1000>;
> >> +        mediatek,smi = <&smi_common>;
> >> +        clocks = <&mmsys CLK_MM_SMI_LARB0>,
> >> +             <&mmsys CLK_MM_SMI_LARB0>;
> >> +        clock-names = "apb", "smi";
> >> +        power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>;
> >> +    };
> >> +
> >>      imgsys: syscon at 15000000 {
> >>          compatible = "mediatek,mt2701-imgsys", "syscon";
> >>          reg = <0 0x15000000 0 0x1000>;
> >> @@ -241,6 +272,16 @@
> >>          status = "disabled";
> >>      };
> >>
> >> +    larb2: larb at 15001000 {
> >> +        compatible = "mediatek,mt2701-smi-larb";
> >> +        reg = <0 0x15001000 0 0x1000>;
> >> +        mediatek,smi = <&smi_common>;
> >> +        clocks = <&imgsys CLK_IMG_SMI_COMM>,
> >> +             <&imgsys CLK_IMG_SMI_COMM>;
> >> +        clock-names = "apb", "smi";
> >> +        power-domains = <&scpsys MT2701_POWER_DOMAIN_ISP>;
> >> +    };
> >> +
> >>      vdecsys: syscon at 16000000 {
> >>          compatible = "mediatek,mt2701-vdecsys", "syscon";
> >>          reg = <0 0x16000000 0 0x1000>;
> >> @@ -248,6 +289,16 @@
> >>          status = "disabled";
> >>      };
> >>
> >> +    larb1: larb at 16010000 {
> >> +        compatible = "mediatek,mt2701-smi-larb";
> >> +        reg = <0 0x16010000 0 0x1000>;
> >> +        mediatek,smi = <&smi_common>;
> >> +        clocks = <&vdecsys CLK_VDEC_CKGEN>,
> >> +             <&vdecsys CLK_VDEC_LARB>;
> >> +        clock-names = "apb", "smi";
> >> +        power-domains = <&scpsys MT2701_POWER_DOMAIN_VDEC>;
> >> +    };
> >> +
> >>      hifsys: syscon at 1a000000 {
> >>          compatible = "mediatek,mt2701-hifsys", "syscon";
> >>          reg = <0 0x1a000000 0 0x1000>;
> >>




From garlic.tseng at mediatek.com  Sun Jul  3 18:59:17 2016
From: garlic.tseng at mediatek.com (Garlic Tseng)
Date: Mon, 4 Jul 2016 09:59:17 +0800
Subject: [alsa-devel] [PATCH v5 7/9] ASoC: bt-sco: extend rate and add a
 general compatible string
In-Reply-To: <CAGb2v67rgj4efyTZpZ-79NnCRM=KLJCJedte594qgSjMMB5xsQ@mail.gmail.com>
References: <1466149440-23889-1-git-send-email-garlic.tseng@mediatek.com>
 <1466149440-23889-8-git-send-email-garlic.tseng@mediatek.com>
 <20160629191500.GU6247@sirena.org.uk>
 <1467291345.11091.16.camel@mtksdaap41>
 <1467341386.21689.6.camel@mtksdaap41> <20160701161105.GY6247@sirena.org.uk>
 <CAGb2v67rgj4efyTZpZ-79NnCRM=KLJCJedte594qgSjMMB5xsQ@mail.gmail.com>
Message-ID: <1467597557.11819.4.camel@mtksdaap41>

On Sat, 2016-07-02 at 17:05 +0800, Chen-Yu Tsai wrote:

Hi,

> Could we also make this driver directly configurable from Kconfig,
> and not just selected by platforms (currently Samsung) or by building
> all coddecs?
> 
> Thanks
> ChenYu

I'll add configure prompt for SND_SOC_BT_SCO in next patchset.
Thanks for comment.

Garlic




From garlic.tseng at mediatek.com  Sun Jul  3 19:28:52 2016
From: garlic.tseng at mediatek.com (Garlic Tseng)
Date: Mon, 4 Jul 2016 10:28:52 +0800
Subject: [alsa-devel] [PATCH v5 6/9] ASoC: mediatek: add mt2701 platform
 driver implementation.
In-Reply-To: <1467293981.17087.18.camel@mtksdaap41>
References: <1466149440-23889-1-git-send-email-garlic.tseng@mediatek.com>
 <1466149440-23889-7-git-send-email-garlic.tseng@mediatek.com>
 <20160629191322.GT6247@sirena.org.uk>
 <1467293981.17087.18.camel@mtksdaap41>
Message-ID: <1467599332.11819.11.camel@mtksdaap41>

On Thu, 2016-06-30 at 21:39 +0800, Garlic Tseng wrote:
> On Wed, 2016-06-29 at 20:13 +0100, Mark Brown wrote:
> > On Fri, Jun 17, 2016 at 03:43:57PM +0800, Garlic Tseng wrote:
> > 
> > > +static int mt2701_afe_i2s_set_clkdiv(struct snd_soc_dai *dai, int div_id,
> > > +				     int div)
> > > +{
> > 
> > Why are we adding a set_clkdiv() operation?  I would expect the driver
> > to be able to figure things out automatically.
> > 
> > > +	case DIV_ID_MCLK_TO_BCK:
> > > +		afe_priv->i2s_path[i2s_num].div_mclk_to_bck = div;
> > > +		break;
> > > +	case DIV_ID_BCK_TO_LRCK:
> > > +		afe_priv->i2s_path[i2s_num].div_bck_to_lrck = div;
> > > +		break;
> > 
> > Especially in the case where we're configuring LRCLK, that's trivial
> > when we know the sample rate which we have to know anyway.
> 
> Oh... actually I want to say 'div_mclk_over_bck' and 'div_bck_over_lrck'
> I'll fix the naming if we decide to reserve the set_clkdiv() operation.
> (omit some comment)

Hi Mark, I recognize that we can set mclk by set_sysclk, fix bck to 64fs
and let lrck be the same as sample rate so yes we don't need set_clkdiv.

Thanks for comment, I'll fix that in the next patch.

Garlic





From jamesjj.liao at mediatek.com  Sun Jul  3 20:51:48 2016
From: jamesjj.liao at mediatek.com (James Liao)
Date: Mon, 4 Jul 2016 11:51:48 +0800
Subject: [PATCH v9 01/10] clk: fix initial state of critical clock's
 parents
In-Reply-To: <20160702012140.GB17071@codeaurora.org>
References: <1466581229-2342-1-git-send-email-erin.lo@mediatek.com>
 <1466581229-2342-2-git-send-email-erin.lo@mediatek.com>
 <20160702012140.GB17071@codeaurora.org>
Message-ID: <1467604308.26485.4.camel@mtksdaap41>

On Fri, 2016-07-01 at 18:21 -0700, Stephen Boyd wrote:
> (Resending to everyone)
> 
> On 06/22, Erin Lo wrote:
> > From: James Liao <jamesjj.liao at mediatek.com>
> > 
> > This patch fixed wrong state of parent clocks if they are registered
> > after critical clocks.
> > 
> > Signed-off-by: James Liao <jamesjj.liao at mediatek.com>
> > Signed-off-by: Erin Lo <erin.lo at mediatek.com>
> 
> It would be nice if you included the information about the
> problem from James' previous mail. This says what it does, but
> doesn't explain what the problem is and how it is fixing it.
> 
> > ---
> >  drivers/clk/clk.c | 9 ++++++++-
> >  1 file changed, 8 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> > index d584004..e9f5f89 100644
> > --- a/drivers/clk/clk.c
> > +++ b/drivers/clk/clk.c
> > @@ -2388,8 +2388,15 @@ static int __clk_core_init(struct clk_core *core)
> >  	hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) {
> >  		struct clk_core *parent = __clk_init_parent(orphan);
> >  
> > -		if (parent)
> > +		if (parent) {
> >  			clk_core_reparent(orphan, parent);
> > +
> > +			if (orphan->prepare_count)
> > +				clk_core_prepare(parent);
> > +
> > +			if (orphan->enable_count)
> > +				clk_core_enable(parent);
> > +		}
> >  	}
> 
> I'm pretty sure I pointed this problem out to Mike when the
> critical clk patches were being pushed. I can't recall what the
> plan was though to fix the problem. I'm pretty sure he said that
> clk_core_reparent() would take care of it, but obviously it is
> not doing that. Or perhaps it was that clk handoff should figure
> out that the parents of a critical clk are also on and thus keep
> them on.

Hi Mike

Is there any other patch to fix this issue? Or did I misuse critical
clock flag?


Best regards,

James




From ck.hu at mediatek.com  Sun Jul  3 22:19:33 2016
From: ck.hu at mediatek.com (CK Hu)
Date: Mon, 4 Jul 2016 13:19:33 +0800
Subject: [GIT PULL] drm/mediatek: MT8173 gamma & dither support
In-Reply-To: <CACvgo52YgRat8Uqhd9qh_ppvk0h=krxYLHL6Cjqs9+EzQaogUg@mail.gmail.com>
References: <1466753238-17216-1-git-send-email-bibby.hsieh@mediatek.com>
 <558c9efc-d197-a6c3-cf7e-f9fcac60ca64@gmail.com>
 <1467026970.23883.16.camel@mtksdaap41>
 <CACvgo52YgRat8Uqhd9qh_ppvk0h=krxYLHL6Cjqs9+EzQaogUg@mail.gmail.com>
Message-ID: <1467609573.31010.3.camel@mtksdaap41>

Hi, Emil:

On Sun, 2016-07-03 at 23:43 +0100, Emil Velikov wrote:
> Hi Bibby,
> 
> On 27 June 2016 at 12:29, Bibby Hsieh <bibby.hsieh at mediatek.com> wrote:
> > On Mon, 2016-06-27 at 12:20 +0200, Matthias Brugger wrote:
> >>
> >> On 06/24/2016 09:27 AM, Bibby Hsieh wrote:
> >> > Hi Dave,
> >> >
> >> > Please consider merging this tag, which contains the v2 MT8173 gamma & dither function patches I sent on 2016-06-17, rebased onto v4.7-rc1. There have been no further comments.
> >> >
> >> > Thanks
> >> > Bibby
> >> >
> >> > The following changes since commit 1a695a905c18548062509178b98bc91e67510864:
> >> >
> >> >   Linux 4.7-rc1 (2016-05-29 16:29:24 GMT)
> >> >
> >> > are available in the git repository at:
> >> >
> >> >   git at github.com:BibbyHsieh/linux4.7-rc1.git
> >> >
> >> > for you to fetch changes up to dd0eb773bc125f5e6bca735d19c08500dc3730f9:
> >> >
> >> >   drm/mediatek: Add gamma correction
> >> >
> >> > -------------------------------------------------------------------------
> >>
> >> As far as I can see, your branch has 3 patches on top from Eddie. It
> >> seems to me as if you didn't send your patches to the mailinglist before?
> >> Anyway this branch does not fulfill the rules to get merged into the
> >> linux kernel.
> >>
> >> Why do you send a pull request? The normal process is to send the
> >> patches via email and if the maintainer wants you can send a pull
> >> request once the patches are ready to be merged.
> >>
> >> Regards,
> >> Matthias
> >>
> >
> > I sent v1 and v2 on 2016-06-14 and 06-17 respectively [0-8].
> > After I made some modifications according to Daniel Vetter's comments,
> > there had been no further comments and I sent the pull request as the
> > other sub-sys.
> >
> > I'm sorry for my mistake, I will re-arrange the tree for upstream.
> > Next time, I will check with maintainer by email first, and sent the
> > pull request.
> >
> It might be a bit hard to find out who's the maintainer considering
> MAINTAINERS has no entry for this driver.
> 
> Looking at how things are going Philipp Zabel will be the more likely
> person for the task, yet I would be nice if someone from the Mediatek
> squad is helping him out - CK Hu perhaps ?
> 
> Regards,
> Emil

I'm willing to be one of Mediatek DRM driver maintainer. I wish this
would make things easier.

Regards,
CK



From garlic.tseng at mediatek.com  Mon Jul  4 00:06:42 2016
From: garlic.tseng at mediatek.com (Garlic Tseng)
Date: Mon, 4 Jul 2016 15:06:42 +0800
Subject: [alsa-devel] [PATCH] ASoC: bt-sco: add config prompt
Message-ID: <1467616002-10447-1-git-send-email-garlic.tseng@mediatek.com>

Add config prompt for bt-sco codec driver

Signed-off-by: Garlic Tseng <garlic.tseng at mediatek.com>
---
 sound/soc/codecs/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index f2f8603..1cd6ab3 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -383,7 +383,7 @@ config SND_SOC_ALC5632
 	tristate
 
 config SND_SOC_BT_SCO
-	tristate
+	tristate "Dummy BT SCO codec driver"
 
 config SND_SOC_CQ0093VC
 	tristate
-- 
1.9.1



From matthias.bgg at gmail.com  Mon Jul  4 01:00:20 2016
From: matthias.bgg at gmail.com (Matthias Brugger)
Date: Mon, 4 Jul 2016 10:00:20 +0200
Subject: [PATCH v4 5/5] ARM: dts: mt2701: add iommu/smi dtsi node for
 mt2701
In-Reply-To: <1467595950.8420.2.camel@mtksdaap41>
References: <1465379461-14757-1-git-send-email-honghui.zhang@mediatek.com>
 <1465379461-14757-6-git-send-email-honghui.zhang@mediatek.com>
 <09eaf7a5-2b18-1ea6-5699-2e968c6b79a4@gmail.com>
 <51441f39-e5b5-2cce-63ab-47bd3cf298b3@gmail.com>
 <1467595950.8420.2.camel@mtksdaap41>
Message-ID: <577A1794.5040509@gmail.com>



On 04/07/16 03:32, Honghui Zhang wrote:
> On Sun, 2016-07-03 at 21:12 +0200, Matthias Brugger wrote:
>>
>> On 07/03/2016 08:24 AM, Matthias Brugger wrote:
>>>
>>>
>>> On 06/08/2016 11:51 AM, honghui.zhang at mediatek.com wrote:
>>>> From: Honghui Zhang <honghui.zhang at mediatek.com>
>>>>
>>>> Add the dtsi node of iommu and smi for mt2701.
>>>>
>>>> Signed-off-by: Honghui Zhang <honghui.zhang at mediatek.com>
>>>> ---
>>>>   arch/arm/boot/dts/mt2701.dtsi | 51
>>>> +++++++++++++++++++++++++++++++++++++++++++
>>>>   1 file changed, 51 insertions(+)
>>>>
>>>
>>> Applied,
>>
>> Please resend the patch including the infracfg and mmsys node.
>>
>
> Hi, Matthias,
>
> Please hold this one.
> This one is based on CCF "arm: dts: mt2701: Add clock controller device
> nodes"[1] and power domain patch "Mediatek MT2701 SCPSYS power domain
> support v7"[2],
> But these two patchset are still being reviewed now.
>
> Do you think it's better that I send this one later after ccf and power
> domain patch got merged? I will send this patch later if it's OK with
> you.
>

Sounds good.

Thanks a lot,
Matthias

> Thanks.
> [1] https://patchwork.kernel.org/patch/9109081
> [2]
> http://lists.infradead.org/pipermail/linux-mediatek/2016-May/005429.html
>
>> Regards,
>> Matthias
>>
>>>
>>> Thanks.
>>>
>>>> diff --git a/arch/arm/boot/dts/mt2701.dtsi
>>>> b/arch/arm/boot/dts/mt2701.dtsi
>>>> index 42d5a37..363de0d 100644
>>>> --- a/arch/arm/boot/dts/mt2701.dtsi
>>>> +++ b/arch/arm/boot/dts/mt2701.dtsi
>>>> @@ -16,6 +16,7 @@
>>>>   #include <dt-bindings/power/mt2701-power.h>
>>>>   #include <dt-bindings/interrupt-controller/irq.h>
>>>>   #include <dt-bindings/interrupt-controller/arm-gic.h>
>>>> +#include <dt-bindings/memory/mt2701-larb-port.h>
>>>>   #include "skeleton64.dtsi"
>>>>   #include "mt2701-pinfunc.h"
>>>>
>>>> @@ -160,6 +161,16 @@
>>>>           clock-names = "system-clk", "rtc-clk";
>>>>       };
>>>>
>>>> +    smi_common: smi at 1000c000 {
>>>> +        compatible = "mediatek,mt2701-smi-common";
>>>> +        reg = <0 0x1000c000 0 0x1000>;
>>>> +        clocks = <&infracfg CLK_INFRA_SMI>,
>>>> +             <&mmsys CLK_MM_SMI_COMMON>,
>>>> +             <&infracfg CLK_INFRA_SMI>;
>>>> +        clock-names = "apb", "smi", "async";
>>>> +        power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>;
>>>> +    };
>>>> +
>>>>       sysirq: interrupt-controller at 10200100 {
>>>>           compatible = "mediatek,mt2701-sysirq",
>>>>                    "mediatek,mt6577-sysirq";
>>>> @@ -169,6 +180,16 @@
>>>>           reg = <0 0x10200100 0 0x1c>;
>>>>       };
>>>>
>>>> +    iommu: mmsys_iommu at 10205000 {
>>>> +        compatible = "mediatek,mt2701-m4u";
>>>> +        reg = <0 0x10205000 0 0x1000>;
>>>> +        interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_LOW>;
>>>> +        clocks = <&infracfg CLK_INFRA_M4U>;
>>>> +        clock-names = "bclk";
>>>> +        mediatek,larbs = <&larb0 &larb1 &larb2>;
>>>> +        #iommu-cells = <1>;
>>>> +    };
>>>> +
>>>>       apmixedsys: syscon at 10209000 {
>>>>           compatible = "mediatek,mt2701-apmixedsys", "syscon";
>>>>           reg = <0 0x10209000 0 0x1000>;
>>>> @@ -234,6 +255,16 @@
>>>>           status = "disabled";
>>>>       };
>>>>
>>>> +    larb0: larb at 14010000 {
>>>> +        compatible = "mediatek,mt2701-smi-larb";
>>>> +        reg = <0 0x14010000 0 0x1000>;
>>>> +        mediatek,smi = <&smi_common>;
>>>> +        clocks = <&mmsys CLK_MM_SMI_LARB0>,
>>>> +             <&mmsys CLK_MM_SMI_LARB0>;
>>>> +        clock-names = "apb", "smi";
>>>> +        power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>;
>>>> +    };
>>>> +
>>>>       imgsys: syscon at 15000000 {
>>>>           compatible = "mediatek,mt2701-imgsys", "syscon";
>>>>           reg = <0 0x15000000 0 0x1000>;
>>>> @@ -241,6 +272,16 @@
>>>>           status = "disabled";
>>>>       };
>>>>
>>>> +    larb2: larb at 15001000 {
>>>> +        compatible = "mediatek,mt2701-smi-larb";
>>>> +        reg = <0 0x15001000 0 0x1000>;
>>>> +        mediatek,smi = <&smi_common>;
>>>> +        clocks = <&imgsys CLK_IMG_SMI_COMM>,
>>>> +             <&imgsys CLK_IMG_SMI_COMM>;
>>>> +        clock-names = "apb", "smi";
>>>> +        power-domains = <&scpsys MT2701_POWER_DOMAIN_ISP>;
>>>> +    };
>>>> +
>>>>       vdecsys: syscon at 16000000 {
>>>>           compatible = "mediatek,mt2701-vdecsys", "syscon";
>>>>           reg = <0 0x16000000 0 0x1000>;
>>>> @@ -248,6 +289,16 @@
>>>>           status = "disabled";
>>>>       };
>>>>
>>>> +    larb1: larb at 16010000 {
>>>> +        compatible = "mediatek,mt2701-smi-larb";
>>>> +        reg = <0 0x16010000 0 0x1000>;
>>>> +        mediatek,smi = <&smi_common>;
>>>> +        clocks = <&vdecsys CLK_VDEC_CKGEN>,
>>>> +             <&vdecsys CLK_VDEC_LARB>;
>>>> +        clock-names = "apb", "smi";
>>>> +        power-domains = <&scpsys MT2701_POWER_DOMAIN_VDEC>;
>>>> +    };
>>>> +
>>>>       hifsys: syscon at 1a000000 {
>>>>           compatible = "mediatek,mt2701-hifsys", "syscon";
>>>>           reg = <0 0x1a000000 0 0x1000>;
>>>>
>
>


From broonie at kernel.org  Mon Jul  4 01:58:40 2016
From: broonie at kernel.org (Mark Brown)
Date: Mon, 04 Jul 2016 10:58:40 +0200
Subject: Applied "ASoC: bt-sco: add config prompt" to the asoc tree
In-Reply-To: <1467616002-10447-1-git-send-email-garlic.tseng@mediatek.com>
Message-ID: <E1bJziC-0004QM-4E@finisterre>

The patch

   ASoC: bt-sco: add config prompt

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 8b0b50d8a3e3ccfa4632a227102b97994ed95fc0 Mon Sep 17 00:00:00 2001
From: Garlic Tseng <garlic.tseng at mediatek.com>
Date: Mon, 4 Jul 2016 15:06:42 +0800
Subject: [PATCH] ASoC: bt-sco: add config prompt

Add config prompt for bt-sco codec driver

Signed-off-by: Garlic Tseng <garlic.tseng at mediatek.com>
Signed-off-by: Mark Brown <broonie at kernel.org>
---
 sound/soc/codecs/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 4d82a58ff6b0..3ba998a79165 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -371,7 +371,7 @@ config SND_SOC_ALC5632
 	tristate
 
 config SND_SOC_BT_SCO
-	tristate
+	tristate "Dummy BT SCO codec driver"
 
 config SND_SOC_CQ0093VC
 	tristate
-- 
2.8.1



From andrew-ct.chen at mediatek.com  Mon Jul  4 03:48:34 2016
From: andrew-ct.chen at mediatek.com (Andrew-CT Chen)
Date: Mon, 4 Jul 2016 18:48:34 +0800
Subject: pull request: lunux-firmware: Add Mediatek MT8173 VPU firmware
Message-ID: <1467629314-31902-1-git-send-email-andrew-ct.chen@mediatek.com>

Hi linux-firmware maintainers,

The following changes since commit 3ef7857d511ce6a91c5ce609da76c4702651cfa5:

  amdgpu: update polaris ucode (2016-06-28 14:31:11 -0400)

are available in the git repository at:

  https://github.com/andrewct-chen/vpu-linux-firmware.git vpu_encode

for you to fetch changes up to 40876d7b3c911161ab71bc84a6e90f257a13cdc4:

  mediatek: Add mt8173 VPU firmware (2016-07-04 16:26:54 +0800)

----------------------------------------------------------------
Andrew-CT Chen (1):
      mediatek: Add mt8173 VPU firmware

 WHENCE    |   19 +++++++++++++++++++
 vpu_d.bin |  Bin 0 -> 4084848 bytes
 vpu_p.bin |  Bin 0 -> 131036 bytes
 3 files changed, 19 insertions(+)
 create mode 100644 vpu_d.bin
 create mode 100644 vpu_p.bin


From garlic.tseng at mediatek.com  Mon Jul  4 03:56:24 2016
From: garlic.tseng at mediatek.com (Garlic Tseng)
Date: Mon, 4 Jul 2016 18:56:24 +0800
Subject: [alsa-devel] [PATCH 0/4] ASoC: Mediatek: add MT2701 platform and
 machine driver
Message-ID: <1467629788-14411-1-git-send-email-garlic.tseng@mediatek.com>

Some patches of the patchset "ASoC: Mediatek: Add support for MT2701 SOC"
have been applied to the broonie tree, so I send a new patchset for the 
remaining patches.

The patchset adds mt2701 support based on Mediatek AFE common structure.

Change since the previous patchset:
* remove unnecessary set_clkdiv and set_fmt ops in mt2701 platform driver
* add another snd_soc_dai_driver for bt-sco codec to support 8k and 16k



Garlic Tseng (4):
  ASoC: mediatek: add mt2701 platform driver implementation.
  ASoC: bt-sco: extend rate and add a general compatible string
  ASoC: mediatek: add BT implementation
  ASoC: mediatek: Add mt2701-cs42448 driver and config option.

 Documentation/devicetree/bindings/sound/bt-sco.txt |    2 +-
 sound/soc/codecs/bt-sco.c                          |   52 +-
 sound/soc/mediatek/Kconfig                         |   21 +
 sound/soc/mediatek/Makefile                        |    1 +
 sound/soc/mediatek/mt2701/Makefile                 |   19 +
 sound/soc/mediatek/mt2701/mt2701-afe-common.h      |    9 -
 sound/soc/mediatek/mt2701/mt2701-afe-pcm.c         | 1654 ++++++++++++++++++++
 sound/soc/mediatek/mt2701/mt2701-cs42448.c         |  412 +++++
 8 files changed, 2144 insertions(+), 26 deletions(-)
 create mode 100644 sound/soc/mediatek/mt2701/Makefile
 create mode 100644 sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
 create mode 100644 sound/soc/mediatek/mt2701/mt2701-cs42448.c

-- 
1.9.1



From garlic.tseng at mediatek.com  Mon Jul  4 03:56:26 2016
From: garlic.tseng at mediatek.com (Garlic Tseng)
Date: Mon, 4 Jul 2016 18:56:26 +0800
Subject: [alsa-devel] [PATCH 2/4] ASoC: bt-sco: extend rate and add a general
 compatible string
In-Reply-To: <1467629788-14411-1-git-send-email-garlic.tseng@mediatek.com>
References: <1467629788-14411-1-git-send-email-garlic.tseng@mediatek.com>
Message-ID: <1467629788-14411-3-git-send-email-garlic.tseng@mediatek.com>

Add supports for 16k (wideband BT) and add a general compatible
string "linux,bt-sco"

Signed-off-by: Garlic Tseng <garlic.tseng at mediatek.com>
---
 Documentation/devicetree/bindings/sound/bt-sco.txt |  2 +-
 sound/soc/codecs/bt-sco.c                          | 52 +++++++++++++++-------
 2 files changed, 37 insertions(+), 17 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/bt-sco.txt b/Documentation/devicetree/bindings/sound/bt-sco.txt
index 29b8e5d..641edf7 100644
--- a/Documentation/devicetree/bindings/sound/bt-sco.txt
+++ b/Documentation/devicetree/bindings/sound/bt-sco.txt
@@ -4,7 +4,7 @@ This device support generic Bluetooth SCO link.
 
 Required properties:
 
-  - compatible : "delta,dfbmcs320"
+  - compatible : "delta,dfbmcs320" or "linux,bt-sco"
 
 Example:
 
diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c
index b084ad1..2a8d0ee 100644
--- a/sound/soc/codecs/bt-sco.c
+++ b/sound/soc/codecs/bt-sco.c
@@ -25,22 +25,41 @@ static const struct snd_soc_dapm_route bt_sco_routes[] = {
 	{ "TX", NULL, "Playback" },
 };
 
-static struct snd_soc_dai_driver bt_sco_dai = {
-	.name = "bt-sco-pcm",
-	.playback = {
-		.stream_name = "Playback",
-		.channels_min = 1,
-		.channels_max = 1,
-		.rates = SNDRV_PCM_RATE_8000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-	.capture = {
-		 .stream_name = "Capture",
-		.channels_min = 1,
-		.channels_max = 1,
-		.rates = SNDRV_PCM_RATE_8000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+static struct snd_soc_dai_driver bt_sco_dai[] = {
+	{
+		.name = "bt-sco-pcm",
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = SNDRV_PCM_RATE_8000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.capture = {
+			 .stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = SNDRV_PCM_RATE_8000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
 	},
+	{
+		.name = "bt-sco-pcm-wb",
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.capture = {
+			 .stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+	}
 };
 
 static struct snd_soc_codec_driver soc_codec_dev_bt_sco = {
@@ -53,7 +72,7 @@ static struct snd_soc_codec_driver soc_codec_dev_bt_sco = {
 static int bt_sco_probe(struct platform_device *pdev)
 {
 	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_bt_sco,
-			&bt_sco_dai, 1);
+				      bt_sco_dai, ARRAY_SIZE(bt_sco_dai));
 }
 
 static int bt_sco_remove(struct platform_device *pdev)
@@ -77,6 +96,7 @@ MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids);
 #if defined(CONFIG_OF)
 static const struct of_device_id bt_sco_codec_of_match[] = {
 	{ .compatible = "delta,dfbmcs320", },
+	{ .compatible = "linux,bt-sco", },
 	{},
 };
 MODULE_DEVICE_TABLE(of, bt_sco_codec_of_match);
-- 
1.9.1



From garlic.tseng at mediatek.com  Mon Jul  4 03:56:25 2016
From: garlic.tseng at mediatek.com (Garlic Tseng)
Date: Mon, 4 Jul 2016 18:56:25 +0800
Subject: [alsa-devel] [PATCH 1/4] ASoC: mediatek: add mt2701 platform driver
 implementation.
In-Reply-To: <1467629788-14411-1-git-send-email-garlic.tseng@mediatek.com>
References: <1467629788-14411-1-git-send-email-garlic.tseng@mediatek.com>
Message-ID: <1467629788-14411-2-git-send-email-garlic.tseng@mediatek.com>

Add mt2701 platform driver implementation for playback and capture.
The implement follow DAPM structure (memory interface as FE and I2S
as BE).
Because of the hardware design, i2s out required to be enabled when
we need to enable i2s in. This patch includes the implementation.

Signed-off-by: Garlic Tseng <garlic.tseng at mediatek.com>
---
 sound/soc/mediatek/mt2701/mt2701-afe-common.h |    9 -
 sound/soc/mediatek/mt2701/mt2701-afe-pcm.c    | 1515 +++++++++++++++++++++++++
 2 files changed, 1515 insertions(+), 9 deletions(-)
 create mode 100644 sound/soc/mediatek/mt2701/mt2701-afe-pcm.c

diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-common.h b/sound/soc/mediatek/mt2701/mt2701-afe-common.h
index c77166e..c19430e 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-common.h
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-common.h
@@ -69,11 +69,6 @@ enum {
 	MT2701_IRQ_ASYS_END,
 };
 
-enum {
-	DIV_ID_MCLK_TO_BCK,
-	DIV_ID_BCK_TO_LRCK,
-};
-
 /* 2701 clock def */
 enum audio_system_clock_type {
 	MT2701_AUD_INFRA_SYS_AUDIO,
@@ -163,10 +158,6 @@ enum mt2701_i2s_dir {
 struct mt2701_i2s_path {
 	int dai_id;
 	int mclk_rate;
-	int div_mclk_to_bck;
-	int div_bck_to_lrck;
-	int format;
-	snd_pcm_format_t stream_fmt;
 	int on[I2S_DIR_NUM];
 	int occupied[I2S_DIR_NUM];
 	const struct mt2701_i2s_data *i2s_data[2];
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
new file mode 100644
index 0000000..c865ba1
--- /dev/null
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
@@ -0,0 +1,1515 @@
+/*
+ * Mediatek ALSA SoC AFE platform driver for 2701
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Garlic Tseng <garlic.tseng at mediatek.com>
+ *             Ir Lian <ir.lian at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+
+#include "mt2701-afe-common.h"
+
+#include "mt2701-afe-clock-ctrl.h"
+#include "../common/mtk-afe-platform-driver.h"
+#include "../common/mtk-afe-fe-dai.h"
+
+#define AFE_IRQ_STATUS_BITS	0xff
+
+static const struct snd_pcm_hardware mt2701_afe_hardware = {
+	.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED
+		| SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE
+		   | SNDRV_PCM_FMTBIT_S32_LE,
+	.period_bytes_min = 1024,
+	.period_bytes_max = 1024 * 256,
+	.periods_min = 4,
+	.periods_max = 1024,
+	.buffer_bytes_max = 1024 * 1024 * 16,
+	.fifo_size = 0,
+};
+
+struct mt2701_afe_rate {
+	unsigned int rate;
+	unsigned int regvalue;
+};
+
+static const struct mt2701_afe_rate mt2701_afe_i2s_rates[] = {
+	{ .rate = 8000, .regvalue = 0 },
+	{ .rate = 12000, .regvalue = 1 },
+	{ .rate = 16000, .regvalue = 2 },
+	{ .rate = 24000, .regvalue = 3 },
+	{ .rate = 32000, .regvalue = 4 },
+	{ .rate = 48000, .regvalue = 5 },
+	{ .rate = 96000, .regvalue = 6 },
+	{ .rate = 192000, .regvalue = 7 },
+	{ .rate = 384000, .regvalue = 8 },
+	{ .rate = 7350, .regvalue = 16 },
+	{ .rate = 11025, .regvalue = 17 },
+	{ .rate = 14700, .regvalue = 18 },
+	{ .rate = 22050, .regvalue = 19 },
+	{ .rate = 29400, .regvalue = 20 },
+	{ .rate = 44100, .regvalue = 21 },
+	{ .rate = 88200, .regvalue = 22 },
+	{ .rate = 176400, .regvalue = 23 },
+	{ .rate = 352800, .regvalue = 24 },
+};
+
+int mt2701_dai_num_to_i2s(struct mtk_base_afe *afe, int num)
+{
+	int val = num - MT2701_IO_I2S;
+
+	if (val < 0 || val >= MT2701_I2S_NUM) {
+		dev_err(afe->dev, "%s, num not available, num %d, val %d\n",
+			__func__, num, val);
+		return -EINVAL;
+	}
+	return val;
+}
+
+static int mt2701_afe_i2s_fs(unsigned int sample_rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mt2701_afe_i2s_rates); i++)
+		if (mt2701_afe_i2s_rates[i].rate == sample_rate)
+			return mt2701_afe_i2s_rates[i].regvalue;
+
+	return -EINVAL;
+}
+
+static int mt2701_afe_i2s_startup(struct snd_pcm_substream *substream,
+				  struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+	int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
+	int clk_num = MT2701_AUD_AUD_I2S1_MCLK + i2s_num;
+	int ret = 0;
+
+	if (i2s_num < 0)
+		return i2s_num;
+
+	/* enable mclk */
+	ret = clk_prepare_enable(afe_priv->clocks[clk_num]);
+	if (ret)
+		dev_err(afe->dev, "Failed to enable mclk for I2S: %d\n",
+			i2s_num);
+
+	return ret;
+}
+
+static int mt2701_afe_i2s_path_shutdown(struct snd_pcm_substream *substream,
+					struct snd_soc_dai *dai,
+					int dir_invert)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+	int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
+	struct mt2701_i2s_path *i2s_path;
+	const struct mt2701_i2s_data *i2s_data;
+	int stream_dir = substream->stream;
+
+	if (i2s_num < 0)
+		return i2s_num;
+
+	i2s_path = &afe_priv->i2s_path[i2s_num];
+
+	if (dir_invert)	{
+		if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK)
+			stream_dir = SNDRV_PCM_STREAM_CAPTURE;
+		else
+			stream_dir = SNDRV_PCM_STREAM_PLAYBACK;
+	}
+	i2s_data = i2s_path->i2s_data[stream_dir];
+
+	i2s_path->on[stream_dir]--;
+	if (i2s_path->on[stream_dir] < 0) {
+		dev_warn(afe->dev, "i2s_path->on: %d, dir: %d\n",
+			 i2s_path->on[stream_dir], stream_dir);
+		i2s_path->on[stream_dir] = 0;
+	}
+	if (i2s_path->on[stream_dir])
+		return 0;
+
+	/* disable i2s */
+	regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg,
+			   ASYS_I2S_CON_I2S_EN, 0);
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
+			   1 << i2s_data->i2s_pwn_shift,
+			   1 << i2s_data->i2s_pwn_shift);
+	return 0;
+}
+
+static void mt2701_afe_i2s_shutdown(struct snd_pcm_substream *substream,
+				    struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+	int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
+	struct mt2701_i2s_path *i2s_path;
+	int clk_num = MT2701_AUD_AUD_I2S1_MCLK + i2s_num;
+
+	if (i2s_num < 0)
+		return;
+
+	i2s_path = &afe_priv->i2s_path[i2s_num];
+
+	if (i2s_path->occupied[substream->stream])
+		i2s_path->occupied[substream->stream] = 0;
+	else
+		goto I2S_UNSTART;
+
+	mt2701_afe_i2s_path_shutdown(substream, dai, 0);
+
+	/* need to disable i2s-out path when disable i2s-in */
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		mt2701_afe_i2s_path_shutdown(substream, dai, 1);
+
+I2S_UNSTART:
+	/* disable mclk */
+	clk_disable_unprepare(afe_priv->clocks[clk_num]);
+}
+
+static int mt2701_i2s_path_prepare_enable(struct snd_pcm_substream *substream,
+					  struct snd_soc_dai *dai,
+					  int dir_invert)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+	int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
+	struct mt2701_i2s_path *i2s_path;
+	const struct mt2701_i2s_data *i2s_data;
+	struct snd_pcm_runtime * const runtime = substream->runtime;
+	int reg, fs, w_len = 1; /* now we support bck 64bits only */
+	int stream_dir = substream->stream;
+	unsigned int mask = 0, val = 0;
+
+	if (i2s_num < 0)
+		return i2s_num;
+
+	i2s_path = &afe_priv->i2s_path[i2s_num];
+
+	if (dir_invert) {
+		if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK)
+			stream_dir = SNDRV_PCM_STREAM_CAPTURE;
+		else
+			stream_dir = SNDRV_PCM_STREAM_PLAYBACK;
+	}
+	i2s_data = i2s_path->i2s_data[stream_dir];
+
+	/* no need to enable if already done */
+	i2s_path->on[stream_dir]++;
+
+	if (i2s_path->on[stream_dir] != 1)
+		return 0;
+
+	fs = mt2701_afe_i2s_fs(runtime->rate);
+
+	mask = ASYS_I2S_CON_FS |
+	       ASYS_I2S_CON_I2S_COUPLE_MODE | /* 0 */
+	       ASYS_I2S_CON_I2S_MODE |
+	       ASYS_I2S_CON_WIDE_MODE;
+
+	val = ASYS_I2S_CON_FS_SET(fs) |
+	      ASYS_I2S_CON_I2S_MODE |
+	      ASYS_I2S_CON_WIDE_MODE_SET(w_len);
+
+	if (stream_dir == SNDRV_PCM_STREAM_CAPTURE) {
+		mask |= ASYS_I2S_IN_PHASE_FIX;
+		val |= ASYS_I2S_IN_PHASE_FIX;
+	}
+
+	regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg, mask, val);
+
+	if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK)
+		reg = ASMO_TIMING_CON1;
+	else
+		reg = ASMI_TIMING_CON1;
+
+	regmap_update_bits(afe->regmap, reg,
+			   i2s_data->i2s_asrc_fs_mask
+			   << i2s_data->i2s_asrc_fs_shift,
+			   fs << i2s_data->i2s_asrc_fs_shift);
+
+	/* enable i2s */
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
+			   1 << i2s_data->i2s_pwn_shift,
+			   0 << i2s_data->i2s_pwn_shift);
+
+	/* reset i2s hw status before enable */
+	regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg,
+			   ASYS_I2S_CON_RESET, ASYS_I2S_CON_RESET);
+	udelay(1);
+	regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg,
+			   ASYS_I2S_CON_RESET, 0);
+	udelay(1);
+	regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg,
+			   ASYS_I2S_CON_I2S_EN, ASYS_I2S_CON_I2S_EN);
+	return 0;
+}
+
+static int mt2701_afe_i2s_prepare(struct snd_pcm_substream *substream,
+				  struct snd_soc_dai *dai)
+{
+	int clk_domain;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+	int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
+	struct mt2701_i2s_path *i2s_path;
+	int mclk_rate;
+
+	if (i2s_num < 0)
+		return i2s_num;
+
+	i2s_path = &afe_priv->i2s_path[i2s_num];
+	mclk_rate = i2s_path->mclk_rate;
+
+	if (i2s_path->occupied[substream->stream])
+		return -EBUSY;
+	i2s_path->occupied[substream->stream] = 1;
+
+	if (MT2701_PLL_DOMAIN_0_RATE % mclk_rate == 0) {
+		clk_domain = 0;
+	} else if (MT2701_PLL_DOMAIN_1_RATE % mclk_rate == 0) {
+		clk_domain = 1;
+	} else {
+		dev_err(dai->dev, "%s() bad mclk rate %d\n",
+			__func__, mclk_rate);
+		return -EINVAL;
+	}
+	mt2701_mclk_configuration(afe, i2s_num, clk_domain, mclk_rate);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		mt2701_i2s_path_prepare_enable(substream, dai, 0);
+	} else {
+		/* need to enable i2s-out path when enable i2s-in */
+		/* prepare for another direction "out" */
+		mt2701_i2s_path_prepare_enable(substream, dai, 1);
+		/* prepare for "in" */
+		mt2701_i2s_path_prepare_enable(substream, dai, 0);
+	}
+
+	return 0;
+}
+
+static int mt2701_afe_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+				     unsigned int freq, int dir)
+{
+	struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+	int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
+
+	if (i2s_num < 0)
+		return i2s_num;
+
+	/* mclk */
+	if (dir == SND_SOC_CLOCK_IN) {
+		dev_warn(dai->dev,
+			 "%s() warning: mt2701 doesn't support mclk input\n",
+			__func__);
+		return -EINVAL;
+	}
+	afe_priv->i2s_path[i2s_num].mclk_rate = freq;
+	return 0;
+}
+
+static int mt2701_simple_fe_startup(struct snd_pcm_substream *substream,
+				    struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	int stream_dir = substream->stream;
+	int memif_num = rtd->cpu_dai->id;
+	struct mtk_base_afe_memif *memif_tmp;
+
+	/* can't run single DL & DLM at the same time */
+	if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK) {
+		memif_tmp = &afe->memif[MT2701_MEMIF_DLM];
+		if (memif_tmp->substream) {
+			dev_warn(afe->dev, "%s memif is not available, stream_dir %d, memif_num %d\n",
+				 __func__, stream_dir, memif_num);
+			return -EBUSY;
+		}
+	}
+	return mtk_afe_fe_startup(substream, dai);
+}
+
+static int mt2701_simple_fe_hw_params(struct snd_pcm_substream *substream,
+				      struct snd_pcm_hw_params *params,
+				      struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	int stream_dir = substream->stream;
+
+	/* single DL use PAIR_INTERLEAVE */
+	if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK) {
+		regmap_update_bits(afe->regmap,
+				   AFE_MEMIF_PBUF_SIZE,
+				   AFE_MEMIF_PBUF_SIZE_DLM_MASK,
+				   AFE_MEMIF_PBUF_SIZE_PAIR_INTERLEAVE);
+	}
+	return mtk_afe_fe_hw_params(substream, params, dai);
+}
+
+static int mt2701_dlm_fe_startup(struct snd_pcm_substream *substream,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mtk_base_afe_memif *memif_tmp;
+	const struct mtk_base_memif_data *memif_data;
+	int i;
+
+	for (i = MT2701_MEMIF_DL1; i < MT2701_MEMIF_DL_SINGLE_NUM; ++i) {
+		memif_tmp = &afe->memif[i];
+		if (memif_tmp->substream)
+			return -EBUSY;
+	}
+
+	/* enable agent for all signal DL (due to hw design) */
+	for (i = MT2701_MEMIF_DL1; i < MT2701_MEMIF_DL_SINGLE_NUM; ++i) {
+		memif_data = afe->memif[i].data;
+		regmap_update_bits(afe->regmap,
+				   memif_data->agent_disable_reg,
+				   1 << memif_data->agent_disable_shift,
+				   0 << memif_data->agent_disable_shift);
+	}
+
+	return mtk_afe_fe_startup(substream, dai);
+}
+
+static void mt2701_dlm_fe_shutdown(struct snd_pcm_substream *substream,
+				   struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	const struct mtk_base_memif_data *memif_data;
+	int i;
+
+	for (i = MT2701_MEMIF_DL1; i < MT2701_MEMIF_DL_SINGLE_NUM; ++i) {
+		memif_data = afe->memif[i].data;
+		regmap_update_bits(afe->regmap,
+				   memif_data->agent_disable_reg,
+				   1 << memif_data->agent_disable_shift,
+				   1 << memif_data->agent_disable_shift);
+	}
+	return mtk_afe_fe_shutdown(substream, dai);
+}
+
+static int mt2701_dlm_fe_hw_params(struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params,
+				   struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	int channels = params_channels(params);
+
+	regmap_update_bits(afe->regmap,
+			   AFE_MEMIF_PBUF_SIZE,
+			   AFE_MEMIF_PBUF_SIZE_DLM_MASK,
+			   AFE_MEMIF_PBUF_SIZE_FULL_INTERLEAVE);
+	regmap_update_bits(afe->regmap,
+			   AFE_MEMIF_PBUF_SIZE,
+			   AFE_MEMIF_PBUF_SIZE_DLM_BYTE_MASK,
+			   AFE_MEMIF_PBUF_SIZE_DLM_32BYTES);
+	regmap_update_bits(afe->regmap,
+			   AFE_MEMIF_PBUF_SIZE,
+			   AFE_MEMIF_PBUF_SIZE_DLM_CH_MASK,
+			   AFE_MEMIF_PBUF_SIZE_DLM_CH(channels));
+
+	return mtk_afe_fe_hw_params(substream, params, dai);
+}
+
+static int mt2701_dlm_fe_trigger(struct snd_pcm_substream *substream,
+				 int cmd, struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mtk_base_afe_memif *memif_tmp = &afe->memif[MT2701_MEMIF_DL1];
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		regmap_update_bits(afe->regmap, memif_tmp->data->enable_reg,
+				   1 << memif_tmp->data->enable_shift,
+				   1 << memif_tmp->data->enable_shift);
+		mtk_afe_fe_trigger(substream, cmd, dai);
+		return 0;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		mtk_afe_fe_trigger(substream, cmd, dai);
+		regmap_update_bits(afe->regmap, memif_tmp->data->enable_reg,
+				   1 << memif_tmp->data->enable_shift, 0);
+
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mt2701_memif_fs(struct snd_pcm_substream *substream,
+			   unsigned int rate)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	int fs;
+
+	if (rtd->cpu_dai->id != MT2701_MEMIF_ULBT)
+		fs = mt2701_afe_i2s_fs(rate);
+	else
+		fs = (rate == 16000 ? 1 : 0);
+	return fs;
+}
+
+static int mt2701_irq_fs(struct snd_pcm_substream *substream, unsigned int rate)
+{
+	return mt2701_afe_i2s_fs(rate);
+}
+
+/* FE DAIs */
+static const struct snd_soc_dai_ops mt2701_single_memif_dai_ops = {
+	.startup	= mt2701_simple_fe_startup,
+	.shutdown	= mtk_afe_fe_shutdown,
+	.hw_params	= mt2701_simple_fe_hw_params,
+	.hw_free	= mtk_afe_fe_hw_free,
+	.prepare	= mtk_afe_fe_prepare,
+	.trigger	= mtk_afe_fe_trigger,
+
+};
+
+static const struct snd_soc_dai_ops mt2701_dlm_memif_dai_ops = {
+	.startup	= mt2701_dlm_fe_startup,
+	.shutdown	= mt2701_dlm_fe_shutdown,
+	.hw_params	= mt2701_dlm_fe_hw_params,
+	.hw_free	= mtk_afe_fe_hw_free,
+	.prepare	= mtk_afe_fe_prepare,
+	.trigger	= mt2701_dlm_fe_trigger,
+};
+
+/* I2S BE DAIs */
+static const struct snd_soc_dai_ops mt2701_afe_i2s_ops = {
+	.startup	= mt2701_afe_i2s_startup,
+	.shutdown	= mt2701_afe_i2s_shutdown,
+	.prepare	= mt2701_afe_i2s_prepare,
+	.set_sysclk	= mt2701_afe_i2s_set_sysclk,
+};
+
+static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
+	/* FE DAIs: memory intefaces to CPU */
+	{
+		.name = "PCM_multi",
+		.id = MT2701_MEMIF_DLM,
+		.suspend = mtk_afe_dai_suspend,
+		.resume = mtk_afe_dai_resume,
+		.playback = {
+			.stream_name = "DLM",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE
+				| SNDRV_PCM_FMTBIT_S24_LE
+				| SNDRV_PCM_FMTBIT_S32_LE)
+
+		},
+		.ops = &mt2701_dlm_memif_dai_ops,
+	},
+	{
+		.name = "PCM0",
+		.id = MT2701_MEMIF_UL1,
+		.suspend = mtk_afe_dai_suspend,
+		.resume = mtk_afe_dai_resume,
+		.capture = {
+			.stream_name = "UL1",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE
+				| SNDRV_PCM_FMTBIT_S24_LE
+				| SNDRV_PCM_FMTBIT_S32_LE)
+		},
+		.ops = &mt2701_single_memif_dai_ops,
+	},
+	{
+		.name = "PCM1",
+		.id = MT2701_MEMIF_UL2,
+		.suspend = mtk_afe_dai_suspend,
+		.resume = mtk_afe_dai_resume,
+		.capture = {
+			.stream_name = "UL2",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE
+				| SNDRV_PCM_FMTBIT_S24_LE
+				| SNDRV_PCM_FMTBIT_S32_LE)
+
+		},
+		.ops = &mt2701_single_memif_dai_ops,
+	},
+	/* BE DAIs */
+	{
+		.name = "I2S0",
+		.id = MT2701_IO_I2S,
+		.playback = {
+			.stream_name = "I2S0 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE
+				| SNDRV_PCM_FMTBIT_S24_LE
+				| SNDRV_PCM_FMTBIT_S32_LE)
+
+		},
+		.capture = {
+			.stream_name = "I2S0 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE
+				| SNDRV_PCM_FMTBIT_S24_LE
+				| SNDRV_PCM_FMTBIT_S32_LE)
+
+		},
+		.ops = &mt2701_afe_i2s_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.name = "I2S1",
+		.id = MT2701_IO_2ND_I2S,
+		.playback = {
+			.stream_name = "I2S1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE
+				| SNDRV_PCM_FMTBIT_S24_LE
+				| SNDRV_PCM_FMTBIT_S32_LE)
+			},
+		.capture = {
+			.stream_name = "I2S1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE
+				| SNDRV_PCM_FMTBIT_S24_LE
+				| SNDRV_PCM_FMTBIT_S32_LE)
+			},
+		.ops = &mt2701_afe_i2s_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.name = "I2S2",
+		.id = MT2701_IO_3RD_I2S,
+		.playback = {
+			.stream_name = "I2S2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE
+				| SNDRV_PCM_FMTBIT_S24_LE
+				| SNDRV_PCM_FMTBIT_S32_LE)
+			},
+		.capture = {
+			.stream_name = "I2S2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE
+				| SNDRV_PCM_FMTBIT_S24_LE
+				| SNDRV_PCM_FMTBIT_S32_LE)
+			},
+		.ops = &mt2701_afe_i2s_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.name = "I2S3",
+		.id = MT2701_IO_4TH_I2S,
+		.playback = {
+			.stream_name = "I2S3 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE
+				| SNDRV_PCM_FMTBIT_S24_LE
+				| SNDRV_PCM_FMTBIT_S32_LE)
+			},
+		.capture = {
+			.stream_name = "I2S3 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE
+				| SNDRV_PCM_FMTBIT_S24_LE
+				| SNDRV_PCM_FMTBIT_S32_LE)
+			},
+		.ops = &mt2701_afe_i2s_ops,
+		.symmetric_rates = 1,
+	},
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o00_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN0, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o01_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN1, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o02_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I02 Switch", AFE_CONN2, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o03_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN3, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o14_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN14, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o15_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I12 Switch", AFE_CONN15, 12, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o16_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I13 Switch", AFE_CONN16, 13, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o17_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN17, 14, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o18_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN18, 15, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o19_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN19, 16, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o20_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN20, 17, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o21_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN21, 18, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o22_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN22, 19, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o23_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN23, 20, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o24_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN24, 21, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o31_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I35 Switch", AFE_CONN41, 9, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_i02_mix[] = {
+	SOC_DAPM_SINGLE("I2S0 Switch", SND_SOC_NOPM, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s0[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Multich I2S0 Out Switch",
+				    ASYS_I2SO1_CON, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s1[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Multich I2S1 Out Switch",
+				    ASYS_I2SO2_CON, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s2[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Multich I2S2 Out Switch",
+				    PWR2_TOP_CON, 17, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s3[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Multich I2S3 Out Switch",
+				    PWR2_TOP_CON, 18, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s4[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Multich I2S4 Out Switch",
+				    PWR2_TOP_CON, 19, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc0[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Asrc0 out Switch", AUDIO_TOP_CON4, 14, 1,
+				    1),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc1[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Asrc1 out Switch", AUDIO_TOP_CON4, 15, 1,
+				    1),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc2[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Asrc2 out Switch", PWR2_TOP_CON, 6, 1,
+				    1),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc3[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Asrc3 out Switch", PWR2_TOP_CON, 7, 1,
+				    1),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc4[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Asrc4 out Switch", PWR2_TOP_CON, 8, 1,
+				    1),
+};
+
+static const struct snd_soc_dapm_widget mt2701_afe_pcm_widgets[] = {
+	/* inter-connections */
+	SND_SOC_DAPM_MIXER("I00", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I01", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I02", SND_SOC_NOPM, 0, 0, mt2701_afe_i02_mix,
+			   ARRAY_SIZE(mt2701_afe_i02_mix)),
+	SND_SOC_DAPM_MIXER("I03", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I12", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I13", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I14", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I15", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I16", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I17", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I18", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I19", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I26", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I35", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER("O00", SND_SOC_NOPM, 0, 0, mt2701_afe_o00_mix,
+			   ARRAY_SIZE(mt2701_afe_o00_mix)),
+	SND_SOC_DAPM_MIXER("O01", SND_SOC_NOPM, 0, 0, mt2701_afe_o01_mix,
+			   ARRAY_SIZE(mt2701_afe_o01_mix)),
+	SND_SOC_DAPM_MIXER("O02", SND_SOC_NOPM, 0, 0, mt2701_afe_o02_mix,
+			   ARRAY_SIZE(mt2701_afe_o02_mix)),
+	SND_SOC_DAPM_MIXER("O03", SND_SOC_NOPM, 0, 0, mt2701_afe_o03_mix,
+			   ARRAY_SIZE(mt2701_afe_o03_mix)),
+	SND_SOC_DAPM_MIXER("O14", SND_SOC_NOPM, 0, 0, mt2701_afe_o14_mix,
+			   ARRAY_SIZE(mt2701_afe_o14_mix)),
+	SND_SOC_DAPM_MIXER("O15", SND_SOC_NOPM, 0, 0, mt2701_afe_o15_mix,
+			   ARRAY_SIZE(mt2701_afe_o15_mix)),
+	SND_SOC_DAPM_MIXER("O16", SND_SOC_NOPM, 0, 0, mt2701_afe_o16_mix,
+			   ARRAY_SIZE(mt2701_afe_o16_mix)),
+	SND_SOC_DAPM_MIXER("O17", SND_SOC_NOPM, 0, 0, mt2701_afe_o17_mix,
+			   ARRAY_SIZE(mt2701_afe_o17_mix)),
+	SND_SOC_DAPM_MIXER("O18", SND_SOC_NOPM, 0, 0, mt2701_afe_o18_mix,
+			   ARRAY_SIZE(mt2701_afe_o18_mix)),
+	SND_SOC_DAPM_MIXER("O19", SND_SOC_NOPM, 0, 0, mt2701_afe_o19_mix,
+			   ARRAY_SIZE(mt2701_afe_o19_mix)),
+	SND_SOC_DAPM_MIXER("O20", SND_SOC_NOPM, 0, 0, mt2701_afe_o20_mix,
+			   ARRAY_SIZE(mt2701_afe_o20_mix)),
+	SND_SOC_DAPM_MIXER("O21", SND_SOC_NOPM, 0, 0, mt2701_afe_o21_mix,
+			   ARRAY_SIZE(mt2701_afe_o21_mix)),
+	SND_SOC_DAPM_MIXER("O22", SND_SOC_NOPM, 0, 0, mt2701_afe_o22_mix,
+			   ARRAY_SIZE(mt2701_afe_o22_mix)),
+	SND_SOC_DAPM_MIXER("O31", SND_SOC_NOPM, 0, 0, mt2701_afe_o31_mix,
+			   ARRAY_SIZE(mt2701_afe_o31_mix)),
+
+	SND_SOC_DAPM_MIXER("I12I13", SND_SOC_NOPM, 0, 0,
+			   mt2701_afe_multi_ch_out_i2s0,
+			   ARRAY_SIZE(mt2701_afe_multi_ch_out_i2s0)),
+	SND_SOC_DAPM_MIXER("I14I15", SND_SOC_NOPM, 0, 0,
+			   mt2701_afe_multi_ch_out_i2s1,
+			   ARRAY_SIZE(mt2701_afe_multi_ch_out_i2s1)),
+	SND_SOC_DAPM_MIXER("I16I17", SND_SOC_NOPM, 0, 0,
+			   mt2701_afe_multi_ch_out_i2s2,
+			   ARRAY_SIZE(mt2701_afe_multi_ch_out_i2s2)),
+	SND_SOC_DAPM_MIXER("I18I19", SND_SOC_NOPM, 0, 0,
+			   mt2701_afe_multi_ch_out_i2s3,
+			   ARRAY_SIZE(mt2701_afe_multi_ch_out_i2s3)),
+
+	SND_SOC_DAPM_MIXER("ASRC_O0", SND_SOC_NOPM, 0, 0,
+			   mt2701_afe_multi_ch_out_asrc0,
+			   ARRAY_SIZE(mt2701_afe_multi_ch_out_asrc0)),
+	SND_SOC_DAPM_MIXER("ASRC_O1", SND_SOC_NOPM, 0, 0,
+			   mt2701_afe_multi_ch_out_asrc1,
+			   ARRAY_SIZE(mt2701_afe_multi_ch_out_asrc1)),
+	SND_SOC_DAPM_MIXER("ASRC_O2", SND_SOC_NOPM, 0, 0,
+			   mt2701_afe_multi_ch_out_asrc2,
+			   ARRAY_SIZE(mt2701_afe_multi_ch_out_asrc2)),
+	SND_SOC_DAPM_MIXER("ASRC_O3", SND_SOC_NOPM, 0, 0,
+			   mt2701_afe_multi_ch_out_asrc3,
+			   ARRAY_SIZE(mt2701_afe_multi_ch_out_asrc3)),
+};
+
+static const struct snd_soc_dapm_route mt2701_afe_pcm_routes[] = {
+	{"I12", NULL, "DL1"},
+	{"I13", NULL, "DL1"},
+	{"I35", NULL, "DLBT"},
+
+	{"I2S0 Playback", NULL, "O15"},
+	{"I2S0 Playback", NULL, "O16"},
+
+	{"I2S1 Playback", NULL, "O17"},
+	{"I2S1 Playback", NULL, "O18"},
+	{"I2S2 Playback", NULL, "O19"},
+	{"I2S2 Playback", NULL, "O20"},
+	{"I2S3 Playback", NULL, "O21"},
+	{"I2S3 Playback", NULL, "O22"},
+	{"BT Playback", NULL, "O31"},
+
+	{"UL1", NULL, "O00"},
+	{"UL1", NULL, "O01"},
+	{"UL2", NULL, "O02"},
+	{"UL2", NULL, "O03"},
+	{"ULBT", NULL, "O14"},
+
+	{"I00", NULL, "I2S0 Capture"},
+	{"I01", NULL, "I2S0 Capture"},
+
+	{"I02", NULL, "I2S1 Capture"},
+	{"I03", NULL, "I2S1 Capture"},
+	/* I02,03 link to UL2, also need to open I2S0 */
+	{"I02", "I2S0 Switch", "I2S0 Capture"},
+
+	{"I26", NULL, "BT Capture"},
+
+	{"ASRC_O0", "Asrc0 out Switch", "DLM"},
+	{"ASRC_O1", "Asrc1 out Switch", "DLM"},
+	{"ASRC_O2", "Asrc2 out Switch", "DLM"},
+	{"ASRC_O3", "Asrc3 out Switch", "DLM"},
+
+	{"I12I13", "Multich I2S0 Out Switch", "ASRC_O0"},
+	{"I14I15", "Multich I2S1 Out Switch", "ASRC_O1"},
+	{"I16I17", "Multich I2S2 Out Switch", "ASRC_O2"},
+	{"I18I19", "Multich I2S3 Out Switch", "ASRC_O3"},
+
+	{ "I12", NULL, "I12I13" },
+	{ "I13", NULL, "I12I13" },
+	{ "I14", NULL, "I14I15" },
+	{ "I15", NULL, "I14I15" },
+	{ "I16", NULL, "I16I17" },
+	{ "I17", NULL, "I16I17" },
+	{ "I18", NULL, "I18I19" },
+	{ "I19", NULL, "I18I19" },
+
+	{ "O00", "I00 Switch", "I00" },
+	{ "O01", "I01 Switch", "I01" },
+	{ "O02", "I02 Switch", "I02" },
+	{ "O03", "I03 Switch", "I03" },
+	{ "O14", "I26 Switch", "I26" },
+	{ "O15", "I12 Switch", "I12" },
+	{ "O16", "I13 Switch", "I13" },
+	{ "O17", "I14 Switch", "I14" },
+	{ "O18", "I15 Switch", "I15" },
+	{ "O19", "I16 Switch", "I16" },
+	{ "O20", "I17 Switch", "I17" },
+	{ "O21", "I18 Switch", "I18" },
+	{ "O22", "I19 Switch", "I19" },
+	{ "O31", "I35 Switch", "I35" },
+
+};
+
+static const struct snd_soc_component_driver mt2701_afe_pcm_dai_component = {
+	.name = "mt2701-afe-pcm-dai",
+	.dapm_widgets = mt2701_afe_pcm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(mt2701_afe_pcm_widgets),
+	.dapm_routes = mt2701_afe_pcm_routes,
+	.num_dapm_routes = ARRAY_SIZE(mt2701_afe_pcm_routes),
+};
+
+static const struct mtk_base_memif_data memif_data[MT2701_MEMIF_NUM] = {
+	{
+		.name = "DL1",
+		.id = MT2701_MEMIF_DL1,
+		.reg_ofs_base = AFE_DL1_BASE,
+		.reg_ofs_cur = AFE_DL1_CUR,
+		.fs_reg = AFE_DAC_CON1,
+		.fs_shift = 0,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_DAC_CON3,
+		.mono_shift = 16,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 1,
+		.hd_reg = AFE_MEMIF_HD_CON0,
+		.hd_shift = 0,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 6,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	{
+		.name = "DL2",
+		.id = MT2701_MEMIF_DL2,
+		.reg_ofs_base = AFE_DL2_BASE,
+		.reg_ofs_cur = AFE_DL2_CUR,
+		.fs_reg = AFE_DAC_CON1,
+		.fs_shift = 5,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_DAC_CON3,
+		.mono_shift = 17,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 2,
+		.hd_reg = AFE_MEMIF_HD_CON0,
+		.hd_shift = 2,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 7,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	{
+		.name = "DL3",
+		.id = MT2701_MEMIF_DL3,
+		.reg_ofs_base = AFE_DL3_BASE,
+		.reg_ofs_cur = AFE_DL3_CUR,
+		.fs_reg = AFE_DAC_CON1,
+		.fs_shift = 10,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_DAC_CON3,
+		.mono_shift = 18,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 3,
+		.hd_reg = AFE_MEMIF_HD_CON0,
+		.hd_shift = 4,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 8,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	{
+		.name = "DL4",
+		.id = MT2701_MEMIF_DL4,
+		.reg_ofs_base = AFE_DL4_BASE,
+		.reg_ofs_cur = AFE_DL4_CUR,
+		.fs_reg = AFE_DAC_CON1,
+		.fs_shift = 15,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_DAC_CON3,
+		.mono_shift = 19,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 4,
+		.hd_reg = AFE_MEMIF_HD_CON0,
+		.hd_shift = 6,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 9,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	{
+		.name = "DL5",
+		.id = MT2701_MEMIF_DL5,
+		.reg_ofs_base = AFE_DL5_BASE,
+		.reg_ofs_cur = AFE_DL5_CUR,
+		.fs_reg = AFE_DAC_CON1,
+		.fs_shift = 20,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_DAC_CON3,
+		.mono_shift = 20,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 5,
+		.hd_reg = AFE_MEMIF_HD_CON0,
+		.hd_shift = 8,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 10,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	{
+		.name = "DLM",
+		.id = MT2701_MEMIF_DLM,
+		.reg_ofs_base = AFE_DLMCH_BASE,
+		.reg_ofs_cur = AFE_DLMCH_CUR,
+		.fs_reg = AFE_DAC_CON1,
+		.fs_shift = 0,
+		.fs_maskbit = 0x1f,
+		.mono_reg = -1,
+		.mono_shift = -1,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 7,
+		.hd_reg = AFE_MEMIF_PBUF_SIZE,
+		.hd_shift = 28,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 12,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	{
+		.name = "UL1",
+		.id = MT2701_MEMIF_UL1,
+		.reg_ofs_base = AFE_VUL_BASE,
+		.reg_ofs_cur = AFE_VUL_CUR,
+		.fs_reg = AFE_DAC_CON2,
+		.fs_shift = 0,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_DAC_CON4,
+		.mono_shift = 0,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 10,
+		.hd_reg = AFE_MEMIF_HD_CON1,
+		.hd_shift = 0,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 0,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	{
+		.name = "UL2",
+		.id = MT2701_MEMIF_UL2,
+		.reg_ofs_base = AFE_UL2_BASE,
+		.reg_ofs_cur = AFE_UL2_CUR,
+		.fs_reg = AFE_DAC_CON2,
+		.fs_shift = 5,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_DAC_CON4,
+		.mono_shift = 2,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 11,
+		.hd_reg = AFE_MEMIF_HD_CON1,
+		.hd_shift = 2,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 1,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	{
+		.name = "UL3",
+		.id = MT2701_MEMIF_UL3,
+		.reg_ofs_base = AFE_UL3_BASE,
+		.reg_ofs_cur = AFE_UL3_CUR,
+		.fs_reg = AFE_DAC_CON2,
+		.fs_shift = 10,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_DAC_CON4,
+		.mono_shift = 4,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 12,
+		.hd_reg = AFE_MEMIF_HD_CON0,
+		.hd_shift = 0,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 2,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	{
+		.name = "UL4",
+		.id = MT2701_MEMIF_UL4,
+		.reg_ofs_base = AFE_UL4_BASE,
+		.reg_ofs_cur = AFE_UL4_CUR,
+		.fs_reg = AFE_DAC_CON2,
+		.fs_shift = 15,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_DAC_CON4,
+		.mono_shift = 6,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 13,
+		.hd_reg = AFE_MEMIF_HD_CON0,
+		.hd_shift = 6,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 3,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	{
+		.name = "UL5",
+		.id = MT2701_MEMIF_UL5,
+		.reg_ofs_base = AFE_UL5_BASE,
+		.reg_ofs_cur = AFE_UL5_CUR,
+		.fs_reg = AFE_DAC_CON2,
+		.fs_shift = 20,
+		.mono_reg = AFE_DAC_CON4,
+		.mono_shift = 8,
+		.fs_maskbit = 0x1f,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 14,
+		.hd_reg = AFE_MEMIF_HD_CON0,
+		.hd_shift = 8,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 4,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	{
+		.name = "DLBT",
+		.id = MT2701_MEMIF_DLBT,
+		.reg_ofs_base = AFE_ARB1_BASE,
+		.reg_ofs_cur = AFE_ARB1_CUR,
+		.fs_reg = AFE_DAC_CON3,
+		.fs_shift = 10,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_DAC_CON3,
+		.mono_shift = 22,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 8,
+		.hd_reg = AFE_MEMIF_HD_CON0,
+		.hd_shift = 14,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 13,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	{
+		.name = "ULBT",
+		.id = MT2701_MEMIF_ULBT,
+		.reg_ofs_base = AFE_DAI_BASE,
+		.reg_ofs_cur = AFE_DAI_CUR,
+		.fs_reg = AFE_DAC_CON2,
+		.fs_shift = 30,
+		.fs_maskbit = 0x1,
+		.mono_reg = -1,
+		.mono_shift = -1,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 17,
+		.hd_reg = AFE_MEMIF_HD_CON1,
+		.hd_shift = 20,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 16,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+};
+
+static const struct mtk_base_irq_data irq_data[MT2701_IRQ_ASYS_END] = {
+	{
+		.id = MT2701_IRQ_ASYS_IRQ1,
+		.irq_cnt_reg = ASYS_IRQ1_CON,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0xffffff,
+		.irq_fs_reg = ASYS_IRQ1_CON,
+		.irq_fs_shift = 24,
+		.irq_fs_maskbit = 0x1f,
+		.irq_en_reg = ASYS_IRQ1_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg = ASYS_IRQ_CLR,
+		.irq_clr_shift = 0,
+	},
+	{
+		.id = MT2701_IRQ_ASYS_IRQ2,
+		.irq_cnt_reg = ASYS_IRQ2_CON,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0xffffff,
+		.irq_fs_reg = ASYS_IRQ2_CON,
+		.irq_fs_shift = 24,
+		.irq_fs_maskbit = 0x1f,
+		.irq_en_reg = ASYS_IRQ2_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg = ASYS_IRQ_CLR,
+		.irq_clr_shift = 1,
+	},
+	{
+		.id = MT2701_IRQ_ASYS_IRQ3,
+		.irq_cnt_reg = ASYS_IRQ3_CON,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0xffffff,
+		.irq_fs_reg = ASYS_IRQ3_CON,
+		.irq_fs_shift = 24,
+		.irq_fs_maskbit = 0x1f,
+		.irq_en_reg = ASYS_IRQ3_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg = ASYS_IRQ_CLR,
+		.irq_clr_shift = 2,
+	}
+};
+
+static const struct mt2701_i2s_data mt2701_i2s_data[MT2701_I2S_NUM][2] = {
+	{
+		{
+			.i2s_ctrl_reg = ASYS_I2SO1_CON,
+			.i2s_pwn_shift = 6,
+			.i2s_asrc_fs_shift = 0,
+			.i2s_asrc_fs_mask = 0x1f,
+
+		},
+		{
+			.i2s_ctrl_reg = ASYS_I2SIN1_CON,
+			.i2s_pwn_shift = 0,
+			.i2s_asrc_fs_shift = 0,
+			.i2s_asrc_fs_mask = 0x1f,
+
+		},
+	},
+	{
+		{
+			.i2s_ctrl_reg = ASYS_I2SO2_CON,
+			.i2s_pwn_shift = 7,
+			.i2s_asrc_fs_shift = 5,
+			.i2s_asrc_fs_mask = 0x1f,
+
+		},
+		{
+			.i2s_ctrl_reg = ASYS_I2SIN2_CON,
+			.i2s_pwn_shift = 1,
+			.i2s_asrc_fs_shift = 5,
+			.i2s_asrc_fs_mask = 0x1f,
+
+		},
+	},
+	{
+		{
+			.i2s_ctrl_reg = ASYS_I2SO3_CON,
+			.i2s_pwn_shift = 8,
+			.i2s_asrc_fs_shift = 10,
+			.i2s_asrc_fs_mask = 0x1f,
+
+		},
+		{
+			.i2s_ctrl_reg = ASYS_I2SIN3_CON,
+			.i2s_pwn_shift = 2,
+			.i2s_asrc_fs_shift = 10,
+			.i2s_asrc_fs_mask = 0x1f,
+
+		},
+	},
+	{
+		{
+			.i2s_ctrl_reg = ASYS_I2SO4_CON,
+			.i2s_pwn_shift = 9,
+			.i2s_asrc_fs_shift = 15,
+			.i2s_asrc_fs_mask = 0x1f,
+
+		},
+		{
+			.i2s_ctrl_reg = ASYS_I2SIN4_CON,
+			.i2s_pwn_shift = 3,
+			.i2s_asrc_fs_shift = 15,
+			.i2s_asrc_fs_mask = 0x1f,
+
+		},
+	},
+};
+
+static const struct regmap_config mt2701_afe_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = AFE_END_ADDR,
+	.cache_type = REGCACHE_NONE,
+};
+
+static irqreturn_t mt2701_asys_isr(int irq_id, void *dev)
+{
+	int id;
+	struct mtk_base_afe *afe = dev;
+	struct mtk_base_afe_memif *memif;
+	struct mtk_base_afe_irq *irq;
+	u32 status;
+
+	regmap_read(afe->regmap, ASYS_IRQ_STATUS, &status);
+	regmap_write(afe->regmap, ASYS_IRQ_CLR, status);
+
+	for (id = 0; id < MT2701_MEMIF_NUM; ++id) {
+		memif = &afe->memif[id];
+		if (memif->irq_usage < 0)
+			continue;
+		irq = &afe->irqs[memif->irq_usage];
+		if (status & 1 << (irq->irq_data->irq_clr_shift))
+			snd_pcm_period_elapsed(memif->substream);
+	}
+	return IRQ_HANDLED;
+}
+
+static int mt2701_afe_runtime_suspend(struct device *dev)
+{
+	struct mtk_base_afe *afe = dev_get_drvdata(dev);
+
+	mt2701_afe_disable_clock(afe);
+	return 0;
+}
+
+static int mt2701_afe_runtime_resume(struct device *dev)
+{
+	struct mtk_base_afe *afe = dev_get_drvdata(dev);
+
+	return mt2701_afe_enable_clock(afe);
+}
+
+static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev)
+{
+	int ret, i;
+	unsigned int irq_id;
+	struct mtk_base_afe *afe;
+	struct mt2701_afe_private *afe_priv;
+	struct resource *res;
+	struct device *dev;
+
+	ret = 0;
+	afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
+	afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
+					  GFP_KERNEL);
+	afe_priv = afe->platform_priv;
+	if (!afe)
+		return -ENOMEM;
+
+	afe->dev = &pdev->dev;
+	dev = afe->dev;
+
+	irq_id = platform_get_irq(pdev, 0);
+	if (!irq_id) {
+		dev_err(dev, "%s no irq found\n", dev->of_node->name);
+		return -ENXIO;
+	}
+	ret = devm_request_irq(dev, irq_id, mt2701_asys_isr,
+			       IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
+	if (ret) {
+		dev_err(dev, "could not request_irq for asys-isr\n");
+		return ret;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	afe->base_addr = devm_ioremap_resource(&pdev->dev, res);
+
+	if (IS_ERR(afe->base_addr))
+		return PTR_ERR(afe->base_addr);
+
+	afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr,
+		&mt2701_afe_regmap_config);
+	if (IS_ERR(afe->regmap))
+		return PTR_ERR(afe->regmap);
+
+	mutex_init(&afe->irq_alloc_lock);
+
+	/* memif initialize */
+	afe->memif_size = MT2701_MEMIF_NUM;
+	afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif),
+				  GFP_KERNEL);
+
+	if (!afe->memif)
+		return -ENOMEM;
+
+	for (i = 0; i < afe->memif_size; i++) {
+		afe->memif[i].data = &memif_data[i];
+		afe->memif[i].irq_usage = -1;
+	}
+
+	/* irq initialize */
+	afe->irqs_size = MT2701_IRQ_ASYS_END;
+	afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs),
+				 GFP_KERNEL);
+
+	if (!afe->irqs)
+		return -ENOMEM;
+
+	for (i = 0; i < afe->irqs_size; i++)
+		afe->irqs[i].irq_data = &irq_data[i];
+
+	/* I2S initialize */
+	for (i = 0; i < MT2701_I2S_NUM; i++) {
+		afe_priv->i2s_path[i].i2s_data[I2S_OUT]
+			= &mt2701_i2s_data[i][I2S_OUT];
+		afe_priv->i2s_path[i].i2s_data[I2S_IN]
+			= &mt2701_i2s_data[i][I2S_IN];
+	}
+
+	afe->mtk_afe_hardware = &mt2701_afe_hardware;
+	afe->memif_fs = mt2701_memif_fs;
+	afe->irq_fs = mt2701_irq_fs;
+
+	afe->reg_back_up_list = mt2701_afe_backup_list;
+	afe->reg_back_up_list_num = ARRAY_SIZE(mt2701_afe_backup_list);
+	afe->runtime_resume = mt2701_afe_runtime_resume;
+	afe->runtime_suspend = mt2701_afe_runtime_suspend;
+
+	/* initial audio related clock */
+	ret = mt2701_init_clock(afe);
+	if (ret) {
+		dev_err(dev, "init clock error\n");
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, afe);
+	pm_runtime_enable(&pdev->dev);
+	if (!pm_runtime_enabled(&pdev->dev))
+		goto err_pm_disable;
+
+	ret = snd_soc_register_platform(&pdev->dev, &mtk_afe_pcm_platform);
+	if (ret) {
+		dev_warn(dev, "err_platform\n");
+		goto err_platform;
+	}
+
+	ret = snd_soc_register_component(&pdev->dev,
+					 &mt2701_afe_pcm_dai_component,
+					 mt2701_afe_pcm_dais,
+					 ARRAY_SIZE(mt2701_afe_pcm_dais));
+	if (ret) {
+		dev_warn(dev, "err_dai_component\n");
+		goto err_dai_component;
+	}
+
+	mt2701_afe_runtime_resume(&pdev->dev);
+
+	return 0;
+
+err_dai_component:
+	snd_soc_unregister_component(&pdev->dev);
+
+err_platform:
+	snd_soc_unregister_platform(&pdev->dev);
+
+err_pm_disable:
+	pm_runtime_disable(&pdev->dev);
+
+	return ret;
+}
+
+static int mt2701_afe_pcm_dev_remove(struct platform_device *pdev)
+{
+	struct mtk_base_afe *afe = platform_get_drvdata(pdev);
+
+	pm_runtime_disable(&pdev->dev);
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		mt2701_afe_runtime_suspend(&pdev->dev);
+
+	snd_soc_unregister_component(&pdev->dev);
+	snd_soc_unregister_platform(&pdev->dev);
+	/* disable afe clock */
+	mt2701_afe_disable_clock(afe);
+	return 0;
+}
+
+static const struct of_device_id mt2701_afe_pcm_dt_match[] = {
+	{ .compatible = "mediatek,mt2701-audio", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mt2701_afe_pcm_dt_match);
+
+static const struct dev_pm_ops mt2701_afe_pm_ops = {
+	SET_RUNTIME_PM_OPS(mt2701_afe_runtime_suspend,
+			   mt2701_afe_runtime_resume, NULL)
+};
+
+static struct platform_driver mt2701_afe_pcm_driver = {
+	.driver = {
+		   .name = "mt2701-audio",
+		   .of_match_table = mt2701_afe_pcm_dt_match,
+#ifdef CONFIG_PM
+		   .pm = &mt2701_afe_pm_ops,
+#endif
+	},
+	.probe = mt2701_afe_pcm_dev_probe,
+	.remove = mt2701_afe_pcm_dev_remove,
+};
+
+module_platform_driver(mt2701_afe_pcm_driver);
+
+MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver for 2701");
+MODULE_AUTHOR("Garlic Tseng <garlic.tseng at mediatek.com>");
+MODULE_LICENSE("GPL v2");
+
-- 
1.9.1



From garlic.tseng at mediatek.com  Mon Jul  4 03:56:27 2016
From: garlic.tseng at mediatek.com (Garlic Tseng)
Date: Mon, 4 Jul 2016 18:56:27 +0800
Subject: [alsa-devel] [PATCH 3/4] ASoC: mediatek: add BT implementation
In-Reply-To: <1467629788-14411-1-git-send-email-garlic.tseng@mediatek.com>
References: <1467629788-14411-1-git-send-email-garlic.tseng@mediatek.com>
Message-ID: <1467629788-14411-4-git-send-email-garlic.tseng@mediatek.com>

Add BT implementation for mt2701 platform driver.

Signed-off-by: Garlic Tseng <garlic.tseng at mediatek.com>
---
 sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | 139 +++++++++++++++++++++++++++++
 1 file changed, 139 insertions(+)

diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
index c865ba1..6c14d68 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
@@ -333,6 +333,86 @@ static int mt2701_afe_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 	return 0;
 }
 
+static int mt2701_btmrg_startup(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
+			   AUDIO_TOP_CON4_PDN_MRGIF, 0);
+
+	afe_priv->mrg_enable[substream->stream] = 1;
+	return 0;
+}
+
+static int mt2701_btmrg_hw_params(struct snd_pcm_substream *substream,
+				  struct snd_pcm_hw_params *params,
+				  struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	int stream_fs;
+	u32 val, msk;
+
+	stream_fs = params_rate(params);
+
+	if ((stream_fs != 8000) && (stream_fs != 16000)) {
+		dev_err(afe->dev, "%s() btmgr not supprt this stream_fs %d\n",
+			__func__, stream_fs);
+		return -EINVAL;
+	}
+
+	regmap_update_bits(afe->regmap, AFE_MRGIF_CON,
+			   AFE_MRGIF_CON_I2S_MODE_MASK,
+			   AFE_MRGIF_CON_I2S_MODE_32K);
+
+	val = AFE_DAIBT_CON0_BT_FUNC_EN | AFE_DAIBT_CON0_BT_FUNC_RDY
+	      | AFE_DAIBT_CON0_MRG_USE;
+	msk = val;
+
+	if (stream_fs == 16000)
+		val |= AFE_DAIBT_CON0_BT_WIDE_MODE_EN;
+
+	msk |= AFE_DAIBT_CON0_BT_WIDE_MODE_EN;
+
+	regmap_update_bits(afe->regmap, AFE_DAIBT_CON0, msk, val);
+
+	regmap_update_bits(afe->regmap, AFE_DAIBT_CON0,
+			   AFE_DAIBT_CON0_DAIBT_EN,
+			   AFE_DAIBT_CON0_DAIBT_EN);
+	regmap_update_bits(afe->regmap, AFE_MRGIF_CON,
+			   AFE_MRGIF_CON_MRG_I2S_EN,
+			   AFE_MRGIF_CON_MRG_I2S_EN);
+	regmap_update_bits(afe->regmap, AFE_MRGIF_CON,
+			   AFE_MRGIF_CON_MRG_EN,
+			   AFE_MRGIF_CON_MRG_EN);
+	return 0;
+}
+
+static void mt2701_btmrg_shutdown(struct snd_pcm_substream *substream,
+				  struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+
+	/* if the other direction stream is not occupied */
+	if (!afe_priv->mrg_enable[!substream->stream]) {
+		regmap_update_bits(afe->regmap, AFE_DAIBT_CON0,
+				   AFE_DAIBT_CON0_DAIBT_EN, 0);
+		regmap_update_bits(afe->regmap, AFE_MRGIF_CON,
+				   AFE_MRGIF_CON_MRG_EN, 0);
+		regmap_update_bits(afe->regmap, AFE_MRGIF_CON,
+				   AFE_MRGIF_CON_MRG_I2S_EN, 0);
+		regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
+				   AUDIO_TOP_CON4_PDN_MRGIF,
+				   AUDIO_TOP_CON4_PDN_MRGIF);
+	}
+	afe_priv->mrg_enable[substream->stream] = 0;
+}
+
 static int mt2701_simple_fe_startup(struct snd_pcm_substream *substream,
 				    struct snd_soc_dai *dai)
 {
@@ -514,6 +594,13 @@ static const struct snd_soc_dai_ops mt2701_afe_i2s_ops = {
 	.set_sysclk	= mt2701_afe_i2s_set_sysclk,
 };
 
+/* MRG BE DAIs */
+static struct snd_soc_dai_ops mt2701_btmrg_ops = {
+	.startup = mt2701_btmrg_startup,
+	.shutdown = mt2701_btmrg_shutdown,
+	.hw_params = mt2701_btmrg_hw_params,
+};
+
 static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
 	/* FE DAIs: memory intefaces to CPU */
 	{
@@ -566,6 +653,36 @@ static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
 		},
 		.ops = &mt2701_single_memif_dai_ops,
 	},
+	{
+		.name = "PCM_BT_DL",
+		.id = MT2701_MEMIF_DLBT,
+		.suspend = mtk_afe_dai_suspend,
+		.resume = mtk_afe_dai_resume,
+		.playback = {
+			.stream_name = "DLBT",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = (SNDRV_PCM_RATE_8000
+				| SNDRV_PCM_RATE_16000),
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.ops = &mt2701_single_memif_dai_ops,
+	},
+	{
+		.name = "PCM_BT_UL",
+		.id = MT2701_MEMIF_ULBT,
+		.suspend = mtk_afe_dai_suspend,
+		.resume = mtk_afe_dai_resume,
+		.capture = {
+			.stream_name = "ULBT",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = (SNDRV_PCM_RATE_8000
+				| SNDRV_PCM_RATE_16000),
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.ops = &mt2701_single_memif_dai_ops,
+	},
 	/* BE DAIs */
 	{
 		.name = "I2S0",
@@ -665,6 +782,28 @@ static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
 		.ops = &mt2701_afe_i2s_ops,
 		.symmetric_rates = 1,
 	},
+	{
+		.name = "MRG BT",
+		.id = MT2701_IO_MRG,
+		.playback = {
+			.stream_name = "BT Playback",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = (SNDRV_PCM_RATE_8000
+				| SNDRV_PCM_RATE_16000),
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.capture = {
+			.stream_name = "BT Capture",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = (SNDRV_PCM_RATE_8000
+				| SNDRV_PCM_RATE_16000),
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.ops = &mt2701_btmrg_ops,
+		.symmetric_rates = 1,
+	}
 };
 
 static const struct snd_kcontrol_new mt2701_afe_o00_mix[] = {
-- 
1.9.1



From garlic.tseng at mediatek.com  Mon Jul  4 03:56:28 2016
From: garlic.tseng at mediatek.com (Garlic Tseng)
Date: Mon, 4 Jul 2016 18:56:28 +0800
Subject: [alsa-devel] [PATCH 4/4] ASoC: mediatek: Add mt2701-cs42448 driver
 and config option.
In-Reply-To: <1467629788-14411-1-git-send-email-garlic.tseng@mediatek.com>
References: <1467629788-14411-1-git-send-email-garlic.tseng@mediatek.com>
Message-ID: <1467629788-14411-5-git-send-email-garlic.tseng@mediatek.com>

Add machine driver and config option for MT2701.

Signed-off-by: Garlic Tseng <garlic.tseng at mediatek.com>
---
 sound/soc/mediatek/Kconfig                 |  21 ++
 sound/soc/mediatek/Makefile                |   1 +
 sound/soc/mediatek/mt2701/Makefile         |  19 ++
 sound/soc/mediatek/mt2701/mt2701-cs42448.c | 412 +++++++++++++++++++++++++++++
 4 files changed, 453 insertions(+)
 create mode 100644 sound/soc/mediatek/mt2701/Makefile
 create mode 100644 sound/soc/mediatek/mt2701/mt2701-cs42448.c

diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 705904b..2fbe543 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -1,6 +1,27 @@
 config SND_SOC_MEDIATEK
 	tristate
 
+config SND_SOC_MT2701
+	tristate "ASoC support for Mediatek MT2701 chip"
+	depends on ARCH_MEDIATEK
+	select SND_SOC_MEDIATEK
+	help
+	  This adds ASoC driver for Mediatek MT2701 boards
+	  that can be used with other codecs.
+	  Select Y if you have such device.
+	  If unsure select "N".
+
+config SND_SOC_MT2701_CS42448
+	tristate "ASoc Audio driver for MT2701 with CS42448 codec"
+	depends on SND_SOC_MT2701
+	select SND_SOC_CS42XX8_I2C
+	select SND_SOC_BT_SCO
+	help
+	  This adds ASoC driver for Mediatek MT2701 boards
+	  with the CS42448 codecs.
+	  Select Y if you have such device.
+	  If unsure select "N".
+
 config SND_SOC_MT8173
 	tristate "ASoC support for Mediatek MT8173 chip"
 	depends on ARCH_MEDIATEK
diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile
index 4fe8068..6bcab35 100644
--- a/sound/soc/mediatek/Makefile
+++ b/sound/soc/mediatek/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_SND_SOC_MEDIATEK) += common/
+obj-$(CONFIG_SND_SOC_MT2701) += mt2701/
 obj-$(CONFIG_SND_SOC_MT8173) += mt8173/
diff --git a/sound/soc/mediatek/mt2701/Makefile b/sound/soc/mediatek/mt2701/Makefile
new file mode 100644
index 0000000..31c3d04
--- /dev/null
+++ b/sound/soc/mediatek/mt2701/Makefile
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2015 MediaTek Inc.
+#
+# 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.
+#
+
+# platform driver
+snd-soc-mt2701-afe-objs := mt2701-afe-pcm.o mt2701-afe-clock-ctrl.o
+obj-$(CONFIG_SND_SOC_MT2701) += snd-soc-mt2701-afe.o
+
+# machine driver
+obj-$(CONFIG_SND_SOC_MT2701_CS42448) += mt2701-cs42448.o
diff --git a/sound/soc/mediatek/mt2701/mt2701-cs42448.c b/sound/soc/mediatek/mt2701/mt2701-cs42448.c
new file mode 100644
index 0000000..1e7e8d4
--- /dev/null
+++ b/sound/soc/mediatek/mt2701/mt2701-cs42448.c
@@ -0,0 +1,412 @@
+/*
+ * mt2701-cs42448.c  --  MT2701 CS42448 ALSA SoC machine driver
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ir Lian <ir.lian at mediatek.com>
+ *              Garlic Tseng <garlic.tseng at mediatek.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#include <linux/module.h>
+#include <sound/soc.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/of_gpio.h>
+
+#include "mt2701-afe-common.h"
+
+struct mt2701_cs42448_private {
+	int i2s1_in_mux;
+	int i2s1_in_mux_gpio_sel_1;
+	int i2s1_in_mux_gpio_sel_2;
+};
+
+static const char * const i2sin_mux_switch_text[] = {
+	"ADC_SDOUT2",
+	"ADC_SDOUT3",
+	"I2S_IN_1",
+	"I2S_IN_2",
+};
+
+static const struct soc_enum i2sin_mux_enum =
+	SOC_ENUM_SINGLE_EXT(4, i2sin_mux_switch_text);
+
+static int mt2701_cs42448_i2sin1_mux_get(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+	struct mt2701_cs42448_private *priv = snd_soc_card_get_drvdata(card);
+
+	ucontrol->value.integer.value[0] = priv->i2s1_in_mux;
+	return 0;
+}
+
+static int mt2701_cs42448_i2sin1_mux_set(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+	struct mt2701_cs42448_private *priv = snd_soc_card_get_drvdata(card);
+
+	if (ucontrol->value.integer.value[0] == priv->i2s1_in_mux)
+		return 0;
+
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 0);
+		gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 0);
+		break;
+	case 1:
+		gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 1);
+		gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 0);
+		break;
+	case 2:
+		gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 0);
+		gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 1);
+		break;
+	case 3:
+		gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 1);
+		gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 1);
+		break;
+	default:
+		dev_warn(card->dev, "%s invalid setting\n", __func__);
+	}
+
+	priv->i2s1_in_mux = ucontrol->value.integer.value[0];
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget
+			mt2701_cs42448_asoc_card_dapm_widgets[] = {
+	SND_SOC_DAPM_LINE("Line Out Jack", NULL),
+	SND_SOC_DAPM_MIC("AMIC", NULL),
+	SND_SOC_DAPM_LINE("Tuner In", NULL),
+	SND_SOC_DAPM_LINE("Satellite Tuner In", NULL),
+	SND_SOC_DAPM_LINE("AUX In", NULL),
+};
+
+static const struct snd_kcontrol_new mt2701_cs42448_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Line Out Jack"),
+	SOC_DAPM_PIN_SWITCH("AMIC"),
+	SOC_DAPM_PIN_SWITCH("Tuner In"),
+	SOC_DAPM_PIN_SWITCH("Satellite Tuner In"),
+	SOC_DAPM_PIN_SWITCH("AUX In"),
+	SOC_ENUM_EXT("I2SIN1_MUX_Switch", i2sin_mux_enum,
+		     mt2701_cs42448_i2sin1_mux_get,
+		     mt2701_cs42448_i2sin1_mux_set),
+};
+
+static const unsigned int mt2701_cs42448_sampling_rates[] = {48000};
+
+static struct snd_pcm_hw_constraint_list mt2701_cs42448_constraints_rates = {
+		.count = ARRAY_SIZE(mt2701_cs42448_sampling_rates),
+		.list = mt2701_cs42448_sampling_rates,
+		.mask = 0,
+};
+
+static int mt2701_cs42448_fe_ops_startup(struct snd_pcm_substream *substream)
+{
+	int err;
+
+	err = snd_pcm_hw_constraint_list(substream->runtime, 0,
+					 SNDRV_PCM_HW_PARAM_RATE,
+					 &mt2701_cs42448_constraints_rates);
+	if (err < 0) {
+		dev_err(substream->pcm->card->dev,
+			"%s snd_pcm_hw_constraint_list failed: 0x%x\n",
+			__func__, err);
+		return err;
+	}
+	return 0;
+}
+
+static struct snd_soc_ops mt2701_cs42448_48k_fe_ops = {
+	.startup = mt2701_cs42448_fe_ops_startup,
+};
+
+static int mt2701_cs42448_be_ops_hw_params(struct snd_pcm_substream *substream,
+					   struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	unsigned int mclk_rate;
+	unsigned int rate = params_rate(params);
+	unsigned int div_mclk_over_bck = rate > 192000 ? 2 : 4;
+	unsigned int div_bck_over_lrck = 64;
+
+	mclk_rate = rate * div_bck_over_lrck * div_mclk_over_bck;
+
+	/* mt2701 mclk */
+	snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_rate, SND_SOC_CLOCK_OUT);
+
+	/* codec mclk */
+	snd_soc_dai_set_sysclk(codec_dai, 0, mclk_rate, SND_SOC_CLOCK_IN);
+
+	return 0;
+}
+
+static struct snd_soc_ops mt2701_cs42448_be_ops = {
+	.hw_params = mt2701_cs42448_be_ops_hw_params
+};
+
+enum {
+	DAI_LINK_FE_MULTI_CH_OUT,
+	DAI_LINK_FE_PCM0_IN,
+	DAI_LINK_FE_PCM1_IN,
+	DAI_LINK_FE_BT_OUT,
+	DAI_LINK_FE_BT_IN,
+	DAI_LINK_BE_I2S0,
+	DAI_LINK_BE_I2S1,
+	DAI_LINK_BE_I2S2,
+	DAI_LINK_BE_I2S3,
+	DAI_LINK_BE_MRG_BT,
+};
+
+static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = {
+	/* FE */
+	[DAI_LINK_FE_MULTI_CH_OUT] = {
+		.name = "mt2701-cs42448-multi-ch-out",
+		.stream_name = "mt2701-cs42448-multi-ch-out",
+		.cpu_dai_name = "PCM_multi",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.ops = &mt2701_cs42448_48k_fe_ops,
+		.dynamic = 1,
+		.dpcm_playback = 1,
+	},
+	[DAI_LINK_FE_PCM0_IN] = {
+		.name = "mt2701-cs42448-pcm0",
+		.stream_name = "mt2701-cs42448-pcm0-data-UL",
+		.cpu_dai_name = "PCM0",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.ops = &mt2701_cs42448_48k_fe_ops,
+		.dynamic = 1,
+		.dpcm_capture = 1,
+	},
+	[DAI_LINK_FE_PCM1_IN] = {
+		.name = "mt2701-cs42448-pcm1-data-UL",
+		.stream_name = "mt2701-cs42448-pcm1-data-UL",
+		.cpu_dai_name = "PCM1",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.ops = &mt2701_cs42448_48k_fe_ops,
+		.dynamic = 1,
+		.dpcm_capture = 1,
+	},
+	[DAI_LINK_FE_BT_OUT] = {
+		.name = "mt2701-cs42448-pcm-BT-out",
+		.stream_name = "mt2701-cs42448-pcm-BT",
+		.cpu_dai_name = "PCM_BT_DL",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+	},
+	[DAI_LINK_FE_BT_IN] = {
+		.name = "mt2701-cs42448-pcm-BT-in",
+		.stream_name = "mt2701-cs42448-pcm-BT",
+		.cpu_dai_name = "PCM_BT_UL",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+	},
+	/* BE */
+	[DAI_LINK_BE_I2S0] = {
+		.name = "mt2701-cs42448-I2S0",
+		.cpu_dai_name = "I2S0",
+		.no_pcm = 1,
+		.codec_dai_name = "cs42448",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+			 | SND_SOC_DAIFMT_GATED,
+		.ops = &mt2701_cs42448_be_ops,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+	},
+	[DAI_LINK_BE_I2S1] = {
+		.name = "mt2701-cs42448-I2S1",
+		.cpu_dai_name = "I2S1",
+		.no_pcm = 1,
+		.codec_dai_name = "cs42448",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+			 | SND_SOC_DAIFMT_GATED,
+		.ops = &mt2701_cs42448_be_ops,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+	},
+	[DAI_LINK_BE_I2S2] = {
+		.name = "mt2701-cs42448-I2S2",
+		.cpu_dai_name = "I2S2",
+		.no_pcm = 1,
+		.codec_dai_name = "cs42448",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+			 | SND_SOC_DAIFMT_GATED,
+		.ops = &mt2701_cs42448_be_ops,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+	},
+	[DAI_LINK_BE_I2S3] = {
+		.name = "mt2701-cs42448-I2S3",
+		.cpu_dai_name = "I2S3",
+		.no_pcm = 1,
+		.codec_dai_name = "cs42448",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+			 | SND_SOC_DAIFMT_GATED,
+		.ops = &mt2701_cs42448_be_ops,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+	},
+	[DAI_LINK_BE_MRG_BT] = {
+		.name = "mt2701-cs42448-MRG-BT",
+		.cpu_dai_name = "MRG BT",
+		.no_pcm = 1,
+		.codec_dai_name = "bt-sco-pcm-wb",
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+	},
+};
+
+static struct snd_soc_card mt2701_cs42448_soc_card = {
+	.name = "mt2701-cs42448",
+	.owner = THIS_MODULE,
+	.dai_link = mt2701_cs42448_dai_links,
+	.num_links = ARRAY_SIZE(mt2701_cs42448_dai_links),
+	.controls = mt2701_cs42448_controls,
+	.num_controls = ARRAY_SIZE(mt2701_cs42448_controls),
+	.dapm_widgets = mt2701_cs42448_asoc_card_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(mt2701_cs42448_asoc_card_dapm_widgets),
+};
+
+static int mt2701_cs42448_machine_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &mt2701_cs42448_soc_card;
+	int ret;
+	int i;
+	struct device_node *platform_node, *codec_node, *codec_node_bt_mrg;
+	struct mt2701_cs42448_private *priv =
+		devm_kzalloc(&pdev->dev, sizeof(struct mt2701_cs42448_private),
+			     GFP_KERNEL);
+	struct device *dev = &pdev->dev;
+
+	if (!priv)
+		return -ENOMEM;
+
+	platform_node = of_parse_phandle(pdev->dev.of_node,
+					 "mediatek,platform", 0);
+	if (!platform_node) {
+		dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+		return -EINVAL;
+	}
+	for (i = 0; i < card->num_links; i++) {
+		if (mt2701_cs42448_dai_links[i].platform_name)
+			continue;
+		mt2701_cs42448_dai_links[i].platform_of_node = platform_node;
+	}
+
+	card->dev = dev;
+
+	codec_node = of_parse_phandle(pdev->dev.of_node,
+				      "mediatek,audio-codec", 0);
+	if (!codec_node) {
+		dev_err(&pdev->dev,
+			"Property 'audio-codec' missing or invalid\n");
+		return -EINVAL;
+	}
+	for (i = 0; i < card->num_links; i++) {
+		if (mt2701_cs42448_dai_links[i].codec_name)
+			continue;
+		mt2701_cs42448_dai_links[i].codec_of_node = codec_node;
+	}
+
+	codec_node_bt_mrg = of_parse_phandle(pdev->dev.of_node,
+					     "mediatek,audio-codec-bt-mrg", 0);
+	if (!codec_node_bt_mrg) {
+		dev_err(&pdev->dev,
+			"Property 'audio-codec-bt-mrg' missing or invalid\n");
+		return -EINVAL;
+	}
+	mt2701_cs42448_dai_links[DAI_LINK_BE_MRG_BT].codec_of_node
+							= codec_node_bt_mrg;
+
+	ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
+	if (ret) {
+		dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret);
+		return ret;
+	}
+
+	priv->i2s1_in_mux_gpio_sel_1 =
+		of_get_named_gpio(dev->of_node, "i2s1-in-sel-gpio1", 0);
+	if (gpio_is_valid(priv->i2s1_in_mux_gpio_sel_1)) {
+		ret = devm_gpio_request(dev, priv->i2s1_in_mux_gpio_sel_1,
+					"i2s1_in_mux_gpio_sel_1");
+		if (ret)
+			dev_warn(&pdev->dev, "%s devm_gpio_request fail %d\n",
+				 __func__, ret);
+		gpio_direction_output(priv->i2s1_in_mux_gpio_sel_1, 0);
+	}
+
+	priv->i2s1_in_mux_gpio_sel_2 =
+		of_get_named_gpio(dev->of_node, "i2s1-in-sel-gpio2", 0);
+	if (gpio_is_valid(priv->i2s1_in_mux_gpio_sel_2)) {
+		ret = devm_gpio_request(dev, priv->i2s1_in_mux_gpio_sel_2,
+					"i2s1_in_mux_gpio_sel_2");
+		if (ret)
+			dev_warn(&pdev->dev, "%s devm_gpio_request fail2 %d\n",
+				 __func__, ret);
+		gpio_direction_output(priv->i2s1_in_mux_gpio_sel_2, 0);
+	}
+	snd_soc_card_set_drvdata(card, priv);
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+
+	if (ret)
+		dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
+			__func__, ret);
+	return ret;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id mt2701_cs42448_machine_dt_match[] = {
+	{.compatible = "mediatek,mt2701-cs42448-machine",},
+	{}
+};
+#endif
+
+static struct platform_driver mt2701_cs42448_machine = {
+	.driver = {
+		.name = "mt2701-cs42448",
+		   #ifdef CONFIG_OF
+		   .of_match_table = mt2701_cs42448_machine_dt_match,
+		   #endif
+	},
+	.probe = mt2701_cs42448_machine_probe,
+};
+
+module_platform_driver(mt2701_cs42448_machine);
+
+/* Module information */
+MODULE_DESCRIPTION("MT2701 CS42448 ALSA SoC machine driver");
+MODULE_AUTHOR("Ir Lian <ir.lian at mediatek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("mt2701 cs42448 soc card");
-- 
1.9.1



From andrew-ct.chen at mediatek.com  Mon Jul  4 04:09:15 2016
From: andrew-ct.chen at mediatek.com (andrew-ct chen)
Date: Mon, 4 Jul 2016 19:09:15 +0800
Subject: [PATCH v3 0/9] Add MT8173 Video Decoder Driver
In-Reply-To: <7ee128a2-f026-5404-bbac-6b5c1bee51e7@xs4all.nl>
References: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
 <20160607112235.475c2e4c@recife.lan> <575746EE.3030706@cisco.com>
 <1465902488.27938.7.camel@mtksdaap41> <20160616075428.0fde4aaa@recife.lan>
 <8a46c1e7-1f27-1e67-8c05-b133598b6a66@xs4all.nl>
 <1467373995.17297.2.camel@mtksdaap41>
 <7ee128a2-f026-5404-bbac-6b5c1bee51e7@xs4all.nl>
Message-ID: <1467630555.18007.8.camel@mtksdaap41>

On Fri, 2016-07-01 at 14:00 +0200, Hans Verkuil wrote:
> On 07/01/2016 01:53 PM, andrew-ct chen wrote:
> > On Fri, 2016-07-01 at 12:11 +0200, Hans Verkuil wrote:
> >> On 06/16/2016 12:54 PM, Mauro Carvalho Chehab wrote:
> >>> Em Tue, 14 Jun 2016 19:08:08 +0800
> >>> tiffany lin <tiffany.lin at mediatek.com> escreveu:
> >>>
> >>>> Hi Mauro,
> >>>>
> >>>>
> >>>> On Wed, 2016-06-08 at 07:13 +0900, Hans Verkuil wrote:
> >>>>>
> >>>>> On 06/07/2016 11:22 PM, Mauro Carvalho Chehab wrote:  
> >>>>>> Em Mon, 30 May 2016 20:29:14 +0800
> >>>>>> Tiffany Lin <tiffany.lin at mediatek.com> escreveu:
> >>>>>>  
> >>>>>>> ==============
> >>>>>>>   Introduction
> >>>>>>> ==============
> >>>>>>>
> >>>>>>> The purpose of this series is to add the driver for video codec hw embedded in the Mediatek's MT8173 SoCs.
> >>>>>>> Mediatek Video Codec is able to handle video decoding of in a range of formats.
> >>>>>>>
> >>>>>>> This patch series add Mediatek block format V4L2_PIX_FMT_MT21, the decoder driver will decoded bitstream to
> >>>>>>> V4L2_PIX_FMT_MT21 format.
> >>>>>>>
> >>>>>>> This patch series rely on MTK VPU driver in patch series "Add MT8173 Video Encoder Driver and VPU Driver"[1]
> >>>>>>> and patch "CHROMIUM: v4l: Add V4L2_PIX_FMT_VP9 definition"[2] for VP9 support.
> >>>>>>> Mediatek Video Decoder driver rely on VPU driver to load, communicate with VPU.
> >>>>>>>
> >>>>>>> Internally the driver uses videobuf2 framework and MTK IOMMU and MTK SMI both have been merged in v4.6-rc1.
> >>>>>>>
> >>>>>>> [1]https://patchwork.linuxtv.org/patch/33734/
> >>>>>>> [2]https://chromium-review.googlesource.com/#/c/245241/  
> >>>>>>
> >>>>>> Hmm... I'm not seeing the firmware for this driver at the
> >>>>>> linux-firmware tree:
> >>>>>> 	https://git.kernel.org/cgit/linux/kernel/git/firmware/linux-firmware.git/log/
> >>>>>>
> >>>>>> Nor I'm seeing any pull request for them. Did you send it?
> >>>>>> I'll only merge the driver upstream after seeing such pull request.  
> >>>>>   
> >>>> Sorry, I am not familiar with how to upstream firmware.
> >>>> Do you mean we need to upstream vpu firmware first before merge encoder
> >>>> driver upstream?
> >>>
> >>> Please look at this page:
> >>> 	https://linuxtv.org/wiki/index.php/Development:_How_to_submit_patches#Firmware_submission
> >>>
> >>> The information here can also be useful:
> >>> 	https://www.kernel.org/doc/readme/firmware-README.AddingFirmware
> >>>
> >>> In summary, you need to provide redistribution rights for the
> >>> firmware blob. You can either submit it to me or directly to
> >>> linux-firmware. In the latter, please c/c me on such patch.
> >>
> >> Tiffany, what is the status of the firmware submission?
> >>
> >> Regards,


> >>
> >> 	Hans
> > 
> > Hi Hans,
> > We are working on firmware test to make sure that both decoder and
> > encoder work well. Hopes it can be ready (firmware submission) on July 4
> > or July 5.
> 
> OK, great! Just wanted to make sure that this work was progressing and not stalled.
> 
> Thanks!
> 
> 	Hans

Hi Hans,

We have submitted VPU firmware for encoder as the following link.
http://lists.infradead.org/pipermail/linux-mediatek/2016-July/006082.html
If the series of decoder patches apply, we will update the VPU firmware
for decoder support.

Thanks!.
	
	Andrew



From john at phrozen.org  Mon Jul  4 06:37:10 2016
From: john at phrozen.org (John Crispin)
Date: Mon,  4 Jul 2016 15:37:10 +0200
Subject: [PATCH] net-next: mediatek: remove superfluous free_irq() call
Message-ID: <1467639430-64370-1-git-send-email-john@phrozen.org>

Commit 8067302973a1 ("net-next: mediatek: add support for IRQ grouping")
adds handling for irq 1 and 2 to the uninit function but did not remove
irq 0 which is not used since irq grouping was introduced. Fix this by
removing the superfluous call to free_irq().

Reported-by: Arnd Bergmann <arnd at arndb.de>
Signed-off-by: John Crispin <john at phrozen.org>
---
 drivers/net/ethernet/mediatek/mtk_eth_soc.c |    1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index fbab9b2..682797e 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -1492,7 +1492,6 @@ static void mtk_uninit(struct net_device *dev)
 	phy_disconnect(mac->phy_dev);
 	mtk_mdio_cleanup(eth);
 	mtk_irq_disable(eth, ~0);
-	free_irq(eth->irq[0], dev);
 	free_irq(eth->irq[1], dev);
 	free_irq(eth->irq[2], dev);
 }
-- 
1.7.10.4



From arnd at arndb.de  Mon Jul  4 06:47:30 2016
From: arnd at arndb.de (Arnd Bergmann)
Date: Mon, 04 Jul 2016 15:47:30 +0200
Subject: [PATCH] net-next: mediatek: remove superfluous free_irq() call
In-Reply-To: <1467639430-64370-1-git-send-email-john@phrozen.org>
References: <1467639430-64370-1-git-send-email-john@phrozen.org>
Message-ID: <6569336.G6c12n4Gqk@wuerfel>

On Monday, July 4, 2016 3:37:10 PM CEST John Crispin wrote:
> Commit 8067302973a1 ("net-next: mediatek: add support for IRQ grouping")
> adds handling for irq 1 and 2 to the uninit function but did not remove
> irq 0 which is not used since irq grouping was introduced. Fix this by
> removing the superfluous call to free_irq().
> 
> Reported-by: Arnd Bergmann <arnd at arndb.de>
> Signed-off-by: John Crispin <john at phrozen.org>
> 

Acked-by: Arnd Bergmann <arnd at arndb.de>

Thanks for the quick update!


From broonie at kernel.org  Mon Jul  4 07:44:06 2016
From: broonie at kernel.org (Mark Brown)
Date: Mon, 4 Jul 2016 16:44:06 +0200
Subject: [alsa-devel] [PATCH 3/4] ASoC: mediatek: add BT implementation
In-Reply-To: <1467629788-14411-4-git-send-email-garlic.tseng@mediatek.com>
References: <1467629788-14411-1-git-send-email-garlic.tseng@mediatek.com>
 <1467629788-14411-4-git-send-email-garlic.tseng@mediatek.com>
Message-ID: <20160704144406.GH6247@sirena.org.uk>

On Mon, Jul 04, 2016 at 06:56:27PM +0800, Garlic Tseng wrote:

> +static int mt2701_btmrg_startup(struct snd_pcm_substream *substream,
> +				struct snd_soc_dai *dai)
> +{
> +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
> +	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
> +	struct mt2701_afe_private *afe_priv = afe->platform_priv;
> +
> +	regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
> +			   AUDIO_TOP_CON4_PDN_MRGIF, 0);

We really shouldn't be writing the registers or other internal data of
the device.  Instead we should be getting the driver for the relevant
hardware component to do it.  If we just write to registers that makes
the interoperation with the real driver for the device more fragile than
it should be, people might update the main driver without noticing the
external driver.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mediatek/attachments/20160704/37f4746c/attachment.sig>

From broonie at kernel.org  Mon Jul  4 07:49:31 2016
From: broonie at kernel.org (Mark Brown)
Date: Mon, 04 Jul 2016 16:49:31 +0200
Subject: Applied "ASoC: mediatek: Add mt2701-cs42448 driver and config
 option." to the asoc tree
In-Reply-To: <1467629788-14411-5-git-send-email-garlic.tseng@mediatek.com>
Message-ID: <E1bK5Bj-0007I3-6V@finisterre>

The patch

   ASoC: mediatek: Add mt2701-cs42448 driver and config option.

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 1f458d53f76c25a8240736294453e95bd9a34e18 Mon Sep 17 00:00:00 2001
From: Garlic Tseng <garlic.tseng at mediatek.com>
Date: Mon, 4 Jul 2016 18:56:28 +0800
Subject: [PATCH] ASoC: mediatek: Add mt2701-cs42448 driver and config option.

Add machine driver and config option for MT2701.

Signed-off-by: Garlic Tseng <garlic.tseng at mediatek.com>
Signed-off-by: Mark Brown <broonie at kernel.org>
---
 sound/soc/mediatek/Kconfig                 |  21 ++
 sound/soc/mediatek/Makefile                |   1 +
 sound/soc/mediatek/mt2701/Makefile         |  19 ++
 sound/soc/mediatek/mt2701/mt2701-cs42448.c | 412 +++++++++++++++++++++++++++++
 4 files changed, 453 insertions(+)
 create mode 100644 sound/soc/mediatek/mt2701/Makefile
 create mode 100644 sound/soc/mediatek/mt2701/mt2701-cs42448.c

diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 705904ba10f7..2fbe5434f03b 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -1,6 +1,27 @@
 config SND_SOC_MEDIATEK
 	tristate
 
+config SND_SOC_MT2701
+	tristate "ASoC support for Mediatek MT2701 chip"
+	depends on ARCH_MEDIATEK
+	select SND_SOC_MEDIATEK
+	help
+	  This adds ASoC driver for Mediatek MT2701 boards
+	  that can be used with other codecs.
+	  Select Y if you have such device.
+	  If unsure select "N".
+
+config SND_SOC_MT2701_CS42448
+	tristate "ASoc Audio driver for MT2701 with CS42448 codec"
+	depends on SND_SOC_MT2701
+	select SND_SOC_CS42XX8_I2C
+	select SND_SOC_BT_SCO
+	help
+	  This adds ASoC driver for Mediatek MT2701 boards
+	  with the CS42448 codecs.
+	  Select Y if you have such device.
+	  If unsure select "N".
+
 config SND_SOC_MT8173
 	tristate "ASoC support for Mediatek MT8173 chip"
 	depends on ARCH_MEDIATEK
diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile
index 4fe8068542f1..6bcab35dc828 100644
--- a/sound/soc/mediatek/Makefile
+++ b/sound/soc/mediatek/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_SND_SOC_MEDIATEK) += common/
+obj-$(CONFIG_SND_SOC_MT2701) += mt2701/
 obj-$(CONFIG_SND_SOC_MT8173) += mt8173/
diff --git a/sound/soc/mediatek/mt2701/Makefile b/sound/soc/mediatek/mt2701/Makefile
new file mode 100644
index 000000000000..31c3d04d4942
--- /dev/null
+++ b/sound/soc/mediatek/mt2701/Makefile
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2015 MediaTek Inc.
+#
+# 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.
+#
+
+# platform driver
+snd-soc-mt2701-afe-objs := mt2701-afe-pcm.o mt2701-afe-clock-ctrl.o
+obj-$(CONFIG_SND_SOC_MT2701) += snd-soc-mt2701-afe.o
+
+# machine driver
+obj-$(CONFIG_SND_SOC_MT2701_CS42448) += mt2701-cs42448.o
diff --git a/sound/soc/mediatek/mt2701/mt2701-cs42448.c b/sound/soc/mediatek/mt2701/mt2701-cs42448.c
new file mode 100644
index 000000000000..1e7e8d43fd8a
--- /dev/null
+++ b/sound/soc/mediatek/mt2701/mt2701-cs42448.c
@@ -0,0 +1,412 @@
+/*
+ * mt2701-cs42448.c  --  MT2701 CS42448 ALSA SoC machine driver
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ir Lian <ir.lian at mediatek.com>
+ *              Garlic Tseng <garlic.tseng at mediatek.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#include <linux/module.h>
+#include <sound/soc.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/of_gpio.h>
+
+#include "mt2701-afe-common.h"
+
+struct mt2701_cs42448_private {
+	int i2s1_in_mux;
+	int i2s1_in_mux_gpio_sel_1;
+	int i2s1_in_mux_gpio_sel_2;
+};
+
+static const char * const i2sin_mux_switch_text[] = {
+	"ADC_SDOUT2",
+	"ADC_SDOUT3",
+	"I2S_IN_1",
+	"I2S_IN_2",
+};
+
+static const struct soc_enum i2sin_mux_enum =
+	SOC_ENUM_SINGLE_EXT(4, i2sin_mux_switch_text);
+
+static int mt2701_cs42448_i2sin1_mux_get(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+	struct mt2701_cs42448_private *priv = snd_soc_card_get_drvdata(card);
+
+	ucontrol->value.integer.value[0] = priv->i2s1_in_mux;
+	return 0;
+}
+
+static int mt2701_cs42448_i2sin1_mux_set(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+	struct mt2701_cs42448_private *priv = snd_soc_card_get_drvdata(card);
+
+	if (ucontrol->value.integer.value[0] == priv->i2s1_in_mux)
+		return 0;
+
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 0);
+		gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 0);
+		break;
+	case 1:
+		gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 1);
+		gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 0);
+		break;
+	case 2:
+		gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 0);
+		gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 1);
+		break;
+	case 3:
+		gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 1);
+		gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 1);
+		break;
+	default:
+		dev_warn(card->dev, "%s invalid setting\n", __func__);
+	}
+
+	priv->i2s1_in_mux = ucontrol->value.integer.value[0];
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget
+			mt2701_cs42448_asoc_card_dapm_widgets[] = {
+	SND_SOC_DAPM_LINE("Line Out Jack", NULL),
+	SND_SOC_DAPM_MIC("AMIC", NULL),
+	SND_SOC_DAPM_LINE("Tuner In", NULL),
+	SND_SOC_DAPM_LINE("Satellite Tuner In", NULL),
+	SND_SOC_DAPM_LINE("AUX In", NULL),
+};
+
+static const struct snd_kcontrol_new mt2701_cs42448_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Line Out Jack"),
+	SOC_DAPM_PIN_SWITCH("AMIC"),
+	SOC_DAPM_PIN_SWITCH("Tuner In"),
+	SOC_DAPM_PIN_SWITCH("Satellite Tuner In"),
+	SOC_DAPM_PIN_SWITCH("AUX In"),
+	SOC_ENUM_EXT("I2SIN1_MUX_Switch", i2sin_mux_enum,
+		     mt2701_cs42448_i2sin1_mux_get,
+		     mt2701_cs42448_i2sin1_mux_set),
+};
+
+static const unsigned int mt2701_cs42448_sampling_rates[] = {48000};
+
+static struct snd_pcm_hw_constraint_list mt2701_cs42448_constraints_rates = {
+		.count = ARRAY_SIZE(mt2701_cs42448_sampling_rates),
+		.list = mt2701_cs42448_sampling_rates,
+		.mask = 0,
+};
+
+static int mt2701_cs42448_fe_ops_startup(struct snd_pcm_substream *substream)
+{
+	int err;
+
+	err = snd_pcm_hw_constraint_list(substream->runtime, 0,
+					 SNDRV_PCM_HW_PARAM_RATE,
+					 &mt2701_cs42448_constraints_rates);
+	if (err < 0) {
+		dev_err(substream->pcm->card->dev,
+			"%s snd_pcm_hw_constraint_list failed: 0x%x\n",
+			__func__, err);
+		return err;
+	}
+	return 0;
+}
+
+static struct snd_soc_ops mt2701_cs42448_48k_fe_ops = {
+	.startup = mt2701_cs42448_fe_ops_startup,
+};
+
+static int mt2701_cs42448_be_ops_hw_params(struct snd_pcm_substream *substream,
+					   struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	unsigned int mclk_rate;
+	unsigned int rate = params_rate(params);
+	unsigned int div_mclk_over_bck = rate > 192000 ? 2 : 4;
+	unsigned int div_bck_over_lrck = 64;
+
+	mclk_rate = rate * div_bck_over_lrck * div_mclk_over_bck;
+
+	/* mt2701 mclk */
+	snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_rate, SND_SOC_CLOCK_OUT);
+
+	/* codec mclk */
+	snd_soc_dai_set_sysclk(codec_dai, 0, mclk_rate, SND_SOC_CLOCK_IN);
+
+	return 0;
+}
+
+static struct snd_soc_ops mt2701_cs42448_be_ops = {
+	.hw_params = mt2701_cs42448_be_ops_hw_params
+};
+
+enum {
+	DAI_LINK_FE_MULTI_CH_OUT,
+	DAI_LINK_FE_PCM0_IN,
+	DAI_LINK_FE_PCM1_IN,
+	DAI_LINK_FE_BT_OUT,
+	DAI_LINK_FE_BT_IN,
+	DAI_LINK_BE_I2S0,
+	DAI_LINK_BE_I2S1,
+	DAI_LINK_BE_I2S2,
+	DAI_LINK_BE_I2S3,
+	DAI_LINK_BE_MRG_BT,
+};
+
+static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = {
+	/* FE */
+	[DAI_LINK_FE_MULTI_CH_OUT] = {
+		.name = "mt2701-cs42448-multi-ch-out",
+		.stream_name = "mt2701-cs42448-multi-ch-out",
+		.cpu_dai_name = "PCM_multi",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.ops = &mt2701_cs42448_48k_fe_ops,
+		.dynamic = 1,
+		.dpcm_playback = 1,
+	},
+	[DAI_LINK_FE_PCM0_IN] = {
+		.name = "mt2701-cs42448-pcm0",
+		.stream_name = "mt2701-cs42448-pcm0-data-UL",
+		.cpu_dai_name = "PCM0",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.ops = &mt2701_cs42448_48k_fe_ops,
+		.dynamic = 1,
+		.dpcm_capture = 1,
+	},
+	[DAI_LINK_FE_PCM1_IN] = {
+		.name = "mt2701-cs42448-pcm1-data-UL",
+		.stream_name = "mt2701-cs42448-pcm1-data-UL",
+		.cpu_dai_name = "PCM1",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.ops = &mt2701_cs42448_48k_fe_ops,
+		.dynamic = 1,
+		.dpcm_capture = 1,
+	},
+	[DAI_LINK_FE_BT_OUT] = {
+		.name = "mt2701-cs42448-pcm-BT-out",
+		.stream_name = "mt2701-cs42448-pcm-BT",
+		.cpu_dai_name = "PCM_BT_DL",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+	},
+	[DAI_LINK_FE_BT_IN] = {
+		.name = "mt2701-cs42448-pcm-BT-in",
+		.stream_name = "mt2701-cs42448-pcm-BT",
+		.cpu_dai_name = "PCM_BT_UL",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+	},
+	/* BE */
+	[DAI_LINK_BE_I2S0] = {
+		.name = "mt2701-cs42448-I2S0",
+		.cpu_dai_name = "I2S0",
+		.no_pcm = 1,
+		.codec_dai_name = "cs42448",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+			 | SND_SOC_DAIFMT_GATED,
+		.ops = &mt2701_cs42448_be_ops,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+	},
+	[DAI_LINK_BE_I2S1] = {
+		.name = "mt2701-cs42448-I2S1",
+		.cpu_dai_name = "I2S1",
+		.no_pcm = 1,
+		.codec_dai_name = "cs42448",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+			 | SND_SOC_DAIFMT_GATED,
+		.ops = &mt2701_cs42448_be_ops,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+	},
+	[DAI_LINK_BE_I2S2] = {
+		.name = "mt2701-cs42448-I2S2",
+		.cpu_dai_name = "I2S2",
+		.no_pcm = 1,
+		.codec_dai_name = "cs42448",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+			 | SND_SOC_DAIFMT_GATED,
+		.ops = &mt2701_cs42448_be_ops,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+	},
+	[DAI_LINK_BE_I2S3] = {
+		.name = "mt2701-cs42448-I2S3",
+		.cpu_dai_name = "I2S3",
+		.no_pcm = 1,
+		.codec_dai_name = "cs42448",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+			 | SND_SOC_DAIFMT_GATED,
+		.ops = &mt2701_cs42448_be_ops,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+	},
+	[DAI_LINK_BE_MRG_BT] = {
+		.name = "mt2701-cs42448-MRG-BT",
+		.cpu_dai_name = "MRG BT",
+		.no_pcm = 1,
+		.codec_dai_name = "bt-sco-pcm-wb",
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+	},
+};
+
+static struct snd_soc_card mt2701_cs42448_soc_card = {
+	.name = "mt2701-cs42448",
+	.owner = THIS_MODULE,
+	.dai_link = mt2701_cs42448_dai_links,
+	.num_links = ARRAY_SIZE(mt2701_cs42448_dai_links),
+	.controls = mt2701_cs42448_controls,
+	.num_controls = ARRAY_SIZE(mt2701_cs42448_controls),
+	.dapm_widgets = mt2701_cs42448_asoc_card_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(mt2701_cs42448_asoc_card_dapm_widgets),
+};
+
+static int mt2701_cs42448_machine_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &mt2701_cs42448_soc_card;
+	int ret;
+	int i;
+	struct device_node *platform_node, *codec_node, *codec_node_bt_mrg;
+	struct mt2701_cs42448_private *priv =
+		devm_kzalloc(&pdev->dev, sizeof(struct mt2701_cs42448_private),
+			     GFP_KERNEL);
+	struct device *dev = &pdev->dev;
+
+	if (!priv)
+		return -ENOMEM;
+
+	platform_node = of_parse_phandle(pdev->dev.of_node,
+					 "mediatek,platform", 0);
+	if (!platform_node) {
+		dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+		return -EINVAL;
+	}
+	for (i = 0; i < card->num_links; i++) {
+		if (mt2701_cs42448_dai_links[i].platform_name)
+			continue;
+		mt2701_cs42448_dai_links[i].platform_of_node = platform_node;
+	}
+
+	card->dev = dev;
+
+	codec_node = of_parse_phandle(pdev->dev.of_node,
+				      "mediatek,audio-codec", 0);
+	if (!codec_node) {
+		dev_err(&pdev->dev,
+			"Property 'audio-codec' missing or invalid\n");
+		return -EINVAL;
+	}
+	for (i = 0; i < card->num_links; i++) {
+		if (mt2701_cs42448_dai_links[i].codec_name)
+			continue;
+		mt2701_cs42448_dai_links[i].codec_of_node = codec_node;
+	}
+
+	codec_node_bt_mrg = of_parse_phandle(pdev->dev.of_node,
+					     "mediatek,audio-codec-bt-mrg", 0);
+	if (!codec_node_bt_mrg) {
+		dev_err(&pdev->dev,
+			"Property 'audio-codec-bt-mrg' missing or invalid\n");
+		return -EINVAL;
+	}
+	mt2701_cs42448_dai_links[DAI_LINK_BE_MRG_BT].codec_of_node
+							= codec_node_bt_mrg;
+
+	ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
+	if (ret) {
+		dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret);
+		return ret;
+	}
+
+	priv->i2s1_in_mux_gpio_sel_1 =
+		of_get_named_gpio(dev->of_node, "i2s1-in-sel-gpio1", 0);
+	if (gpio_is_valid(priv->i2s1_in_mux_gpio_sel_1)) {
+		ret = devm_gpio_request(dev, priv->i2s1_in_mux_gpio_sel_1,
+					"i2s1_in_mux_gpio_sel_1");
+		if (ret)
+			dev_warn(&pdev->dev, "%s devm_gpio_request fail %d\n",
+				 __func__, ret);
+		gpio_direction_output(priv->i2s1_in_mux_gpio_sel_1, 0);
+	}
+
+	priv->i2s1_in_mux_gpio_sel_2 =
+		of_get_named_gpio(dev->of_node, "i2s1-in-sel-gpio2", 0);
+	if (gpio_is_valid(priv->i2s1_in_mux_gpio_sel_2)) {
+		ret = devm_gpio_request(dev, priv->i2s1_in_mux_gpio_sel_2,
+					"i2s1_in_mux_gpio_sel_2");
+		if (ret)
+			dev_warn(&pdev->dev, "%s devm_gpio_request fail2 %d\n",
+				 __func__, ret);
+		gpio_direction_output(priv->i2s1_in_mux_gpio_sel_2, 0);
+	}
+	snd_soc_card_set_drvdata(card, priv);
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+
+	if (ret)
+		dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
+			__func__, ret);
+	return ret;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id mt2701_cs42448_machine_dt_match[] = {
+	{.compatible = "mediatek,mt2701-cs42448-machine",},
+	{}
+};
+#endif
+
+static struct platform_driver mt2701_cs42448_machine = {
+	.driver = {
+		.name = "mt2701-cs42448",
+		   #ifdef CONFIG_OF
+		   .of_match_table = mt2701_cs42448_machine_dt_match,
+		   #endif
+	},
+	.probe = mt2701_cs42448_machine_probe,
+};
+
+module_platform_driver(mt2701_cs42448_machine);
+
+/* Module information */
+MODULE_DESCRIPTION("MT2701 CS42448 ALSA SoC machine driver");
+MODULE_AUTHOR("Ir Lian <ir.lian at mediatek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("mt2701 cs42448 soc card");
-- 
2.8.1



From broonie at kernel.org  Mon Jul  4 07:49:42 2016
From: broonie at kernel.org (Mark Brown)
Date: Mon, 04 Jul 2016 16:49:42 +0200
Subject: Applied "ASoC: bt-sco: extend rate and add a general compatible
 string" to the asoc tree
In-Reply-To: <1467629788-14411-3-git-send-email-garlic.tseng@mediatek.com>
Message-ID: <E1bK5Bu-0007K5-6d@finisterre>

The patch

   ASoC: bt-sco: extend rate and add a general compatible string

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 5947e1b4992e2852b5176df6a554b5ebfbc9eff2 Mon Sep 17 00:00:00 2001
From: Garlic Tseng <garlic.tseng at mediatek.com>
Date: Mon, 4 Jul 2016 18:56:26 +0800
Subject: [PATCH] ASoC: bt-sco: extend rate and add a general compatible string

Add supports for 16k (wideband BT) and add a general compatible
string "linux,bt-sco"

Signed-off-by: Garlic Tseng <garlic.tseng at mediatek.com>
Signed-off-by: Mark Brown <broonie at kernel.org>
---
 Documentation/devicetree/bindings/sound/bt-sco.txt |  2 +-
 sound/soc/codecs/bt-sco.c                          | 52 +++++++++++++++-------
 2 files changed, 37 insertions(+), 17 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/bt-sco.txt b/Documentation/devicetree/bindings/sound/bt-sco.txt
index 29b8e5d40203..641edf75e184 100644
--- a/Documentation/devicetree/bindings/sound/bt-sco.txt
+++ b/Documentation/devicetree/bindings/sound/bt-sco.txt
@@ -4,7 +4,7 @@ This device support generic Bluetooth SCO link.
 
 Required properties:
 
-  - compatible : "delta,dfbmcs320"
+  - compatible : "delta,dfbmcs320" or "linux,bt-sco"
 
 Example:
 
diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c
index b084ad113e96..2a8d0ee141d4 100644
--- a/sound/soc/codecs/bt-sco.c
+++ b/sound/soc/codecs/bt-sco.c
@@ -25,22 +25,41 @@ static const struct snd_soc_dapm_route bt_sco_routes[] = {
 	{ "TX", NULL, "Playback" },
 };
 
-static struct snd_soc_dai_driver bt_sco_dai = {
-	.name = "bt-sco-pcm",
-	.playback = {
-		.stream_name = "Playback",
-		.channels_min = 1,
-		.channels_max = 1,
-		.rates = SNDRV_PCM_RATE_8000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-	.capture = {
-		 .stream_name = "Capture",
-		.channels_min = 1,
-		.channels_max = 1,
-		.rates = SNDRV_PCM_RATE_8000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+static struct snd_soc_dai_driver bt_sco_dai[] = {
+	{
+		.name = "bt-sco-pcm",
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = SNDRV_PCM_RATE_8000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.capture = {
+			 .stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = SNDRV_PCM_RATE_8000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
 	},
+	{
+		.name = "bt-sco-pcm-wb",
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.capture = {
+			 .stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+	}
 };
 
 static struct snd_soc_codec_driver soc_codec_dev_bt_sco = {
@@ -53,7 +72,7 @@ static struct snd_soc_codec_driver soc_codec_dev_bt_sco = {
 static int bt_sco_probe(struct platform_device *pdev)
 {
 	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_bt_sco,
-			&bt_sco_dai, 1);
+				      bt_sco_dai, ARRAY_SIZE(bt_sco_dai));
 }
 
 static int bt_sco_remove(struct platform_device *pdev)
@@ -77,6 +96,7 @@ MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids);
 #if defined(CONFIG_OF)
 static const struct of_device_id bt_sco_codec_of_match[] = {
 	{ .compatible = "delta,dfbmcs320", },
+	{ .compatible = "linux,bt-sco", },
 	{},
 };
 MODULE_DEVICE_TABLE(of, bt_sco_codec_of_match);
-- 
2.8.1



From broonie at kernel.org  Mon Jul  4 07:49:36 2016
From: broonie at kernel.org (Mark Brown)
Date: Mon, 04 Jul 2016 16:49:36 +0200
Subject: Applied "ASoC: mediatek: add mt2701 platform driver implementation."
 to the asoc tree
In-Reply-To: <1467629788-14411-2-git-send-email-garlic.tseng@mediatek.com>
Message-ID: <E1bK5Bo-0007J3-V8@finisterre>

The patch

   ASoC: mediatek: add mt2701 platform driver implementation.

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 43a6a7e71063ef2db753b1d28cc600117de7c5f7 Mon Sep 17 00:00:00 2001
From: Garlic Tseng <garlic.tseng at mediatek.com>
Date: Mon, 4 Jul 2016 18:56:25 +0800
Subject: [PATCH] ASoC: mediatek: add mt2701 platform driver implementation.

Add mt2701 platform driver implementation for playback and capture.
The implement follow DAPM structure (memory interface as FE and I2S
as BE).
Because of the hardware design, i2s out required to be enabled when
we need to enable i2s in. This patch includes the implementation.

Signed-off-by: Garlic Tseng <garlic.tseng at mediatek.com>
Signed-off-by: Mark Brown <broonie at kernel.org>
---
 sound/soc/mediatek/mt2701/mt2701-afe-common.h |    9 -
 sound/soc/mediatek/mt2701/mt2701-afe-pcm.c    | 1515 +++++++++++++++++++++++++
 2 files changed, 1515 insertions(+), 9 deletions(-)
 create mode 100644 sound/soc/mediatek/mt2701/mt2701-afe-pcm.c

diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-common.h b/sound/soc/mediatek/mt2701/mt2701-afe-common.h
index c77166eb7132..c19430e98adf 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-common.h
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-common.h
@@ -69,11 +69,6 @@ enum {
 	MT2701_IRQ_ASYS_END,
 };
 
-enum {
-	DIV_ID_MCLK_TO_BCK,
-	DIV_ID_BCK_TO_LRCK,
-};
-
 /* 2701 clock def */
 enum audio_system_clock_type {
 	MT2701_AUD_INFRA_SYS_AUDIO,
@@ -163,10 +158,6 @@ enum mt2701_i2s_dir {
 struct mt2701_i2s_path {
 	int dai_id;
 	int mclk_rate;
-	int div_mclk_to_bck;
-	int div_bck_to_lrck;
-	int format;
-	snd_pcm_format_t stream_fmt;
 	int on[I2S_DIR_NUM];
 	int occupied[I2S_DIR_NUM];
 	const struct mt2701_i2s_data *i2s_data[2];
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
new file mode 100644
index 000000000000..c865ba13617c
--- /dev/null
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
@@ -0,0 +1,1515 @@
+/*
+ * Mediatek ALSA SoC AFE platform driver for 2701
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Garlic Tseng <garlic.tseng at mediatek.com>
+ *             Ir Lian <ir.lian at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+
+#include "mt2701-afe-common.h"
+
+#include "mt2701-afe-clock-ctrl.h"
+#include "../common/mtk-afe-platform-driver.h"
+#include "../common/mtk-afe-fe-dai.h"
+
+#define AFE_IRQ_STATUS_BITS	0xff
+
+static const struct snd_pcm_hardware mt2701_afe_hardware = {
+	.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED
+		| SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE
+		   | SNDRV_PCM_FMTBIT_S32_LE,
+	.period_bytes_min = 1024,
+	.period_bytes_max = 1024 * 256,
+	.periods_min = 4,
+	.periods_max = 1024,
+	.buffer_bytes_max = 1024 * 1024 * 16,
+	.fifo_size = 0,
+};
+
+struct mt2701_afe_rate {
+	unsigned int rate;
+	unsigned int regvalue;
+};
+
+static const struct mt2701_afe_rate mt2701_afe_i2s_rates[] = {
+	{ .rate = 8000, .regvalue = 0 },
+	{ .rate = 12000, .regvalue = 1 },
+	{ .rate = 16000, .regvalue = 2 },
+	{ .rate = 24000, .regvalue = 3 },
+	{ .rate = 32000, .regvalue = 4 },
+	{ .rate = 48000, .regvalue = 5 },
+	{ .rate = 96000, .regvalue = 6 },
+	{ .rate = 192000, .regvalue = 7 },
+	{ .rate = 384000, .regvalue = 8 },
+	{ .rate = 7350, .regvalue = 16 },
+	{ .rate = 11025, .regvalue = 17 },
+	{ .rate = 14700, .regvalue = 18 },
+	{ .rate = 22050, .regvalue = 19 },
+	{ .rate = 29400, .regvalue = 20 },
+	{ .rate = 44100, .regvalue = 21 },
+	{ .rate = 88200, .regvalue = 22 },
+	{ .rate = 176400, .regvalue = 23 },
+	{ .rate = 352800, .regvalue = 24 },
+};
+
+int mt2701_dai_num_to_i2s(struct mtk_base_afe *afe, int num)
+{
+	int val = num - MT2701_IO_I2S;
+
+	if (val < 0 || val >= MT2701_I2S_NUM) {
+		dev_err(afe->dev, "%s, num not available, num %d, val %d\n",
+			__func__, num, val);
+		return -EINVAL;
+	}
+	return val;
+}
+
+static int mt2701_afe_i2s_fs(unsigned int sample_rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mt2701_afe_i2s_rates); i++)
+		if (mt2701_afe_i2s_rates[i].rate == sample_rate)
+			return mt2701_afe_i2s_rates[i].regvalue;
+
+	return -EINVAL;
+}
+
+static int mt2701_afe_i2s_startup(struct snd_pcm_substream *substream,
+				  struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+	int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
+	int clk_num = MT2701_AUD_AUD_I2S1_MCLK + i2s_num;
+	int ret = 0;
+
+	if (i2s_num < 0)
+		return i2s_num;
+
+	/* enable mclk */
+	ret = clk_prepare_enable(afe_priv->clocks[clk_num]);
+	if (ret)
+		dev_err(afe->dev, "Failed to enable mclk for I2S: %d\n",
+			i2s_num);
+
+	return ret;
+}
+
+static int mt2701_afe_i2s_path_shutdown(struct snd_pcm_substream *substream,
+					struct snd_soc_dai *dai,
+					int dir_invert)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+	int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
+	struct mt2701_i2s_path *i2s_path;
+	const struct mt2701_i2s_data *i2s_data;
+	int stream_dir = substream->stream;
+
+	if (i2s_num < 0)
+		return i2s_num;
+
+	i2s_path = &afe_priv->i2s_path[i2s_num];
+
+	if (dir_invert)	{
+		if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK)
+			stream_dir = SNDRV_PCM_STREAM_CAPTURE;
+		else
+			stream_dir = SNDRV_PCM_STREAM_PLAYBACK;
+	}
+	i2s_data = i2s_path->i2s_data[stream_dir];
+
+	i2s_path->on[stream_dir]--;
+	if (i2s_path->on[stream_dir] < 0) {
+		dev_warn(afe->dev, "i2s_path->on: %d, dir: %d\n",
+			 i2s_path->on[stream_dir], stream_dir);
+		i2s_path->on[stream_dir] = 0;
+	}
+	if (i2s_path->on[stream_dir])
+		return 0;
+
+	/* disable i2s */
+	regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg,
+			   ASYS_I2S_CON_I2S_EN, 0);
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
+			   1 << i2s_data->i2s_pwn_shift,
+			   1 << i2s_data->i2s_pwn_shift);
+	return 0;
+}
+
+static void mt2701_afe_i2s_shutdown(struct snd_pcm_substream *substream,
+				    struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+	int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
+	struct mt2701_i2s_path *i2s_path;
+	int clk_num = MT2701_AUD_AUD_I2S1_MCLK + i2s_num;
+
+	if (i2s_num < 0)
+		return;
+
+	i2s_path = &afe_priv->i2s_path[i2s_num];
+
+	if (i2s_path->occupied[substream->stream])
+		i2s_path->occupied[substream->stream] = 0;
+	else
+		goto I2S_UNSTART;
+
+	mt2701_afe_i2s_path_shutdown(substream, dai, 0);
+
+	/* need to disable i2s-out path when disable i2s-in */
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		mt2701_afe_i2s_path_shutdown(substream, dai, 1);
+
+I2S_UNSTART:
+	/* disable mclk */
+	clk_disable_unprepare(afe_priv->clocks[clk_num]);
+}
+
+static int mt2701_i2s_path_prepare_enable(struct snd_pcm_substream *substream,
+					  struct snd_soc_dai *dai,
+					  int dir_invert)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+	int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
+	struct mt2701_i2s_path *i2s_path;
+	const struct mt2701_i2s_data *i2s_data;
+	struct snd_pcm_runtime * const runtime = substream->runtime;
+	int reg, fs, w_len = 1; /* now we support bck 64bits only */
+	int stream_dir = substream->stream;
+	unsigned int mask = 0, val = 0;
+
+	if (i2s_num < 0)
+		return i2s_num;
+
+	i2s_path = &afe_priv->i2s_path[i2s_num];
+
+	if (dir_invert) {
+		if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK)
+			stream_dir = SNDRV_PCM_STREAM_CAPTURE;
+		else
+			stream_dir = SNDRV_PCM_STREAM_PLAYBACK;
+	}
+	i2s_data = i2s_path->i2s_data[stream_dir];
+
+	/* no need to enable if already done */
+	i2s_path->on[stream_dir]++;
+
+	if (i2s_path->on[stream_dir] != 1)
+		return 0;
+
+	fs = mt2701_afe_i2s_fs(runtime->rate);
+
+	mask = ASYS_I2S_CON_FS |
+	       ASYS_I2S_CON_I2S_COUPLE_MODE | /* 0 */
+	       ASYS_I2S_CON_I2S_MODE |
+	       ASYS_I2S_CON_WIDE_MODE;
+
+	val = ASYS_I2S_CON_FS_SET(fs) |
+	      ASYS_I2S_CON_I2S_MODE |
+	      ASYS_I2S_CON_WIDE_MODE_SET(w_len);
+
+	if (stream_dir == SNDRV_PCM_STREAM_CAPTURE) {
+		mask |= ASYS_I2S_IN_PHASE_FIX;
+		val |= ASYS_I2S_IN_PHASE_FIX;
+	}
+
+	regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg, mask, val);
+
+	if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK)
+		reg = ASMO_TIMING_CON1;
+	else
+		reg = ASMI_TIMING_CON1;
+
+	regmap_update_bits(afe->regmap, reg,
+			   i2s_data->i2s_asrc_fs_mask
+			   << i2s_data->i2s_asrc_fs_shift,
+			   fs << i2s_data->i2s_asrc_fs_shift);
+
+	/* enable i2s */
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
+			   1 << i2s_data->i2s_pwn_shift,
+			   0 << i2s_data->i2s_pwn_shift);
+
+	/* reset i2s hw status before enable */
+	regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg,
+			   ASYS_I2S_CON_RESET, ASYS_I2S_CON_RESET);
+	udelay(1);
+	regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg,
+			   ASYS_I2S_CON_RESET, 0);
+	udelay(1);
+	regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg,
+			   ASYS_I2S_CON_I2S_EN, ASYS_I2S_CON_I2S_EN);
+	return 0;
+}
+
+static int mt2701_afe_i2s_prepare(struct snd_pcm_substream *substream,
+				  struct snd_soc_dai *dai)
+{
+	int clk_domain;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+	int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
+	struct mt2701_i2s_path *i2s_path;
+	int mclk_rate;
+
+	if (i2s_num < 0)
+		return i2s_num;
+
+	i2s_path = &afe_priv->i2s_path[i2s_num];
+	mclk_rate = i2s_path->mclk_rate;
+
+	if (i2s_path->occupied[substream->stream])
+		return -EBUSY;
+	i2s_path->occupied[substream->stream] = 1;
+
+	if (MT2701_PLL_DOMAIN_0_RATE % mclk_rate == 0) {
+		clk_domain = 0;
+	} else if (MT2701_PLL_DOMAIN_1_RATE % mclk_rate == 0) {
+		clk_domain = 1;
+	} else {
+		dev_err(dai->dev, "%s() bad mclk rate %d\n",
+			__func__, mclk_rate);
+		return -EINVAL;
+	}
+	mt2701_mclk_configuration(afe, i2s_num, clk_domain, mclk_rate);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		mt2701_i2s_path_prepare_enable(substream, dai, 0);
+	} else {
+		/* need to enable i2s-out path when enable i2s-in */
+		/* prepare for another direction "out" */
+		mt2701_i2s_path_prepare_enable(substream, dai, 1);
+		/* prepare for "in" */
+		mt2701_i2s_path_prepare_enable(substream, dai, 0);
+	}
+
+	return 0;
+}
+
+static int mt2701_afe_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+				     unsigned int freq, int dir)
+{
+	struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+	int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
+
+	if (i2s_num < 0)
+		return i2s_num;
+
+	/* mclk */
+	if (dir == SND_SOC_CLOCK_IN) {
+		dev_warn(dai->dev,
+			 "%s() warning: mt2701 doesn't support mclk input\n",
+			__func__);
+		return -EINVAL;
+	}
+	afe_priv->i2s_path[i2s_num].mclk_rate = freq;
+	return 0;
+}
+
+static int mt2701_simple_fe_startup(struct snd_pcm_substream *substream,
+				    struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	int stream_dir = substream->stream;
+	int memif_num = rtd->cpu_dai->id;
+	struct mtk_base_afe_memif *memif_tmp;
+
+	/* can't run single DL & DLM at the same time */
+	if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK) {
+		memif_tmp = &afe->memif[MT2701_MEMIF_DLM];
+		if (memif_tmp->substream) {
+			dev_warn(afe->dev, "%s memif is not available, stream_dir %d, memif_num %d\n",
+				 __func__, stream_dir, memif_num);
+			return -EBUSY;
+		}
+	}
+	return mtk_afe_fe_startup(substream, dai);
+}
+
+static int mt2701_simple_fe_hw_params(struct snd_pcm_substream *substream,
+				      struct snd_pcm_hw_params *params,
+				      struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	int stream_dir = substream->stream;
+
+	/* single DL use PAIR_INTERLEAVE */
+	if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK) {
+		regmap_update_bits(afe->regmap,
+				   AFE_MEMIF_PBUF_SIZE,
+				   AFE_MEMIF_PBUF_SIZE_DLM_MASK,
+				   AFE_MEMIF_PBUF_SIZE_PAIR_INTERLEAVE);
+	}
+	return mtk_afe_fe_hw_params(substream, params, dai);
+}
+
+static int mt2701_dlm_fe_startup(struct snd_pcm_substream *substream,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mtk_base_afe_memif *memif_tmp;
+	const struct mtk_base_memif_data *memif_data;
+	int i;
+
+	for (i = MT2701_MEMIF_DL1; i < MT2701_MEMIF_DL_SINGLE_NUM; ++i) {
+		memif_tmp = &afe->memif[i];
+		if (memif_tmp->substream)
+			return -EBUSY;
+	}
+
+	/* enable agent for all signal DL (due to hw design) */
+	for (i = MT2701_MEMIF_DL1; i < MT2701_MEMIF_DL_SINGLE_NUM; ++i) {
+		memif_data = afe->memif[i].data;
+		regmap_update_bits(afe->regmap,
+				   memif_data->agent_disable_reg,
+				   1 << memif_data->agent_disable_shift,
+				   0 << memif_data->agent_disable_shift);
+	}
+
+	return mtk_afe_fe_startup(substream, dai);
+}
+
+static void mt2701_dlm_fe_shutdown(struct snd_pcm_substream *substream,
+				   struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	const struct mtk_base_memif_data *memif_data;
+	int i;
+
+	for (i = MT2701_MEMIF_DL1; i < MT2701_MEMIF_DL_SINGLE_NUM; ++i) {
+		memif_data = afe->memif[i].data;
+		regmap_update_bits(afe->regmap,
+				   memif_data->agent_disable_reg,
+				   1 << memif_data->agent_disable_shift,
+				   1 << memif_data->agent_disable_shift);
+	}
+	return mtk_afe_fe_shutdown(substream, dai);
+}
+
+static int mt2701_dlm_fe_hw_params(struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params,
+				   struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	int channels = params_channels(params);
+
+	regmap_update_bits(afe->regmap,
+			   AFE_MEMIF_PBUF_SIZE,
+			   AFE_MEMIF_PBUF_SIZE_DLM_MASK,
+			   AFE_MEMIF_PBUF_SIZE_FULL_INTERLEAVE);
+	regmap_update_bits(afe->regmap,
+			   AFE_MEMIF_PBUF_SIZE,
+			   AFE_MEMIF_PBUF_SIZE_DLM_BYTE_MASK,
+			   AFE_MEMIF_PBUF_SIZE_DLM_32BYTES);
+	regmap_update_bits(afe->regmap,
+			   AFE_MEMIF_PBUF_SIZE,
+			   AFE_MEMIF_PBUF_SIZE_DLM_CH_MASK,
+			   AFE_MEMIF_PBUF_SIZE_DLM_CH(channels));
+
+	return mtk_afe_fe_hw_params(substream, params, dai);
+}
+
+static int mt2701_dlm_fe_trigger(struct snd_pcm_substream *substream,
+				 int cmd, struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mtk_base_afe_memif *memif_tmp = &afe->memif[MT2701_MEMIF_DL1];
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		regmap_update_bits(afe->regmap, memif_tmp->data->enable_reg,
+				   1 << memif_tmp->data->enable_shift,
+				   1 << memif_tmp->data->enable_shift);
+		mtk_afe_fe_trigger(substream, cmd, dai);
+		return 0;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		mtk_afe_fe_trigger(substream, cmd, dai);
+		regmap_update_bits(afe->regmap, memif_tmp->data->enable_reg,
+				   1 << memif_tmp->data->enable_shift, 0);
+
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mt2701_memif_fs(struct snd_pcm_substream *substream,
+			   unsigned int rate)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	int fs;
+
+	if (rtd->cpu_dai->id != MT2701_MEMIF_ULBT)
+		fs = mt2701_afe_i2s_fs(rate);
+	else
+		fs = (rate == 16000 ? 1 : 0);
+	return fs;
+}
+
+static int mt2701_irq_fs(struct snd_pcm_substream *substream, unsigned int rate)
+{
+	return mt2701_afe_i2s_fs(rate);
+}
+
+/* FE DAIs */
+static const struct snd_soc_dai_ops mt2701_single_memif_dai_ops = {
+	.startup	= mt2701_simple_fe_startup,
+	.shutdown	= mtk_afe_fe_shutdown,
+	.hw_params	= mt2701_simple_fe_hw_params,
+	.hw_free	= mtk_afe_fe_hw_free,
+	.prepare	= mtk_afe_fe_prepare,
+	.trigger	= mtk_afe_fe_trigger,
+
+};
+
+static const struct snd_soc_dai_ops mt2701_dlm_memif_dai_ops = {
+	.startup	= mt2701_dlm_fe_startup,
+	.shutdown	= mt2701_dlm_fe_shutdown,
+	.hw_params	= mt2701_dlm_fe_hw_params,
+	.hw_free	= mtk_afe_fe_hw_free,
+	.prepare	= mtk_afe_fe_prepare,
+	.trigger	= mt2701_dlm_fe_trigger,
+};
+
+/* I2S BE DAIs */
+static const struct snd_soc_dai_ops mt2701_afe_i2s_ops = {
+	.startup	= mt2701_afe_i2s_startup,
+	.shutdown	= mt2701_afe_i2s_shutdown,
+	.prepare	= mt2701_afe_i2s_prepare,
+	.set_sysclk	= mt2701_afe_i2s_set_sysclk,
+};
+
+static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
+	/* FE DAIs: memory intefaces to CPU */
+	{
+		.name = "PCM_multi",
+		.id = MT2701_MEMIF_DLM,
+		.suspend = mtk_afe_dai_suspend,
+		.resume = mtk_afe_dai_resume,
+		.playback = {
+			.stream_name = "DLM",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE
+				| SNDRV_PCM_FMTBIT_S24_LE
+				| SNDRV_PCM_FMTBIT_S32_LE)
+
+		},
+		.ops = &mt2701_dlm_memif_dai_ops,
+	},
+	{
+		.name = "PCM0",
+		.id = MT2701_MEMIF_UL1,
+		.suspend = mtk_afe_dai_suspend,
+		.resume = mtk_afe_dai_resume,
+		.capture = {
+			.stream_name = "UL1",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE
+				| SNDRV_PCM_FMTBIT_S24_LE
+				| SNDRV_PCM_FMTBIT_S32_LE)
+		},
+		.ops = &mt2701_single_memif_dai_ops,
+	},
+	{
+		.name = "PCM1",
+		.id = MT2701_MEMIF_UL2,
+		.suspend = mtk_afe_dai_suspend,
+		.resume = mtk_afe_dai_resume,
+		.capture = {
+			.stream_name = "UL2",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE
+				| SNDRV_PCM_FMTBIT_S24_LE
+				| SNDRV_PCM_FMTBIT_S32_LE)
+
+		},
+		.ops = &mt2701_single_memif_dai_ops,
+	},
+	/* BE DAIs */
+	{
+		.name = "I2S0",
+		.id = MT2701_IO_I2S,
+		.playback = {
+			.stream_name = "I2S0 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE
+				| SNDRV_PCM_FMTBIT_S24_LE
+				| SNDRV_PCM_FMTBIT_S32_LE)
+
+		},
+		.capture = {
+			.stream_name = "I2S0 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE
+				| SNDRV_PCM_FMTBIT_S24_LE
+				| SNDRV_PCM_FMTBIT_S32_LE)
+
+		},
+		.ops = &mt2701_afe_i2s_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.name = "I2S1",
+		.id = MT2701_IO_2ND_I2S,
+		.playback = {
+			.stream_name = "I2S1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE
+				| SNDRV_PCM_FMTBIT_S24_LE
+				| SNDRV_PCM_FMTBIT_S32_LE)
+			},
+		.capture = {
+			.stream_name = "I2S1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE
+				| SNDRV_PCM_FMTBIT_S24_LE
+				| SNDRV_PCM_FMTBIT_S32_LE)
+			},
+		.ops = &mt2701_afe_i2s_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.name = "I2S2",
+		.id = MT2701_IO_3RD_I2S,
+		.playback = {
+			.stream_name = "I2S2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE
+				| SNDRV_PCM_FMTBIT_S24_LE
+				| SNDRV_PCM_FMTBIT_S32_LE)
+			},
+		.capture = {
+			.stream_name = "I2S2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE
+				| SNDRV_PCM_FMTBIT_S24_LE
+				| SNDRV_PCM_FMTBIT_S32_LE)
+			},
+		.ops = &mt2701_afe_i2s_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.name = "I2S3",
+		.id = MT2701_IO_4TH_I2S,
+		.playback = {
+			.stream_name = "I2S3 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE
+				| SNDRV_PCM_FMTBIT_S24_LE
+				| SNDRV_PCM_FMTBIT_S32_LE)
+			},
+		.capture = {
+			.stream_name = "I2S3 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE
+				| SNDRV_PCM_FMTBIT_S24_LE
+				| SNDRV_PCM_FMTBIT_S32_LE)
+			},
+		.ops = &mt2701_afe_i2s_ops,
+		.symmetric_rates = 1,
+	},
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o00_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN0, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o01_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN1, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o02_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I02 Switch", AFE_CONN2, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o03_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN3, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o14_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN14, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o15_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I12 Switch", AFE_CONN15, 12, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o16_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I13 Switch", AFE_CONN16, 13, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o17_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN17, 14, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o18_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN18, 15, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o19_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN19, 16, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o20_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN20, 17, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o21_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN21, 18, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o22_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN22, 19, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o23_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN23, 20, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o24_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN24, 21, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o31_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I35 Switch", AFE_CONN41, 9, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_i02_mix[] = {
+	SOC_DAPM_SINGLE("I2S0 Switch", SND_SOC_NOPM, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s0[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Multich I2S0 Out Switch",
+				    ASYS_I2SO1_CON, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s1[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Multich I2S1 Out Switch",
+				    ASYS_I2SO2_CON, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s2[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Multich I2S2 Out Switch",
+				    PWR2_TOP_CON, 17, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s3[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Multich I2S3 Out Switch",
+				    PWR2_TOP_CON, 18, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s4[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Multich I2S4 Out Switch",
+				    PWR2_TOP_CON, 19, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc0[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Asrc0 out Switch", AUDIO_TOP_CON4, 14, 1,
+				    1),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc1[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Asrc1 out Switch", AUDIO_TOP_CON4, 15, 1,
+				    1),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc2[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Asrc2 out Switch", PWR2_TOP_CON, 6, 1,
+				    1),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc3[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Asrc3 out Switch", PWR2_TOP_CON, 7, 1,
+				    1),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc4[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Asrc4 out Switch", PWR2_TOP_CON, 8, 1,
+				    1),
+};
+
+static const struct snd_soc_dapm_widget mt2701_afe_pcm_widgets[] = {
+	/* inter-connections */
+	SND_SOC_DAPM_MIXER("I00", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I01", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I02", SND_SOC_NOPM, 0, 0, mt2701_afe_i02_mix,
+			   ARRAY_SIZE(mt2701_afe_i02_mix)),
+	SND_SOC_DAPM_MIXER("I03", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I12", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I13", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I14", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I15", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I16", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I17", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I18", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I19", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I26", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I35", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER("O00", SND_SOC_NOPM, 0, 0, mt2701_afe_o00_mix,
+			   ARRAY_SIZE(mt2701_afe_o00_mix)),
+	SND_SOC_DAPM_MIXER("O01", SND_SOC_NOPM, 0, 0, mt2701_afe_o01_mix,
+			   ARRAY_SIZE(mt2701_afe_o01_mix)),
+	SND_SOC_DAPM_MIXER("O02", SND_SOC_NOPM, 0, 0, mt2701_afe_o02_mix,
+			   ARRAY_SIZE(mt2701_afe_o02_mix)),
+	SND_SOC_DAPM_MIXER("O03", SND_SOC_NOPM, 0, 0, mt2701_afe_o03_mix,
+			   ARRAY_SIZE(mt2701_afe_o03_mix)),
+	SND_SOC_DAPM_MIXER("O14", SND_SOC_NOPM, 0, 0, mt2701_afe_o14_mix,
+			   ARRAY_SIZE(mt2701_afe_o14_mix)),
+	SND_SOC_DAPM_MIXER("O15", SND_SOC_NOPM, 0, 0, mt2701_afe_o15_mix,
+			   ARRAY_SIZE(mt2701_afe_o15_mix)),
+	SND_SOC_DAPM_MIXER("O16", SND_SOC_NOPM, 0, 0, mt2701_afe_o16_mix,
+			   ARRAY_SIZE(mt2701_afe_o16_mix)),
+	SND_SOC_DAPM_MIXER("O17", SND_SOC_NOPM, 0, 0, mt2701_afe_o17_mix,
+			   ARRAY_SIZE(mt2701_afe_o17_mix)),
+	SND_SOC_DAPM_MIXER("O18", SND_SOC_NOPM, 0, 0, mt2701_afe_o18_mix,
+			   ARRAY_SIZE(mt2701_afe_o18_mix)),
+	SND_SOC_DAPM_MIXER("O19", SND_SOC_NOPM, 0, 0, mt2701_afe_o19_mix,
+			   ARRAY_SIZE(mt2701_afe_o19_mix)),
+	SND_SOC_DAPM_MIXER("O20", SND_SOC_NOPM, 0, 0, mt2701_afe_o20_mix,
+			   ARRAY_SIZE(mt2701_afe_o20_mix)),
+	SND_SOC_DAPM_MIXER("O21", SND_SOC_NOPM, 0, 0, mt2701_afe_o21_mix,
+			   ARRAY_SIZE(mt2701_afe_o21_mix)),
+	SND_SOC_DAPM_MIXER("O22", SND_SOC_NOPM, 0, 0, mt2701_afe_o22_mix,
+			   ARRAY_SIZE(mt2701_afe_o22_mix)),
+	SND_SOC_DAPM_MIXER("O31", SND_SOC_NOPM, 0, 0, mt2701_afe_o31_mix,
+			   ARRAY_SIZE(mt2701_afe_o31_mix)),
+
+	SND_SOC_DAPM_MIXER("I12I13", SND_SOC_NOPM, 0, 0,
+			   mt2701_afe_multi_ch_out_i2s0,
+			   ARRAY_SIZE(mt2701_afe_multi_ch_out_i2s0)),
+	SND_SOC_DAPM_MIXER("I14I15", SND_SOC_NOPM, 0, 0,
+			   mt2701_afe_multi_ch_out_i2s1,
+			   ARRAY_SIZE(mt2701_afe_multi_ch_out_i2s1)),
+	SND_SOC_DAPM_MIXER("I16I17", SND_SOC_NOPM, 0, 0,
+			   mt2701_afe_multi_ch_out_i2s2,
+			   ARRAY_SIZE(mt2701_afe_multi_ch_out_i2s2)),
+	SND_SOC_DAPM_MIXER("I18I19", SND_SOC_NOPM, 0, 0,
+			   mt2701_afe_multi_ch_out_i2s3,
+			   ARRAY_SIZE(mt2701_afe_multi_ch_out_i2s3)),
+
+	SND_SOC_DAPM_MIXER("ASRC_O0", SND_SOC_NOPM, 0, 0,
+			   mt2701_afe_multi_ch_out_asrc0,
+			   ARRAY_SIZE(mt2701_afe_multi_ch_out_asrc0)),
+	SND_SOC_DAPM_MIXER("ASRC_O1", SND_SOC_NOPM, 0, 0,
+			   mt2701_afe_multi_ch_out_asrc1,
+			   ARRAY_SIZE(mt2701_afe_multi_ch_out_asrc1)),
+	SND_SOC_DAPM_MIXER("ASRC_O2", SND_SOC_NOPM, 0, 0,
+			   mt2701_afe_multi_ch_out_asrc2,
+			   ARRAY_SIZE(mt2701_afe_multi_ch_out_asrc2)),
+	SND_SOC_DAPM_MIXER("ASRC_O3", SND_SOC_NOPM, 0, 0,
+			   mt2701_afe_multi_ch_out_asrc3,
+			   ARRAY_SIZE(mt2701_afe_multi_ch_out_asrc3)),
+};
+
+static const struct snd_soc_dapm_route mt2701_afe_pcm_routes[] = {
+	{"I12", NULL, "DL1"},
+	{"I13", NULL, "DL1"},
+	{"I35", NULL, "DLBT"},
+
+	{"I2S0 Playback", NULL, "O15"},
+	{"I2S0 Playback", NULL, "O16"},
+
+	{"I2S1 Playback", NULL, "O17"},
+	{"I2S1 Playback", NULL, "O18"},
+	{"I2S2 Playback", NULL, "O19"},
+	{"I2S2 Playback", NULL, "O20"},
+	{"I2S3 Playback", NULL, "O21"},
+	{"I2S3 Playback", NULL, "O22"},
+	{"BT Playback", NULL, "O31"},
+
+	{"UL1", NULL, "O00"},
+	{"UL1", NULL, "O01"},
+	{"UL2", NULL, "O02"},
+	{"UL2", NULL, "O03"},
+	{"ULBT", NULL, "O14"},
+
+	{"I00", NULL, "I2S0 Capture"},
+	{"I01", NULL, "I2S0 Capture"},
+
+	{"I02", NULL, "I2S1 Capture"},
+	{"I03", NULL, "I2S1 Capture"},
+	/* I02,03 link to UL2, also need to open I2S0 */
+	{"I02", "I2S0 Switch", "I2S0 Capture"},
+
+	{"I26", NULL, "BT Capture"},
+
+	{"ASRC_O0", "Asrc0 out Switch", "DLM"},
+	{"ASRC_O1", "Asrc1 out Switch", "DLM"},
+	{"ASRC_O2", "Asrc2 out Switch", "DLM"},
+	{"ASRC_O3", "Asrc3 out Switch", "DLM"},
+
+	{"I12I13", "Multich I2S0 Out Switch", "ASRC_O0"},
+	{"I14I15", "Multich I2S1 Out Switch", "ASRC_O1"},
+	{"I16I17", "Multich I2S2 Out Switch", "ASRC_O2"},
+	{"I18I19", "Multich I2S3 Out Switch", "ASRC_O3"},
+
+	{ "I12", NULL, "I12I13" },
+	{ "I13", NULL, "I12I13" },
+	{ "I14", NULL, "I14I15" },
+	{ "I15", NULL, "I14I15" },
+	{ "I16", NULL, "I16I17" },
+	{ "I17", NULL, "I16I17" },
+	{ "I18", NULL, "I18I19" },
+	{ "I19", NULL, "I18I19" },
+
+	{ "O00", "I00 Switch", "I00" },
+	{ "O01", "I01 Switch", "I01" },
+	{ "O02", "I02 Switch", "I02" },
+	{ "O03", "I03 Switch", "I03" },
+	{ "O14", "I26 Switch", "I26" },
+	{ "O15", "I12 Switch", "I12" },
+	{ "O16", "I13 Switch", "I13" },
+	{ "O17", "I14 Switch", "I14" },
+	{ "O18", "I15 Switch", "I15" },
+	{ "O19", "I16 Switch", "I16" },
+	{ "O20", "I17 Switch", "I17" },
+	{ "O21", "I18 Switch", "I18" },
+	{ "O22", "I19 Switch", "I19" },
+	{ "O31", "I35 Switch", "I35" },
+
+};
+
+static const struct snd_soc_component_driver mt2701_afe_pcm_dai_component = {
+	.name = "mt2701-afe-pcm-dai",
+	.dapm_widgets = mt2701_afe_pcm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(mt2701_afe_pcm_widgets),
+	.dapm_routes = mt2701_afe_pcm_routes,
+	.num_dapm_routes = ARRAY_SIZE(mt2701_afe_pcm_routes),
+};
+
+static const struct mtk_base_memif_data memif_data[MT2701_MEMIF_NUM] = {
+	{
+		.name = "DL1",
+		.id = MT2701_MEMIF_DL1,
+		.reg_ofs_base = AFE_DL1_BASE,
+		.reg_ofs_cur = AFE_DL1_CUR,
+		.fs_reg = AFE_DAC_CON1,
+		.fs_shift = 0,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_DAC_CON3,
+		.mono_shift = 16,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 1,
+		.hd_reg = AFE_MEMIF_HD_CON0,
+		.hd_shift = 0,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 6,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	{
+		.name = "DL2",
+		.id = MT2701_MEMIF_DL2,
+		.reg_ofs_base = AFE_DL2_BASE,
+		.reg_ofs_cur = AFE_DL2_CUR,
+		.fs_reg = AFE_DAC_CON1,
+		.fs_shift = 5,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_DAC_CON3,
+		.mono_shift = 17,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 2,
+		.hd_reg = AFE_MEMIF_HD_CON0,
+		.hd_shift = 2,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 7,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	{
+		.name = "DL3",
+		.id = MT2701_MEMIF_DL3,
+		.reg_ofs_base = AFE_DL3_BASE,
+		.reg_ofs_cur = AFE_DL3_CUR,
+		.fs_reg = AFE_DAC_CON1,
+		.fs_shift = 10,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_DAC_CON3,
+		.mono_shift = 18,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 3,
+		.hd_reg = AFE_MEMIF_HD_CON0,
+		.hd_shift = 4,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 8,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	{
+		.name = "DL4",
+		.id = MT2701_MEMIF_DL4,
+		.reg_ofs_base = AFE_DL4_BASE,
+		.reg_ofs_cur = AFE_DL4_CUR,
+		.fs_reg = AFE_DAC_CON1,
+		.fs_shift = 15,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_DAC_CON3,
+		.mono_shift = 19,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 4,
+		.hd_reg = AFE_MEMIF_HD_CON0,
+		.hd_shift = 6,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 9,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	{
+		.name = "DL5",
+		.id = MT2701_MEMIF_DL5,
+		.reg_ofs_base = AFE_DL5_BASE,
+		.reg_ofs_cur = AFE_DL5_CUR,
+		.fs_reg = AFE_DAC_CON1,
+		.fs_shift = 20,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_DAC_CON3,
+		.mono_shift = 20,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 5,
+		.hd_reg = AFE_MEMIF_HD_CON0,
+		.hd_shift = 8,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 10,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	{
+		.name = "DLM",
+		.id = MT2701_MEMIF_DLM,
+		.reg_ofs_base = AFE_DLMCH_BASE,
+		.reg_ofs_cur = AFE_DLMCH_CUR,
+		.fs_reg = AFE_DAC_CON1,
+		.fs_shift = 0,
+		.fs_maskbit = 0x1f,
+		.mono_reg = -1,
+		.mono_shift = -1,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 7,
+		.hd_reg = AFE_MEMIF_PBUF_SIZE,
+		.hd_shift = 28,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 12,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	{
+		.name = "UL1",
+		.id = MT2701_MEMIF_UL1,
+		.reg_ofs_base = AFE_VUL_BASE,
+		.reg_ofs_cur = AFE_VUL_CUR,
+		.fs_reg = AFE_DAC_CON2,
+		.fs_shift = 0,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_DAC_CON4,
+		.mono_shift = 0,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 10,
+		.hd_reg = AFE_MEMIF_HD_CON1,
+		.hd_shift = 0,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 0,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	{
+		.name = "UL2",
+		.id = MT2701_MEMIF_UL2,
+		.reg_ofs_base = AFE_UL2_BASE,
+		.reg_ofs_cur = AFE_UL2_CUR,
+		.fs_reg = AFE_DAC_CON2,
+		.fs_shift = 5,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_DAC_CON4,
+		.mono_shift = 2,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 11,
+		.hd_reg = AFE_MEMIF_HD_CON1,
+		.hd_shift = 2,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 1,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	{
+		.name = "UL3",
+		.id = MT2701_MEMIF_UL3,
+		.reg_ofs_base = AFE_UL3_BASE,
+		.reg_ofs_cur = AFE_UL3_CUR,
+		.fs_reg = AFE_DAC_CON2,
+		.fs_shift = 10,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_DAC_CON4,
+		.mono_shift = 4,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 12,
+		.hd_reg = AFE_MEMIF_HD_CON0,
+		.hd_shift = 0,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 2,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	{
+		.name = "UL4",
+		.id = MT2701_MEMIF_UL4,
+		.reg_ofs_base = AFE_UL4_BASE,
+		.reg_ofs_cur = AFE_UL4_CUR,
+		.fs_reg = AFE_DAC_CON2,
+		.fs_shift = 15,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_DAC_CON4,
+		.mono_shift = 6,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 13,
+		.hd_reg = AFE_MEMIF_HD_CON0,
+		.hd_shift = 6,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 3,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	{
+		.name = "UL5",
+		.id = MT2701_MEMIF_UL5,
+		.reg_ofs_base = AFE_UL5_BASE,
+		.reg_ofs_cur = AFE_UL5_CUR,
+		.fs_reg = AFE_DAC_CON2,
+		.fs_shift = 20,
+		.mono_reg = AFE_DAC_CON4,
+		.mono_shift = 8,
+		.fs_maskbit = 0x1f,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 14,
+		.hd_reg = AFE_MEMIF_HD_CON0,
+		.hd_shift = 8,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 4,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	{
+		.name = "DLBT",
+		.id = MT2701_MEMIF_DLBT,
+		.reg_ofs_base = AFE_ARB1_BASE,
+		.reg_ofs_cur = AFE_ARB1_CUR,
+		.fs_reg = AFE_DAC_CON3,
+		.fs_shift = 10,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_DAC_CON3,
+		.mono_shift = 22,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 8,
+		.hd_reg = AFE_MEMIF_HD_CON0,
+		.hd_shift = 14,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 13,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	{
+		.name = "ULBT",
+		.id = MT2701_MEMIF_ULBT,
+		.reg_ofs_base = AFE_DAI_BASE,
+		.reg_ofs_cur = AFE_DAI_CUR,
+		.fs_reg = AFE_DAC_CON2,
+		.fs_shift = 30,
+		.fs_maskbit = 0x1,
+		.mono_reg = -1,
+		.mono_shift = -1,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 17,
+		.hd_reg = AFE_MEMIF_HD_CON1,
+		.hd_shift = 20,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 16,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+};
+
+static const struct mtk_base_irq_data irq_data[MT2701_IRQ_ASYS_END] = {
+	{
+		.id = MT2701_IRQ_ASYS_IRQ1,
+		.irq_cnt_reg = ASYS_IRQ1_CON,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0xffffff,
+		.irq_fs_reg = ASYS_IRQ1_CON,
+		.irq_fs_shift = 24,
+		.irq_fs_maskbit = 0x1f,
+		.irq_en_reg = ASYS_IRQ1_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg = ASYS_IRQ_CLR,
+		.irq_clr_shift = 0,
+	},
+	{
+		.id = MT2701_IRQ_ASYS_IRQ2,
+		.irq_cnt_reg = ASYS_IRQ2_CON,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0xffffff,
+		.irq_fs_reg = ASYS_IRQ2_CON,
+		.irq_fs_shift = 24,
+		.irq_fs_maskbit = 0x1f,
+		.irq_en_reg = ASYS_IRQ2_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg = ASYS_IRQ_CLR,
+		.irq_clr_shift = 1,
+	},
+	{
+		.id = MT2701_IRQ_ASYS_IRQ3,
+		.irq_cnt_reg = ASYS_IRQ3_CON,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0xffffff,
+		.irq_fs_reg = ASYS_IRQ3_CON,
+		.irq_fs_shift = 24,
+		.irq_fs_maskbit = 0x1f,
+		.irq_en_reg = ASYS_IRQ3_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg = ASYS_IRQ_CLR,
+		.irq_clr_shift = 2,
+	}
+};
+
+static const struct mt2701_i2s_data mt2701_i2s_data[MT2701_I2S_NUM][2] = {
+	{
+		{
+			.i2s_ctrl_reg = ASYS_I2SO1_CON,
+			.i2s_pwn_shift = 6,
+			.i2s_asrc_fs_shift = 0,
+			.i2s_asrc_fs_mask = 0x1f,
+
+		},
+		{
+			.i2s_ctrl_reg = ASYS_I2SIN1_CON,
+			.i2s_pwn_shift = 0,
+			.i2s_asrc_fs_shift = 0,
+			.i2s_asrc_fs_mask = 0x1f,
+
+		},
+	},
+	{
+		{
+			.i2s_ctrl_reg = ASYS_I2SO2_CON,
+			.i2s_pwn_shift = 7,
+			.i2s_asrc_fs_shift = 5,
+			.i2s_asrc_fs_mask = 0x1f,
+
+		},
+		{
+			.i2s_ctrl_reg = ASYS_I2SIN2_CON,
+			.i2s_pwn_shift = 1,
+			.i2s_asrc_fs_shift = 5,
+			.i2s_asrc_fs_mask = 0x1f,
+
+		},
+	},
+	{
+		{
+			.i2s_ctrl_reg = ASYS_I2SO3_CON,
+			.i2s_pwn_shift = 8,
+			.i2s_asrc_fs_shift = 10,
+			.i2s_asrc_fs_mask = 0x1f,
+
+		},
+		{
+			.i2s_ctrl_reg = ASYS_I2SIN3_CON,
+			.i2s_pwn_shift = 2,
+			.i2s_asrc_fs_shift = 10,
+			.i2s_asrc_fs_mask = 0x1f,
+
+		},
+	},
+	{
+		{
+			.i2s_ctrl_reg = ASYS_I2SO4_CON,
+			.i2s_pwn_shift = 9,
+			.i2s_asrc_fs_shift = 15,
+			.i2s_asrc_fs_mask = 0x1f,
+
+		},
+		{
+			.i2s_ctrl_reg = ASYS_I2SIN4_CON,
+			.i2s_pwn_shift = 3,
+			.i2s_asrc_fs_shift = 15,
+			.i2s_asrc_fs_mask = 0x1f,
+
+		},
+	},
+};
+
+static const struct regmap_config mt2701_afe_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = AFE_END_ADDR,
+	.cache_type = REGCACHE_NONE,
+};
+
+static irqreturn_t mt2701_asys_isr(int irq_id, void *dev)
+{
+	int id;
+	struct mtk_base_afe *afe = dev;
+	struct mtk_base_afe_memif *memif;
+	struct mtk_base_afe_irq *irq;
+	u32 status;
+
+	regmap_read(afe->regmap, ASYS_IRQ_STATUS, &status);
+	regmap_write(afe->regmap, ASYS_IRQ_CLR, status);
+
+	for (id = 0; id < MT2701_MEMIF_NUM; ++id) {
+		memif = &afe->memif[id];
+		if (memif->irq_usage < 0)
+			continue;
+		irq = &afe->irqs[memif->irq_usage];
+		if (status & 1 << (irq->irq_data->irq_clr_shift))
+			snd_pcm_period_elapsed(memif->substream);
+	}
+	return IRQ_HANDLED;
+}
+
+static int mt2701_afe_runtime_suspend(struct device *dev)
+{
+	struct mtk_base_afe *afe = dev_get_drvdata(dev);
+
+	mt2701_afe_disable_clock(afe);
+	return 0;
+}
+
+static int mt2701_afe_runtime_resume(struct device *dev)
+{
+	struct mtk_base_afe *afe = dev_get_drvdata(dev);
+
+	return mt2701_afe_enable_clock(afe);
+}
+
+static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev)
+{
+	int ret, i;
+	unsigned int irq_id;
+	struct mtk_base_afe *afe;
+	struct mt2701_afe_private *afe_priv;
+	struct resource *res;
+	struct device *dev;
+
+	ret = 0;
+	afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
+	afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
+					  GFP_KERNEL);
+	afe_priv = afe->platform_priv;
+	if (!afe)
+		return -ENOMEM;
+
+	afe->dev = &pdev->dev;
+	dev = afe->dev;
+
+	irq_id = platform_get_irq(pdev, 0);
+	if (!irq_id) {
+		dev_err(dev, "%s no irq found\n", dev->of_node->name);
+		return -ENXIO;
+	}
+	ret = devm_request_irq(dev, irq_id, mt2701_asys_isr,
+			       IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
+	if (ret) {
+		dev_err(dev, "could not request_irq for asys-isr\n");
+		return ret;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	afe->base_addr = devm_ioremap_resource(&pdev->dev, res);
+
+	if (IS_ERR(afe->base_addr))
+		return PTR_ERR(afe->base_addr);
+
+	afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr,
+		&mt2701_afe_regmap_config);
+	if (IS_ERR(afe->regmap))
+		return PTR_ERR(afe->regmap);
+
+	mutex_init(&afe->irq_alloc_lock);
+
+	/* memif initialize */
+	afe->memif_size = MT2701_MEMIF_NUM;
+	afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif),
+				  GFP_KERNEL);
+
+	if (!afe->memif)
+		return -ENOMEM;
+
+	for (i = 0; i < afe->memif_size; i++) {
+		afe->memif[i].data = &memif_data[i];
+		afe->memif[i].irq_usage = -1;
+	}
+
+	/* irq initialize */
+	afe->irqs_size = MT2701_IRQ_ASYS_END;
+	afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs),
+				 GFP_KERNEL);
+
+	if (!afe->irqs)
+		return -ENOMEM;
+
+	for (i = 0; i < afe->irqs_size; i++)
+		afe->irqs[i].irq_data = &irq_data[i];
+
+	/* I2S initialize */
+	for (i = 0; i < MT2701_I2S_NUM; i++) {
+		afe_priv->i2s_path[i].i2s_data[I2S_OUT]
+			= &mt2701_i2s_data[i][I2S_OUT];
+		afe_priv->i2s_path[i].i2s_data[I2S_IN]
+			= &mt2701_i2s_data[i][I2S_IN];
+	}
+
+	afe->mtk_afe_hardware = &mt2701_afe_hardware;
+	afe->memif_fs = mt2701_memif_fs;
+	afe->irq_fs = mt2701_irq_fs;
+
+	afe->reg_back_up_list = mt2701_afe_backup_list;
+	afe->reg_back_up_list_num = ARRAY_SIZE(mt2701_afe_backup_list);
+	afe->runtime_resume = mt2701_afe_runtime_resume;
+	afe->runtime_suspend = mt2701_afe_runtime_suspend;
+
+	/* initial audio related clock */
+	ret = mt2701_init_clock(afe);
+	if (ret) {
+		dev_err(dev, "init clock error\n");
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, afe);
+	pm_runtime_enable(&pdev->dev);
+	if (!pm_runtime_enabled(&pdev->dev))
+		goto err_pm_disable;
+
+	ret = snd_soc_register_platform(&pdev->dev, &mtk_afe_pcm_platform);
+	if (ret) {
+		dev_warn(dev, "err_platform\n");
+		goto err_platform;
+	}
+
+	ret = snd_soc_register_component(&pdev->dev,
+					 &mt2701_afe_pcm_dai_component,
+					 mt2701_afe_pcm_dais,
+					 ARRAY_SIZE(mt2701_afe_pcm_dais));
+	if (ret) {
+		dev_warn(dev, "err_dai_component\n");
+		goto err_dai_component;
+	}
+
+	mt2701_afe_runtime_resume(&pdev->dev);
+
+	return 0;
+
+err_dai_component:
+	snd_soc_unregister_component(&pdev->dev);
+
+err_platform:
+	snd_soc_unregister_platform(&pdev->dev);
+
+err_pm_disable:
+	pm_runtime_disable(&pdev->dev);
+
+	return ret;
+}
+
+static int mt2701_afe_pcm_dev_remove(struct platform_device *pdev)
+{
+	struct mtk_base_afe *afe = platform_get_drvdata(pdev);
+
+	pm_runtime_disable(&pdev->dev);
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		mt2701_afe_runtime_suspend(&pdev->dev);
+
+	snd_soc_unregister_component(&pdev->dev);
+	snd_soc_unregister_platform(&pdev->dev);
+	/* disable afe clock */
+	mt2701_afe_disable_clock(afe);
+	return 0;
+}
+
+static const struct of_device_id mt2701_afe_pcm_dt_match[] = {
+	{ .compatible = "mediatek,mt2701-audio", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mt2701_afe_pcm_dt_match);
+
+static const struct dev_pm_ops mt2701_afe_pm_ops = {
+	SET_RUNTIME_PM_OPS(mt2701_afe_runtime_suspend,
+			   mt2701_afe_runtime_resume, NULL)
+};
+
+static struct platform_driver mt2701_afe_pcm_driver = {
+	.driver = {
+		   .name = "mt2701-audio",
+		   .of_match_table = mt2701_afe_pcm_dt_match,
+#ifdef CONFIG_PM
+		   .pm = &mt2701_afe_pm_ops,
+#endif
+	},
+	.probe = mt2701_afe_pcm_dev_probe,
+	.remove = mt2701_afe_pcm_dev_remove,
+};
+
+module_platform_driver(mt2701_afe_pcm_driver);
+
+MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver for 2701");
+MODULE_AUTHOR("Garlic Tseng <garlic.tseng at mediatek.com>");
+MODULE_LICENSE("GPL v2");
+
-- 
2.8.1



From garlic.tseng at mediatek.com  Mon Jul  4 18:52:13 2016
From: garlic.tseng at mediatek.com (Garlic Tseng)
Date: Tue, 5 Jul 2016 09:52:13 +0800
Subject: [alsa-devel] [PATCH 3/4] ASoC: mediatek: add BT implementation
In-Reply-To: <20160704144406.GH6247@sirena.org.uk>
References: <1467629788-14411-1-git-send-email-garlic.tseng@mediatek.com>
 <1467629788-14411-4-git-send-email-garlic.tseng@mediatek.com>
 <20160704144406.GH6247@sirena.org.uk>
Message-ID: <1467683533.4212.16.camel@mtksdaap41>

On Mon, 2016-07-04 at 16:44 +0200, Mark Brown wrote:
> On Mon, Jul 04, 2016 at 06:56:27PM +0800, Garlic Tseng wrote:
> 
> > +static int mt2701_btmrg_startup(struct snd_pcm_substream *substream,
> > +				struct snd_soc_dai *dai)
> > +{
> > +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
> > +	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
> > +	struct mt2701_afe_private *afe_priv = afe->platform_priv;
> > +
> > +	regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
> > +			   AUDIO_TOP_CON4_PDN_MRGIF, 0);
> 
> We really shouldn't be writing the registers or other internal data of
> the device.  Instead we should be getting the driver for the relevant
> hardware component to do it.  If we just write to registers that makes
> the interoperation with the real driver for the device more fragile than
> it should be, people might update the main driver without noticing the
> external driver.

The AUDIO_TOP_CON4 is a reg of the ASoC hw module. All the registers
which are set in the btmrg operator belong to ASoC hardware. The reg
writing you mention above is to power up the MRG interface in the ASoC
module.

When we start BT link, we need to start some hardware component belongs
to ASoC module. Of course we also need to start up the BT module
(including start up the MRG interface hw in BT chip), but it is not in
the ASoC driver.



From zhiyong.tao at mediatek.com  Mon Jul  4 20:50:07 2016
From: zhiyong.tao at mediatek.com (Zhiyong Tao)
Date: Tue, 5 Jul 2016 11:50:07 +0800
Subject: [PATCH v2 0/3] AUXADC: Mediatek auxadc driver 
Message-ID: <1467690610-20550-1-git-send-email-zhiyong.tao@mediatek.com>

This series includes three patches:
1.Change the device tree binding documentation.
2.Add auxadc driver based on linux iio.
3.Add auxadc nodes in the mediatek MT2701 dtsi file.

changes in patch 2:
1).Change the file name mt65xx_auxadc.c to mt6577_auxadc.c.
2).Add 'depends on ARCH_MEDIATEK || COMPILE_TEST and HAS_IOMEM' for MEDIATEK_MT65XX_AUXADC config.
3).Add check case for return value of 'readl_poll_timeout'.
4).Remove returning 1 and 0 for SCALE and OFFSET. use channel type 'IIO_CHAN_INFO_PROCESSED' instead of 'IIO_CHAN_INFO_RAW'.
5).Remove 'IIO_CHAN_INFO_OFFSET' and 'IIO_CHAN_INFO_SCALE' in 'MT65XX_AUXADC_CHANNEL' channel type.
6).Add check case when auxadc power on failure. if auxadc power on failure, clk_disable_unprepare should be executed.
7).Put 'platform_set_drvdata' before 'iio_device_register'.
8).Fix coding style and spelling error.

Zhiyong Tao (3):
  dt-bindings: auxadc: Add binding document for Mediatek auxadc.
  auxadc: Add Mediatek auxadc driver for mt2701.
  arm: dts: auxadc: Add auxadc node.

 .../devicetree/bindings/iio/adc/mt65xx_auxadc.txt  |   27 ++
 .../devicetree/bindings/soc/mediatek/auxadc.txt    |   21 --
 arch/arm/boot/dts/mt2701.dtsi                      |    9 +
 drivers/iio/adc/Kconfig                            |   13 +
 drivers/iio/adc/Makefile                           |    1 +
 drivers/iio/adc/mt6577_auxadc.c                    |  301 ++++++++++++++++++++
 6 files changed, 351 insertions(+), 21 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iio/adc/mt65xx_auxadc.txt
 delete mode 100644 Documentation/devicetree/bindings/soc/mediatek/auxadc.txt
 create mode 100644 drivers/iio/adc/mt6577_auxadc.c



From zhiyong.tao at mediatek.com  Mon Jul  4 20:50:08 2016
From: zhiyong.tao at mediatek.com (Zhiyong Tao)
Date: Tue, 5 Jul 2016 11:50:08 +0800
Subject: [PATCH v2 1/3] dt-bindings: auxadc: Add binding document for Mediatek
 auxadc.
In-Reply-To: <1467690610-20550-1-git-send-email-zhiyong.tao@mediatek.com>
References: <1467690610-20550-1-git-send-email-zhiyong.tao@mediatek.com>
Message-ID: <1467690610-20550-2-git-send-email-zhiyong.tao@mediatek.com>

The commit adds the device tree binding documentation for the mediatek
auxadc found on Mediatek MT2701.
Thermal gets auxadc sample data by iio device.
So the commit changes auxadc device tree binding documentation from
/soc/mediatek/auxadc.txt to /iio/adc/mt65xx_auxadc.txt.

Signed-off-by: Zhiyong Tao <zhiyong.tao at mediatek.com>
---
 .../devicetree/bindings/iio/adc/mt65xx_auxadc.txt  |   27 ++++++++++++++++++++
 .../devicetree/bindings/soc/mediatek/auxadc.txt    |   21 ---------------
 2 files changed, 27 insertions(+), 21 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iio/adc/mt65xx_auxadc.txt
 delete mode 100644 Documentation/devicetree/bindings/soc/mediatek/auxadc.txt

diff --git a/Documentation/devicetree/bindings/iio/adc/mt65xx_auxadc.txt b/Documentation/devicetree/bindings/iio/adc/mt65xx_auxadc.txt
new file mode 100644
index 0000000..47fcd1b
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/mt65xx_auxadc.txt
@@ -0,0 +1,27 @@
+* Mediatek AUXADC - Analog to Digital Converter on Mediatek mobile soc (mt65xx/mt81xx/mt27xx)
+===============
+
+The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found
+in some Mediatek SoCs which among other things measures the temperatures
+in the SoC. It can be used directly with register accesses, but it is also
+used by thermal controller which reads the temperatures from the AUXADC
+directly via its own bus interface. See
+Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
+for the Thermal Controller which holds a phandle to the AUXADC.
+
+Required properties:
+  - compatible: "mediatek,mt2701-auxadc" or "mediatek,mt8173-auxadc"
+  - reg: Address range of the AUXADC unit.
+  - clocks: Should contain a clock specifier for each entry in clock-names
+  - clock-names: Should contain "main".
+  - io-channel-cells: Should be 1, see ../iio-bindings.txt
+
+Example:
+
+auxadc: auxadc at 11001000 {
+	compatible = "mediatek,mt2701-auxadc";
+	reg = <0 0x11001000 0 0x1000>;
+	clocks = <&pericfg CLK_PERI_AUXADC>;
+	clock-names = "main";
+	#io-channel-cells = <1>;
+};
diff --git a/Documentation/devicetree/bindings/soc/mediatek/auxadc.txt b/Documentation/devicetree/bindings/soc/mediatek/auxadc.txt
deleted file mode 100644
index bdb7829..0000000
--- a/Documentation/devicetree/bindings/soc/mediatek/auxadc.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-MediaTek AUXADC
-===============
-
-The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found
-in some Mediatek SoCs which among other things measures the temperatures
-in the SoC. It can be used directly with register accesses, but it is also
-used by thermal controller which reads the temperatures from the AUXADC
-directly via its own bus interface. See
-Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
-for the Thermal Controller which holds a phandle to the AUXADC.
-
-Required properties:
-- compatible: Must be "mediatek,mt8173-auxadc"
-- reg: Address range of the AUXADC unit
-
-Example:
-
-auxadc: auxadc at 11001000 {
-	compatible = "mediatek,mt8173-auxadc";
-	reg = <0 0x11001000 0 0x1000>;
-};
-- 
1.7.9.5



From zhiyong.tao at mediatek.com  Mon Jul  4 20:50:09 2016
From: zhiyong.tao at mediatek.com (Zhiyong Tao)
Date: Tue, 5 Jul 2016 11:50:09 +0800
Subject: [PATCH v2 2/3] auxadc: Add Mediatek auxadc driver for mt2701.
In-Reply-To: <1467690610-20550-1-git-send-email-zhiyong.tao@mediatek.com>
References: <1467690610-20550-1-git-send-email-zhiyong.tao@mediatek.com>
Message-ID: <1467690610-20550-3-git-send-email-zhiyong.tao@mediatek.com>

Add Mediatek auxadc driver based on iio.
It will register a device in iio and support iio.
So thermal can read auxadc channel to sample data by iio device.
It is tested successfully on mt2701 platform.
Mt8173 and mt6577 platforms are not tested.
But the expectation is compatible.

Signed-off-by: Zhiyong Tao <zhiyong.tao at mediatek.com>
---
 drivers/iio/adc/Kconfig         |   13 ++
 drivers/iio/adc/Makefile        |    1 +
 drivers/iio/adc/mt6577_auxadc.c |  301 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 315 insertions(+)
 create mode 100644 drivers/iio/adc/mt6577_auxadc.c

diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 25378c5..66e9b44 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -315,6 +315,19 @@ config MEN_Z188_ADC
 	  This driver can also be built as a module. If so, the module will be
 	  called men_z188_adc.
 
+config MEDIATEK_MT65XX_AUXADC
+	tristate "MediaTek AUXADC driver"
+	depends on ARCH_MEDIATEK || COMPILE_TEST
+	depends on HAS_IOMEM
+	help
+	  Say yes here to enable support for MediaTek mt65xx AUXADC.
+
+	  The driver supports immediate mode operation to read from one of sixteen
+	  channels (external or internal).
+
+	  This driver can also be built as a module. If so, the module will be
+	  called mt6577_auxadc.
+
 config MXS_LRADC
         tristate "Freescale i.MX23/i.MX28 LRADC"
         depends on (ARCH_MXS || COMPILE_TEST) && HAS_IOMEM
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 38638d4..14a630f 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_MAX1363) += max1363.o
 obj-$(CONFIG_MCP320X) += mcp320x.o
 obj-$(CONFIG_MCP3422) += mcp3422.o
 obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
+obj-$(CONFIG_MEDIATEK_MT65XX_AUXADC) += mt6577_auxadc.o
 obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
 obj-$(CONFIG_NAU7802) += nau7802.o
 obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c
new file mode 100644
index 0000000..a56531a
--- /dev/null
+++ b/drivers/iio/adc/mt6577_auxadc.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Zhiyong Tao <zhiyong.tao at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/iopoll.h>
+#include <linux/io.h>
+#include <linux/iio/iio.h>
+
+/* Registers definitions */
+#define MT65XX_AUXADC_CON0                    0x00
+#define MT65XX_AUXADC_CON1                    0x04
+#define MT65XX_AUXADC_CON2                    0x10
+#define MT65XX_AUXADC_STA                     BIT(0)
+
+#define MT65XX_AUXADC_DAT0                    0x14
+#define MT65XX_AUXADC_RDY0                    BIT(12)
+
+#define MT65XX_AUXADC_MISC                    0x94
+#define MT65XX_AUXADC_PDN_EN                  BIT(14)
+
+#define MT65XX_AUXADC_DAT_MASK                0xfff
+#define MT65XX_AUXADC_SLEEP_US                1000
+#define MT65XX_AUXADC_TIMEOUT_US              10000
+#define MT65XX_AUXADC_POWER_READY_MS          1
+#define MT65XX_AUXADC_SAMPLE_READY_US         25
+
+struct mt65xx_auxadc_device {
+	void __iomem *reg_base;
+	struct clk *adc_clk;
+	struct mutex lock;
+	unsigned int power_ready_ms;
+	unsigned int sample_ready_us;
+};
+
+#define MT65XX_AUXADC_CHANNEL(idx) {				    \
+		.type = IIO_VOLTAGE,				    \
+		.indexed = 1,					    \
+		.channel = (idx),				    \
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
+}
+
+static const struct iio_chan_spec mt65xx_auxadc_iio_channels[] = {
+	MT65XX_AUXADC_CHANNEL(0),
+	MT65XX_AUXADC_CHANNEL(1),
+	MT65XX_AUXADC_CHANNEL(2),
+	MT65XX_AUXADC_CHANNEL(3),
+	MT65XX_AUXADC_CHANNEL(4),
+	MT65XX_AUXADC_CHANNEL(5),
+	MT65XX_AUXADC_CHANNEL(6),
+	MT65XX_AUXADC_CHANNEL(7),
+	MT65XX_AUXADC_CHANNEL(8),
+	MT65XX_AUXADC_CHANNEL(9),
+	MT65XX_AUXADC_CHANNEL(10),
+	MT65XX_AUXADC_CHANNEL(11),
+	MT65XX_AUXADC_CHANNEL(12),
+	MT65XX_AUXADC_CHANNEL(13),
+	MT65XX_AUXADC_CHANNEL(14),
+	MT65XX_AUXADC_CHANNEL(15),
+};
+
+static int mt65xx_auxadc_read(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan)
+{
+	u32 rawdata, val;
+	void __iomem *reg_channel;
+	int ret;
+	struct mt65xx_auxadc_device *adc_dev = iio_priv(indio_dev);
+
+	reg_channel = adc_dev->reg_base + MT65XX_AUXADC_DAT0 +
+		      chan->channel * 0x04;
+
+	mutex_lock(&adc_dev->lock);
+
+	val = readl(adc_dev->reg_base + MT65XX_AUXADC_CON1);
+	val &= ~(1 << chan->channel);
+	writel(val, adc_dev->reg_base + MT65XX_AUXADC_CON1);
+
+	/* read channel and make sure old ready bit == 0 */
+	ret = readl_poll_timeout(reg_channel, val,
+				 ((val & MT65XX_AUXADC_RDY0) == 0),
+				 MT65XX_AUXADC_SLEEP_US,
+				 MT65XX_AUXADC_TIMEOUT_US);
+	if (ret < 0) {
+		dev_err(indio_dev->dev.parent,
+			"wait for channel[%d] ready bit clear time out\n",
+			chan->channel);
+
+		mutex_unlock(&adc_dev->lock);
+
+		return -EINVAL;
+	}
+
+	/* set bit to trigger sample */
+	val = readl(adc_dev->reg_base + MT65XX_AUXADC_CON1);
+	val |= 1 << chan->channel;
+	writel(val, adc_dev->reg_base + MT65XX_AUXADC_CON1);
+
+	/* we must delay here for hardware sample channel data */
+	udelay(adc_dev->sample_ready_us);
+
+	/* check MTK_AUXADC_CON2 if auxadc is idle */
+	ret = readl_poll_timeout(adc_dev->reg_base + MT65XX_AUXADC_CON2, val,
+				 ((val & MT65XX_AUXADC_STA) == 0),
+				 MT65XX_AUXADC_SLEEP_US,
+				 MT65XX_AUXADC_TIMEOUT_US);
+	if (ret < 0) {
+		dev_err(indio_dev->dev.parent,
+			"wait for auxadc idle time out\n");
+
+		mutex_unlock(&adc_dev->lock);
+
+		return -EINVAL;
+	}
+
+	/* read channel and make sure ready bit == 1 */
+	ret = readl_poll_timeout(reg_channel, val,
+				 ((val & MT65XX_AUXADC_RDY0) != 0),
+				 MT65XX_AUXADC_SLEEP_US,
+				 MT65XX_AUXADC_TIMEOUT_US);
+	if (ret < 0) {
+		dev_err(indio_dev->dev.parent,
+			"wait for channel[%d] data ready time out\n",
+			chan->channel);
+
+		mutex_unlock(&adc_dev->lock);
+
+		return -EINVAL;
+	}
+
+	/* read data */
+	rawdata = readl(reg_channel) & MT65XX_AUXADC_DAT_MASK;
+
+	mutex_unlock(&adc_dev->lock);
+
+	return rawdata;
+}
+
+static int mt65xx_auxadc_read_raw(struct iio_dev *indio_dev,
+				  struct iio_chan_spec const *chan,
+				  int *val,
+				  int *val2,
+				  long info)
+{
+	int ret;
+
+	switch (info) {
+	case IIO_CHAN_INFO_PROCESSED:
+		*val = mt65xx_auxadc_read(indio_dev, chan);
+		if (*val < 0) {
+			dev_err(indio_dev->dev.parent,
+				"failed to sample data on channel[%d]\n",
+				chan->channel);
+			return -EIO;
+		}
+		ret = IIO_VAL_INT;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static const struct iio_info mt65xx_auxadc_info = {
+	.driver_module = THIS_MODULE,
+	.read_raw = &mt65xx_auxadc_read_raw,
+};
+
+static int mt65xx_auxadc_probe(struct platform_device *pdev)
+{
+	struct mt65xx_auxadc_device *adc_dev;
+	unsigned long adc_clk_rate;
+	struct resource *res;
+	struct iio_dev *indio_dev;
+	int ret;
+	u32 val;
+
+	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	adc_dev = iio_priv(indio_dev);
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->name = dev_name(&pdev->dev);
+	indio_dev->info = &mt65xx_auxadc_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = mt65xx_auxadc_iio_channels;
+	indio_dev->num_channels = ARRAY_SIZE(mt65xx_auxadc_iio_channels);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	adc_dev->reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(adc_dev->reg_base)) {
+		dev_err(&pdev->dev, "failed to get auxadc base address.\n");
+		return PTR_ERR(adc_dev->reg_base);
+	}
+
+	adc_dev->adc_clk = devm_clk_get(&pdev->dev, "main");
+	if (IS_ERR(adc_dev->adc_clk)) {
+		dev_err(&pdev->dev, "failed to get auxadc clock\n");
+		return PTR_ERR(adc_dev->adc_clk);
+	}
+
+	ret = clk_prepare_enable(adc_dev->adc_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable auxadc clock\n");
+		return ret;
+	}
+
+	adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
+	if (!adc_clk_rate) {
+		dev_err(&pdev->dev, "null clock rate!\n");
+		goto err_disable_clk;
+	}
+
+	adc_dev->power_ready_ms = MT65XX_AUXADC_POWER_READY_MS;
+	adc_dev->sample_ready_us = MT65XX_AUXADC_SAMPLE_READY_US;
+
+	mutex_init(&adc_dev->lock);
+
+	val = readl(adc_dev->reg_base + MT65XX_AUXADC_MISC);
+	val |= MT65XX_AUXADC_PDN_EN;
+	writel(val, adc_dev->reg_base + MT65XX_AUXADC_MISC);
+	mdelay(adc_dev->power_ready_ms);
+
+	val = readl(adc_dev->reg_base + MT65XX_AUXADC_MISC);
+	if ((val & MT65XX_AUXADC_PDN_EN) == 0) {
+		dev_err(&pdev->dev, "failed to enable auxadc power!\n");
+		goto err_disable_clk;
+	}
+
+	platform_set_drvdata(pdev, indio_dev);
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to register iio device!\n");
+		return ret;
+	}
+
+	return 0;
+
+err_disable_clk:
+	clk_disable_unprepare(adc_dev->adc_clk);
+	return -EINVAL;
+}
+
+static int mt65xx_auxadc_remove(struct platform_device *pdev)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+	struct mt65xx_auxadc_device *adc_dev = iio_priv(indio_dev);
+	u32 val;
+
+	iio_device_unregister(indio_dev);
+
+	val = readl(adc_dev->reg_base + MT65XX_AUXADC_MISC);
+	val &= ~MT65XX_AUXADC_PDN_EN;
+	writel(val, adc_dev->reg_base + MT65XX_AUXADC_MISC);
+
+	clk_disable_unprepare(adc_dev->adc_clk);
+
+	return 0;
+}
+
+static const struct of_device_id mt65xx_auxadc_of_match[] = {
+	{ .compatible = "mediatek,mt2701-auxadc", },
+	{ .compatible = "mediatek,mt8173-auxadc", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, mt65xx_auxadc_of_match);
+
+static struct platform_driver mt65xx_auxadc_driver = {
+	.driver = {
+		.name   = "mt65xx-auxadc",
+		.of_match_table = mt65xx_auxadc_of_match,
+	},
+	.probe	= mt65xx_auxadc_probe,
+	.remove	= mt65xx_auxadc_remove,
+};
+module_platform_driver(mt65xx_auxadc_driver);
+
+MODULE_AUTHOR("Zhiyong Tao <zhiyong.tao at mediatek.com>");
+MODULE_DESCRIPTION("MTK AUXADC Device Driver");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5



From zhiyong.tao at mediatek.com  Mon Jul  4 20:50:10 2016
From: zhiyong.tao at mediatek.com (Zhiyong Tao)
Date: Tue, 5 Jul 2016 11:50:10 +0800
Subject: [PATCH v2 3/3] arm: dts: auxadc: Add auxadc node.
In-Reply-To: <1467690610-20550-1-git-send-email-zhiyong.tao@mediatek.com>
References: <1467690610-20550-1-git-send-email-zhiyong.tao@mediatek.com>
Message-ID: <1467690610-20550-4-git-send-email-zhiyong.tao@mediatek.com>

The commit adds auxadc nodes to the Mediatek MT2701 dtsi file.

Signed-off-by: Zhiyong Tao <zhiyong.tao at mediatek.com>
---
 arch/arm/boot/dts/mt2701.dtsi |    9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
index 42d5a37..464c86a 100644
--- a/arch/arm/boot/dts/mt2701.dtsi
+++ b/arch/arm/boot/dts/mt2701.dtsi
@@ -187,6 +187,15 @@
 		      <0 0x10216000 0 0x2000>;
 	};
 
+	auxadc: auxadc at 11001000 {
+		compatible = "mediatek,mt2701-auxadc";
+		reg = <0 0x11001000 0 0x1000>;
+		clocks = <&pericfg CLK_PERI_AUXADC>;
+		clock-names = "main";
+		#io-channel-cells = <1>;
+		status = "disabled";
+	};
+
 	uart0: serial at 11002000 {
 		compatible = "mediatek,mt2701-uart",
 			     "mediatek,mt6577-uart";
-- 
1.7.9.5



From davem at davemloft.net  Mon Jul  4 23:56:45 2016
From: davem at davemloft.net (David Miller)
Date: Mon, 04 Jul 2016 23:56:45 -0700 (PDT)
Subject: [PATCH] net-next: mediatek: remove superfluous free_irq() call
In-Reply-To: <1467639430-64370-1-git-send-email-john@phrozen.org>
References: <1467639430-64370-1-git-send-email-john@phrozen.org>
Message-ID: <20160704.235645.267168312192459724.davem@davemloft.net>

From: John Crispin <john at phrozen.org>
Date: Mon,  4 Jul 2016 15:37:10 +0200

> Commit 8067302973a1 ("net-next: mediatek: add support for IRQ grouping")
> adds handling for irq 1 and 2 to the uninit function but did not remove
> irq 0 which is not used since irq grouping was introduced. Fix this by
> removing the superfluous call to free_irq().
> 
> Reported-by: Arnd Bergmann <arnd at arndb.de>
> Signed-off-by: John Crispin <john at phrozen.org>

Applied.


From broonie at kernel.org  Tue Jul  5 01:12:32 2016
From: broonie at kernel.org (Mark Brown)
Date: Tue, 5 Jul 2016 10:12:32 +0200
Subject: [alsa-devel] [PATCH 3/4] ASoC: mediatek: add BT implementation
In-Reply-To: <1467683533.4212.16.camel@mtksdaap41>
References: <1467629788-14411-1-git-send-email-garlic.tseng@mediatek.com>
 <1467629788-14411-4-git-send-email-garlic.tseng@mediatek.com>
 <20160704144406.GH6247@sirena.org.uk>
 <1467683533.4212.16.camel@mtksdaap41>
Message-ID: <20160705081232.GL6247@sirena.org.uk>

On Tue, Jul 05, 2016 at 09:52:13AM +0800, Garlic Tseng wrote:
> On Mon, 2016-07-04 at 16:44 +0200, Mark Brown wrote:

> > We really shouldn't be writing the registers or other internal data of
> > the device.  Instead we should be getting the driver for the relevant
> > hardware component to do it.  If we just write to registers that makes
> > the interoperation with the real driver for the device more fragile than
> > it should be, people might update the main driver without noticing the
> > external driver.

> The AUDIO_TOP_CON4 is a reg of the ASoC hw module. All the registers
> which are set in the btmrg operator belong to ASoC hardware. The reg
> writing you mention above is to power up the MRG interface in the ASoC
> module.

The problem is that this is the machine driver, not a driver for the
chip that's being controlled.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mediatek/attachments/20160705/3ec84cf9/attachment.sig>

From pmeerw at pmeerw.net  Tue Jul  5 01:15:04 2016
From: pmeerw at pmeerw.net (Peter Meerwald-Stadler)
Date: Tue, 5 Jul 2016 10:15:04 +0200 (CEST)
Subject: [PATCH v2 2/3] auxadc: Add Mediatek auxadc driver for mt2701.
In-Reply-To: <1467690610-20550-3-git-send-email-zhiyong.tao@mediatek.com>
References: <1467690610-20550-1-git-send-email-zhiyong.tao@mediatek.com>
 <1467690610-20550-3-git-send-email-zhiyong.tao@mediatek.com>
Message-ID: <alpine.DEB.2.02.1607051008510.26091@pmeerw.net>


> Add Mediatek auxadc driver based on iio.
> It will register a device in iio and support iio.
> So thermal can read auxadc channel to sample data by iio device.
> It is tested successfully on mt2701 platform.
> Mt8173 and mt6577 platforms are not tested.
> But the expectation is compatible.

comments below
 
> Signed-off-by: Zhiyong Tao <zhiyong.tao at mediatek.com>
> ---
>  drivers/iio/adc/Kconfig         |   13 ++
>  drivers/iio/adc/Makefile        |    1 +
>  drivers/iio/adc/mt6577_auxadc.c |  301 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 315 insertions(+)
>  create mode 100644 drivers/iio/adc/mt6577_auxadc.c
> 
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 25378c5..66e9b44 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -315,6 +315,19 @@ config MEN_Z188_ADC
>  	  This driver can also be built as a module. If so, the module will be
>  	  called men_z188_adc.
>  
> +config MEDIATEK_MT65XX_AUXADC
> +	tristate "MediaTek AUXADC driver"
> +	depends on ARCH_MEDIATEK || COMPILE_TEST
> +	depends on HAS_IOMEM
> +	help
> +	  Say yes here to enable support for MediaTek mt65xx AUXADC.
> +
> +	  The driver supports immediate mode operation to read from one of sixteen
> +	  channels (external or internal).
> +
> +	  This driver can also be built as a module. If so, the module will be
> +	  called mt6577_auxadc.
> +
>  config MXS_LRADC
>          tristate "Freescale i.MX23/i.MX28 LRADC"
>          depends on (ARCH_MXS || COMPILE_TEST) && HAS_IOMEM
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index 38638d4..14a630f 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -31,6 +31,7 @@ obj-$(CONFIG_MAX1363) += max1363.o
>  obj-$(CONFIG_MCP320X) += mcp320x.o
>  obj-$(CONFIG_MCP3422) += mcp3422.o
>  obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
> +obj-$(CONFIG_MEDIATEK_MT65XX_AUXADC) += mt6577_auxadc.o

not strictly alphabethic

>  obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
>  obj-$(CONFIG_NAU7802) += nau7802.o
>  obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
> diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c
> new file mode 100644
> index 0000000..a56531a
> --- /dev/null
> +++ b/drivers/iio/adc/mt6577_auxadc.c
> @@ -0,0 +1,301 @@
> +/*
> + * Copyright (c) 2016 MediaTek Inc.
> + * Author: Zhiyong Tao <zhiyong.tao at mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/iopoll.h>
> +#include <linux/io.h>
> +#include <linux/iio/iio.h>
> +
> +/* Registers definitions */

Register definitions

> +#define MT65XX_AUXADC_CON0                    0x00

usually the prefix matches the driver name

> +#define MT65XX_AUXADC_CON1                    0x04
> +#define MT65XX_AUXADC_CON2                    0x10
> +#define MT65XX_AUXADC_STA                     BIT(0)
> +
> +#define MT65XX_AUXADC_DAT0                    0x14
> +#define MT65XX_AUXADC_RDY0                    BIT(12)
> +
> +#define MT65XX_AUXADC_MISC                    0x94
> +#define MT65XX_AUXADC_PDN_EN                  BIT(14)
> +
> +#define MT65XX_AUXADC_DAT_MASK                0xfff
> +#define MT65XX_AUXADC_SLEEP_US                1000
> +#define MT65XX_AUXADC_TIMEOUT_US              10000
> +#define MT65XX_AUXADC_POWER_READY_MS          1
> +#define MT65XX_AUXADC_SAMPLE_READY_US         25
> +
> +struct mt65xx_auxadc_device {
> +	void __iomem *reg_base;
> +	struct clk *adc_clk;
> +	struct mutex lock;
> +	unsigned int power_ready_ms;
> +	unsigned int sample_ready_us;

why are the delays stored in the struct, you could use the #defines above 
directly?

> +};
> +
> +#define MT65XX_AUXADC_CHANNEL(idx) {				    \
> +		.type = IIO_VOLTAGE,				    \
> +		.indexed = 1,					    \
> +		.channel = (idx),				    \
> +		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
> +}
> +
> +static const struct iio_chan_spec mt65xx_auxadc_iio_channels[] = {
> +	MT65XX_AUXADC_CHANNEL(0),
> +	MT65XX_AUXADC_CHANNEL(1),
> +	MT65XX_AUXADC_CHANNEL(2),
> +	MT65XX_AUXADC_CHANNEL(3),
> +	MT65XX_AUXADC_CHANNEL(4),
> +	MT65XX_AUXADC_CHANNEL(5),
> +	MT65XX_AUXADC_CHANNEL(6),
> +	MT65XX_AUXADC_CHANNEL(7),
> +	MT65XX_AUXADC_CHANNEL(8),
> +	MT65XX_AUXADC_CHANNEL(9),
> +	MT65XX_AUXADC_CHANNEL(10),
> +	MT65XX_AUXADC_CHANNEL(11),
> +	MT65XX_AUXADC_CHANNEL(12),
> +	MT65XX_AUXADC_CHANNEL(13),
> +	MT65XX_AUXADC_CHANNEL(14),
> +	MT65XX_AUXADC_CHANNEL(15),
> +};
> +
> +static int mt65xx_auxadc_read(struct iio_dev *indio_dev,
> +			      struct iio_chan_spec const *chan)
> +{
> +	u32 rawdata, val;
> +	void __iomem *reg_channel;
> +	int ret;
> +	struct mt65xx_auxadc_device *adc_dev = iio_priv(indio_dev);
> +
> +	reg_channel = adc_dev->reg_base + MT65XX_AUXADC_DAT0 +
> +		      chan->channel * 0x04;
> +
> +	mutex_lock(&adc_dev->lock);
> +
> +	val = readl(adc_dev->reg_base + MT65XX_AUXADC_CON1);
> +	val &= ~(1 << chan->channel);
> +	writel(val, adc_dev->reg_base + MT65XX_AUXADC_CON1);
> +
> +	/* read channel and make sure old ready bit == 0 */
> +	ret = readl_poll_timeout(reg_channel, val,
> +				 ((val & MT65XX_AUXADC_RDY0) == 0),
> +				 MT65XX_AUXADC_SLEEP_US,
> +				 MT65XX_AUXADC_TIMEOUT_US);
> +	if (ret < 0) {
> +		dev_err(indio_dev->dev.parent,
> +			"wait for channel[%d] ready bit clear time out\n",
> +			chan->channel);
> +
> +		mutex_unlock(&adc_dev->lock);
> +
> +		return -EINVAL;

I'd use -ETIMEDOUT

> +	}
> +
> +	/* set bit to trigger sample */
> +	val = readl(adc_dev->reg_base + MT65XX_AUXADC_CON1);
> +	val |= 1 << chan->channel;
> +	writel(val, adc_dev->reg_base + MT65XX_AUXADC_CON1);
> +
> +	/* we must delay here for hardware sample channel data */
> +	udelay(adc_dev->sample_ready_us);
> +
> +	/* check MTK_AUXADC_CON2 if auxadc is idle */
> +	ret = readl_poll_timeout(adc_dev->reg_base + MT65XX_AUXADC_CON2, val,
> +				 ((val & MT65XX_AUXADC_STA) == 0),
> +				 MT65XX_AUXADC_SLEEP_US,
> +				 MT65XX_AUXADC_TIMEOUT_US);
> +	if (ret < 0) {
> +		dev_err(indio_dev->dev.parent,
> +			"wait for auxadc idle time out\n");
> +
> +		mutex_unlock(&adc_dev->lock);
> +
> +		return -EINVAL;
> +	}
> +
> +	/* read channel and make sure ready bit == 1 */
> +	ret = readl_poll_timeout(reg_channel, val,
> +				 ((val & MT65XX_AUXADC_RDY0) != 0),
> +				 MT65XX_AUXADC_SLEEP_US,
> +				 MT65XX_AUXADC_TIMEOUT_US);
> +	if (ret < 0) {
> +		dev_err(indio_dev->dev.parent,
> +			"wait for channel[%d] data ready time out\n",
> +			chan->channel);
> +
> +		mutex_unlock(&adc_dev->lock);
> +
> +		return -EINVAL;
> +	}
> +
> +	/* read data */
> +	rawdata = readl(reg_channel) & MT65XX_AUXADC_DAT_MASK;
> +
> +	mutex_unlock(&adc_dev->lock);
> +
> +	return rawdata;
> +}
> +
> +static int mt65xx_auxadc_read_raw(struct iio_dev *indio_dev,
> +				  struct iio_chan_spec const *chan,
> +				  int *val,
> +				  int *val2,
> +				  long info)
> +{
> +	int ret;
> +
> +	switch (info) {
> +	case IIO_CHAN_INFO_PROCESSED:
> +		*val = mt65xx_auxadc_read(indio_dev, chan);
> +		if (*val < 0) {
> +			dev_err(indio_dev->dev.parent,
> +				"failed to sample data on channel[%d]\n",
> +				chan->channel);
> +			return -EIO;

I suggest to return *val and not change the error code

> +		}
> +		ret = IIO_VAL_INT;

return IIO_VAL_INT seems simpler

> +		break;
> +	default:

return -EINVAL ...

> +		ret = -EINVAL;
> +		break;
> +	}
> +

... and drop next line

> +	return ret;
> +}
> +
> +static const struct iio_info mt65xx_auxadc_info = {
> +	.driver_module = THIS_MODULE,
> +	.read_raw = &mt65xx_auxadc_read_raw,
> +};
> +
> +static int mt65xx_auxadc_probe(struct platform_device *pdev)
> +{
> +	struct mt65xx_auxadc_device *adc_dev;
> +	unsigned long adc_clk_rate;
> +	struct resource *res;
> +	struct iio_dev *indio_dev;
> +	int ret;
> +	u32 val;
> +
> +	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
> +	if (!indio_dev)
> +		return -ENOMEM;
> +
> +	adc_dev = iio_priv(indio_dev);
> +	indio_dev->dev.parent = &pdev->dev;
> +	indio_dev->name = dev_name(&pdev->dev);
> +	indio_dev->info = &mt65xx_auxadc_info;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->channels = mt65xx_auxadc_iio_channels;
> +	indio_dev->num_channels = ARRAY_SIZE(mt65xx_auxadc_iio_channels);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	adc_dev->reg_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(adc_dev->reg_base)) {
> +		dev_err(&pdev->dev, "failed to get auxadc base address.\n");
> +		return PTR_ERR(adc_dev->reg_base);
> +	}
> +
> +	adc_dev->adc_clk = devm_clk_get(&pdev->dev, "main");
> +	if (IS_ERR(adc_dev->adc_clk)) {
> +		dev_err(&pdev->dev, "failed to get auxadc clock\n");
> +		return PTR_ERR(adc_dev->adc_clk);
> +	}
> +
> +	ret = clk_prepare_enable(adc_dev->adc_clk);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to enable auxadc clock\n");
> +		return ret;
> +	}
> +
> +	adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
> +	if (!adc_clk_rate) {
> +		dev_err(&pdev->dev, "null clock rate!\n");
> +		goto err_disable_clk;
> +	}
> +
> +	adc_dev->power_ready_ms = MT65XX_AUXADC_POWER_READY_MS;
> +	adc_dev->sample_ready_us = MT65XX_AUXADC_SAMPLE_READY_US;
> +
> +	mutex_init(&adc_dev->lock);
> +
> +	val = readl(adc_dev->reg_base + MT65XX_AUXADC_MISC);
> +	val |= MT65XX_AUXADC_PDN_EN;
> +	writel(val, adc_dev->reg_base + MT65XX_AUXADC_MISC);
> +	mdelay(adc_dev->power_ready_ms);
> +
> +	val = readl(adc_dev->reg_base + MT65XX_AUXADC_MISC);
> +	if ((val & MT65XX_AUXADC_PDN_EN) == 0) {
> +		dev_err(&pdev->dev, "failed to enable auxadc power!\n");
> +		goto err_disable_clk;
> +	}
> +
> +	platform_set_drvdata(pdev, indio_dev);
> +
> +	ret = iio_device_register(indio_dev);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "failed to register iio device!\n");

need to power off and unprepare clock here
> +		return ret;
> +	}
> +
> +	return 0;
> +
> +err_disable_clk:
> +	clk_disable_unprepare(adc_dev->adc_clk);
> +	return -EINVAL;
> +}
> +
> +static int mt65xx_auxadc_remove(struct platform_device *pdev)
> +{
> +	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
> +	struct mt65xx_auxadc_device *adc_dev = iio_priv(indio_dev);
> +	u32 val;
> +
> +	iio_device_unregister(indio_dev);
> +
> +	val = readl(adc_dev->reg_base + MT65XX_AUXADC_MISC);
> +	val &= ~MT65XX_AUXADC_PDN_EN;
> +	writel(val, adc_dev->reg_base + MT65XX_AUXADC_MISC);
> +
> +	clk_disable_unprepare(adc_dev->adc_clk);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mt65xx_auxadc_of_match[] = {
> +	{ .compatible = "mediatek,mt2701-auxadc", },
> +	{ .compatible = "mediatek,mt8173-auxadc", },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, mt65xx_auxadc_of_match);
> +
> +static struct platform_driver mt65xx_auxadc_driver = {
> +	.driver = {
> +		.name   = "mt65xx-auxadc",
> +		.of_match_table = mt65xx_auxadc_of_match,
> +	},
> +	.probe	= mt65xx_auxadc_probe,
> +	.remove	= mt65xx_auxadc_remove,
> +};
> +module_platform_driver(mt65xx_auxadc_driver);
> +
> +MODULE_AUTHOR("Zhiyong Tao <zhiyong.tao at mediatek.com>");
> +MODULE_DESCRIPTION("MTK AUXADC Device Driver");
> +MODULE_LICENSE("GPL v2");
> 

-- 

Peter Meerwald-Stadler
+43-664-2444418 (mobile)


From garlic.tseng at mediatek.com  Tue Jul  5 01:59:15 2016
From: garlic.tseng at mediatek.com (Garlic Tseng)
Date: Tue, 5 Jul 2016 16:59:15 +0800
Subject: [alsa-devel] [PATCH 3/4] ASoC: mediatek: add BT implementation
In-Reply-To: <20160705081232.GL6247@sirena.org.uk>
References: <1467629788-14411-1-git-send-email-garlic.tseng@mediatek.com>
 <1467629788-14411-4-git-send-email-garlic.tseng@mediatek.com>
 <20160704144406.GH6247@sirena.org.uk> <1467683533.4212.16.camel@mtksdaap41>
 <20160705081232.GL6247@sirena.org.uk>
Message-ID: <1467709155.10413.7.camel@mtksdaap41>

On Tue, 2016-07-05 at 10:12 +0200, Mark Brown wrote:
> On Tue, Jul 05, 2016 at 09:52:13AM +0800, Garlic Tseng wrote:
> > On Mon, 2016-07-04 at 16:44 +0200, Mark Brown wrote:
> 
> > > We really shouldn't be writing the registers or other internal data of
> > > the device.  Instead we should be getting the driver for the relevant
> > > hardware component to do it.  If we just write to registers that makes
> > > the interoperation with the real driver for the device more fragile than
> > > it should be, people might update the main driver without noticing the
> > > external driver.
> 
> > The AUDIO_TOP_CON4 is a reg of the ASoC hw module. All the registers
> > which are set in the btmrg operator belong to ASoC hardware. The reg
> > writing you mention above is to power up the MRG interface in the ASoC
> > module.
> 
> The problem is that this is the machine driver, not a driver for the
> chip that's being controlled.

The patch is for platform driver "mt2701-afe-pcm.c", which contorls the
ASoC module, not for machine driver. Maybe the patch sequence is
confusing and I'm sorry about that. Or did I misunderstand your comment?





From p.zabel at pengutronix.de  Tue Jul  5 02:16:10 2016
From: p.zabel at pengutronix.de (Philipp Zabel)
Date: Tue,  5 Jul 2016 11:16:10 +0200
Subject: [PATCH v16 2/2] arm64: dts: mt8173-evb: enable HDMI output
In-Reply-To: <1467710170-22176-1-git-send-email-p.zabel@pengutronix.de>
References: <1467710170-22176-1-git-send-email-p.zabel@pengutronix.de>
Message-ID: <1467710170-22176-2-git-send-email-p.zabel@pengutronix.de>

Add an HDMI connector node and enable the devices that are part of the
HDMI display path: cec, dpi0, hdmi_phy, and hdmi0.

Signed-off-by: Philipp Zabel <p.zabel at pengutronix.de>
---
No changes since v15.
---
 arch/arm64/boot/dts/mediatek/mt8173-evb.dts | 38 +++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
index 7453a47..2a7f731 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
@@ -42,6 +42,44 @@
 		gpio = <&pio 130 GPIO_ACTIVE_HIGH>;
 		enable-active-high;
 	};
+
+	connector {
+		compatible = "hdmi-connector";
+		label = "hdmi";
+		type = "d";
+
+		port {
+			hdmi_connector_in: endpoint {
+				remote-endpoint = <&hdmi0_out>;
+			};
+		};
+	};
+};
+
+&cec {
+	status = "okay";
+};
+
+&dpi0 {
+	status = "okay";
+};
+
+&hdmi_phy {
+	status = "okay";
+};
+
+&hdmi0 {
+	status = "okay";
+
+	ports {
+		port at 1 {
+			reg = <1>;
+
+			hdmi0_out: endpoint {
+				remote-endpoint = <&hdmi_connector_in>;
+			};
+		};
+	};
 };
 
 &i2c1 {
-- 
2.8.1



From p.zabel at pengutronix.de  Tue Jul  5 02:16:09 2016
From: p.zabel at pengutronix.de (Philipp Zabel)
Date: Tue,  5 Jul 2016 11:16:09 +0200
Subject: [PATCH v16 1/2] arm64: dts: mt8173: Add HDMI related nodes
Message-ID: <1467710170-22176-1-git-send-email-p.zabel@pengutronix.de>

From: CK Hu <ck.hu at mediatek.com>

This patch adds the device nodes for the HDMI encoder, HDMI PHY,
and HDMI CEC modules.

Signed-off-by: CK Hu <ck.hu at mediatek.com>
Signed-off-by: Cawa Cheng <cawa.cheng at mediatek.com>
Signed-off-by: Jie Qiu <jie.qiu at mediatek.com>
Signed-off-by: Daniel Kurtz <djkurtz at chromium.org>
Signed-off-by: Philipp Zabel <p.zabel at pengutronix.de>
---
No changes since v15. The corresponding HDMI drivers have been merged into
drm-next with commit 2a3467063ae3 ("Merge tag 'mediatek-drm-2016-06-20' of
git://git.pengutronix.de/git/pza/linux into drm-next")
---
 arch/arm64/boot/dts/mediatek/mt8173.dtsi | 77 ++++++++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
index 78529e4..ea59d09 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -242,6 +242,16 @@
 				     <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
 
+			hdmi_pin: xxx {
+
+				/*hdmi htplg pin*/
+				pins1 {
+					pinmux = <MT8173_PIN_21_HTPLG__FUNC_HTPLG>;
+					input-enable;
+					bias-pull-down;
+				};
+			};
+
 			i2c0_pins_a: i2c0 {
 				pins1 {
 					pinmux = <MT8173_PIN_45_SDA0__FUNC_SDA0>,
@@ -329,6 +339,14 @@
 			clock-names = "spi", "wrap";
 		};
 
+		cec: cec at 10013000 {
+			compatible = "mediatek,mt8173-cec";
+			reg = <0 0x10013000 0 0xbc>;
+			interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&infracfg CLK_INFRA_CEC>;
+			status = "disabled";
+		};
+
 		sysirq: intpol-controller at 10200620 {
 			compatible = "mediatek,mt8173-sysirq",
 				     "mediatek,mt6577-sysirq";
@@ -360,6 +378,19 @@
 			#clock-cells = <1>;
 		};
 
+		hdmi_phy: hdmi-phy at 10209100 {
+			compatible = "mediatek,mt8173-hdmi-phy";
+			reg = <0 0x10209100 0 0x24>;
+			clocks = <&apmixedsys CLK_APMIXED_HDMI_REF>;
+			clock-names = "pll_ref";
+			clock-output-names = "hdmitx_dig_cts";
+			mediatek,ibias = <0xa>;
+			mediatek,ibias_up = <0x1c>;
+			#clock-cells = <0>;
+			#phy-cells = <0>;
+			status = "disabled";
+		};
+
 		mipi_tx0: mipi-dphy at 10215000 {
 			compatible = "mediatek,mt8173-mipi-tx";
 			reg = <0 0x10215000 0 0x1000>;
@@ -554,6 +585,14 @@
 			status = "disabled";
 		};
 
+		hdmiddc0: i2c at 11012000 {
+			compatible = "mediatek,mt8173-hdmi-ddc";
+			interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_LOW>;
+			reg = <0 0x11012000 0 0x1C>;
+			clocks = <&pericfg CLK_PERI_I2C5>;
+			clock-names = "ddc-i2c";
+		};
+
 		i2c6: i2c at 11013000 {
 			compatible = "mediatek,mt8173-i2c";
 			reg = <0 0x11013000 0 0x70>,
@@ -862,6 +901,12 @@
 				 <&apmixedsys CLK_APMIXED_TVDPLL>;
 			clock-names = "pixel", "engine", "pll";
 			status = "disabled";
+
+			port {
+				dpi0_out: endpoint {
+					remote-endpoint = <&hdmi0_in>;
+				};
+			};
 		};
 
 		pwm0: pwm at 1401e000 {
@@ -919,6 +964,38 @@
 			clocks = <&mmsys CLK_MM_DISP_OD>;
 		};
 
+		hdmi0: hdmi at 14025000 {
+			compatible = "mediatek,mt8173-hdmi";
+			reg = <0 0x14025000 0 0x400>;
+			interrupts = <GIC_SPI 206 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&mmsys CLK_MM_HDMI_PIXEL>,
+				 <&mmsys CLK_MM_HDMI_PLLCK>,
+				 <&mmsys CLK_MM_HDMI_AUDIO>,
+				 <&mmsys CLK_MM_HDMI_SPDIF>;
+			clock-names = "pixel", "pll", "bclk", "spdif";
+			pinctrl-names = "default";
+			pinctrl-0 = <&hdmi_pin>;
+			phys = <&hdmi_phy>;
+			phy-names = "hdmi";
+			mediatek,syscon-hdmi = <&mmsys 0x900>;
+			assigned-clocks = <&topckgen CLK_TOP_HDMI_SEL>;
+			assigned-clock-parents = <&hdmi_phy>;
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+
+					hdmi0_in: endpoint {
+						remote-endpoint = <&dpi0_out>;
+					};
+				};
+			};
+		};
+
 		larb4: larb at 14027000 {
 			compatible = "mediatek,mt8173-smi-larb";
 			reg = <0 0x14027000 0 0x1000>;
-- 
2.8.1



From p.zabel at pengutronix.de  Tue Jul  5 02:26:21 2016
From: p.zabel at pengutronix.de (Philipp Zabel)
Date: Tue,  5 Jul 2016 11:26:21 +0200
Subject: [PATCH v8] ASoC: mediatek: Add HDMI dai-links to the mt8173-rt5650
 machine driver
Message-ID: <1467710781-23590-1-git-send-email-p.zabel@pengutronix.de>

From: PC Liao <pc.liao at mediatek.com>

This patch adds HDMI audio output support to the MT8173 RT5650 machine
driver.

Signed-off-by: PC Liao <pc.liao at mediatek.com>
Signed-off-by: Philipp Zabel <p.zabel at pengutronix.de>
---
Changes since v7:
 - Rebased onto asoc/for-next
---
 .../devicetree/bindings/sound/mt8173-rt5650.txt    |  5 +++--
 sound/soc/mediatek/Kconfig                         |  1 +
 sound/soc/mediatek/mt8173/mt8173-rt5650.c          | 26 ++++++++++++++++++++++
 3 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/mt8173-rt5650.txt b/Documentation/devicetree/bindings/sound/mt8173-rt5650.txt
index f250fc7..29dce2a 100644
--- a/Documentation/devicetree/bindings/sound/mt8173-rt5650.txt
+++ b/Documentation/devicetree/bindings/sound/mt8173-rt5650.txt
@@ -1,8 +1,9 @@
-MT8173 with RT5650 CODECS
+MT8173 with RT5650 CODECS and HDMI via I2S
 
 Required properties:
 - compatible : "mediatek,mt8173-rt5650"
 - mediatek,audio-codec: the phandles of rt5650 codecs
+                        and of the hdmi encoder node
 - mediatek,platform: the phandle of MT8173 ASoC platform
 
 Optional subnodes:
@@ -20,7 +21,7 @@ Example:
 
 	sound {
 		compatible = "mediatek,mt8173-rt5650";
-		mediatek,audio-codec = <&rt5650>;
+		mediatek,audio-codec = <&rt5650 &hdmi0>;
 		mediatek,platform = <&afe>;
 		mediatek,mclk = <0>;
 		codec-capture {
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 2fbe543..05cf809 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -46,6 +46,7 @@ config SND_SOC_MT8173_RT5650
 	tristate "ASoC Audio driver for MT8173 with RT5650 codec"
 	depends on SND_SOC_MT8173 && I2C
 	select SND_SOC_RT5645
+	select SND_SOC_HDMI_CODEC
 	help
 	  This adds ASoC driver for Mediatek MT8173 boards
 	  with the RT5650 audio codec.
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
index d478976..ba65f41 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
@@ -169,7 +169,9 @@ static struct snd_soc_dai_link_component mt8173_rt5650_codecs[] = {
 enum {
 	DAI_LINK_PLAYBACK,
 	DAI_LINK_CAPTURE,
+	DAI_LINK_HDMI,
 	DAI_LINK_CODEC_I2S,
+	DAI_LINK_HDMI_I2S,
 };
 
 /* Digital audio interface glue - connects codec <---> CPU */
@@ -195,6 +197,16 @@ static struct snd_soc_dai_link mt8173_rt5650_dais[] = {
 		.dynamic = 1,
 		.dpcm_capture = 1,
 	},
+	[DAI_LINK_HDMI] = {
+		.name = "HDMI",
+		.stream_name = "HDMI PCM",
+		.cpu_dai_name = "HDMI",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+	},
 	/* Back End DAI links */
 	[DAI_LINK_CODEC_I2S] = {
 		.name = "Codec",
@@ -210,6 +222,13 @@ static struct snd_soc_dai_link mt8173_rt5650_dais[] = {
 		.dpcm_playback = 1,
 		.dpcm_capture = 1,
 	},
+	[DAI_LINK_HDMI_I2S] = {
+		.name = "HDMI BE",
+		.cpu_dai_name = "HDMIO",
+		.no_pcm = 1,
+		.codec_dai_name = "i2s-hifi",
+		.dpcm_playback = 1,
+	},
 };
 
 static struct snd_soc_card mt8173_rt5650_card = {
@@ -284,6 +303,13 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev)
 		}
 	}
 
+	mt8173_rt5650_dais[DAI_LINK_HDMI_I2S].codec_of_node =
+		of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 1);
+	if (!mt8173_rt5650_dais[DAI_LINK_HDMI_I2S].codec_of_node) {
+		dev_err(&pdev->dev,
+			"Property 'audio-codec' missing or invalid\n");
+		return -EINVAL;
+	}
 	card->dev = &pdev->dev;
 	platform_set_drvdata(pdev, card);
 
-- 
2.8.1



From broonie at kernel.org  Tue Jul  5 02:55:51 2016
From: broonie at kernel.org (Mark Brown)
Date: Tue, 05 Jul 2016 11:55:51 +0200
Subject: Applied "ASoC: mediatek: add BT implementation" to the asoc tree
In-Reply-To: <1467629788-14411-4-git-send-email-garlic.tseng@mediatek.com>
Message-ID: <E1bKN55-0002TQ-SY@finisterre>

The patch

   ASoC: mediatek: add BT implementation

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 4bdc8d452c18a5b4f439a1bffdda6789c4a6c606 Mon Sep 17 00:00:00 2001
From: Garlic Tseng <garlic.tseng at mediatek.com>
Date: Mon, 4 Jul 2016 18:56:27 +0800
Subject: [PATCH] ASoC: mediatek: add BT implementation

Add BT implementation for mt2701 platform driver.

Signed-off-by: Garlic Tseng <garlic.tseng at mediatek.com>
Signed-off-by: Mark Brown <broonie at kernel.org>
---
 sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | 139 +++++++++++++++++++++++++++++
 1 file changed, 139 insertions(+)

diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
index c865ba13617c..6c14d686bfa1 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
@@ -333,6 +333,86 @@ static int mt2701_afe_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 	return 0;
 }
 
+static int mt2701_btmrg_startup(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
+			   AUDIO_TOP_CON4_PDN_MRGIF, 0);
+
+	afe_priv->mrg_enable[substream->stream] = 1;
+	return 0;
+}
+
+static int mt2701_btmrg_hw_params(struct snd_pcm_substream *substream,
+				  struct snd_pcm_hw_params *params,
+				  struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	int stream_fs;
+	u32 val, msk;
+
+	stream_fs = params_rate(params);
+
+	if ((stream_fs != 8000) && (stream_fs != 16000)) {
+		dev_err(afe->dev, "%s() btmgr not supprt this stream_fs %d\n",
+			__func__, stream_fs);
+		return -EINVAL;
+	}
+
+	regmap_update_bits(afe->regmap, AFE_MRGIF_CON,
+			   AFE_MRGIF_CON_I2S_MODE_MASK,
+			   AFE_MRGIF_CON_I2S_MODE_32K);
+
+	val = AFE_DAIBT_CON0_BT_FUNC_EN | AFE_DAIBT_CON0_BT_FUNC_RDY
+	      | AFE_DAIBT_CON0_MRG_USE;
+	msk = val;
+
+	if (stream_fs == 16000)
+		val |= AFE_DAIBT_CON0_BT_WIDE_MODE_EN;
+
+	msk |= AFE_DAIBT_CON0_BT_WIDE_MODE_EN;
+
+	regmap_update_bits(afe->regmap, AFE_DAIBT_CON0, msk, val);
+
+	regmap_update_bits(afe->regmap, AFE_DAIBT_CON0,
+			   AFE_DAIBT_CON0_DAIBT_EN,
+			   AFE_DAIBT_CON0_DAIBT_EN);
+	regmap_update_bits(afe->regmap, AFE_MRGIF_CON,
+			   AFE_MRGIF_CON_MRG_I2S_EN,
+			   AFE_MRGIF_CON_MRG_I2S_EN);
+	regmap_update_bits(afe->regmap, AFE_MRGIF_CON,
+			   AFE_MRGIF_CON_MRG_EN,
+			   AFE_MRGIF_CON_MRG_EN);
+	return 0;
+}
+
+static void mt2701_btmrg_shutdown(struct snd_pcm_substream *substream,
+				  struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+
+	/* if the other direction stream is not occupied */
+	if (!afe_priv->mrg_enable[!substream->stream]) {
+		regmap_update_bits(afe->regmap, AFE_DAIBT_CON0,
+				   AFE_DAIBT_CON0_DAIBT_EN, 0);
+		regmap_update_bits(afe->regmap, AFE_MRGIF_CON,
+				   AFE_MRGIF_CON_MRG_EN, 0);
+		regmap_update_bits(afe->regmap, AFE_MRGIF_CON,
+				   AFE_MRGIF_CON_MRG_I2S_EN, 0);
+		regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
+				   AUDIO_TOP_CON4_PDN_MRGIF,
+				   AUDIO_TOP_CON4_PDN_MRGIF);
+	}
+	afe_priv->mrg_enable[substream->stream] = 0;
+}
+
 static int mt2701_simple_fe_startup(struct snd_pcm_substream *substream,
 				    struct snd_soc_dai *dai)
 {
@@ -514,6 +594,13 @@ static const struct snd_soc_dai_ops mt2701_afe_i2s_ops = {
 	.set_sysclk	= mt2701_afe_i2s_set_sysclk,
 };
 
+/* MRG BE DAIs */
+static struct snd_soc_dai_ops mt2701_btmrg_ops = {
+	.startup = mt2701_btmrg_startup,
+	.shutdown = mt2701_btmrg_shutdown,
+	.hw_params = mt2701_btmrg_hw_params,
+};
+
 static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
 	/* FE DAIs: memory intefaces to CPU */
 	{
@@ -566,6 +653,36 @@ static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
 		},
 		.ops = &mt2701_single_memif_dai_ops,
 	},
+	{
+		.name = "PCM_BT_DL",
+		.id = MT2701_MEMIF_DLBT,
+		.suspend = mtk_afe_dai_suspend,
+		.resume = mtk_afe_dai_resume,
+		.playback = {
+			.stream_name = "DLBT",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = (SNDRV_PCM_RATE_8000
+				| SNDRV_PCM_RATE_16000),
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.ops = &mt2701_single_memif_dai_ops,
+	},
+	{
+		.name = "PCM_BT_UL",
+		.id = MT2701_MEMIF_ULBT,
+		.suspend = mtk_afe_dai_suspend,
+		.resume = mtk_afe_dai_resume,
+		.capture = {
+			.stream_name = "ULBT",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = (SNDRV_PCM_RATE_8000
+				| SNDRV_PCM_RATE_16000),
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.ops = &mt2701_single_memif_dai_ops,
+	},
 	/* BE DAIs */
 	{
 		.name = "I2S0",
@@ -665,6 +782,28 @@ static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
 		.ops = &mt2701_afe_i2s_ops,
 		.symmetric_rates = 1,
 	},
+	{
+		.name = "MRG BT",
+		.id = MT2701_IO_MRG,
+		.playback = {
+			.stream_name = "BT Playback",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = (SNDRV_PCM_RATE_8000
+				| SNDRV_PCM_RATE_16000),
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.capture = {
+			.stream_name = "BT Capture",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = (SNDRV_PCM_RATE_8000
+				| SNDRV_PCM_RATE_16000),
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.ops = &mt2701_btmrg_ops,
+		.symmetric_rates = 1,
+	}
 };
 
 static const struct snd_kcontrol_new mt2701_afe_o00_mix[] = {
-- 
2.8.1



From kyle at infradead.org  Tue Jul  5 06:43:23 2016
From: kyle at infradead.org (Kyle McMartin)
Date: Tue, 5 Jul 2016 09:43:23 -0400
Subject: pull request: lunux-firmware: Add Mediatek MT8173 VPU firmware
In-Reply-To: <1467629314-31902-1-git-send-email-andrew-ct.chen@mediatek.com>
References: <1467629314-31902-1-git-send-email-andrew-ct.chen@mediatek.com>
Message-ID: <20160705134323.GC8680@merlin.infradead.org>

On Mon, Jul 04, 2016 at 06:48:34PM +0800, Andrew-CT Chen wrote:
> Hi linux-firmware maintainers,
> 
> The following changes since commit 3ef7857d511ce6a91c5ce609da76c4702651cfa5:
> 
>   amdgpu: update polaris ucode (2016-06-28 14:31:11 -0400)
> 
> are available in the git repository at:
> 
>   https://github.com/andrewct-chen/vpu-linux-firmware.git vpu_encode
> 
> for you to fetch changes up to 40876d7b3c911161ab71bc84a6e90f257a13cdc4:
> 
>   mediatek: Add mt8173 VPU firmware (2016-07-04 16:26:54 +0800)

Pulled, thanks.

regards, --Kyle

> 
> ----------------------------------------------------------------
> Andrew-CT Chen (1):
>       mediatek: Add mt8173 VPU firmware
> 
>  WHENCE    |   19 +++++++++++++++++++
>  vpu_d.bin |  Bin 0 -> 4084848 bytes
>  vpu_p.bin |  Bin 0 -> 131036 bytes
>  3 files changed, 19 insertions(+)
>  create mode 100644 vpu_d.bin
>  create mode 100644 vpu_p.bin
> 


From robh at kernel.org  Tue Jul  5 13:43:20 2016
From: robh at kernel.org (Rob Herring)
Date: Tue, 5 Jul 2016 15:43:20 -0500
Subject: [PATCH v2 1/3] dt-bindings: auxadc: Add binding document for
 Mediatek auxadc.
In-Reply-To: <1467690610-20550-2-git-send-email-zhiyong.tao@mediatek.com>
References: <1467690610-20550-1-git-send-email-zhiyong.tao@mediatek.com>
 <1467690610-20550-2-git-send-email-zhiyong.tao@mediatek.com>
Message-ID: <20160705204320.GA5064@rob-hp-laptop>

On Tue, Jul 05, 2016 at 11:50:08AM +0800, Zhiyong Tao wrote:
> The commit adds the device tree binding documentation for the mediatek
> auxadc found on Mediatek MT2701.
> Thermal gets auxadc sample data by iio device.
> So the commit changes auxadc device tree binding documentation from
> /soc/mediatek/auxadc.txt to /iio/adc/mt65xx_auxadc.txt.
> 
> Signed-off-by: Zhiyong Tao <zhiyong.tao at mediatek.com>
> ---
>  .../devicetree/bindings/iio/adc/mt65xx_auxadc.txt  |   27 ++++++++++++++++++++
>  .../devicetree/bindings/soc/mediatek/auxadc.txt    |   21 ---------------
>  2 files changed, 27 insertions(+), 21 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/iio/adc/mt65xx_auxadc.txt
>  delete mode 100644 Documentation/devicetree/bindings/soc/mediatek/auxadc.txt

Next time, use the git-format-patch -M option to send so only the 
changes have to be reviewed.

> 
> diff --git a/Documentation/devicetree/bindings/iio/adc/mt65xx_auxadc.txt b/Documentation/devicetree/bindings/iio/adc/mt65xx_auxadc.txt
> new file mode 100644
> index 0000000..47fcd1b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/adc/mt65xx_auxadc.txt
> @@ -0,0 +1,27 @@
> +* Mediatek AUXADC - Analog to Digital Converter on Mediatek mobile soc (mt65xx/mt81xx/mt27xx)
> +===============
> +
> +The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found
> +in some Mediatek SoCs which among other things measures the temperatures
> +in the SoC. It can be used directly with register accesses, but it is also
> +used by thermal controller which reads the temperatures from the AUXADC
> +directly via its own bus interface. See
> +Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
> +for the Thermal Controller which holds a phandle to the AUXADC.
> +
> +Required properties:
> +  - compatible: "mediatek,mt2701-auxadc" or "mediatek,mt8173-auxadc"
> +  - reg: Address range of the AUXADC unit.
> +  - clocks: Should contain a clock specifier for each entry in clock-names
> +  - clock-names: Should contain "main".
> +  - io-channel-cells: Should be 1, see ../iio-bindings.txt

Should be #io-channel-cells

> +
> +Example:
> +
> +auxadc: auxadc at 11001000 {

Should be adc at ...

> +	compatible = "mediatek,mt2701-auxadc";
> +	reg = <0 0x11001000 0 0x1000>;
> +	clocks = <&pericfg CLK_PERI_AUXADC>;
> +	clock-names = "main";
> +	#io-channel-cells = <1>;
> +};
> diff --git a/Documentation/devicetree/bindings/soc/mediatek/auxadc.txt b/Documentation/devicetree/bindings/soc/mediatek/auxadc.txt
> deleted file mode 100644
> index bdb7829..0000000
> --- a/Documentation/devicetree/bindings/soc/mediatek/auxadc.txt
> +++ /dev/null
> @@ -1,21 +0,0 @@
> -MediaTek AUXADC
> -===============
> -
> -The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found
> -in some Mediatek SoCs which among other things measures the temperatures
> -in the SoC. It can be used directly with register accesses, but it is also
> -used by thermal controller which reads the temperatures from the AUXADC
> -directly via its own bus interface. See
> -Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
> -for the Thermal Controller which holds a phandle to the AUXADC.
> -
> -Required properties:
> -- compatible: Must be "mediatek,mt8173-auxadc"
> -- reg: Address range of the AUXADC unit
> -
> -Example:
> -
> -auxadc: auxadc at 11001000 {
> -	compatible = "mediatek,mt8173-auxadc";
> -	reg = <0 0x11001000 0 0x1000>;
> -};
> -- 
> 1.7.9.5
> 


From jamesjj.liao at mediatek.com  Tue Jul  5 22:17:02 2016
From: jamesjj.liao at mediatek.com (James Liao)
Date: Wed, 6 Jul 2016 13:17:02 +0800
Subject: [PATCH v7 4/4] soc: mediatek: Add MT2701 scpsys driver
In-Reply-To: <0ed4df8f-334a-e32d-e378-2ebdd80038e7@gmail.com>
References: <1463390894-32062-1-git-send-email-jamesjj.liao@mediatek.com>
 <1463390894-32062-5-git-send-email-jamesjj.liao@mediatek.com>
 <0ed4df8f-334a-e32d-e378-2ebdd80038e7@gmail.com>
Message-ID: <1467782222.26485.7.camel@mtksdaap41>

On Sat, 2016-07-02 at 18:41 +0200, Matthias Brugger wrote:
> 
> On 05/16/2016 11:28 AM, James Liao wrote:
> > From: Shunli Wang <shunli.wang at mediatek.com>
> >
> > Add scpsys driver for MT2701.
> >
> > mtk-scpsys now supports MT8173 (arm64) and MT2701 (arm). So it should
> > be enabled on both arm64 and arm platforms.
> >
> > Signed-off-by: Shunli Wang <shunli.wang at mediatek.com>
> > Signed-off-by: James Liao <jamesjj.liao at mediatek.com>
> > Reviewed-by: Kevin Hilman <khilman at baylibre.com>
> > ---
> >  drivers/soc/mediatek/Kconfig      |   2 +-
> >  drivers/soc/mediatek/mtk-scpsys.c | 117 +++++++++++++++++++++++++++++++++++++-
> >  2 files changed, 116 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
> > index 0a4ea80..609bb34 100644
> > --- a/drivers/soc/mediatek/Kconfig
> > +++ b/drivers/soc/mediatek/Kconfig
> > @@ -23,7 +23,7 @@ config MTK_PMIC_WRAP
> >  config MTK_SCPSYS
> >  	bool "MediaTek SCPSYS Support"
> >  	depends on ARCH_MEDIATEK || COMPILE_TEST
> > -	default ARM64 && ARCH_MEDIATEK
> > +	default ARCH_MEDIATEK
> >  	select REGMAP
> >  	select MTK_INFRACFG
> >  	select PM_GENERIC_DOMAINS if PM
> > diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
> > index 00c0adb..f4d1230 100644
> > --- a/drivers/soc/mediatek/mtk-scpsys.c
> > +++ b/drivers/soc/mediatek/mtk-scpsys.c
> > @@ -20,6 +20,7 @@
> >  #include <linux/regulator/consumer.h>
> >  #include <linux/soc/mediatek/infracfg.h>
> >
> > +#include <dt-bindings/power/mt2701-power.h>
> >  #include <dt-bindings/power/mt8173-power.h>
> >
> >  #define SPM_VDE_PWR_CON			0x0210
> > @@ -27,8 +28,13 @@
> >  #define SPM_VEN_PWR_CON			0x0230
> >  #define SPM_ISP_PWR_CON			0x0238
> >  #define SPM_DIS_PWR_CON			0x023c
> > +#define SPM_CONN_PWR_CON		0x0280
> >  #define SPM_VEN2_PWR_CON		0x0298
> > -#define SPM_AUDIO_PWR_CON		0x029c
> > +#define SPM_AUDIO_PWR_CON		0x029c	/* MT8173 */
> > +#define SPM_BDP_PWR_CON			0x029c	/* MT2701 */
> > +#define SPM_ETH_PWR_CON			0x02a0
> > +#define SPM_HIF_PWR_CON			0x02a4
> > +#define SPM_IFR_MSC_PWR_CON		0x02a8
> >  #define SPM_MFG_2D_PWR_CON		0x02c0
> >  #define SPM_MFG_ASYNC_PWR_CON		0x02c4
> >  #define SPM_USB_PWR_CON			0x02cc
> > @@ -42,10 +48,15 @@
> >  #define PWR_ON_2ND_BIT			BIT(3)
> >  #define PWR_CLK_DIS_BIT			BIT(4)
> >
> > +#define PWR_STATUS_CONN			BIT(1)
> >  #define PWR_STATUS_DISP			BIT(3)
> >  #define PWR_STATUS_MFG			BIT(4)
> >  #define PWR_STATUS_ISP			BIT(5)
> >  #define PWR_STATUS_VDEC			BIT(7)
> > +#define PWR_STATUS_BDP			BIT(14)
> > +#define PWR_STATUS_ETH			BIT(15)
> > +#define PWR_STATUS_HIF			BIT(16)
> > +#define PWR_STATUS_IFR_MSC		BIT(17)
> >  #define PWR_STATUS_VENC_LT		BIT(20)
> >  #define PWR_STATUS_VENC			BIT(21)
> >  #define PWR_STATUS_MFG_2D		BIT(22)
> > @@ -59,6 +70,7 @@ enum clk_id {
> >  	CLK_MFG,
> >  	CLK_VENC,
> >  	CLK_VENC_LT,
> > +	CLK_ETHIF,
> >  	CLK_MAX,
> >  };
> >
> > @@ -321,7 +333,8 @@ static void init_clks(struct platform_device *pdev, struct clk *clk[CLK_MAX])
> >  		CLK_MM,
> >  		CLK_MFG,
> >  		CLK_VENC,
> > -		CLK_VENC_LT
> > +		CLK_VENC_LT,
> > +		CLK_ETHIF
> >  	};
> >
> >  	static const char * const clk_names[] = {
> > @@ -329,6 +342,7 @@ static void init_clks(struct platform_device *pdev, struct clk *clk[CLK_MAX])
> >  		"mfg",
> >  		"venc",
> >  		"venc_lt",
> > +		"ethif",
> >  	};
> >
> >  	int i;
> > @@ -459,6 +473,102 @@ static void mtk_register_power_domains(struct platform_device *pdev,
> >  }
> >
> >  /*
> > + * MT2701 power domain support
> > + */
> > +
> > +static const struct scp_domain_data scp_domain_data_mt2701[] = {
> > +	[MT2701_POWER_DOMAIN_CONN] = {
> > +		.name = "conn",
> > +		.sta_mask = PWR_STATUS_CONN,
> > +		.ctl_offs = SPM_CONN_PWR_CON,
> > +		.bus_prot_mask = 0x0104,
> > +		.active_wakeup = true,
> 
> .clk_id = {CLK_NONE},
> 
> > +	},
> > +	[MT2701_POWER_DOMAIN_DISP] = {
> > +		.name = "disp",
> > +		.sta_mask = PWR_STATUS_DISP,
> > +		.ctl_offs = SPM_DIS_PWR_CON,
> > +		.sram_pdn_bits = GENMASK(11, 8),
> > +		.clk_id = {CLK_MM},
> > +		.bus_prot_mask = 0x0002,
> > +		.active_wakeup = true,
> > +	},
> > +	[MT2701_POWER_DOMAIN_MFG] = {
> > +		.name = "mfg",
> > +		.sta_mask = PWR_STATUS_MFG,
> > +		.ctl_offs = SPM_MFG_PWR_CON,
> > +		.sram_pdn_bits = GENMASK(11, 8),
> > +		.sram_pdn_ack_bits = GENMASK(12, 12),
> > +		.clk_id = {CLK_MFG},
> > +		.active_wakeup = true,
> > +	},
> > +	[MT2701_POWER_DOMAIN_VDEC] = {
> > +		.name = "vdec",
> > +		.sta_mask = PWR_STATUS_VDEC,
> > +		.ctl_offs = SPM_VDE_PWR_CON,
> > +		.sram_pdn_bits = GENMASK(11, 8),
> > +		.sram_pdn_ack_bits = GENMASK(12, 12),
> > +		.clk_id = {CLK_MM},
> > +		.active_wakeup = true,
> > +	},
> > +	[MT2701_POWER_DOMAIN_ISP] = {
> > +		.name = "isp",
> > +		.sta_mask = PWR_STATUS_ISP,
> > +		.ctl_offs = SPM_ISP_PWR_CON,
> > +		.sram_pdn_bits = GENMASK(11, 8),
> > +		.sram_pdn_ack_bits = GENMASK(13, 12),
> > +		.clk_id = {CLK_MM},
> > +		.active_wakeup = true,
> > +	},
> > +	[MT2701_POWER_DOMAIN_BDP] = {
> > +		.name = "bdp",
> > +		.sta_mask = PWR_STATUS_BDP,
> > +		.ctl_offs = SPM_BDP_PWR_CON,
> > +		.sram_pdn_bits = GENMASK(11, 8),
> > +		.active_wakeup = true,
> 
> same here.
> 
> > +	},
> > +	[MT2701_POWER_DOMAIN_ETH] = {
> > +		.name = "eth",
> > +		.sta_mask = PWR_STATUS_ETH,
> > +		.ctl_offs = SPM_ETH_PWR_CON,
> > +		.sram_pdn_bits = GENMASK(11, 8),
> > +		.sram_pdn_ack_bits = GENMASK(15, 12),
> > +		.clk_id = {CLK_ETHIF},
> > +		.active_wakeup = true,
> > +	},
> > +	[MT2701_POWER_DOMAIN_HIF] = {
> > +		.name = "hif",
> > +		.sta_mask = PWR_STATUS_HIF,
> > +		.ctl_offs = SPM_HIF_PWR_CON,
> > +		.sram_pdn_bits = GENMASK(11, 8),
> > +		.sram_pdn_ack_bits = GENMASK(15, 12),
> > +		.clk_id = {CLK_ETHIF},
> > +		.active_wakeup = true,
> > +	},
> > +	[MT2701_POWER_DOMAIN_IFR_MSC] = {
> > +		.name = "ifr_msc",
> > +		.sta_mask = PWR_STATUS_IFR_MSC,
> > +		.ctl_offs = SPM_IFR_MSC_PWR_CON,
> > +		.active_wakeup = true,
> 
> same here.

Hi Matthias,

I'll add them in next patch.


Best regards,

James

> > +	},
> > +};
> > +
> > +#define NUM_DOMAINS_MT2701	ARRAY_SIZE(scp_domain_data_mt2701)
> > +
> > +static int __init scpsys_probe_mt2701(struct platform_device *pdev)
> > +{
> > +	struct scp *scp;
> > +
> > +	scp = init_scp(pdev, scp_domain_data_mt2701, NUM_DOMAINS_MT2701);
> > +	if (IS_ERR(scp))
> > +		return PTR_ERR(scp);
> > +
> > +	mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT2701);
> > +
> > +	return 0;
> > +}
> > +
> > +/*
> >   * MT8173 power domain support
> >   */
> >
> > @@ -587,6 +697,9 @@ static int __init scpsys_probe_mt8173(struct platform_device *pdev)
> >
> >  static const struct of_device_id of_scpsys_match_tbl[] = {
> >  	{
> > +		.compatible = "mediatek,mt2701-scpsys",
> > +		.data = scpsys_probe_mt2701,
> > +	}, {
> >  		.compatible = "mediatek,mt8173-scpsys",
> >  		.data = scpsys_probe_mt8173,
> >  	}, {
> >




From jamesjj.liao at mediatek.com  Tue Jul  5 22:22:20 2016
From: jamesjj.liao at mediatek.com (James Liao)
Date: Wed, 6 Jul 2016 13:22:20 +0800
Subject: [PATCH v7 2/4] soc: mediatek: Init MT8173 scpsys driver earlier
In-Reply-To: <34025ec4-19d3-8b25-d669-50c6f19159cd@gmail.com>
References: <1463390894-32062-1-git-send-email-jamesjj.liao@mediatek.com>
 <1463390894-32062-3-git-send-email-jamesjj.liao@mediatek.com>
 <34025ec4-19d3-8b25-d669-50c6f19159cd@gmail.com>
Message-ID: <1467782540.26485.11.camel@mtksdaap41>

On Sat, 2016-07-02 at 18:35 +0200, Matthias Brugger wrote:
> 
> On 05/16/2016 11:28 AM, James Liao wrote:
> > Some power domain comsumers may init before module_init.
> > So the power domain provider (scpsys) need to be initialized
> > earlier too.
> >
> > Take an example for our IOMMU (M4U) and SMI. SMI is a bridge
> > between IOMMU and multimedia HW. SMI is responsible to
> > enable/disable iommu and help transfer data for each multimedia
> > HW. Both of them have to wait until the power and clocks are
> > enabled.
> >
> > So scpsys driver should be initialized before SMI, and SMI should
> > be initialized before IOMMU, and then init IOMMU consumers
> > (display/vdec/venc/camera etc.).
> >
> > IOMMU is subsys_init by default. So we need to init scpsys driver
> > before subsys_init.
> >
> > Signed-off-by: James Liao <jamesjj.liao at mediatek.com>
> > Reviewed-by: Kevin Hilman <khilman at baylibre.com>
> > ---
> >  drivers/soc/mediatek/mtk-scpsys.c | 19 ++++++++++++++++++-
> >  1 file changed, 18 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
> > index 5870a24..00c0adb 100644
> > --- a/drivers/soc/mediatek/mtk-scpsys.c
> > +++ b/drivers/soc/mediatek/mtk-scpsys.c
> > @@ -617,4 +617,21 @@ static struct platform_driver scpsys_drv = {
> >  		.of_match_table = of_match_ptr(of_scpsys_match_tbl),
> >  	},
> >  };
> > -builtin_platform_driver(scpsys_drv);
> > +
> > +static int __init scpsys_drv_init(void)
> > +{
> > +	return platform_driver_register(&scpsys_drv);
> > +}
> > +
> > +/*
> > + * There are some Mediatek drivers which depend on the power domain driver need
> > + * to probe in earlier initcall levels. So scpsys driver also need to probe
> > + * earlier.
> > + *
> > + * IOMMU(M4U) and SMI drivers for example. SMI is a bridge between IOMMU and
> > + * multimedia HW. IOMMU depends on SMI, and SMI is a power domain consumer,
> > + * so the proper probe sequence should be scpsys -> SMI -> IOMMU driver.
> > + * IOMMU drivers are initialized during subsys_init by default, so we need to
> > + * move SMI and scpsys drivers to subsys_init or earlier init levels.
> > + */
> > +subsys_initcall(scpsys_drv_init);
> >
> 
> Can't we achieve this with probe deferring? I'm not really keen on 
> coding the order of the different drivers like this.

Hi Matthias,

Some drivers such as IOMMU don't support probe deferring. So scpsys need
to init before them by changing init level.


Best regards,

James




From jamesjj.liao at mediatek.com  Tue Jul  5 22:39:24 2016
From: jamesjj.liao at mediatek.com (James Liao)
Date: Wed, 6 Jul 2016 13:39:24 +0800
Subject: [PATCH v7 1/4] soc: mediatek: Refine scpsys to support multiple
 platform
In-Reply-To: <6762e420-0d68-0376-b584-bfc878b5e95f@gmail.com>
References: <1463390894-32062-1-git-send-email-jamesjj.liao@mediatek.com>
 <1463390894-32062-2-git-send-email-jamesjj.liao@mediatek.com>
 <6762e420-0d68-0376-b584-bfc878b5e95f@gmail.com>
Message-ID: <1467783564.26485.22.camel@mtksdaap41>

Hi Matthias,

On Sat, 2016-07-02 at 18:33 +0200, Matthias Brugger wrote:
> 
> On 05/16/2016 11:28 AM, James Liao wrote:
> > Refine scpsys driver common code to support multiple SoC / platform.
> >
> > Signed-off-by: James Liao <jamesjj.liao at mediatek.com>
> > Reviewed-by: Kevin Hilman <khilman at baylibre.com>
> > ---
> >  drivers/soc/mediatek/mtk-scpsys.c | 363 +++++++++++++++++++++++---------------
> >  1 file changed, 220 insertions(+), 143 deletions(-)
> >
> > diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
> > index 57e781c..5870a24 100644
> > --- a/drivers/soc/mediatek/mtk-scpsys.c
> > +++ b/drivers/soc/mediatek/mtk-scpsys.c
> > @@ -11,17 +11,15 @@
> >   * GNU General Public License for more details.
> >   */
> >  #include <linux/clk.h>
> > -#include <linux/delay.h>
> > +#include <linux/init.h>
> >  #include <linux/io.h>
> > -#include <linux/kernel.h>
> >  #include <linux/mfd/syscon.h>
> > -#include <linux/init.h>
> >  #include <linux/of_device.h>
> >  #include <linux/platform_device.h>
> >  #include <linux/pm_domain.h>
> > -#include <linux/regmap.h>
> > -#include <linux/soc/mediatek/infracfg.h>
> >  #include <linux/regulator/consumer.h>
> > +#include <linux/soc/mediatek/infracfg.h>
> > +
> >  #include <dt-bindings/power/mt8173-power.h>
> >
> >  #define SPM_VDE_PWR_CON			0x0210
> > @@ -34,6 +32,7 @@
> >  #define SPM_MFG_2D_PWR_CON		0x02c0
> >  #define SPM_MFG_ASYNC_PWR_CON		0x02c4
> >  #define SPM_USB_PWR_CON			0x02cc
> > +
> >  #define SPM_PWR_STATUS			0x060c
> >  #define SPM_PWR_STATUS_2ND		0x0610
> >
> > @@ -55,12 +54,12 @@
> >  #define PWR_STATUS_USB			BIT(25)
> >
> >  enum clk_id {
> > -	MT8173_CLK_NONE,
> > -	MT8173_CLK_MM,
> > -	MT8173_CLK_MFG,
> > -	MT8173_CLK_VENC,
> > -	MT8173_CLK_VENC_LT,
> > -	MT8173_CLK_MAX,
> > +	CLK_NONE,
> > +	CLK_MM,
> > +	CLK_MFG,
> > +	CLK_VENC,
> > +	CLK_VENC_LT,
> > +	CLK_MAX,
> >  };
> >
> >  #define MAX_CLKS	2
> > @@ -76,98 +75,6 @@ struct scp_domain_data {
> >  	bool active_wakeup;
> >  };
> >
> > -static const struct scp_domain_data scp_domain_data[] = {
> > -	[MT8173_POWER_DOMAIN_VDEC] = {
> > -		.name = "vdec",
> > -		.sta_mask = PWR_STATUS_VDEC,
> > -		.ctl_offs = SPM_VDE_PWR_CON,
> > -		.sram_pdn_bits = GENMASK(11, 8),
> > -		.sram_pdn_ack_bits = GENMASK(12, 12),
> > -		.clk_id = {MT8173_CLK_MM},
> > -	},
> > -	[MT8173_POWER_DOMAIN_VENC] = {
> > -		.name = "venc",
> > -		.sta_mask = PWR_STATUS_VENC,
> > -		.ctl_offs = SPM_VEN_PWR_CON,
> > -		.sram_pdn_bits = GENMASK(11, 8),
> > -		.sram_pdn_ack_bits = GENMASK(15, 12),
> > -		.clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC},
> > -	},
> > -	[MT8173_POWER_DOMAIN_ISP] = {
> > -		.name = "isp",
> > -		.sta_mask = PWR_STATUS_ISP,
> > -		.ctl_offs = SPM_ISP_PWR_CON,
> > -		.sram_pdn_bits = GENMASK(11, 8),
> > -		.sram_pdn_ack_bits = GENMASK(13, 12),
> > -		.clk_id = {MT8173_CLK_MM},
> > -	},
> > -	[MT8173_POWER_DOMAIN_MM] = {
> > -		.name = "mm",
> > -		.sta_mask = PWR_STATUS_DISP,
> > -		.ctl_offs = SPM_DIS_PWR_CON,
> > -		.sram_pdn_bits = GENMASK(11, 8),
> > -		.sram_pdn_ack_bits = GENMASK(12, 12),
> > -		.clk_id = {MT8173_CLK_MM},
> > -		.bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
> > -			MT8173_TOP_AXI_PROT_EN_MM_M1,
> > -	},
> > -	[MT8173_POWER_DOMAIN_VENC_LT] = {
> > -		.name = "venc_lt",
> > -		.sta_mask = PWR_STATUS_VENC_LT,
> > -		.ctl_offs = SPM_VEN2_PWR_CON,
> > -		.sram_pdn_bits = GENMASK(11, 8),
> > -		.sram_pdn_ack_bits = GENMASK(15, 12),
> > -		.clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC_LT},
> > -	},
> > -	[MT8173_POWER_DOMAIN_AUDIO] = {
> > -		.name = "audio",
> > -		.sta_mask = PWR_STATUS_AUDIO,
> > -		.ctl_offs = SPM_AUDIO_PWR_CON,
> > -		.sram_pdn_bits = GENMASK(11, 8),
> > -		.sram_pdn_ack_bits = GENMASK(15, 12),
> > -		.clk_id = {MT8173_CLK_NONE},
> > -	},
> > -	[MT8173_POWER_DOMAIN_USB] = {
> > -		.name = "usb",
> > -		.sta_mask = PWR_STATUS_USB,
> > -		.ctl_offs = SPM_USB_PWR_CON,
> > -		.sram_pdn_bits = GENMASK(11, 8),
> > -		.sram_pdn_ack_bits = GENMASK(15, 12),
> > -		.clk_id = {MT8173_CLK_NONE},
> > -		.active_wakeup = true,
> > -	},
> > -	[MT8173_POWER_DOMAIN_MFG_ASYNC] = {
> > -		.name = "mfg_async",
> > -		.sta_mask = PWR_STATUS_MFG_ASYNC,
> > -		.ctl_offs = SPM_MFG_ASYNC_PWR_CON,
> > -		.sram_pdn_bits = GENMASK(11, 8),
> > -		.sram_pdn_ack_bits = 0,
> > -		.clk_id = {MT8173_CLK_MFG},
> > -	},
> > -	[MT8173_POWER_DOMAIN_MFG_2D] = {
> > -		.name = "mfg_2d",
> > -		.sta_mask = PWR_STATUS_MFG_2D,
> > -		.ctl_offs = SPM_MFG_2D_PWR_CON,
> > -		.sram_pdn_bits = GENMASK(11, 8),
> > -		.sram_pdn_ack_bits = GENMASK(13, 12),
> > -		.clk_id = {MT8173_CLK_NONE},
> > -	},
> > -	[MT8173_POWER_DOMAIN_MFG] = {
> > -		.name = "mfg",
> > -		.sta_mask = PWR_STATUS_MFG,
> > -		.ctl_offs = SPM_MFG_PWR_CON,
> > -		.sram_pdn_bits = GENMASK(13, 8),
> > -		.sram_pdn_ack_bits = GENMASK(21, 16),
> > -		.clk_id = {MT8173_CLK_NONE},
> > -		.bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
> > -			MT8173_TOP_AXI_PROT_EN_MFG_M0 |
> > -			MT8173_TOP_AXI_PROT_EN_MFG_M1 |
> > -			MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT,
> > -	},
> > -};
> > -
> > -#define NUM_DOMAINS	ARRAY_SIZE(scp_domain_data)
> > -
> >  struct scp;
> >
> >  struct scp_domain {
> > @@ -179,7 +86,7 @@ struct scp_domain {
> >  };
> >
> >  struct scp {
> > -	struct scp_domain domains[NUM_DOMAINS];
> > +	struct scp_domain *domains;
> >  	struct genpd_onecell_data pd_data;
> >  	struct device *dev;
> >  	void __iomem *base;
> > @@ -408,57 +315,69 @@ static bool scpsys_active_wakeup(struct device *dev)
> >  	return scpd->data->active_wakeup;
> >  }
> >
> > -static int scpsys_probe(struct platform_device *pdev)
> > +static void init_clks(struct platform_device *pdev, struct clk *clk[CLK_MAX])
> > +{
> > +	enum clk_id clk_ids[] = {
> > +		CLK_MM,
> > +		CLK_MFG,
> > +		CLK_VENC,
> > +		CLK_VENC_LT
> > +	};
> > +
> > +	static const char * const clk_names[] = {
> > +		"mm",
> > +		"mfg",
> > +		"venc",
> > +		"venc_lt",
> > +	};
> > +
> > +	int i;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(clk_ids); i++)
> > +		clk[clk_ids[i]] = devm_clk_get(&pdev->dev, clk_names[i]);
> 
> We can use the global enum clk_id and stat with i = 1, right?

You are right. I'll change the start value with i = CLK_NONE + 1 in next
patch.

> > +}
> > +
> > +static struct scp *init_scp(struct platform_device *pdev,
> > +			const struct scp_domain_data *scp_domain_data, int num)
> >  {
> >  	struct genpd_onecell_data *pd_data;
> >  	struct resource *res;
> > -	int i, j, ret;
> > +	int i, j;
> >  	struct scp *scp;
> > -	struct clk *clk[MT8173_CLK_MAX];
> > +	struct clk *clk[CLK_MAX];
> >
> >  	scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL);
> >  	if (!scp)
> > -		return -ENOMEM;
> > +		return ERR_PTR(-ENOMEM);
> >
> >  	scp->dev = &pdev->dev;
> >
> >  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >  	scp->base = devm_ioremap_resource(&pdev->dev, res);
> >  	if (IS_ERR(scp->base))
> > -		return PTR_ERR(scp->base);
> > -
> > -	pd_data = &scp->pd_data;
> > -
> > -	pd_data->domains = devm_kzalloc(&pdev->dev,
> > -			sizeof(*pd_data->domains) * NUM_DOMAINS, GFP_KERNEL);
> > -	if (!pd_data->domains)
> > -		return -ENOMEM;
> > -
> > -	clk[MT8173_CLK_MM] = devm_clk_get(&pdev->dev, "mm");
> > -	if (IS_ERR(clk[MT8173_CLK_MM]))
> > -		return PTR_ERR(clk[MT8173_CLK_MM]);
> > -
> > -	clk[MT8173_CLK_MFG] = devm_clk_get(&pdev->dev, "mfg");
> > -	if (IS_ERR(clk[MT8173_CLK_MFG]))
> > -		return PTR_ERR(clk[MT8173_CLK_MFG]);
> > -
> > -	clk[MT8173_CLK_VENC] = devm_clk_get(&pdev->dev, "venc");
> > -	if (IS_ERR(clk[MT8173_CLK_VENC]))
> > -		return PTR_ERR(clk[MT8173_CLK_VENC]);
> > -
> > -	clk[MT8173_CLK_VENC_LT] = devm_clk_get(&pdev->dev, "venc_lt");
> > -	if (IS_ERR(clk[MT8173_CLK_VENC_LT]))
> > -		return PTR_ERR(clk[MT8173_CLK_VENC_LT]);
> > +		return ERR_CAST(scp->base);
> >
> >  	scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
> >  			"infracfg");
> >  	if (IS_ERR(scp->infracfg)) {
> >  		dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n",
> >  				PTR_ERR(scp->infracfg));
> > -		return PTR_ERR(scp->infracfg);
> > +		return ERR_CAST(scp->infracfg);
> >  	}
> >
> > -	for (i = 0; i < NUM_DOMAINS; i++) {
> > +	scp->domains = devm_kzalloc(&pdev->dev,
> > +				sizeof(*scp->domains) * num, GFP_KERNEL);
> > +	if (!scp->domains)
> > +		return ERR_PTR(-ENOMEM);
> > +
> > +	pd_data = &scp->pd_data;
> > +
> > +	pd_data->domains = devm_kzalloc(&pdev->dev,
> > +			sizeof(*pd_data->domains) * num, GFP_KERNEL);
> > +	if (!pd_data->domains)
> > +		return ERR_PTR(-ENOMEM);
> > +
> > +	for (i = 0; i < num; i++) {
> >  		struct scp_domain *scpd = &scp->domains[i];
> >  		const struct scp_domain_data *data = &scp_domain_data[i];
> >
> > @@ -467,28 +386,54 @@ static int scpsys_probe(struct platform_device *pdev)
> >  			if (PTR_ERR(scpd->supply) == -ENODEV)
> >  				scpd->supply = NULL;
> >  			else
> > -				return PTR_ERR(scpd->supply);
> > +				return ERR_CAST(scpd->supply);
> >  		}
> >  	}
> >
> > -	pd_data->num_domains = NUM_DOMAINS;
> > +	pd_data->num_domains = num;
> >
> > -	for (i = 0; i < NUM_DOMAINS; i++) {
> > +	init_clks(pdev, clk);
> > +
> > +	for (i = 0; i < num; i++) {
> >  		struct scp_domain *scpd = &scp->domains[i];
> >  		struct generic_pm_domain *genpd = &scpd->genpd;
> >  		const struct scp_domain_data *data = &scp_domain_data[i];
> >
> > +		for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
> > +			struct clk *c = clk[data->clk_id[j]];
> > +
> > +			if (IS_ERR(c)) {
> > +				dev_err(&pdev->dev, "%s: clk unavailable\n",
> > +					data->name);
> > +				return ERR_CAST(c);
> > +			}
> > +
> > +			scpd->clk[j] = c;
> 
> Put this in the else branch. Apart from that is there any reason you 

Do you mean to change like this?

	if (IS_ERR(c)) {
		...
		return ERR_CAST(c);
	} else {
		scpd->clk[j] = c;
	}

checkpatch.pl will warn for above code due to it returns in 'if' branch.

> moved the for up in the function? If not, I would prefer not to move it, 
> to make it easier to read the diff.

The new 'for' block are far different from original one. And I think
it's easy to read if we keep simple assign statements in the same block.

> Apart from that, the patch looks good to me.
> Sorry for the delay in responding.

Thanks for your comments.


Best regards,

James



From hverkuil at xs4all.nl  Wed Jul  6 06:19:50 2016
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Wed, 6 Jul 2016 15:19:50 +0200
Subject: [PATCH v3 0/9] Add MT8173 Video Decoder Driver
In-Reply-To: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
References: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
Message-ID: <577D0576.2050706@xs4all.nl>

Hi Tiffany,

I plan to review this patch series on Friday, but one obvious question is
what the reason for these failures is:

> 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_QUERYCTRL/MENU: OK
>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-controls.cpp(357): g_ctrl returned an error (11)
>                 test VIDIOC_G/S_CTRL: FAIL
>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-controls.cpp(579): g_ext_ctrls returned an error (11)
>                 test VIDIOC_G/S/TRY_EXT_CTRLS: FAIL
>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-controls.cpp(721): subscribe event for control 'User Controls' failed
>                 test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: FAIL
>                 test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
>                 Standard Controls: 2 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)
>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-formats.cpp(405): expected EINVAL, but got 11 when getting format for buftype 9
>                 test VIDIOC_G_FMT: FAIL
>                 test VIDIOC_TRY_FMT: OK (Not Supported)
>                 test VIDIOC_S_FMT: OK (Not Supported)
>                 test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
> 
>         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
>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-buffers.cpp(500): q.has_expbuf(node)
>                 test VIDIOC_EXPBUF: FAIL
> 
> 
> Total: 38, Succeeded: 33, Failed: 5, Warnings: 0

If it is due to a bug in v4l2-compliance, then let me know and I'll fix it. If not,
then it should be fixed in the driver.

Frankly, it was the presence of these failures that made me think this patch series
wasn't final. Before a v4l2 driver can be accepted in the kernel, v4l2-compliance must pass.

Regards,

	Hans


From weiyj_lk at 163.com  Wed Jul  6 06:30:13 2016
From: weiyj_lk at 163.com (weiyj_lk at 163.com)
Date: Wed,  6 Jul 2016 13:30:13 +0000
Subject: [PATCH -next] net: mediatek: remove .owner field for driver
Message-ID: <1467811813-4864-1-git-send-email-weiyj_lk@163.com>

From: Wei Yongjun <yongjun_wei at trendmicro.com.cn>

Remove .owner field since calls to module_platform_driver() will
set it automatically.

Signed-off-by: Wei Yongjun <yongjun_wei at trendmicro.com.cn>
---
 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 682797e..760f3d7 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -1910,7 +1910,6 @@ static struct platform_driver mtk_driver = {
 	.remove = mtk_remove,
 	.driver = {
 		.name = "mtk_soc_eth",
-		.owner = THIS_MODULE,
 		.of_match_table = of_mtk_match,
 	},
 };




From ulf.hansson at linaro.org  Wed Jul  6 09:21:35 2016
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Wed, 6 Jul 2016 18:21:35 +0200
Subject: fix some host driver defect
In-Reply-To: <1467252061-3791-1-git-send-email-chaotian.jing@mediatek.com>
References: <1467252061-3791-1-git-send-email-chaotian.jing@mediatek.com>
Message-ID: <CAPDyKFoZVoZpKh90hG-QoSdwWSgAdV0b6oup-w-dOQ8atRZ+2w@mail.gmail.com>

On 30 June 2016 at 04:00, Chaotian Jing <chaotian.jing at mediatek.com> wrote:
>
> Chaotian Jing (4):
>   mmc: mediatek: do not tune data for HS400 mode
>   mmc: mediatek: fix CRC error when calling mmc_select_hs400()
>   mmc: mediatek: fix CMD21/CMD19 timeout issue
>   mmc: mediatek: perfer to use rise edge latching
>
>  drivers/mmc/host/mtk-sd.c | 70 +++++++++++++++++++++++++++++++++++++----------
>  1 file changed, 56 insertions(+), 14 deletions(-)
>
> --
> 1.8.1.1.dirty
>

Thanks, applied for next!

Kind regards
Uffe


From davem at davemloft.net  Wed Jul  6 22:31:52 2016
From: davem at davemloft.net (David Miller)
Date: Wed, 06 Jul 2016 22:31:52 -0700 (PDT)
Subject: [PATCH -next] net: mediatek: remove .owner field for driver
In-Reply-To: <1467811813-4864-1-git-send-email-weiyj_lk@163.com>
References: <1467811813-4864-1-git-send-email-weiyj_lk@163.com>
Message-ID: <20160706.223152.980979934196013750.davem@davemloft.net>

From: weiyj_lk at 163.com
Date: Wed,  6 Jul 2016 13:30:13 +0000

> From: Wei Yongjun <yongjun_wei at trendmicro.com.cn>
> 
> Remove .owner field since calls to module_platform_driver() will
> set it automatically.
> 
> Signed-off-by: Wei Yongjun <yongjun_wei at trendmicro.com.cn>

Applied.


From bibby.hsieh at mediatek.com  Thu Jul  7 00:37:07 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Thu, 7 Jul 2016 15:37:07 +0800
Subject: [PATCH v3 0/2] drm/mediatek: MT8173 gamma & dither support 
Message-ID: <1467877029-45236-1-git-send-email-bibby.hsieh@mediatek.com>

This is MT8173 gamma & dither support PATCH v3, based on 4.7-rc1.

Changes since v2:
 -Modify defines to match the register field names in the MT8173 datasheet
 -Made dithering function support hardware mirroring well on two  monitor.

Bibby Hsieh (2):
  drm/mediatek: Add gamma correction
  drm/mediatek: set mt8173 dithering function

 drivers/gpu/drm/mediatek/mtk_disp_ovl.c     |    3 +-
 drivers/gpu/drm/mediatek/mtk_disp_rdma.c    |    3 +-
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c     |   29 ++++-
 drivers/gpu/drm/mediatek/mtk_drm_crtc.h     |    1 +
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |  154 +++++++++++++++++++++++++--
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |   16 ++-
 6 files changed, 192 insertions(+), 14 deletions(-)

-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Thu Jul  7 00:37:08 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Thu, 7 Jul 2016 15:37:08 +0800
Subject: [PATCH v3 1/2] drm/mediatek: Add gamma correction
In-Reply-To: <1467877029-45236-1-git-send-email-bibby.hsieh@mediatek.com>
References: <1467877029-45236-1-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1467877029-45236-2-git-send-email-bibby.hsieh@mediatek.com>

Apply gamma function to correct brightness values.
It applies arbitrary mapping curve to compensate the
incorrect transfer function of the panel.

Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c     |    8 +++
 drivers/gpu/drm/mediatek/mtk_drm_crtc.h     |    1 +
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |   89 ++++++++++++++++++++++++++-
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |   10 +++
 4 files changed, 106 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index 24aa3ba..ee219bb 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -409,6 +409,10 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
 	}
 	if (pending_planes)
 		mtk_crtc->pending_planes = true;
+	if (crtc->state->color_mgmt_changed)
+		for (i = 0; i < mtk_crtc->ddp_comp_nr; i++)
+			mtk_ddp_gamma_set(mtk_crtc->ddp_comp[i], crtc->state);
+
 }
 
 static const struct drm_crtc_funcs mtk_crtc_funcs = {
@@ -418,6 +422,7 @@ static const struct drm_crtc_funcs mtk_crtc_funcs = {
 	.reset			= mtk_drm_crtc_reset,
 	.atomic_duplicate_state	= mtk_drm_crtc_duplicate_state,
 	.atomic_destroy_state	= mtk_drm_crtc_destroy_state,
+	.gamma_set		= drm_atomic_helper_legacy_gamma_set,
 };
 
 static const struct drm_crtc_helper_funcs mtk_crtc_helper_funcs = {
@@ -569,6 +574,9 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
 	if (ret < 0)
 		goto unprepare;
 
+	drm_mode_crtc_set_gamma_size(&mtk_crtc->base, MTK_LUT_SIZE);
+	drm_helper_crtc_enable_color_mgmt(&mtk_crtc->base, MTK_LUT_SIZE,
+					  MTK_LUT_SIZE);
 	priv->crtc[pipe] = &mtk_crtc->base;
 	priv->num_pipes++;
 
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.h b/drivers/gpu/drm/mediatek/mtk_drm_crtc.h
index 81e5566..d332564 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.h
@@ -19,6 +19,7 @@
 #include "mtk_drm_plane.h"
 
 #define OVL_LAYER_NR	4
+#define MTK_LUT_SIZE	512
 
 int mtk_drm_crtc_enable_vblank(struct drm_device *drm, unsigned int pipe);
 void mtk_drm_crtc_disable_vblank(struct drm_device *drm, unsigned int pipe);
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
index 3970fcf..56c5894 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
@@ -24,6 +24,7 @@
 #include "mtk_drm_drv.h"
 #include "mtk_drm_plane.h"
 #include "mtk_drm_ddp_comp.h"
+#include "mtk_drm_crtc.h"
 
 #define DISP_OD_EN				0x0000
 #define DISP_OD_INTEN				0x0008
@@ -38,6 +39,21 @@
 #define DISP_COLOR_WIDTH			0x0c50
 #define DISP_COLOR_HEIGHT			0x0c54
 
+#define DISP_AAL_EN				0x000
+#define DISP_AAL_SIZE				0x030
+
+#define DISP_GAMMA_EN				0x000
+#define DISP_GAMMA_CFG				0x020
+#define DISP_GAMMA_SIZE				0x030
+#define DISP_GAMMA_LUT				0x700
+
+#define LUT_10BIT_MASK				0x3ff
+
+#define AAL_EN			BIT(0)
+
+#define GAMMA_EN		BIT(0)
+#define GAMMA_LUT_EN		BIT(1)
+
 #define	OD_RELAY_MODE		BIT(0)
 
 #define	UFO_BYPASS		BIT(2)
@@ -76,6 +92,61 @@ static void mtk_ufoe_start(struct mtk_ddp_comp *comp)
 	writel(UFO_BYPASS, comp->regs + DISP_REG_UFO_START);
 }
 
+static void mtk_aal_config(struct mtk_ddp_comp *comp, unsigned int w,
+			   unsigned int h, unsigned int vrefresh)
+{
+	writel(h << 16 | w, comp->regs + DISP_AAL_SIZE);
+}
+
+static void mtk_aal_start(struct mtk_ddp_comp *comp)
+{
+	writel(AAL_EN, comp->regs  + DISP_AAL_EN);
+}
+
+static void mtk_aal_stop(struct mtk_ddp_comp *comp)
+{
+	writel_relaxed(0x0, comp->regs  + DISP_AAL_EN);
+}
+
+static void mtk_gamma_config(struct mtk_ddp_comp *comp, unsigned int w,
+			     unsigned int h, unsigned int vrefresh)
+{
+	writel(h << 16 | w, comp->regs + DISP_GAMMA_SIZE);
+}
+
+static void mtk_gamma_start(struct mtk_ddp_comp *comp)
+{
+	writel(GAMMA_EN, comp->regs  + DISP_GAMMA_EN);
+}
+
+static void mtk_gamma_stop(struct mtk_ddp_comp *comp)
+{
+	writel_relaxed(0x0, comp->regs  + DISP_GAMMA_EN);
+}
+
+static void mtk_gamma_set(struct mtk_ddp_comp *comp,
+			  struct drm_crtc_state *state)
+{
+	unsigned int i, reg;
+	struct drm_color_lut *lut;
+	void __iomem *lut_base;
+	u32 word;
+
+	if (state->gamma_lut) {
+		reg = readl(comp->regs + DISP_GAMMA_CFG);
+		reg = reg | GAMMA_LUT_EN;
+		writel(reg, comp->regs + DISP_GAMMA_CFG);
+		lut_base = comp->regs + DISP_GAMMA_LUT;
+		lut = (struct drm_color_lut *)state->gamma_lut->data;
+		for (i = 0; i < MTK_LUT_SIZE; i++) {
+			word = (((lut[i].red >> 6) & LUT_10BIT_MASK) << 20) +
+			      (((lut[i].green >> 6) & LUT_10BIT_MASK) << 10) +
+			      ((lut[i].blue >> 6) & LUT_10BIT_MASK);
+			writel(word, (lut_base + i * 4));
+		}
+	}
+}
+
 static const struct mtk_ddp_comp_funcs ddp_color = {
 	.config = mtk_color_config,
 	.start = mtk_color_start,
@@ -90,6 +161,20 @@ static const struct mtk_ddp_comp_funcs ddp_ufoe = {
 	.start = mtk_ufoe_start,
 };
 
+static const struct mtk_ddp_comp_funcs ddp_aal = {
+	.gamma_set = mtk_gamma_set,
+	.config = mtk_aal_config,
+	.start = mtk_aal_start,
+	.stop = mtk_aal_stop,
+};
+
+static const struct mtk_ddp_comp_funcs ddp_gamma = {
+	.gamma_set = mtk_gamma_set,
+	.config = mtk_gamma_config,
+	.start = mtk_gamma_start,
+	.stop = mtk_gamma_stop,
+};
+
 static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = {
 	[MTK_DISP_OVL] = "ovl",
 	[MTK_DISP_RDMA] = "rdma",
@@ -112,13 +197,13 @@ struct mtk_ddp_comp_match {
 };
 
 static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
-	[DDP_COMPONENT_AAL]	= { MTK_DISP_AAL,	0, NULL },
+	[DDP_COMPONENT_AAL]	= { MTK_DISP_AAL,	0, &ddp_aal },
 	[DDP_COMPONENT_COLOR0]	= { MTK_DISP_COLOR,	0, &ddp_color },
 	[DDP_COMPONENT_COLOR1]	= { MTK_DISP_COLOR,	1, &ddp_color },
 	[DDP_COMPONENT_DPI0]	= { MTK_DPI,		0, NULL },
 	[DDP_COMPONENT_DSI0]	= { MTK_DSI,		0, NULL },
 	[DDP_COMPONENT_DSI1]	= { MTK_DSI,		1, NULL },
-	[DDP_COMPONENT_GAMMA]	= { MTK_DISP_GAMMA,	0, NULL },
+	[DDP_COMPONENT_GAMMA]	= { MTK_DISP_GAMMA,	0, &ddp_gamma },
 	[DDP_COMPONENT_OD]	= { MTK_DISP_OD,	0, &ddp_od },
 	[DDP_COMPONENT_OVL0]	= { MTK_DISP_OVL,	0, NULL },
 	[DDP_COMPONENT_OVL1]	= { MTK_DISP_OVL,	1, NULL },
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
index 6b13ba9..07e17fe 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
@@ -20,6 +20,7 @@ struct device;
 struct device_node;
 struct drm_crtc;
 struct drm_device;
+struct drm_crtc_state;
 struct mtk_plane_state;
 
 enum mtk_ddp_comp_type {
@@ -73,6 +74,8 @@ struct mtk_ddp_comp_funcs {
 	void (*layer_off)(struct mtk_ddp_comp *comp, unsigned int idx);
 	void (*layer_config)(struct mtk_ddp_comp *comp, unsigned int idx,
 			     struct mtk_plane_state *state);
+	void (*gamma_set)(struct mtk_ddp_comp *comp,
+			  struct drm_crtc_state *state);
 };
 
 struct mtk_ddp_comp {
@@ -139,6 +142,13 @@ static inline void mtk_ddp_comp_layer_config(struct mtk_ddp_comp *comp,
 		comp->funcs->layer_config(comp, idx, state);
 }
 
+static inline void mtk_ddp_gamma_set(struct mtk_ddp_comp *comp,
+				     struct drm_crtc_state *state)
+{
+	if (comp->funcs && comp->funcs->gamma_set)
+		comp->funcs->gamma_set(comp, state);
+}
+
 int mtk_ddp_comp_get_id(struct device_node *node,
 			enum mtk_ddp_comp_type comp_type);
 int mtk_ddp_comp_init(struct device *dev, struct device_node *comp_node,
-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Thu Jul  7 00:37:09 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Thu, 7 Jul 2016 15:37:09 +0800
Subject: [PATCH v3 2/2] drm/mediatek: set mt8173 dithering function
In-Reply-To: <1467877029-45236-1-git-send-email-bibby.hsieh@mediatek.com>
References: <1467877029-45236-1-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1467877029-45236-3-git-send-email-bibby.hsieh@mediatek.com>

Some panels only accept bpc (bit per color) 6-bit.
But, the default bpc in mt8173 display data path is 8-bit.
If we didn't enable dithering function to convert bpc,
display cannot show the smooth grayscale image.

In mt8173, the dithering function in OD (OverDrive) and
GAMMA module, we have to config them with
connector->display_mode.bpc when CRTC initial.

1. Clear the default value at *_DITHER_5 and *_DITHER_7 register.
2. Calculate the LSB_ERR_SHIFT bits and ADD_LSHIFT bits two values.
i.e. Input bpc of OD is 10 bits, we assume the bpc of panel is 6-bit,
so, we need to set 4-bit to LSB_ERR_SHIFT and ADD_LSHIFT bits respectively.
3. Then, set the OD or GAMMA to dithering mode depends on path-1 or path-2.

Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c     |    3 +-
 drivers/gpu/drm/mediatek/mtk_disp_rdma.c    |    3 +-
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c     |   21 ++++++--
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |   77 +++++++++++++++++++++++----
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |    6 +--
 5 files changed, 92 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index 8f62671f..019b7ca 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -103,7 +103,8 @@ static void mtk_ovl_stop(struct mtk_ddp_comp *comp)
 }
 
 static void mtk_ovl_config(struct mtk_ddp_comp *comp, unsigned int w,
-			   unsigned int h, unsigned int vrefresh)
+			   unsigned int h, unsigned int vrefresh,
+			   unsigned int bpc)
 {
 	if (w != 0 && h != 0)
 		writel_relaxed(h << 16 | w, comp->regs + DISP_REG_OVL_ROI_SIZE);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
index 5fb80cb..0df05f9 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
@@ -106,7 +106,8 @@ static void mtk_rdma_stop(struct mtk_ddp_comp *comp)
 }
 
 static void mtk_rdma_config(struct mtk_ddp_comp *comp, unsigned int width,
-			    unsigned int height, unsigned int vrefresh)
+			    unsigned int height, unsigned int vrefresh,
+			    unsigned int bpc)
 {
 	unsigned int threshold;
 	unsigned int reg;
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index ee219bb..18c9d0d 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -222,7 +222,9 @@ static void mtk_crtc_ddp_clk_disable(struct mtk_drm_crtc *mtk_crtc)
 static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
 {
 	struct drm_crtc *crtc = &mtk_crtc->base;
-	unsigned int width, height, vrefresh;
+	struct drm_connector *connector;
+	struct drm_encoder *encoder;
+	unsigned int width, height, vrefresh, bpc = 0;
 	int ret;
 	int i;
 
@@ -234,6 +236,19 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
 	height = crtc->state->adjusted_mode.vdisplay;
 	vrefresh = crtc->state->adjusted_mode.vrefresh;
 
+	drm_for_each_encoder(encoder, crtc->dev) {
+		if (encoder->crtc != crtc)
+			continue;
+
+		drm_for_each_connector(connector, crtc->dev) {
+			if (connector->encoder != encoder)
+				continue;
+			if (connector->display_info.bpc >= 3 &&
+			    (bpc == 0 || bpc > connector->display_info.bpc))
+				bpc = connector->display_info.bpc;
+		}
+	}
+
 	ret = pm_runtime_get_sync(crtc->dev->dev);
 	if (ret < 0) {
 		DRM_ERROR("Failed to enable power domain: %d\n", ret);
@@ -266,7 +281,7 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
 	for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
 		struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[i];
 
-		mtk_ddp_comp_config(comp, width, height, vrefresh);
+		mtk_ddp_comp_config(comp, width, height, vrefresh, bpc);
 		mtk_ddp_comp_start(comp);
 	}
 
@@ -469,7 +484,7 @@ void mtk_crtc_ddp_irq(struct drm_crtc *crtc, struct mtk_ddp_comp *ovl)
 	if (state->pending_config) {
 		mtk_ddp_comp_config(ovl, state->pending_width,
 				    state->pending_height,
-				    state->pending_vrefresh);
+				    state->pending_vrefresh, 0);
 
 		state->pending_config = false;
 	}
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
index 56c5894..c10faac 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
@@ -30,7 +30,26 @@
 #define DISP_OD_INTEN				0x0008
 #define DISP_OD_INTSTA				0x000c
 #define DISP_OD_CFG				0x0020
+#define OD_RELAYMODE				BIT(0)
+#define OD_DITHERING				BIT(2)
 #define DISP_OD_SIZE				0x0030
+#define DISP_OD_DITHER_5			0x0114
+#define DISP_OD_DITHER_7			0x011c
+#define DISP_OD_DITHER_15			0x013c
+#define DITHER_LSB_ERR_SHIFT_R(x)		(((x) & 0x7) << 28)
+#define DITHER_OVFLW_BIT_R(x)			(((x) & 0x7) << 24)
+#define DITHER_ADD_LSHIFT_R(x)			(((x) & 0x7) << 20)
+#define DITHER_ADD_RSHIFT_R(x)			(((x) & 0x7) << 16)
+#define DITHER_NEW_BIT_MODE			BIT(0)
+#define DISP_OD_DITHER_16			0x140
+#define DITHER_LSB_ERR_SHIFT_B(x)		(((x) & 0x7) << 28)
+#define DITHER_OVFLW_BIT_B(x)			(((x) & 0x7) << 24)
+#define DITHER_ADD_LSHIFT_B(x)			(((x) & 0x7) << 20)
+#define DITHER_ADD_RSHIFT_B(x)			(((x) & 0x7) << 16)
+#define DITHER_LSB_ERR_SHIFT_G(x)		(((x) & 0x7) << 12)
+#define DITHER_OVFLW_BIT_G(x)			(((x) & 0x7) << 8)
+#define DITHER_ADD_LSHIFT_G(x)			(((x) & 0x7) << 4)
+#define DITHER_ADD_RSHIFT_G(x)			(((x) & 0x7) << 0)
 
 #define DISP_REG_UFO_START			0x0000
 
@@ -44,25 +63,28 @@
 
 #define DISP_GAMMA_EN				0x000
 #define DISP_GAMMA_CFG				0x020
+#define GAMMA_EN				BIT(0)
+#define GAMMA_LUT_EN				BIT(1)
+#define GAMMA_DITHERING				BIT(2)
 #define DISP_GAMMA_SIZE				0x030
 #define DISP_GAMMA_LUT				0x700
+#define DISP_GAMMA_DITHER_5			0x0114
+#define DISP_GAMMA_DITHER_7			0x011c
+#define DISP_GAMMA_DITHER_15			0x013c
+#define DISP_GAMMA_DITHER_16			0x0140
 
 #define LUT_10BIT_MASK				0x3ff
 
 #define AAL_EN			BIT(0)
 
-#define GAMMA_EN		BIT(0)
-#define GAMMA_LUT_EN		BIT(1)
-
-#define	OD_RELAY_MODE		BIT(0)
-
 #define	UFO_BYPASS		BIT(2)
 
 #define	COLOR_BYPASS_ALL	BIT(7)
 #define	COLOR_SEQ_SEL		BIT(13)
 
 static void mtk_color_config(struct mtk_ddp_comp *comp, unsigned int w,
-			     unsigned int h, unsigned int vrefresh)
+			     unsigned int h, unsigned int vrefresh,
+			     unsigned int bpc)
 {
 	writel(w, comp->regs + DISP_COLOR_WIDTH);
 	writel(h, comp->regs + DISP_COLOR_HEIGHT);
@@ -76,14 +98,33 @@ static void mtk_color_start(struct mtk_ddp_comp *comp)
 }
 
 static void mtk_od_config(struct mtk_ddp_comp *comp, unsigned int w,
-			  unsigned int h, unsigned int vrefresh)
+			  unsigned int h, unsigned int vrefresh,
+			  unsigned int bpc)
 {
 	writel(w << 16 | h, comp->regs + DISP_OD_SIZE);
+	if (bpc >= 3 && bpc < 10) {
+		writel(0, comp->regs + DISP_OD_DITHER_5);
+		writel(0, comp->regs + DISP_OD_DITHER_7);
+		writel(DITHER_LSB_ERR_SHIFT_R(10 - bpc) |
+		       DITHER_ADD_LSHIFT_R(10 - bpc) |
+		       DITHER_NEW_BIT_MODE,
+		       comp->regs + DISP_OD_DITHER_15);
+		writel(DITHER_LSB_ERR_SHIFT_B(10 - bpc) |
+		       DITHER_ADD_LSHIFT_B(10 - bpc) |
+		       DITHER_LSB_ERR_SHIFT_G(10 - bpc) |
+		       DITHER_ADD_LSHIFT_G(10 - bpc),
+		       comp->regs + DISP_OD_DITHER_16);
+		writel(OD_DITHERING,
+		       comp->regs + DISP_OD_CFG);
+	} else {
+		writel(OD_RELAYMODE,
+		       comp->regs + DISP_OD_CFG);
+	}
+
 }
 
 static void mtk_od_start(struct mtk_ddp_comp *comp)
 {
-	writel(OD_RELAY_MODE, comp->regs + DISP_OD_CFG);
 	writel(1, comp->regs + DISP_OD_EN);
 }
 
@@ -93,7 +134,8 @@ static void mtk_ufoe_start(struct mtk_ddp_comp *comp)
 }
 
 static void mtk_aal_config(struct mtk_ddp_comp *comp, unsigned int w,
-			   unsigned int h, unsigned int vrefresh)
+			   unsigned int h, unsigned int vrefresh,
+			   unsigned int bpc)
 {
 	writel(h << 16 | w, comp->regs + DISP_AAL_SIZE);
 }
@@ -109,9 +151,24 @@ static void mtk_aal_stop(struct mtk_ddp_comp *comp)
 }
 
 static void mtk_gamma_config(struct mtk_ddp_comp *comp, unsigned int w,
-			     unsigned int h, unsigned int vrefresh)
+			     unsigned int h, unsigned int vrefresh,
+			     unsigned int bpc)
 {
 	writel(h << 16 | w, comp->regs + DISP_GAMMA_SIZE);
+	if (bpc >= 3 && bpc < 10) {
+		writel(0, comp->regs + DISP_GAMMA_DITHER_5);
+		writel(0, comp->regs + DISP_GAMMA_DITHER_7);
+		writel(DITHER_LSB_ERR_SHIFT_R(10 - bpc) |
+		       DITHER_ADD_LSHIFT_R(10 - bpc) |
+		       DITHER_NEW_BIT_MODE,
+		       comp->regs + DISP_GAMMA_DITHER_15);
+		writel(DITHER_LSB_ERR_SHIFT_B(10 - bpc) |
+		       DITHER_ADD_LSHIFT_B(10 - bpc) |
+		       DITHER_LSB_ERR_SHIFT_G(10 - bpc) |
+		       DITHER_ADD_LSHIFT_G(10 - bpc),
+		       comp->regs + DISP_GAMMA_DITHER_16);
+		writel(GAMMA_DITHERING, comp->regs + DISP_GAMMA_CFG);
+	}
 }
 
 static void mtk_gamma_start(struct mtk_ddp_comp *comp)
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
index 07e17fe..c7c2e92 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
@@ -65,7 +65,7 @@ struct mtk_ddp_comp;
 
 struct mtk_ddp_comp_funcs {
 	void (*config)(struct mtk_ddp_comp *comp, unsigned int w,
-		       unsigned int h, unsigned int vrefresh);
+		       unsigned int h, unsigned int vrefresh, unsigned int bpc);
 	void (*start)(struct mtk_ddp_comp *comp);
 	void (*stop)(struct mtk_ddp_comp *comp);
 	void (*enable_vblank)(struct mtk_ddp_comp *comp, struct drm_crtc *crtc);
@@ -89,10 +89,10 @@ struct mtk_ddp_comp {
 
 static inline void mtk_ddp_comp_config(struct mtk_ddp_comp *comp,
 				       unsigned int w, unsigned int h,
-				       unsigned int vrefresh)
+				       unsigned int vrefresh, unsigned int bpc)
 {
 	if (comp->funcs && comp->funcs->config)
-		comp->funcs->config(comp, w, h, vrefresh);
+		comp->funcs->config(comp, w, h, vrefresh, bpc);
 }
 
 static inline void mtk_ddp_comp_start(struct mtk_ddp_comp *comp)
-- 
1.7.9.5



From daniel.lezcano at linaro.org  Thu Jul  7 01:00:47 2016
From: daniel.lezcano at linaro.org (Daniel Lezcano)
Date: Thu,  7 Jul 2016 10:00:47 +0200
Subject: [PATCH 14/93] clocksource/drivers/mtk_timer: Convert init function to
 return error
In-Reply-To: <1467878526-1238-1-git-send-email-daniel.lezcano@linaro.org>
References: <577E0BED.3020608@linaro.org>
 <1467878526-1238-1-git-send-email-daniel.lezcano@linaro.org>
Message-ID: <1467878526-1238-14-git-send-email-daniel.lezcano@linaro.org>

The init functions do not return any error. They behave as the following:

 - panic, thus leading to a kernel crash while another timer may work and
   make the system boot up correctly

 or

 - print an error and let the caller unaware if the state of the system

Change that by converting the init functions to return an error conforming
to the CLOCKSOURCE_OF_RET prototype.

Proper error handling (rollback, errno value) will be changed later case
by case, thus this change just return back an error or success in the init
function.

Signed-off-by: Daniel Lezcano <daniel.lezcano at linaro.org>
Acked-by: Matthias Brugger <matthias.bgg at gmail.com>
---
 drivers/clocksource/mtk_timer.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/clocksource/mtk_timer.c b/drivers/clocksource/mtk_timer.c
index 7e583f8..432a2c0 100644
--- a/drivers/clocksource/mtk_timer.c
+++ b/drivers/clocksource/mtk_timer.c
@@ -181,7 +181,7 @@ static void mtk_timer_enable_irq(struct mtk_clock_event_device *evt, u8 timer)
 			evt->gpt_base + GPT_IRQ_EN_REG);
 }
 
-static void __init mtk_timer_init(struct device_node *node)
+static int __init mtk_timer_init(struct device_node *node)
 {
 	struct mtk_clock_event_device *evt;
 	struct resource res;
@@ -190,7 +190,7 @@ static void __init mtk_timer_init(struct device_node *node)
 
 	evt = kzalloc(sizeof(*evt), GFP_KERNEL);
 	if (!evt)
-		return;
+		return -ENOMEM;
 
 	evt->dev.name = "mtk_tick";
 	evt->dev.rating = 300;
@@ -248,7 +248,7 @@ static void __init mtk_timer_init(struct device_node *node)
 
 	mtk_timer_enable_irq(evt, GPT_CLK_EVT);
 
-	return;
+	return 0;
 
 err_clk_disable:
 	clk_disable_unprepare(clk);
@@ -262,5 +262,7 @@ err_mem:
 	release_mem_region(res.start, resource_size(&res));
 err_kzalloc:
 	kfree(evt);
+
+	return -EINVAL;
 }
-CLOCKSOURCE_OF_DECLARE(mtk_mt6577, "mediatek,mt6577-timer", mtk_timer_init);
+CLOCKSOURCE_OF_DECLARE_RET(mtk_mt6577, "mediatek,mt6577-timer", mtk_timer_init);
-- 
1.9.1



From daniel.lezcano at linaro.org  Thu Jul  7 01:01:45 2016
From: daniel.lezcano at linaro.org (Daniel Lezcano)
Date: Thu,  7 Jul 2016 10:01:45 +0200
Subject: [PATCH 72/93] clocksources: Switch back to the clksrc table
In-Reply-To: <1467878526-1238-1-git-send-email-daniel.lezcano@linaro.org>
References: <577E0BED.3020608@linaro.org>
 <1467878526-1238-1-git-send-email-daniel.lezcano@linaro.org>
Message-ID: <1467878526-1238-72-git-send-email-daniel.lezcano@linaro.org>

All the clocksource drivers's init function are now converted to return
an error code. CLOCKSOURCE_OF_DECLARE is no longer used as well as the
clksrc-of table.

Let's convert back the names:
 - CLOCKSOURCE_OF_DECLARE_RET => CLOCKSOURCE_OF_DECLARE
 - clksrc-of-ret              => clksrc-of

Signed-off-by: Daniel Lezcano <daniel.lezcano at linaro.org>

For exynos_mct and samsung_pwm_timer:
Acked-by: Krzysztof Kozlowski <k.kozlowski at samsung.com>

For arch/arc:
Acked-by: Vineet Gupta <vgupta at synopsys.com>

For mediatek driver:
Acked-by: Matthias Brugger <matthias.bgg at gmail.com>

For the Rockchip-part
Acked-by: Heiko Stuebner <heiko at sntech.de>

For STi :
Acked-by: Patrice Chotard <patrice.chotard at st.com>

For the mps2-timer.c and versatile.c changes:
Acked-by: Liviu Dudau <Liviu.Dudau at arm.com>

For the OXNAS part :
Acked-by: Neil Armstrong <narmstrong at baylibre.com>

For LPC32xx driver:
Acked-by: Sylvain Lemieux <slemieux.tyco at gmail.com>

For Broadcom Kona timer change:
Acked-by: Ray Jui <ray.jui at broadcom.com>

For Sun4i and Sun5i:
Acked-by: Chen-Yu Tsai <wens at csie.org>

For Meson6:
Acked-by: Carlo Caione <carlo at caione.org>

For Keystone:
Acked-by: Santosh Shilimkar <ssantosh at kernel.org>

For NPS:
Acked-by: Noam Camus <noamca at mellanox.com>

For bcm2835:
Acked-by: Eric Anholt <eric at anholt.net>
---
 arch/arc/kernel/time.c                    |  6 +++---
 arch/arm/kernel/smp_twd.c                 |  6 +++---
 arch/microblaze/kernel/timer.c            |  2 +-
 arch/mips/ralink/cevt-rt3352.c            |  2 +-
 arch/nios2/kernel/time.c                  |  2 +-
 drivers/clocksource/arm_arch_timer.c      |  6 +++---
 drivers/clocksource/arm_global_timer.c    |  2 +-
 drivers/clocksource/armv7m_systick.c      |  2 +-
 drivers/clocksource/asm9260_timer.c       |  2 +-
 drivers/clocksource/bcm2835_timer.c       |  2 +-
 drivers/clocksource/bcm_kona_timer.c      |  4 ++--
 drivers/clocksource/cadence_ttc_timer.c   |  2 +-
 drivers/clocksource/clksrc-dbx500-prcmu.c |  2 +-
 drivers/clocksource/clksrc-probe.c        | 14 --------------
 drivers/clocksource/clksrc_st_lpc.c       |  2 +-
 drivers/clocksource/clps711x-timer.c      |  2 +-
 drivers/clocksource/dw_apb_timer_of.c     |  8 ++++----
 drivers/clocksource/exynos_mct.c          |  4 ++--
 drivers/clocksource/fsl_ftm_timer.c       |  2 +-
 drivers/clocksource/h8300_timer16.c       |  2 +-
 drivers/clocksource/h8300_timer8.c        |  2 +-
 drivers/clocksource/h8300_tpu.c           |  2 +-
 drivers/clocksource/meson6_timer.c        |  2 +-
 drivers/clocksource/mips-gic-timer.c      |  2 +-
 drivers/clocksource/moxart_timer.c        |  2 +-
 drivers/clocksource/mps2-timer.c          |  2 +-
 drivers/clocksource/mtk_timer.c           |  2 +-
 drivers/clocksource/mxs_timer.c           |  2 +-
 drivers/clocksource/nomadik-mtu.c         |  2 +-
 drivers/clocksource/pxa_timer.c           |  2 +-
 drivers/clocksource/qcom-timer.c          |  4 ++--
 drivers/clocksource/rockchip_timer.c      |  8 ++++----
 drivers/clocksource/samsung_pwm_timer.c   |  8 ++++----
 drivers/clocksource/sun4i_timer.c         |  2 +-
 drivers/clocksource/tango_xtal.c          |  2 +-
 drivers/clocksource/tegra20_timer.c       |  4 ++--
 drivers/clocksource/time-armada-370-xp.c  |  6 +++---
 drivers/clocksource/time-efm32.c          |  4 ++--
 drivers/clocksource/time-lpc32xx.c        |  2 +-
 drivers/clocksource/time-orion.c          |  2 +-
 drivers/clocksource/time-pistachio.c      |  2 +-
 drivers/clocksource/timer-atlas7.c        |  2 +-
 drivers/clocksource/timer-atmel-pit.c     |  2 +-
 drivers/clocksource/timer-atmel-st.c      |  2 +-
 drivers/clocksource/timer-digicolor.c     |  2 +-
 drivers/clocksource/timer-imx-gpt.c       | 24 ++++++++++++------------
 drivers/clocksource/timer-integrator-ap.c |  2 +-
 drivers/clocksource/timer-keystone.c      |  2 +-
 drivers/clocksource/timer-nps.c           |  4 ++--
 drivers/clocksource/timer-oxnas-rps.c     |  4 ++--
 drivers/clocksource/timer-prima2.c        |  2 +-
 drivers/clocksource/timer-sp804.c         |  4 ++--
 drivers/clocksource/timer-stm32.c         |  2 +-
 drivers/clocksource/timer-sun5i.c         |  4 ++--
 drivers/clocksource/timer-ti-32k.c        |  2 +-
 drivers/clocksource/timer-u300.c          |  2 +-
 drivers/clocksource/versatile.c           |  4 ++--
 drivers/clocksource/vf_pit_timer.c        |  2 +-
 drivers/clocksource/vt8500_timer.c        |  2 +-
 drivers/clocksource/zevio-timer.c         |  2 +-
 include/asm-generic/vmlinux.lds.h         |  2 --
 include/linux/clocksource.h               |  5 +----
 62 files changed, 98 insertions(+), 117 deletions(-)

diff --git a/arch/arc/kernel/time.c b/arch/arc/kernel/time.c
index 09de669..98f22d2 100644
--- a/arch/arc/kernel/time.c
+++ b/arch/arc/kernel/time.c
@@ -130,7 +130,7 @@ static int __init arc_cs_setup_gfrc(struct device_node *node)
 
 	return clocksource_register_hz(&arc_counter_gfrc, arc_timer_freq);
 }
-CLOCKSOURCE_OF_DECLARE_RET(arc_gfrc, "snps,archs-timer-gfrc", arc_cs_setup_gfrc);
+CLOCKSOURCE_OF_DECLARE(arc_gfrc, "snps,archs-timer-gfrc", arc_cs_setup_gfrc);
 
 #endif
 
@@ -192,7 +192,7 @@ static int __init arc_cs_setup_rtc(struct device_node *node)
 
 	return clocksource_register_hz(&arc_counter_rtc, arc_timer_freq);
 }
-CLOCKSOURCE_OF_DECLARE_RET(arc_rtc, "snps,archs-timer-rtc", arc_cs_setup_rtc);
+CLOCKSOURCE_OF_DECLARE(arc_rtc, "snps,archs-timer-rtc", arc_cs_setup_rtc);
 
 #endif
 
@@ -379,7 +379,7 @@ static int __init arc_of_timer_init(struct device_node *np)
 
 	return ret;
 }
-CLOCKSOURCE_OF_DECLARE_RET(arc_clkevt, "snps,arc-timer", arc_of_timer_init);
+CLOCKSOURCE_OF_DECLARE(arc_clkevt, "snps,arc-timer", arc_of_timer_init);
 
 /*
  * Called from start_kernel() - boot CPU only
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index 2b24be4..b6ec65e 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -412,7 +412,7 @@ out:
 	WARN(err, "twd_local_timer_of_register failed (%d)\n", err);
 	return err;
 }
-CLOCKSOURCE_OF_DECLARE_RET(arm_twd_a9, "arm,cortex-a9-twd-timer", twd_local_timer_of_register);
-CLOCKSOURCE_OF_DECLARE_RET(arm_twd_a5, "arm,cortex-a5-twd-timer", twd_local_timer_of_register);
-CLOCKSOURCE_OF_DECLARE_RET(arm_twd_11mp, "arm,arm11mp-twd-timer", twd_local_timer_of_register);
+CLOCKSOURCE_OF_DECLARE(arm_twd_a9, "arm,cortex-a9-twd-timer", twd_local_timer_of_register);
+CLOCKSOURCE_OF_DECLARE(arm_twd_a5, "arm,cortex-a5-twd-timer", twd_local_timer_of_register);
+CLOCKSOURCE_OF_DECLARE(arm_twd_11mp, "arm,arm11mp-twd-timer", twd_local_timer_of_register);
 #endif
diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c
index 7f35e7b..5bbf38b 100644
--- a/arch/microblaze/kernel/timer.c
+++ b/arch/microblaze/kernel/timer.c
@@ -332,5 +332,5 @@ static int __init xilinx_timer_init(struct device_node *timer)
 	return 0;
 }
 
-CLOCKSOURCE_OF_DECLARE_RET(xilinx_timer, "xlnx,xps-timer-1.00.a",
+CLOCKSOURCE_OF_DECLARE(xilinx_timer, "xlnx,xps-timer-1.00.a",
 		       xilinx_timer_init);
diff --git a/arch/mips/ralink/cevt-rt3352.c b/arch/mips/ralink/cevt-rt3352.c
index f2d3c79..f24eee0 100644
--- a/arch/mips/ralink/cevt-rt3352.c
+++ b/arch/mips/ralink/cevt-rt3352.c
@@ -150,4 +150,4 @@ static int __init ralink_systick_init(struct device_node *np)
 	return 0;
 }
 
-CLOCKSOURCE_OF_DECLARE_RET(systick, "ralink,cevt-systick", ralink_systick_init);
+CLOCKSOURCE_OF_DECLARE(systick, "ralink,cevt-systick", ralink_systick_init);
diff --git a/arch/nios2/kernel/time.c b/arch/nios2/kernel/time.c
index b75e40e..d9563dd 100644
--- a/arch/nios2/kernel/time.c
+++ b/arch/nios2/kernel/time.c
@@ -352,4 +352,4 @@ void __init time_init(void)
 	clocksource_probe();
 }
 
-CLOCKSOURCE_OF_DECLARE_RET(nios2_timer, ALTR_TIMER_COMPATIBLE, nios2_time_init);
+CLOCKSOURCE_OF_DECLARE(nios2_timer, ALTR_TIMER_COMPATIBLE, nios2_time_init);
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index d0cda68..9e33309 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -784,8 +784,8 @@ static int __init arch_timer_of_init(struct device_node *np)
 
 	return arch_timer_init();
 }
-CLOCKSOURCE_OF_DECLARE_RET(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init);
-CLOCKSOURCE_OF_DECLARE_RET(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init);
+CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init);
+CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init);
 
 static int __init arch_timer_mem_init(struct device_node *np)
 {
@@ -868,7 +868,7 @@ out:
 	of_node_put(best_frame);
 	return ret;
 }
-CLOCKSOURCE_OF_DECLARE_RET(armv7_arch_timer_mem, "arm,armv7-timer-mem",
+CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem",
 		       arch_timer_mem_init);
 
 #ifdef CONFIG_ACPI
diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c
index 40104fc..2a9ceb6 100644
--- a/drivers/clocksource/arm_global_timer.c
+++ b/drivers/clocksource/arm_global_timer.c
@@ -358,5 +358,5 @@ out_unmap:
 }
 
 /* Only tested on r2p2 and r3p0  */
-CLOCKSOURCE_OF_DECLARE_RET(arm_gt, "arm,cortex-a9-global-timer",
+CLOCKSOURCE_OF_DECLARE(arm_gt, "arm,cortex-a9-global-timer",
 			global_timer_of_register);
diff --git a/drivers/clocksource/armv7m_systick.c b/drivers/clocksource/armv7m_systick.c
index 2b55410..e93af1f 100644
--- a/drivers/clocksource/armv7m_systick.c
+++ b/drivers/clocksource/armv7m_systick.c
@@ -81,5 +81,5 @@ out_unmap:
 	return ret;
 }
 
-CLOCKSOURCE_OF_DECLARE_RET(arm_systick, "arm,armv7m-systick",
+CLOCKSOURCE_OF_DECLARE(arm_systick, "arm,armv7m-systick",
 			system_timer_of_register);
diff --git a/drivers/clocksource/asm9260_timer.c b/drivers/clocksource/asm9260_timer.c
index d113c02..1ba871b 100644
--- a/drivers/clocksource/asm9260_timer.c
+++ b/drivers/clocksource/asm9260_timer.c
@@ -238,5 +238,5 @@ static int __init asm9260_timer_init(struct device_node *np)
 
 	return 0;
 }
-CLOCKSOURCE_OF_DECLARE_RET(asm9260_timer, "alphascale,asm9260-timer",
+CLOCKSOURCE_OF_DECLARE(asm9260_timer, "alphascale,asm9260-timer",
 		asm9260_timer_init);
diff --git a/drivers/clocksource/bcm2835_timer.c b/drivers/clocksource/bcm2835_timer.c
index 2dcf896..e71acf2 100644
--- a/drivers/clocksource/bcm2835_timer.c
+++ b/drivers/clocksource/bcm2835_timer.c
@@ -142,5 +142,5 @@ static int __init bcm2835_timer_init(struct device_node *node)
 
 	return 0;
 }
-CLOCKSOURCE_OF_DECLARE_RET(bcm2835, "brcm,bcm2835-system-timer",
+CLOCKSOURCE_OF_DECLARE(bcm2835, "brcm,bcm2835-system-timer",
 			bcm2835_timer_init);
diff --git a/drivers/clocksource/bcm_kona_timer.c b/drivers/clocksource/bcm_kona_timer.c
index c251aa6..86f87be3d 100644
--- a/drivers/clocksource/bcm_kona_timer.c
+++ b/drivers/clocksource/bcm_kona_timer.c
@@ -195,9 +195,9 @@ static int __init kona_timer_init(struct device_node *node)
 	return 0;
 }
 
-CLOCKSOURCE_OF_DECLARE_RET(brcm_kona, "brcm,kona-timer", kona_timer_init);
+CLOCKSOURCE_OF_DECLARE(brcm_kona, "brcm,kona-timer", kona_timer_init);
 /*
  * bcm,kona-timer is deprecated by brcm,kona-timer
  * being kept here for driver compatibility
  */
-CLOCKSOURCE_OF_DECLARE_RET(bcm_kona, "bcm,kona-timer", kona_timer_init);
+CLOCKSOURCE_OF_DECLARE(bcm_kona, "bcm,kona-timer", kona_timer_init);
diff --git a/drivers/clocksource/cadence_ttc_timer.c b/drivers/clocksource/cadence_ttc_timer.c
index e2e7631..388a77b 100644
--- a/drivers/clocksource/cadence_ttc_timer.c
+++ b/drivers/clocksource/cadence_ttc_timer.c
@@ -539,4 +539,4 @@ static int __init ttc_timer_init(struct device_node *timer)
 	return 0;
 }
 
-CLOCKSOURCE_OF_DECLARE_RET(ttc, "cdns,ttc", ttc_timer_init);
+CLOCKSOURCE_OF_DECLARE(ttc, "cdns,ttc", ttc_timer_init);
diff --git a/drivers/clocksource/clksrc-dbx500-prcmu.c b/drivers/clocksource/clksrc-dbx500-prcmu.c
index 5a59d29..77a365f 100644
--- a/drivers/clocksource/clksrc-dbx500-prcmu.c
+++ b/drivers/clocksource/clksrc-dbx500-prcmu.c
@@ -86,5 +86,5 @@ static int __init clksrc_dbx500_prcmu_init(struct device_node *node)
 #endif
 	return clocksource_register_hz(&clocksource_dbx500_prcmu, RATE_32K);
 }
-CLOCKSOURCE_OF_DECLARE_RET(dbx500_prcmu, "stericsson,db8500-prcmu-timer-4",
+CLOCKSOURCE_OF_DECLARE(dbx500_prcmu, "stericsson,db8500-prcmu-timer-4",
 		       clksrc_dbx500_prcmu_init);
diff --git a/drivers/clocksource/clksrc-probe.c b/drivers/clocksource/clksrc-probe.c
index 5fa6a55..bc62be9 100644
--- a/drivers/clocksource/clksrc-probe.c
+++ b/drivers/clocksource/clksrc-probe.c
@@ -20,19 +20,14 @@
 #include <linux/clocksource.h>
 
 extern struct of_device_id __clksrc_of_table[];
-extern struct of_device_id __clksrc_ret_of_table[];
 
 static const struct of_device_id __clksrc_of_table_sentinel
 	__used __section(__clksrc_of_table_end);
 
-static const struct of_device_id __clksrc_ret_of_table_sentinel
-	__used __section(__clksrc_ret_of_table_end);
-
 void __init clocksource_probe(void)
 {
 	struct device_node *np;
 	const struct of_device_id *match;
-	of_init_fn_1 init_func;
 	of_init_fn_1_ret init_func_ret;
 	unsigned clocksources = 0;
 	int ret;
@@ -41,15 +36,6 @@ void __init clocksource_probe(void)
 		if (!of_device_is_available(np))
 			continue;
 
-		init_func = match->data;
-		init_func(np);
-		clocksources++;
-	}
-
-	for_each_matching_node_and_match(np, __clksrc_ret_of_table, &match) {
-		if (!of_device_is_available(np))
-			continue;
-
 		init_func_ret = match->data;
 
 		ret = init_func_ret(np);
diff --git a/drivers/clocksource/clksrc_st_lpc.c b/drivers/clocksource/clksrc_st_lpc.c
index c9022a9..03cc492 100644
--- a/drivers/clocksource/clksrc_st_lpc.c
+++ b/drivers/clocksource/clksrc_st_lpc.c
@@ -132,4 +132,4 @@ static int __init st_clksrc_of_register(struct device_node *np)
 
 	return ret;
 }
-CLOCKSOURCE_OF_DECLARE_RET(ddata, "st,stih407-lpc", st_clksrc_of_register);
+CLOCKSOURCE_OF_DECLARE(ddata, "st,stih407-lpc", st_clksrc_of_register);
diff --git a/drivers/clocksource/clps711x-timer.c b/drivers/clocksource/clps711x-timer.c
index 3b66198..84aed78 100644
--- a/drivers/clocksource/clps711x-timer.c
+++ b/drivers/clocksource/clps711x-timer.c
@@ -119,5 +119,5 @@ static int __init clps711x_timer_init(struct device_node *np)
 		return -EINVAL;
 	}
 }
-CLOCKSOURCE_OF_DECLARE_RET(clps711x, "cirrus,clps711x-timer", clps711x_timer_init);
+CLOCKSOURCE_OF_DECLARE(clps711x, "cirrus,clps711x-timer", clps711x_timer_init);
 #endif
diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw_apb_timer_of.c
index 4985a2c..aee6c0d 100644
--- a/drivers/clocksource/dw_apb_timer_of.c
+++ b/drivers/clocksource/dw_apb_timer_of.c
@@ -167,7 +167,7 @@ static int __init dw_apb_timer_init(struct device_node *timer)
 
 	return 0;
 }
-CLOCKSOURCE_OF_DECLARE_RET(pc3x2_timer, "picochip,pc3x2-timer", dw_apb_timer_init);
-CLOCKSOURCE_OF_DECLARE_RET(apb_timer_osc, "snps,dw-apb-timer-osc", dw_apb_timer_init);
-CLOCKSOURCE_OF_DECLARE_RET(apb_timer_sp, "snps,dw-apb-timer-sp", dw_apb_timer_init);
-CLOCKSOURCE_OF_DECLARE_RET(apb_timer, "snps,dw-apb-timer", dw_apb_timer_init);
+CLOCKSOURCE_OF_DECLARE(pc3x2_timer, "picochip,pc3x2-timer", dw_apb_timer_init);
+CLOCKSOURCE_OF_DECLARE(apb_timer_osc, "snps,dw-apb-timer-osc", dw_apb_timer_init);
+CLOCKSOURCE_OF_DECLARE(apb_timer_sp, "snps,dw-apb-timer-sp", dw_apb_timer_init);
+CLOCKSOURCE_OF_DECLARE(apb_timer, "snps,dw-apb-timer", dw_apb_timer_init);
diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c
index f6caed0..0d18dd4b 100644
--- a/drivers/clocksource/exynos_mct.c
+++ b/drivers/clocksource/exynos_mct.c
@@ -627,5 +627,5 @@ static int __init mct_init_ppi(struct device_node *np)
 {
 	return mct_init_dt(np, MCT_INT_PPI);
 }
-CLOCKSOURCE_OF_DECLARE_RET(exynos4210, "samsung,exynos4210-mct", mct_init_spi);
-CLOCKSOURCE_OF_DECLARE_RET(exynos4412, "samsung,exynos4412-mct", mct_init_ppi);
+CLOCKSOURCE_OF_DECLARE(exynos4210, "samsung,exynos4210-mct", mct_init_spi);
+CLOCKSOURCE_OF_DECLARE(exynos4412, "samsung,exynos4412-mct", mct_init_ppi);
diff --git a/drivers/clocksource/fsl_ftm_timer.c b/drivers/clocksource/fsl_ftm_timer.c
index 9ad4ca3..738515b 100644
--- a/drivers/clocksource/fsl_ftm_timer.c
+++ b/drivers/clocksource/fsl_ftm_timer.c
@@ -369,4 +369,4 @@ err:
 	kfree(priv);
 	return ret;
 }
-CLOCKSOURCE_OF_DECLARE_RET(flextimer, "fsl,ftm-timer", ftm_timer_init);
+CLOCKSOURCE_OF_DECLARE(flextimer, "fsl,ftm-timer", ftm_timer_init);
diff --git a/drivers/clocksource/h8300_timer16.c b/drivers/clocksource/h8300_timer16.c
index 9d99fc8..07d9d5b 100644
--- a/drivers/clocksource/h8300_timer16.c
+++ b/drivers/clocksource/h8300_timer16.c
@@ -187,5 +187,5 @@ free_clk:
 	return ret;
 }
 
-CLOCKSOURCE_OF_DECLARE_RET(h8300_16bit, "renesas,16bit-timer",
+CLOCKSOURCE_OF_DECLARE(h8300_16bit, "renesas,16bit-timer",
 			   h8300_16timer_init);
diff --git a/drivers/clocksource/h8300_timer8.c b/drivers/clocksource/h8300_timer8.c
index 0292a19..546bb18 100644
--- a/drivers/clocksource/h8300_timer8.c
+++ b/drivers/clocksource/h8300_timer8.c
@@ -215,4 +215,4 @@ free_clk:
 	return ret;
 }
 
-CLOCKSOURCE_OF_DECLARE_RET(h8300_8bit, "renesas,8bit-timer", h8300_8timer_init);
+CLOCKSOURCE_OF_DECLARE(h8300_8bit, "renesas,8bit-timer", h8300_8timer_init);
diff --git a/drivers/clocksource/h8300_tpu.c b/drivers/clocksource/h8300_tpu.c
index 4faf718..7bdf199 100644
--- a/drivers/clocksource/h8300_tpu.c
+++ b/drivers/clocksource/h8300_tpu.c
@@ -154,4 +154,4 @@ free_clk:
 	return ret;
 }
 
-CLOCKSOURCE_OF_DECLARE_RET(h8300_tpu, "renesas,tpu", h8300_tpu_init);
+CLOCKSOURCE_OF_DECLARE(h8300_tpu, "renesas,tpu", h8300_tpu_init);
diff --git a/drivers/clocksource/meson6_timer.c b/drivers/clocksource/meson6_timer.c
index 3a6e78f..52af591 100644
--- a/drivers/clocksource/meson6_timer.c
+++ b/drivers/clocksource/meson6_timer.c
@@ -174,5 +174,5 @@ static int __init meson6_timer_init(struct device_node *node)
 					1, 0xfffe);
 	return 0;
 }
-CLOCKSOURCE_OF_DECLARE_RET(meson6, "amlogic,meson6-timer",
+CLOCKSOURCE_OF_DECLARE(meson6, "amlogic,meson6-timer",
 		       meson6_timer_init);
diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c
index b164b87..1572c7a 100644
--- a/drivers/clocksource/mips-gic-timer.c
+++ b/drivers/clocksource/mips-gic-timer.c
@@ -222,5 +222,5 @@ static void __init gic_clocksource_of_init(struct device_node *node)
 
 	return 0;
 }
-CLOCKSOURCE_OF_DECLARE_RET(mips_gic_timer, "mti,gic-timer",
+CLOCKSOURCE_OF_DECLARE(mips_gic_timer, "mti,gic-timer",
 		       gic_clocksource_of_init);
diff --git a/drivers/clocksource/moxart_timer.c b/drivers/clocksource/moxart_timer.c
index b9c30cd..8414544 100644
--- a/drivers/clocksource/moxart_timer.c
+++ b/drivers/clocksource/moxart_timer.c
@@ -178,4 +178,4 @@ static int __init moxart_timer_init(struct device_node *node)
 
 	return 0;
 }
-CLOCKSOURCE_OF_DECLARE_RET(moxart, "moxa,moxart-timer", moxart_timer_init);
+CLOCKSOURCE_OF_DECLARE(moxart, "moxa,moxart-timer", moxart_timer_init);
diff --git a/drivers/clocksource/mps2-timer.c b/drivers/clocksource/mps2-timer.c
index c303fa9..3e4431e 100644
--- a/drivers/clocksource/mps2-timer.c
+++ b/drivers/clocksource/mps2-timer.c
@@ -274,4 +274,4 @@ static int __init mps2_timer_init(struct device_node *np)
 	return 0;
 }
 
-CLOCKSOURCE_OF_DECLARE_RET(mps2_timer, "arm,mps2-timer", mps2_timer_init);
+CLOCKSOURCE_OF_DECLARE(mps2_timer, "arm,mps2-timer", mps2_timer_init);
diff --git a/drivers/clocksource/mtk_timer.c b/drivers/clocksource/mtk_timer.c
index 432a2c0..9065949 100644
--- a/drivers/clocksource/mtk_timer.c
+++ b/drivers/clocksource/mtk_timer.c
@@ -265,4 +265,4 @@ err_kzalloc:
 
 	return -EINVAL;
 }
-CLOCKSOURCE_OF_DECLARE_RET(mtk_mt6577, "mediatek,mt6577-timer", mtk_timer_init);
+CLOCKSOURCE_OF_DECLARE(mtk_mt6577, "mediatek,mt6577-timer", mtk_timer_init);
diff --git a/drivers/clocksource/mxs_timer.c b/drivers/clocksource/mxs_timer.c
index 17b9d19..630a8d3 100644
--- a/drivers/clocksource/mxs_timer.c
+++ b/drivers/clocksource/mxs_timer.c
@@ -295,4 +295,4 @@ static int __init mxs_timer_init(struct device_node *np)
 
 	return setup_irq(irq, &mxs_timer_irq);
 }
-CLOCKSOURCE_OF_DECLARE_RET(mxs, "fsl,timrot", mxs_timer_init);
+CLOCKSOURCE_OF_DECLARE(mxs, "fsl,timrot", mxs_timer_init);
diff --git a/drivers/clocksource/nomadik-mtu.c b/drivers/clocksource/nomadik-mtu.c
index d2be5b3..3c124d1 100644
--- a/drivers/clocksource/nomadik-mtu.c
+++ b/drivers/clocksource/nomadik-mtu.c
@@ -284,5 +284,5 @@ static int __init nmdk_timer_of_init(struct device_node *node)
 
 	return nmdk_timer_init(base, irq, pclk, clk);
 }
-CLOCKSOURCE_OF_DECLARE_RET(nomadik_mtu, "st,nomadik-mtu",
+CLOCKSOURCE_OF_DECLARE(nomadik_mtu, "st,nomadik-mtu",
 		       nmdk_timer_of_init);
diff --git a/drivers/clocksource/pxa_timer.c b/drivers/clocksource/pxa_timer.c
index 59af75c..937e10b 100644
--- a/drivers/clocksource/pxa_timer.c
+++ b/drivers/clocksource/pxa_timer.c
@@ -213,7 +213,7 @@ static int __init pxa_timer_dt_init(struct device_node *np)
 
 	return pxa_timer_common_init(irq, clk_get_rate(clk));
 }
-CLOCKSOURCE_OF_DECLARE_RET(pxa_timer, "marvell,pxa-timer", pxa_timer_dt_init);
+CLOCKSOURCE_OF_DECLARE(pxa_timer, "marvell,pxa-timer", pxa_timer_dt_init);
 
 /*
  * Legacy timer init for non device-tree boards.
diff --git a/drivers/clocksource/qcom-timer.c b/drivers/clocksource/qcom-timer.c
index 79f73bd..6625763 100644
--- a/drivers/clocksource/qcom-timer.c
+++ b/drivers/clocksource/qcom-timer.c
@@ -273,5 +273,5 @@ static int __init msm_dt_timer_init(struct device_node *np)
 
 	return msm_timer_init(freq, 32, irq, !!percpu_offset);
 }
-CLOCKSOURCE_OF_DECLARE_RET(kpss_timer, "qcom,kpss-timer", msm_dt_timer_init);
-CLOCKSOURCE_OF_DECLARE_RET(scss_timer, "qcom,scss-timer", msm_dt_timer_init);
+CLOCKSOURCE_OF_DECLARE(kpss_timer, "qcom,kpss-timer", msm_dt_timer_init);
+CLOCKSOURCE_OF_DECLARE(scss_timer, "qcom,scss-timer", msm_dt_timer_init);
diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c
index 85aee69..23e267a 100644
--- a/drivers/clocksource/rockchip_timer.c
+++ b/drivers/clocksource/rockchip_timer.c
@@ -205,7 +205,7 @@ static int __init rk3399_timer_init(struct device_node *np)
 	return rk_timer_init(np, TIMER_CONTROL_REG3399);
 }
 
-CLOCKSOURCE_OF_DECLARE_RET(rk3288_timer, "rockchip,rk3288-timer",
-			   rk3288_timer_init);
-CLOCKSOURCE_OF_DECLARE_RET(rk3399_timer, "rockchip,rk3399-timer",
-			   rk3399_timer_init);
+CLOCKSOURCE_OF_DECLARE(rk3288_timer, "rockchip,rk3288-timer",
+		       rk3288_timer_init);
+CLOCKSOURCE_OF_DECLARE(rk3399_timer, "rockchip,rk3399-timer",
+		       rk3399_timer_init);
diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c
index 27a9797..54565bd 100644
--- a/drivers/clocksource/samsung_pwm_timer.c
+++ b/drivers/clocksource/samsung_pwm_timer.c
@@ -466,7 +466,7 @@ static int __init s3c2410_pwm_clocksource_init(struct device_node *np)
 {
 	return samsung_pwm_alloc(np, &s3c24xx_variant);
 }
-CLOCKSOURCE_OF_DECLARE_RET(s3c2410_pwm, "samsung,s3c2410-pwm", s3c2410_pwm_clocksource_init);
+CLOCKSOURCE_OF_DECLARE(s3c2410_pwm, "samsung,s3c2410-pwm", s3c2410_pwm_clocksource_init);
 
 static const struct samsung_pwm_variant s3c64xx_variant = {
 	.bits		= 32,
@@ -479,7 +479,7 @@ static int __init s3c64xx_pwm_clocksource_init(struct device_node *np)
 {
 	return samsung_pwm_alloc(np, &s3c64xx_variant);
 }
-CLOCKSOURCE_OF_DECLARE_RET(s3c6400_pwm, "samsung,s3c6400-pwm", s3c64xx_pwm_clocksource_init);
+CLOCKSOURCE_OF_DECLARE(s3c6400_pwm, "samsung,s3c6400-pwm", s3c64xx_pwm_clocksource_init);
 
 static const struct samsung_pwm_variant s5p64x0_variant = {
 	.bits		= 32,
@@ -492,7 +492,7 @@ static int __init s5p64x0_pwm_clocksource_init(struct device_node *np)
 {
 	return samsung_pwm_alloc(np, &s5p64x0_variant);
 }
-CLOCKSOURCE_OF_DECLARE_RET(s5p6440_pwm, "samsung,s5p6440-pwm", s5p64x0_pwm_clocksource_init);
+CLOCKSOURCE_OF_DECLARE(s5p6440_pwm, "samsung,s5p6440-pwm", s5p64x0_pwm_clocksource_init);
 
 static const struct samsung_pwm_variant s5p_variant = {
 	.bits		= 32,
@@ -505,5 +505,5 @@ static int __init s5p_pwm_clocksource_init(struct device_node *np)
 {
 	return samsung_pwm_alloc(np, &s5p_variant);
 }
-CLOCKSOURCE_OF_DECLARE_RET(s5pc100_pwm, "samsung,s5pc100-pwm", s5p_pwm_clocksource_init);
+CLOCKSOURCE_OF_DECLARE(s5pc100_pwm, "samsung,s5pc100-pwm", s5p_pwm_clocksource_init);
 #endif
diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c
index 4453730..97669ee 100644
--- a/drivers/clocksource/sun4i_timer.c
+++ b/drivers/clocksource/sun4i_timer.c
@@ -226,5 +226,5 @@ static int __init sun4i_timer_init(struct device_node *node)
 
 	return ret;
 }
-CLOCKSOURCE_OF_DECLARE_RET(sun4i, "allwinner,sun4i-a10-timer",
+CLOCKSOURCE_OF_DECLARE(sun4i, "allwinner,sun4i-a10-timer",
 		       sun4i_timer_init);
diff --git a/drivers/clocksource/tango_xtal.c b/drivers/clocksource/tango_xtal.c
index 7dc716c..12fcef8 100644
--- a/drivers/clocksource/tango_xtal.c
+++ b/drivers/clocksource/tango_xtal.c
@@ -53,4 +53,4 @@ static int __init tango_clocksource_init(struct device_node *np)
 	return 0;
 }
 
-CLOCKSOURCE_OF_DECLARE_RET(tango, "sigma,tick-counter", tango_clocksource_init);
+CLOCKSOURCE_OF_DECLARE(tango, "sigma,tick-counter", tango_clocksource_init);
diff --git a/drivers/clocksource/tegra20_timer.c b/drivers/clocksource/tegra20_timer.c
index 543c37e..f960891 100644
--- a/drivers/clocksource/tegra20_timer.c
+++ b/drivers/clocksource/tegra20_timer.c
@@ -237,7 +237,7 @@ static int __init tegra20_init_timer(struct device_node *np)
 
 	return 0;
 }
-CLOCKSOURCE_OF_DECLARE_RET(tegra20_timer, "nvidia,tegra20-timer", tegra20_init_timer);
+CLOCKSOURCE_OF_DECLARE(tegra20_timer, "nvidia,tegra20-timer", tegra20_init_timer);
 
 static int __init tegra20_init_rtc(struct device_node *np)
 {
@@ -261,4 +261,4 @@ static int __init tegra20_init_rtc(struct device_node *np)
 
 	return register_persistent_clock(NULL, tegra_read_persistent_clock64);
 }
-CLOCKSOURCE_OF_DECLARE_RET(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc);
+CLOCKSOURCE_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc);
diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c
index bc4ab48..a4e5923 100644
--- a/drivers/clocksource/time-armada-370-xp.c
+++ b/drivers/clocksource/time-armada-370-xp.c
@@ -371,7 +371,7 @@ static int __init armada_xp_timer_init(struct device_node *np)
 
 	return armada_370_xp_timer_common_init(np);
 }
-CLOCKSOURCE_OF_DECLARE_RET(armada_xp, "marvell,armada-xp-timer",
+CLOCKSOURCE_OF_DECLARE(armada_xp, "marvell,armada-xp-timer",
 		       armada_xp_timer_init);
 
 static int __init armada_375_timer_init(struct device_node *np)
@@ -409,7 +409,7 @@ static int __init armada_375_timer_init(struct device_node *np)
 
 	return armada_370_xp_timer_common_init(np);
 }
-CLOCKSOURCE_OF_DECLARE_RET(armada_375, "marvell,armada-375-timer",
+CLOCKSOURCE_OF_DECLARE(armada_375, "marvell,armada-375-timer",
 		       armada_375_timer_init);
 
 static int __init armada_370_timer_init(struct device_node *np)
@@ -432,5 +432,5 @@ static int __init armada_370_timer_init(struct device_node *np)
 
 	return armada_370_xp_timer_common_init(np);
 }
-CLOCKSOURCE_OF_DECLARE_RET(armada_370, "marvell,armada-370-timer",
+CLOCKSOURCE_OF_DECLARE(armada_370, "marvell,armada-370-timer",
 		       armada_370_timer_init);
diff --git a/drivers/clocksource/time-efm32.c b/drivers/clocksource/time-efm32.c
index 6e2f79f..5ac344b 100644
--- a/drivers/clocksource/time-efm32.c
+++ b/drivers/clocksource/time-efm32.c
@@ -283,5 +283,5 @@ static int __init efm32_timer_init(struct device_node *np)
 
 	return ret;
 }
-CLOCKSOURCE_OF_DECLARE_RET(efm32compat, "efm32,timer", efm32_timer_init);
-CLOCKSOURCE_OF_DECLARE_RET(efm32, "energymicro,efm32-timer", efm32_timer_init);
+CLOCKSOURCE_OF_DECLARE(efm32compat, "efm32,timer", efm32_timer_init);
+CLOCKSOURCE_OF_DECLARE(efm32, "energymicro,efm32-timer", efm32_timer_init);
diff --git a/drivers/clocksource/time-lpc32xx.c b/drivers/clocksource/time-lpc32xx.c
index cb5b866..9649cfd 100644
--- a/drivers/clocksource/time-lpc32xx.c
+++ b/drivers/clocksource/time-lpc32xx.c
@@ -311,4 +311,4 @@ static int __init lpc32xx_timer_init(struct device_node *np)
 
 	return ret;
 }
-CLOCKSOURCE_OF_DECLARE_RET(lpc32xx_timer, "nxp,lpc3220-timer", lpc32xx_timer_init);
+CLOCKSOURCE_OF_DECLARE(lpc32xx_timer, "nxp,lpc3220-timer", lpc32xx_timer_init);
diff --git a/drivers/clocksource/time-orion.c b/drivers/clocksource/time-orion.c
index 5fdeb5d..a28f496 100644
--- a/drivers/clocksource/time-orion.c
+++ b/drivers/clocksource/time-orion.c
@@ -167,4 +167,4 @@ static int __init orion_timer_init(struct device_node *np)
 
 	return 0;
 }
-CLOCKSOURCE_OF_DECLARE_RET(orion_timer, "marvell,orion-timer", orion_timer_init);
+CLOCKSOURCE_OF_DECLARE(orion_timer, "marvell,orion-timer", orion_timer_init);
diff --git a/drivers/clocksource/time-pistachio.c b/drivers/clocksource/time-pistachio.c
index adaaec5..a7d9a08 100644
--- a/drivers/clocksource/time-pistachio.c
+++ b/drivers/clocksource/time-pistachio.c
@@ -214,5 +214,5 @@ static int __init pistachio_clksrc_of_init(struct device_node *node)
 	sched_clock_register(pistachio_read_sched_clock, 32, rate);
 	return clocksource_register_hz(&pcs_gpt.cs, rate);
 }
-CLOCKSOURCE_OF_DECLARE_RET(pistachio_gptimer, "img,pistachio-gptimer",
+CLOCKSOURCE_OF_DECLARE(pistachio_gptimer, "img,pistachio-gptimer",
 		       pistachio_clksrc_of_init);
diff --git a/drivers/clocksource/timer-atlas7.c b/drivers/clocksource/timer-atlas7.c
index 7b1a007..90f8fbc 100644
--- a/drivers/clocksource/timer-atlas7.c
+++ b/drivers/clocksource/timer-atlas7.c
@@ -304,4 +304,4 @@ static int __init sirfsoc_of_timer_init(struct device_node *np)
 
 	return sirfsoc_atlas7_timer_init(np);
 }
-CLOCKSOURCE_OF_DECLARE_RET(sirfsoc_atlas7_timer, "sirf,atlas7-tick", sirfsoc_of_timer_init);
+CLOCKSOURCE_OF_DECLARE(sirfsoc_atlas7_timer, "sirf,atlas7-tick", sirfsoc_of_timer_init);
diff --git a/drivers/clocksource/timer-atmel-pit.c b/drivers/clocksource/timer-atmel-pit.c
index ffaca7c..1ffac0c 100644
--- a/drivers/clocksource/timer-atmel-pit.c
+++ b/drivers/clocksource/timer-atmel-pit.c
@@ -270,5 +270,5 @@ static int __init at91sam926x_pit_dt_init(struct device_node *node)
 
 	return at91sam926x_pit_common_init(data);
 }
-CLOCKSOURCE_OF_DECLARE_RET(at91sam926x_pit, "atmel,at91sam9260-pit",
+CLOCKSOURCE_OF_DECLARE(at91sam926x_pit, "atmel,at91sam9260-pit",
 		       at91sam926x_pit_dt_init);
diff --git a/drivers/clocksource/timer-atmel-st.c b/drivers/clocksource/timer-atmel-st.c
index e9331d3..e90ab5b 100644
--- a/drivers/clocksource/timer-atmel-st.c
+++ b/drivers/clocksource/timer-atmel-st.c
@@ -260,5 +260,5 @@ static int __init atmel_st_timer_init(struct device_node *node)
 	/* register clocksource */
 	return clocksource_register_hz(&clk32k, sclk_rate);
 }
-CLOCKSOURCE_OF_DECLARE_RET(atmel_st_timer, "atmel,at91rm9200-st",
+CLOCKSOURCE_OF_DECLARE(atmel_st_timer, "atmel,at91rm9200-st",
 		       atmel_st_timer_init);
diff --git a/drivers/clocksource/timer-digicolor.c b/drivers/clocksource/timer-digicolor.c
index b929061..10318cc 100644
--- a/drivers/clocksource/timer-digicolor.c
+++ b/drivers/clocksource/timer-digicolor.c
@@ -202,5 +202,5 @@ static int __init digicolor_timer_init(struct device_node *node)
 
 	return 0;
 }
-CLOCKSOURCE_OF_DECLARE_RET(conexant_digicolor, "cnxt,cx92755-timer",
+CLOCKSOURCE_OF_DECLARE(conexant_digicolor, "cnxt,cx92755-timer",
 		       digicolor_timer_init);
diff --git a/drivers/clocksource/timer-imx-gpt.c b/drivers/clocksource/timer-imx-gpt.c
index d5640a74..f595460 100644
--- a/drivers/clocksource/timer-imx-gpt.c
+++ b/drivers/clocksource/timer-imx-gpt.c
@@ -545,15 +545,15 @@ static int __init imx6dl_timer_init_dt(struct device_node *np)
 	return mxc_timer_init_dt(np, GPT_TYPE_IMX6DL);
 }
 
-CLOCKSOURCE_OF_DECLARE_RET(imx1_timer, "fsl,imx1-gpt", imx1_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE_RET(imx21_timer, "fsl,imx21-gpt", imx21_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE_RET(imx27_timer, "fsl,imx27-gpt", imx21_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE_RET(imx31_timer, "fsl,imx31-gpt", imx31_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE_RET(imx25_timer, "fsl,imx25-gpt", imx31_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE_RET(imx50_timer, "fsl,imx50-gpt", imx31_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE_RET(imx51_timer, "fsl,imx51-gpt", imx31_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE_RET(imx53_timer, "fsl,imx53-gpt", imx31_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE_RET(imx6q_timer, "fsl,imx6q-gpt", imx31_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE_RET(imx6dl_timer, "fsl,imx6dl-gpt", imx6dl_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE_RET(imx6sl_timer, "fsl,imx6sl-gpt", imx6dl_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE_RET(imx6sx_timer, "fsl,imx6sx-gpt", imx6dl_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx1_timer, "fsl,imx1-gpt", imx1_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx21_timer, "fsl,imx21-gpt", imx21_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx27_timer, "fsl,imx27-gpt", imx21_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx31_timer, "fsl,imx31-gpt", imx31_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx25_timer, "fsl,imx25-gpt", imx31_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx50_timer, "fsl,imx50-gpt", imx31_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx51_timer, "fsl,imx51-gpt", imx31_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx53_timer, "fsl,imx53-gpt", imx31_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx6q_timer, "fsl,imx6q-gpt", imx31_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx6dl_timer, "fsl,imx6dl-gpt", imx6dl_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx6sl_timer, "fsl,imx6sl-gpt", imx6dl_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx6sx_timer, "fsl,imx6sx-gpt", imx6dl_timer_init_dt);
diff --git a/drivers/clocksource/timer-integrator-ap.c b/drivers/clocksource/timer-integrator-ap.c
index 675face..df6e672 100644
--- a/drivers/clocksource/timer-integrator-ap.c
+++ b/drivers/clocksource/timer-integrator-ap.c
@@ -232,5 +232,5 @@ static int __init integrator_ap_timer_init_of(struct device_node *node)
 	return 0;
 }
 
-CLOCKSOURCE_OF_DECLARE_RET(integrator_ap_timer, "arm,integrator-timer",
+CLOCKSOURCE_OF_DECLARE(integrator_ap_timer, "arm,integrator-timer",
 		       integrator_ap_timer_init_of);
diff --git a/drivers/clocksource/timer-keystone.c b/drivers/clocksource/timer-keystone.c
index 4199823..ab68a47 100644
--- a/drivers/clocksource/timer-keystone.c
+++ b/drivers/clocksource/timer-keystone.c
@@ -226,5 +226,5 @@ err:
 	return error;
 }
 
-CLOCKSOURCE_OF_DECLARE_RET(keystone_timer, "ti,keystone-timer",
+CLOCKSOURCE_OF_DECLARE(keystone_timer, "ti,keystone-timer",
 			   keystone_timer_init);
diff --git a/drivers/clocksource/timer-nps.c b/drivers/clocksource/timer-nps.c
index b5c7b2b..70c149a 100644
--- a/drivers/clocksource/timer-nps.c
+++ b/drivers/clocksource/timer-nps.c
@@ -96,5 +96,5 @@ static int __init nps_timer_init(struct device_node *node)
 	return nps_setup_clocksource(node, clk);
 }
 
-CLOCKSOURCE_OF_DECLARE_RET(ezchip_nps400_clksrc, "ezchip,nps400-timer",
-			   nps_timer_init);
+CLOCKSOURCE_OF_DECLARE(ezchip_nps400_clksrc, "ezchip,nps400-timer",
+		       nps_timer_init);
diff --git a/drivers/clocksource/timer-oxnas-rps.c b/drivers/clocksource/timer-oxnas-rps.c
index 0d99f40..bd887e2 100644
--- a/drivers/clocksource/timer-oxnas-rps.c
+++ b/drivers/clocksource/timer-oxnas-rps.c
@@ -293,5 +293,5 @@ err_alloc:
 	return ret;
 }
 
-CLOCKSOURCE_OF_DECLARE_RET(ox810se_rps,
-			   "oxsemi,ox810se-rps-timer", oxnas_rps_timer_init);
+CLOCKSOURCE_OF_DECLARE(ox810se_rps,
+		       "oxsemi,ox810se-rps-timer", oxnas_rps_timer_init);
diff --git a/drivers/clocksource/timer-prima2.c b/drivers/clocksource/timer-prima2.c
index 7b1084d..dae8a66 100644
--- a/drivers/clocksource/timer-prima2.c
+++ b/drivers/clocksource/timer-prima2.c
@@ -246,5 +246,5 @@ static int __init sirfsoc_prima2_timer_init(struct device_node *np)
 
 	return 0;
 }
-CLOCKSOURCE_OF_DECLARE_RET(sirfsoc_prima2_timer,
+CLOCKSOURCE_OF_DECLARE(sirfsoc_prima2_timer,
 	"sirf,prima2-tick", sirfsoc_prima2_timer_init);
diff --git a/drivers/clocksource/timer-sp804.c b/drivers/clocksource/timer-sp804.c
index 3dc47ef..d078633 100644
--- a/drivers/clocksource/timer-sp804.c
+++ b/drivers/clocksource/timer-sp804.c
@@ -287,7 +287,7 @@ err:
 	iounmap(base);
 	return ret;
 }
-CLOCKSOURCE_OF_DECLARE_RET(sp804, "arm,sp804", sp804_of_init);
+CLOCKSOURCE_OF_DECLARE(sp804, "arm,sp804", sp804_of_init);
 
 static int __init integrator_cp_of_init(struct device_node *np)
 {
@@ -335,4 +335,4 @@ err:
 	iounmap(base);
 	return ret;
 }
-CLOCKSOURCE_OF_DECLARE_RET(intcp, "arm,integrator-cp-timer", integrator_cp_of_init);
+CLOCKSOURCE_OF_DECLARE(intcp, "arm,integrator-cp-timer", integrator_cp_of_init);
diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
index d5bf352..1b2574c 100644
--- a/drivers/clocksource/timer-stm32.c
+++ b/drivers/clocksource/timer-stm32.c
@@ -187,4 +187,4 @@ err_clk_get:
 	return ret;
 }
 
-CLOCKSOURCE_OF_DECLARE_RET(stm32, "st,stm32-timer", stm32_clockevent_init);
+CLOCKSOURCE_OF_DECLARE(stm32, "st,stm32-timer", stm32_clockevent_init);
diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c
index f0a3ffb..c184eb8 100644
--- a/drivers/clocksource/timer-sun5i.c
+++ b/drivers/clocksource/timer-sun5i.c
@@ -346,7 +346,7 @@ static int __init sun5i_timer_init(struct device_node *node)
 
 	return sun5i_setup_clockevent(node, timer_base, clk, irq);
 }
-CLOCKSOURCE_OF_DECLARE_RET(sun5i_a13, "allwinner,sun5i-a13-hstimer",
+CLOCKSOURCE_OF_DECLARE(sun5i_a13, "allwinner,sun5i-a13-hstimer",
 			   sun5i_timer_init);
-CLOCKSOURCE_OF_DECLARE_RET(sun7i_a20, "allwinner,sun7i-a20-hstimer",
+CLOCKSOURCE_OF_DECLARE(sun7i_a20, "allwinner,sun7i-a20-hstimer",
 			   sun5i_timer_init);
diff --git a/drivers/clocksource/timer-ti-32k.c b/drivers/clocksource/timer-ti-32k.c
index e4ad3c6e..92b7e39 100644
--- a/drivers/clocksource/timer-ti-32k.c
+++ b/drivers/clocksource/timer-ti-32k.c
@@ -124,5 +124,5 @@ static int __init ti_32k_timer_init(struct device_node *np)
 
 	return 0;
 }
-CLOCKSOURCE_OF_DECLARE_RET(ti_32k_timer, "ti,omap-counter32k",
+CLOCKSOURCE_OF_DECLARE(ti_32k_timer, "ti,omap-counter32k",
 		ti_32k_timer_init);
diff --git a/drivers/clocksource/timer-u300.c b/drivers/clocksource/timer-u300.c
index a6a0dec..704e40c 100644
--- a/drivers/clocksource/timer-u300.c
+++ b/drivers/clocksource/timer-u300.c
@@ -458,5 +458,5 @@ static int __init u300_timer_init_of(struct device_node *np)
 	return 0;
 }
 
-CLOCKSOURCE_OF_DECLARE_RET(u300_timer, "stericsson,u300-apptimer",
+CLOCKSOURCE_OF_DECLARE(u300_timer, "stericsson,u300-apptimer",
 		       u300_timer_init_of);
diff --git a/drivers/clocksource/versatile.c b/drivers/clocksource/versatile.c
index 8daeffa..220b490 100644
--- a/drivers/clocksource/versatile.c
+++ b/drivers/clocksource/versatile.c
@@ -38,7 +38,7 @@ static int __init versatile_sched_clock_init(struct device_node *node)
 
 	return 0;
 }
-CLOCKSOURCE_OF_DECLARE_RET(vexpress, "arm,vexpress-sysreg",
+CLOCKSOURCE_OF_DECLARE(vexpress, "arm,vexpress-sysreg",
 		       versatile_sched_clock_init);
-CLOCKSOURCE_OF_DECLARE_RET(versatile, "arm,versatile-sysreg",
+CLOCKSOURCE_OF_DECLARE(versatile, "arm,versatile-sysreg",
 		       versatile_sched_clock_init);
diff --git a/drivers/clocksource/vf_pit_timer.c b/drivers/clocksource/vf_pit_timer.c
index ca4dff4..55d8d84 100644
--- a/drivers/clocksource/vf_pit_timer.c
+++ b/drivers/clocksource/vf_pit_timer.c
@@ -201,4 +201,4 @@ static int __init pit_timer_init(struct device_node *np)
 
 	return pit_clockevent_init(clk_rate, irq);
 }
-CLOCKSOURCE_OF_DECLARE_RET(vf610, "fsl,vf610-pit", pit_timer_init);
+CLOCKSOURCE_OF_DECLARE(vf610, "fsl,vf610-pit", pit_timer_init);
diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/vt8500_timer.c
index 1bc8707..b150694 100644
--- a/drivers/clocksource/vt8500_timer.c
+++ b/drivers/clocksource/vt8500_timer.c
@@ -165,4 +165,4 @@ static int __init vt8500_timer_init(struct device_node *np)
 	return 0;
 }
 
-CLOCKSOURCE_OF_DECLARE_RET(vt8500, "via,vt8500-timer", vt8500_timer_init);
+CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init);
diff --git a/drivers/clocksource/zevio-timer.c b/drivers/clocksource/zevio-timer.c
index cb4cf056..9a53f5e 100644
--- a/drivers/clocksource/zevio-timer.c
+++ b/drivers/clocksource/zevio-timer.c
@@ -215,4 +215,4 @@ static int __init zevio_timer_init(struct device_node *node)
 	return zevio_timer_add(node);
 }
 
-CLOCKSOURCE_OF_DECLARE_RET(zevio_timer, "lsi,zevio-timer", zevio_timer_init);
+CLOCKSOURCE_OF_DECLARE(zevio_timer, "lsi,zevio-timer", zevio_timer_init);
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 8c6c626..6a67ab9 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -173,7 +173,6 @@
 	*(__##name##_of_table_end)
 
 #define CLKSRC_OF_TABLES()	OF_TABLE(CONFIG_CLKSRC_OF, clksrc)
-#define CLKSRC_RET_OF_TABLES()	OF_TABLE(CONFIG_CLKSRC_OF, clksrc_ret)
 #define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip)
 #define CLK_OF_TABLES()		OF_TABLE(CONFIG_COMMON_CLK, clk)
 #define IOMMU_OF_TABLES()	OF_TABLE(CONFIG_OF_IOMMU, iommu)
@@ -532,7 +531,6 @@
 	CLK_OF_TABLES()							\
 	RESERVEDMEM_OF_TABLES()						\
 	CLKSRC_OF_TABLES()						\
-	CLKSRC_RET_OF_TABLES()						\
 	IOMMU_OF_TABLES()						\
 	CPU_METHOD_OF_TABLES()						\
 	CPUIDLE_METHOD_OF_TABLES()					\
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 15c3839..0839818 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -244,10 +244,7 @@ extern int clocksource_mmio_init(void __iomem *, const char *,
 extern int clocksource_i8253_init(void);
 
 #define CLOCKSOURCE_OF_DECLARE(name, compat, fn) \
-	OF_DECLARE_1(clksrc, name, compat, fn)
-
-#define CLOCKSOURCE_OF_DECLARE_RET(name, compat, fn) \
-	OF_DECLARE_1_RET(clksrc_ret, name, compat, fn)
+	OF_DECLARE_1_RET(clksrc, name, compat, fn)
 
 #ifdef CONFIG_CLKSRC_PROBE
 extern void clocksource_probe(void);
-- 
1.9.1



From dan.carpenter at oracle.com  Thu Jul  7 01:14:04 2016
From: dan.carpenter at oracle.com (Dan Carpenter)
Date: Thu, 7 Jul 2016 11:14:04 +0300
Subject: [patch] ASoC: mediatek: mt2701: fix some error handling in probe
Message-ID: <20160707081404.GB16645@mwanda>

The check for if the "afe" allocation failed was too late and there
wasn't a check for "afe->platform_priv".

Fixes: 43a6a7e71063 ('ASoC: mediatek: add mt2701 platform driver implementation.')
Signed-off-by: Dan Carpenter <dan.carpenter at oracle.com>

diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
index c865ba1..fc5a87d 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
@@ -1350,11 +1350,13 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev)
 
 	ret = 0;
 	afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
+	if (!afe)
+		return -ENOMEM;
 	afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
 					  GFP_KERNEL);
-	afe_priv = afe->platform_priv;
-	if (!afe)
+	if (!afe->platform_priv)
 		return -ENOMEM;
+	afe_priv = afe->platform_priv;
 
 	afe->dev = &pdev->dev;
 	dev = afe->dev;


From garlic.tseng at mediatek.com  Thu Jul  7 01:26:54 2016
From: garlic.tseng at mediatek.com (Garlic Tseng)
Date: Thu, 7 Jul 2016 16:26:54 +0800
Subject: [patch] ASoC: mediatek: mt2701: fix some error handling in probe
In-Reply-To: <20160707081404.GB16645@mwanda>
References: <20160707081404.GB16645@mwanda>
Message-ID: <1467880014.11610.1.camel@mtksdaap41>

On Thu, 2016-07-07 at 11:14 +0300, Dan Carpenter wrote:
> The check for if the "afe" allocation failed was too late and there
> wasn't a check for "afe->platform_priv".
> 
> Fixes: 43a6a7e71063 ('ASoC: mediatek: add mt2701 platform driver implementation.')
> Signed-off-by: Dan Carpenter <dan.carpenter at oracle.com>
> 
> diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
> index c865ba1..fc5a87d 100644
> --- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
> +++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
> @@ -1350,11 +1350,13 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev)
>  
>  	ret = 0;
>  	afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
> +	if (!afe)
> +		return -ENOMEM;
>  	afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
>  					  GFP_KERNEL);
> -	afe_priv = afe->platform_priv;
> -	if (!afe)
> +	if (!afe->platform_priv)
>  		return -ENOMEM;
> +	afe_priv = afe->platform_priv;
>  
>  	afe->dev = &pdev->dev;
>  	dev = afe->dev;

Acked-by: Garlic Tseng <garlic.tseng at mediatek.com>



From dawei.chien at mediatek.com  Thu Jul  7 02:06:24 2016
From: dawei.chien at mediatek.com (Dawei Chien)
Date: Thu, 7 Jul 2016 17:06:24 +0800
Subject: [PATCH 1/3] dt-bindings: thermal: Add binding document for Mediatek
 thermal controller
In-Reply-To: <1467882386-40544-1-git-send-email-dawei.chien@mediatek.com>
References: <1467882386-40544-1-git-send-email-dawei.chien@mediatek.com>
Message-ID: <1467882386-40544-2-git-send-email-dawei.chien@mediatek.com>

This adds the device tree binding documentation for the mediatek thermal
controller found on Mediatek MT2701.

Signed-off-by: Dawei Chien <dawei.chien at mediatek.com>
---
 .../bindings/thermal/mediatek-thermal.txt          |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt b/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
index 81f9a51..bb55e79 100644
--- a/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
+++ b/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
@@ -8,7 +8,7 @@ apmixedsys register space via AHB bus accesses, so a phandle to the APMIXEDSYS
 is also needed.
 
 Required properties:
-- compatible: "mediatek,mt8173-thermal"
+- compatible: "mediatek,mt8173-thermal" or "mediatek,mt2701-thermal"
 - reg: Address range of the thermal controller
 - interrupts: IRQ for the thermal controller
 - clocks, clock-names: Clocks needed for the thermal controller. required
-- 
1.7.9.5



From dawei.chien at mediatek.com  Thu Jul  7 02:06:26 2016
From: dawei.chien at mediatek.com (Dawei Chien)
Date: Thu, 7 Jul 2016 17:06:26 +0800
Subject: [PATCH 3/3] arm: dts: thermal: add thermal/auxadc node.
In-Reply-To: <1467882386-40544-1-git-send-email-dawei.chien@mediatek.com>
References: <1467882386-40544-1-git-send-email-dawei.chien@mediatek.com>
Message-ID: <1467882386-40544-4-git-send-email-dawei.chien@mediatek.com>

This adds the thermal controller and auxadc nodes
to the Mediatek MT2701 dtsi file.

Signed-off-by: Dawei Chien <dawei.chien at mediatek.com>
---
This patch depned on:
https://patchwork.kernel.org/patch/9213545/
---
 arch/arm/boot/dts/mt2701.dtsi |   43 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
index 2ac8b50..0834a23 100644
--- a/arch/arm/boot/dts/mt2701.dtsi
+++ b/arch/arm/boot/dts/mt2701.dtsi
@@ -77,6 +77,36 @@
 		#clock-cells = <0>;
 	};
 
+	thermal-zones {
+		cpu_thermal: cpu_thermal {
+			polling-delay-passive = <1000>; /* milliseconds */
+			polling-delay = <1000>; /* milliseconds */
+
+			thermal-sensors = <&thermal 0>;
+			sustainable-power = <1000>;
+
+			trips {
+				threshold: trip-point at 0 {
+					temperature = <68000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				target: trip-point at 1 {
+					temperature = <85000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_crit: cpu_crit at 0 {
+					temperature = <115000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+	};
+
 	timer {
 		compatible = "arm,armv7-timer";
 		interrupt-parent = <&gic>;
@@ -183,4 +213,17 @@
 		clocks = <&uart_clk>;
 		status = "disabled";
 	};
+
+	thermal: thermal at 1100b000 {
+		#thermal-sensor-cells = <0>;
+		compatible = "mediatek,mt2701-thermal";
+		reg = <0 0x1100b000 0 0x1000>;
+		interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&pericfg CLK_PERI_THERM>, <&pericfg CLK_PERI_AUXADC>;
+		clock-names = "therm", "auxadc";
+		resets = <&pericfg 0x10>;
+		reset-names = "therm";
+		mediatek,auxadc = <&auxadc>;
+		mediatek,apmixedsys = <&apmixedsys>;
+	};
 };
-- 
1.7.9.5



From dawei.chien at mediatek.com  Thu Jul  7 02:06:23 2016
From: dawei.chien at mediatek.com (Dawei Chien)
Date: Thu, 7 Jul 2016 17:06:23 +0800
Subject: [PATCH 0/3] thermal: Add Mediatek thermal driver for mt2701
Message-ID: <1467882386-40544-1-git-send-email-dawei.chien@mediatek.com>

This series support for mt2701 chip to mtk_thermal.c,
and integrate both mt8173 and mt2701 on the same driver.
MT8173 has four banks and five sensors, and MT2701 has
only one bank and three sensors.



From dawei.chien at mediatek.com  Thu Jul  7 02:06:25 2016
From: dawei.chien at mediatek.com (Dawei Chien)
Date: Thu, 7 Jul 2016 17:06:25 +0800
Subject: [PATCH 2/3] thermal: Add Mediatek thermal driver for mt2701.
In-Reply-To: <1467882386-40544-1-git-send-email-dawei.chien@mediatek.com>
References: <1467882386-40544-1-git-send-email-dawei.chien@mediatek.com>
Message-ID: <1467882386-40544-3-git-send-email-dawei.chien@mediatek.com>

This patch adds support for mt2701 chip to mtk_thermal.c,
and integrate both mt8173 and mt2701 on the same driver.
MT8173 has four banks and five sensors, and MT2701 has
only one bank and three sensors.

Signed-off-by: Dawei Chien <dawei.chien at mediatek.com>
---
 drivers/thermal/mtk_thermal.c |  258 ++++++++++++++++++++++++++---------------
 1 file changed, 165 insertions(+), 93 deletions(-)

diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c
index 262ab0a..860f2e2 100644
--- a/drivers/thermal/mtk_thermal.c
+++ b/drivers/thermal/mtk_thermal.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2015 MediaTek Inc.
  * Author: Hanyi Wu <hanyi.wu at mediatek.com>
  *         Sascha Hauer <s.hauer at pengutronix.de>
+ *         Dawei Chien <dawei.chien at mediatek.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -21,6 +22,7 @@
 #include <linux/nvmem-consumer.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/io.h>
@@ -88,6 +90,7 @@
 #define TEMP_ADCVALIDMASK_VALID_HIGH		BIT(5)
 #define TEMP_ADCVALIDMASK_VALID_POS(bit)	(bit)
 
+/* MT8173 thermal sensors */
 #define MT8173_TS1	0
 #define MT8173_TS2	1
 #define MT8173_TS3	2
@@ -97,35 +100,62 @@
 /* AUXADC channel 11 is used for the temperature sensors */
 #define MT8173_TEMP_AUXADC_CHANNEL	11
 
-/* The total number of temperature sensors in the MT8173 */
-#define MT8173_NUM_SENSORS		5
-
-/* The number of banks in the MT8173 */
-#define MT8173_NUM_ZONES		4
-
-/* The number of sensing points per bank */
-#define MT8173_NUM_SENSORS_PER_ZONE	4
-
 /* Layout of the fuses providing the calibration data */
-#define MT8173_CALIB_BUF0_VALID		BIT(0)
-#define MT8173_CALIB_BUF1_ADC_GE(x)	(((x) >> 22) & 0x3ff)
-#define MT8173_CALIB_BUF0_VTS_TS1(x)	(((x) >> 17) & 0x1ff)
-#define MT8173_CALIB_BUF0_VTS_TS2(x)	(((x) >> 8) & 0x1ff)
-#define MT8173_CALIB_BUF1_VTS_TS3(x)	(((x) >> 0) & 0x1ff)
-#define MT8173_CALIB_BUF2_VTS_TS4(x)	(((x) >> 23) & 0x1ff)
-#define MT8173_CALIB_BUF2_VTS_TSABB(x)	(((x) >> 14) & 0x1ff)
-#define MT8173_CALIB_BUF0_DEGC_CALI(x)	(((x) >> 1) & 0x3f)
-#define MT8173_CALIB_BUF0_O_SLOPE(x)	(((x) >> 26) & 0x3f)
+#define CALIB_BUF0_VALID		BIT(0)
+#define CALIB_BUF1_ADC_GE(x)	(((x) >> 22) & 0x3ff)
+#define CALIB_BUF0_VTS_TS1(x)	(((x) >> 17) & 0x1ff)
+#define CALIB_BUF0_VTS_TS2(x)	(((x) >> 8) & 0x1ff)
+#define CALIB_BUF1_VTS_TS3(x)	(((x) >> 0) & 0x1ff)
+#define CALIB_BUF2_VTS_TS4(x)	(((x) >> 23) & 0x1ff)
+#define CALIB_BUF2_VTS_TS5(x)	(((x) >> 14) & 0x1ff)
+#define CALIB_BUF0_DEGC_CALI(x)	(((x) >> 1) & 0x3f)
+#define CALIB_BUF0_O_SLOPE(x)	(((x) >> 26) & 0x3f)
+
+#define NVMEM_TS1	0
+#define NVMEM_TS2	1
+#define NVMEM_TS3	2
+#define NVMEM_TS4	3
+#define NVMEM_TS5	4
+
+/* MT2701 thermal sensors */
+#define MT2701_TS1	0
+#define MT2701_TS2	1
+#define MT2701_TSABB	2
+
+/* AUXADC channel 11 is used for the temperature sensors */
+#define MT2701_TEMP_AUXADC_CHANNEL	11
 
 #define THERMAL_NAME    "mtk-thermal"
 
+/* Maximum support banks */
+#define MAX_NUM_BANK		5
+
 struct mtk_thermal;
 
+struct thermal_bank_cfg {
+	unsigned int num_sensors;
+	unsigned int sensors[MAX_NUM_BANK];
+};
+
 struct mtk_thermal_bank {
 	struct mtk_thermal *mt;
 	int id;
 };
 
+struct mtk_thermal_sense_point {
+	int msr;
+	int adcpnp;
+};
+
+struct mtk_thermal_data {
+	struct thermal_bank_cfg bank_data[MAX_NUM_BANK];
+	struct mtk_thermal_sense_point sensing_points[MAX_NUM_BANK];
+	int sensor_mux_values[MAX_NUM_BANK];
+	s32 num_banks;
+	s32 num_sensors;
+	s32 auxadc_channel;
+};
+
 struct mtk_thermal {
 	struct device *dev;
 	void __iomem *thermal_base;
@@ -133,27 +163,20 @@ struct mtk_thermal {
 	struct clk *clk_peri_therm;
 	struct clk *clk_auxadc;
 
-	struct mtk_thermal_bank banks[MT8173_NUM_ZONES];
-
+	struct mtk_thermal_bank banks[MAX_NUM_BANK];
+	const struct mtk_thermal_data *conf;
 	/* lock: for getting and putting banks */
 	struct mutex lock;
+	struct thermal_zone_device *tzd;
 
 	/* Calibration values */
 	s32 adc_ge;
 	s32 degc_cali;
 	s32 o_slope;
-	s32 vts[MT8173_NUM_SENSORS];
-
-};
-
-struct mtk_thermal_bank_cfg {
-	unsigned int num_sensors;
-	unsigned int sensors[MT8173_NUM_SENSORS_PER_ZONE];
+	s32 vts[MAX_NUM_BANK];
 };
 
-static const int sensor_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 };
-
-/*
+/**
  * The MT8173 thermal controller has four banks. Each bank can read up to
  * four temperature sensors simultaneously. The MT8173 has a total of 5
  * temperature sensors. We use each bank to measure a certain area of the
@@ -166,42 +189,76 @@ static const int sensor_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 };
  * data, and this indeed needs the temperatures of the individual banks
  * for making better decisions.
  */
-static const struct mtk_thermal_bank_cfg bank_data[] = {
-	{
-		.num_sensors = 2,
-		.sensors = { MT8173_TS2, MT8173_TS3 },
-	}, {
-		.num_sensors = 2,
-		.sensors = { MT8173_TS2, MT8173_TS4 },
-	}, {
-		.num_sensors = 3,
-		.sensors = { MT8173_TS1, MT8173_TS2, MT8173_TSABB },
-	}, {
-		.num_sensors = 1,
-		.sensors = { MT8173_TS2 },
+static const struct mtk_thermal_data mt8173_thermal_data = {
+	.auxadc_channel = MT8173_TEMP_AUXADC_CHANNEL,
+	.num_banks = 4,
+	.num_sensors = 5,
+	.bank_data = {
+		{
+			.num_sensors = 2,
+			.sensors = { MT8173_TS2, MT8173_TS3 },
+		}, {
+			.num_sensors = 2,
+			.sensors = { MT8173_TS2, MT8173_TS4 },
+		}, {
+			.num_sensors = 3,
+			.sensors = { MT8173_TS1, MT8173_TS2, MT8173_TSABB },
+		}, {
+			.num_sensors = 1,
+			.sensors = { MT8173_TS2 },
+		},
 	},
+	.sensing_points = {
+		{
+			.msr = TEMP_MSR0,
+			.adcpnp = TEMP_ADCPNP0,
+		}, {
+			.msr = TEMP_MSR1,
+			.adcpnp = TEMP_ADCPNP1,
+		}, {
+			.msr = TEMP_MSR2,
+			.adcpnp = TEMP_ADCPNP2,
+		}, {
+			.msr = TEMP_MSR3,
+			.adcpnp = TEMP_ADCPNP3,
+		},
+	},
+	.sensor_mux_values = { 0, 1, 2, 3, 16 },
 };
 
-struct mtk_thermal_sense_point {
-	int msr;
-	int adcpnp;
-};
-
-static const struct mtk_thermal_sense_point
-		sensing_points[MT8173_NUM_SENSORS_PER_ZONE] = {
-	{
-		.msr = TEMP_MSR0,
-		.adcpnp = TEMP_ADCPNP0,
-	}, {
-		.msr = TEMP_MSR1,
-		.adcpnp = TEMP_ADCPNP1,
-	}, {
-		.msr = TEMP_MSR2,
-		.adcpnp = TEMP_ADCPNP2,
-	}, {
-		.msr = TEMP_MSR3,
-		.adcpnp = TEMP_ADCPNP3,
+/**
+ * The MT2701 thermal controller has one bank, which can read up to
+ * three temperature sensors simultaneously. The MT2701 has a total of 3
+ * temperature sensors.
+ *
+ * The thermal core only gets the maximum temperature of this one bank,
+ * so the bank concept wouldn't be necessary here. However, the SVS (Smart
+ * Voltage Scaling) unit makes its decisions based on the same bank
+ * data.
+ */
+static const struct mtk_thermal_data mt2701_thermal_data = {
+	.auxadc_channel = MT2701_TEMP_AUXADC_CHANNEL,
+	.num_banks = 1,
+	.num_sensors = 3,
+	.bank_data = {
+		{
+			.num_sensors = 3,
+			.sensors = { MT2701_TS1, MT2701_TS2, MT2701_TSABB },
+		},
 	},
+	.sensing_points = {
+		{
+			.msr = TEMP_MSR0,
+			.adcpnp = TEMP_ADCPNP0,
+		}, {
+			.msr = TEMP_MSR1,
+			.adcpnp = TEMP_ADCPNP1,
+		}, {
+			.msr = TEMP_MSR2,
+			.adcpnp = TEMP_ADCPNP2,
+		},
+	},
+	.sensor_mux_values = { 0, 1, 16},
 };
 
 /**
@@ -270,13 +327,15 @@ static void mtk_thermal_put_bank(struct mtk_thermal_bank *bank)
 static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank)
 {
 	struct mtk_thermal *mt = bank->mt;
+	const struct mtk_thermal_data *conf = mt->conf;
 	int i, temp = INT_MIN, max = INT_MIN;
 	u32 raw;
 
-	for (i = 0; i < bank_data[bank->id].num_sensors; i++) {
-		raw = readl(mt->thermal_base + sensing_points[i].msr);
+	for (i = 0; i < conf->bank_data[bank->id].num_sensors; i++) {
+		raw = readl(mt->thermal_base + conf->sensing_points[i].msr);
 
-		temp = raw_to_mcelsius(mt, bank_data[bank->id].sensors[i], raw);
+		temp = raw_to_mcelsius(mt, conf->bank_data[bank->id].sensors[i],
+				       raw);
 
 		/*
 		 * The first read of a sensor often contains very high bogus
@@ -299,7 +358,7 @@ static int mtk_read_temp(void *data, int *temperature)
 	int i;
 	int tempmax = INT_MIN;
 
-	for (i = 0; i < MT8173_NUM_ZONES; i++) {
+	for (i = 0; i < mt->conf->num_banks; i++) {
 		struct mtk_thermal_bank *bank = &mt->banks[i];
 
 		mtk_thermal_get_bank(bank);
@@ -322,7 +381,7 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num,
 				  u32 apmixed_phys_base, u32 auxadc_phys_base)
 {
 	struct mtk_thermal_bank *bank = &mt->banks[num];
-	const struct mtk_thermal_bank_cfg *cfg = &bank_data[num];
+	const struct mtk_thermal_data *conf = mt->conf;
 	int i;
 
 	bank->id = num;
@@ -368,7 +427,7 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num,
 	 * this value will be stored to TEMP_PNPMUXADDR (TEMP_SPARE0)
 	 * automatically by hw
 	 */
-	writel(BIT(MT8173_TEMP_AUXADC_CHANNEL), mt->thermal_base + TEMP_ADCMUX);
+	writel(BIT(conf->auxadc_channel), mt->thermal_base + TEMP_ADCMUX);
 
 	/* AHB address for auxadc mux selection */
 	writel(auxadc_phys_base + AUXADC_CON1_CLR_V,
@@ -379,18 +438,18 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num,
 	       mt->thermal_base + TEMP_PNPMUXADDR);
 
 	/* AHB value for auxadc enable */
-	writel(BIT(MT8173_TEMP_AUXADC_CHANNEL), mt->thermal_base + TEMP_ADCEN);
+	writel(BIT(conf->auxadc_channel), mt->thermal_base + TEMP_ADCEN);
 
 	/* AHB address for auxadc enable (channel 0 immediate mode selected) */
 	writel(auxadc_phys_base + AUXADC_CON1_SET_V,
 	       mt->thermal_base + TEMP_ADCENADDR);
 
 	/* AHB address for auxadc valid bit */
-	writel(auxadc_phys_base + AUXADC_DATA(MT8173_TEMP_AUXADC_CHANNEL),
+	writel(auxadc_phys_base + AUXADC_DATA(conf->auxadc_channel),
 	       mt->thermal_base + TEMP_ADCVALIDADDR);
 
 	/* AHB address for auxadc voltage output */
-	writel(auxadc_phys_base + AUXADC_DATA(MT8173_TEMP_AUXADC_CHANNEL),
+	writel(auxadc_phys_base + AUXADC_DATA(conf->auxadc_channel),
 	       mt->thermal_base + TEMP_ADCVOLTADDR);
 
 	/* read valid & voltage are at the same register */
@@ -407,11 +466,12 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num,
 	writel(TEMP_ADCWRITECTRL_ADC_MUX_WRITE,
 	       mt->thermal_base + TEMP_ADCWRITECTRL);
 
-	for (i = 0; i < cfg->num_sensors; i++)
-		writel(sensor_mux_values[cfg->sensors[i]],
-		       mt->thermal_base + sensing_points[i].adcpnp);
+	for (i = 0; i < conf->bank_data[num].num_sensors; i++)
+		writel(conf->sensor_mux_values[conf->bank_data[num].sensors[i]],
+		       mt->thermal_base + conf->sensing_points[i].adcpnp);
 
-	writel((1 << cfg->num_sensors) - 1, mt->thermal_base + TEMP_MONCTL0);
+	writel((1 << conf->bank_data[num].num_sensors) - 1,
+	       mt->thermal_base + TEMP_MONCTL0);
 
 	writel(TEMP_ADCWRITECTRL_ADC_PNP_WRITE |
 	       TEMP_ADCWRITECTRL_ADC_MUX_WRITE,
@@ -442,7 +502,7 @@ static int mtk_thermal_get_calibration_data(struct device *dev,
 
 	/* Start with default values */
 	mt->adc_ge = 512;
-	for (i = 0; i < MT8173_NUM_SENSORS; i++)
+	for (i = 0; i < mt->conf->num_sensors; i++)
 		mt->vts[i] = 260;
 	mt->degc_cali = 40;
 	mt->o_slope = 0;
@@ -467,15 +527,15 @@ static int mtk_thermal_get_calibration_data(struct device *dev,
 		goto out;
 	}
 
-	if (buf[0] & MT8173_CALIB_BUF0_VALID) {
-		mt->adc_ge = MT8173_CALIB_BUF1_ADC_GE(buf[1]);
-		mt->vts[MT8173_TS1] = MT8173_CALIB_BUF0_VTS_TS1(buf[0]);
-		mt->vts[MT8173_TS2] = MT8173_CALIB_BUF0_VTS_TS2(buf[0]);
-		mt->vts[MT8173_TS3] = MT8173_CALIB_BUF1_VTS_TS3(buf[1]);
-		mt->vts[MT8173_TS4] = MT8173_CALIB_BUF2_VTS_TS4(buf[2]);
-		mt->vts[MT8173_TSABB] = MT8173_CALIB_BUF2_VTS_TSABB(buf[2]);
-		mt->degc_cali = MT8173_CALIB_BUF0_DEGC_CALI(buf[0]);
-		mt->o_slope = MT8173_CALIB_BUF0_O_SLOPE(buf[0]);
+	if (buf[0] & CALIB_BUF0_VALID) {
+		mt->adc_ge = CALIB_BUF1_ADC_GE(buf[1]);
+		mt->vts[NVMEM_TS1] = CALIB_BUF0_VTS_TS1(buf[0]);
+		mt->vts[NVMEM_TS2] = CALIB_BUF0_VTS_TS2(buf[0]);
+		mt->vts[NVMEM_TS3] = CALIB_BUF1_VTS_TS3(buf[1]);
+		mt->vts[NVMEM_TS4] = CALIB_BUF2_VTS_TS4(buf[1]);
+		mt->vts[NVMEM_TS5] = CALIB_BUF2_VTS_TS5(buf[2]);
+		mt->degc_cali = CALIB_BUF0_DEGC_CALI(buf[0]);
+		mt->o_slope = CALIB_BUF0_O_SLOPE(buf[0]);
 	} else {
 		dev_info(dev, "Device not calibrated, using default calibration values\n");
 	}
@@ -486,18 +546,36 @@ out:
 	return ret;
 }
 
+static const struct of_device_id mtk_thermal_of_match[] = {
+	{
+		.compatible = "mediatek,mt8173-thermal",
+		.data = (void *)&mt8173_thermal_data,
+	},
+	{
+		.compatible = "mediatek,mt2701-thermal",
+		.data = (void *)&mt2701_thermal_data,
+	}, {
+	},
+};
+MODULE_DEVICE_TABLE(of, mtk_thermal_of_match);
+
 static int mtk_thermal_probe(struct platform_device *pdev)
 {
 	int ret, i;
 	struct device_node *auxadc, *apmixedsys, *np = pdev->dev.of_node;
 	struct mtk_thermal *mt;
 	struct resource *res;
+	const struct of_device_id *of_id;
 	u64 auxadc_phys_base, apmixed_phys_base;
 
 	mt = devm_kzalloc(&pdev->dev, sizeof(*mt), GFP_KERNEL);
 	if (!mt)
 		return -ENOMEM;
 
+	of_id = of_match_device(mtk_thermal_of_match, &pdev->dev);
+	if (of_id)
+		mt->conf = (const struct mtk_thermal_data *)of_id->data;
+
 	mt->clk_peri_therm = devm_clk_get(&pdev->dev, "therm");
 	if (IS_ERR(mt->clk_peri_therm))
 		return PTR_ERR(mt->clk_peri_therm);
@@ -565,7 +643,7 @@ static int mtk_thermal_probe(struct platform_device *pdev)
 		goto err_disable_clk_auxadc;
 	}
 
-	for (i = 0; i < MT8173_NUM_ZONES; i++)
+	for (i = 0; i < mt->conf->num_banks; i++)
 		mtk_thermal_init_bank(mt, i, apmixed_phys_base,
 				      auxadc_phys_base);
 
@@ -592,13 +670,6 @@ static int mtk_thermal_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static const struct of_device_id mtk_thermal_of_match[] = {
-	{
-		.compatible = "mediatek,mt8173-thermal",
-	}, {
-	},
-};
-
 static struct platform_driver mtk_thermal_driver = {
 	.probe = mtk_thermal_probe,
 	.remove = mtk_thermal_remove,
@@ -610,6 +681,7 @@ static struct platform_driver mtk_thermal_driver = {
 
 module_platform_driver(mtk_thermal_driver);
 
+MODULE_AUTHOR("Dawei Chien <dawei.chien at mediatek.com>");
 MODULE_AUTHOR("Sascha Hauer <s.hauer at pengutronix.de>");
 MODULE_AUTHOR("Hanyi Wu <hanyi.wu at mediatek.com>");
 MODULE_DESCRIPTION("Mediatek thermal driver");
-- 
1.7.9.5



From broonie at kernel.org  Thu Jul  7 03:01:08 2016
From: broonie at kernel.org (Mark Brown)
Date: Thu, 07 Jul 2016 12:01:08 +0200
Subject: Applied "ASoC: mediatek: mt2701: fix some error handling in probe" to
 the asoc tree
In-Reply-To: <20160707081404.GB16645@mwanda>
Message-ID: <E1bL67I-0000ii-Ks@finisterre>

The patch

   ASoC: mediatek: mt2701: fix some error handling in probe

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From b02c5cc7239b8f58ba5da24092288dd7a9a56acc Mon Sep 17 00:00:00 2001
From: Dan Carpenter <dan.carpenter at oracle.com>
Date: Thu, 7 Jul 2016 11:14:04 +0300
Subject: [PATCH] ASoC: mediatek: mt2701: fix some error handling in probe

The check for if the "afe" allocation failed was too late and there
wasn't a check for "afe->platform_priv".

Fixes: 43a6a7e71063 ('ASoC: mediatek: add mt2701 platform driver implementation.')
Signed-off-by: Dan Carpenter <dan.carpenter at oracle.com>
Acked-by: Garlic Tseng <garlic.tseng at mediatek.com>
Signed-off-by: Mark Brown <broonie at kernel.org>
---
 sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
index 6c14d686bfa1..15522c08a967 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
@@ -1489,11 +1489,13 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev)
 
 	ret = 0;
 	afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
+	if (!afe)
+		return -ENOMEM;
 	afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
 					  GFP_KERNEL);
-	afe_priv = afe->platform_priv;
-	if (!afe)
+	if (!afe->platform_priv)
 		return -ENOMEM;
+	afe_priv = afe->platform_priv;
 
 	afe->dev = &pdev->dev;
 	dev = afe->dev;
-- 
2.8.1



From tiffany.lin at mediatek.com  Thu Jul  7 03:16:52 2016
From: tiffany.lin at mediatek.com (tiffany lin)
Date: Thu, 7 Jul 2016 18:16:52 +0800
Subject: [PATCH v3 0/9] Add MT8173 Video Decoder Driver
In-Reply-To: <577D0576.2050706@xs4all.nl>
References: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
 <577D0576.2050706@xs4all.nl>
Message-ID: <1467886612.21382.18.camel@mtksdaap41>

Hi Hans,


On Wed, 2016-07-06 at 15:19 +0200, Hans Verkuil wrote:
> Hi Tiffany,
> 
> I plan to review this patch series on Friday, but one obvious question is
> what the reason for these failures is:
> 
> > 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_QUERYCTRL/MENU: OK
> >                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-controls.cpp(357): g_ctrl returned an error (11)
> >                 test VIDIOC_G/S_CTRL: FAIL
> >                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-controls.cpp(579): g_ext_ctrls returned an error (11)
> >                 test VIDIOC_G/S/TRY_EXT_CTRLS: FAIL
These fails are because VIDIOC_G_CTRL and VIDIOC_G_EXT_CTRLS return
V4L2_CID_MIN_BUFFERS_FOR_CAPTURE only when dirver in MTK_STATE_HEADER
state, or it will return EAGAIN.
This could help user space get correct value, not default value that may
changed base on media content.

> >                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-controls.cpp(721): subscribe event for control 'User Controls' failed
> >                 test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: FAIL
Driver do not support subscribe event for control 'User Controls' for
now.
Do we need to support this?

> >                 test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
> >                 Standard Controls: 2 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)
> >                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-formats.cpp(405): expected EINVAL, but got 11 when getting format for buftype 9
> >                 test VIDIOC_G_FMT: FAIL
This is because vidioc_vdec_g_fmt only succeed when context is in
MTK_STATE_HEADER state, or user space cannot get correct format data
using this function.

> >                 test VIDIOC_TRY_FMT: OK (Not Supported)
> >                 test VIDIOC_S_FMT: OK (Not Supported)
> >                 test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
> > 
> >         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
> >                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-buffers.cpp(500): q.has_expbuf(node)
Our OUTPUT and CAPTURE queue support both VB2_DMABUF and VB2_MMAP, user
space can select which to use in runtime.
So our driver default support v4l2_m2m_ioctl_expbuf functionality.
In v4l2-compliance test, it will check v4l2_m2m_ioctl_expbuf only valid
when node->valid_memorytype is V4L2_MEMORY_MMAP.
So when go through node->valid_memorytype is V4L2_MEMORY_DMABUF, it
fail.


best regards,
Tiffany



> >                 test VIDIOC_EXPBUF: FAIL
> > 
> > 
> > Total: 38, Succeeded: 33, Failed: 5, Warnings: 0
> 
> If it is due to a bug in v4l2-compliance, then let me know and I'll fix it. If not,
> then it should be fixed in the driver.
> 
> Frankly, it was the presence of these failures that made me think this patch series
> wasn't final. Before a v4l2 driver can be accepted in the kernel, v4l2-compliance must pass.
> 
> Regards,
> 
> 	Hans




From a0393675 at ti.com  Thu Jul  7 04:09:16 2016
From: a0393675 at ti.com (Keerthy)
Date: Thu, 7 Jul 2016 16:39:16 +0530
Subject: [PATCH 1/3] dt-bindings: thermal: Add binding document for
 Mediatek thermal controller
In-Reply-To: <1467882386-40544-2-git-send-email-dawei.chien@mediatek.com>
References: <1467882386-40544-1-git-send-email-dawei.chien@mediatek.com>
 <1467882386-40544-2-git-send-email-dawei.chien@mediatek.com>
Message-ID: <577E385C.9080501@ti.com>



On Thursday 07 July 2016 02:36 PM, Dawei Chien wrote:
> This adds the device tree binding documentation for the mediatek thermal
> controller found on Mediatek MT2701.
>
> Signed-off-by: Dawei Chien <dawei.chien at mediatek.com>
> ---
>   .../bindings/thermal/mediatek-thermal.txt          |    2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt b/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
> index 81f9a51..bb55e79 100644
> --- a/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
> +++ b/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
> @@ -8,7 +8,7 @@ apmixedsys register space via AHB bus accesses, so a phandle to the APMIXEDSYS
>   is also needed.
>
>   Required properties:
> -- compatible: "mediatek,mt8173-thermal"
> +- compatible: "mediatek,mt8173-thermal" or "mediatek,mt2701-thermal"

- compatible :
  - "mediatek,mt8173-thermal" : For MT8173 family of SoCs
  - "mediatek,mt2701-thermal" : For MT2701 family of SoCs

>   - reg: Address range of the thermal controller
>   - interrupts: IRQ for the thermal controller
>   - clocks, clock-names: Clocks needed for the thermal controller. required
>


From hansverk at cisco.com  Thu Jul  7 04:13:53 2016
From: hansverk at cisco.com (Hans Verkuil)
Date: Thu, 7 Jul 2016 13:13:53 +0200
Subject: [PATCH v3 0/9] Add MT8173 Video Decoder Driver
In-Reply-To: <1467886612.21382.18.camel@mtksdaap41>
References: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
 <577D0576.2050706@xs4all.nl> <1467886612.21382.18.camel@mtksdaap41>
Message-ID: <577E3971.1080305@cisco.com>

Hi Tiffany,

On 07/07/16 12:16, tiffany lin wrote:
> Hi Hans,
> 
> 
> On Wed, 2016-07-06 at 15:19 +0200, Hans Verkuil wrote:
>> Hi Tiffany,
>>
>> I plan to review this patch series on Friday, but one obvious question is
>> what the reason for these failures is:
>>
>>> 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_QUERYCTRL/MENU: OK
>>>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-controls.cpp(357): g_ctrl returned an error (11)
>>>                 test VIDIOC_G/S_CTRL: FAIL
>>>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-controls.cpp(579): g_ext_ctrls returned an error (11)
>>>                 test VIDIOC_G/S/TRY_EXT_CTRLS: FAIL
> These fails are because VIDIOC_G_CTRL and VIDIOC_G_EXT_CTRLS return
> V4L2_CID_MIN_BUFFERS_FOR_CAPTURE only when dirver in MTK_STATE_HEADER
> state, or it will return EAGAIN.
> This could help user space get correct value, not default value that may
> changed base on media content.

So this should be improved in v4l2-compliance.

> 
>>>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-controls.cpp(721): subscribe event for control 'User Controls' failed
>>>                 test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: FAIL
> Driver do not support subscribe event for control 'User Controls' for
> now.
> Do we need to support this?

Let me check: this might be a knock-on effect from the previous error.

Which controls does your driver have? (v4l2-ctl -l)

> 
>>>                 test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
>>>                 Standard Controls: 2 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)
>>>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-formats.cpp(405): expected EINVAL, but got 11 when getting format for buftype 9
>>>                 test VIDIOC_G_FMT: FAIL
> This is because vidioc_vdec_g_fmt only succeed when context is in
> MTK_STATE_HEADER state, or user space cannot get correct format data
> using this function.

I'll take a look at this as well.

> 
>>>                 test VIDIOC_TRY_FMT: OK (Not Supported)
>>>                 test VIDIOC_S_FMT: OK (Not Supported)
>>>                 test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
>>>
>>>         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
>>>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-buffers.cpp(500): q.has_expbuf(node)

Don't use v4l-utils-1.6: just use the latest master branch. That way you can
be certain that the latest fixes are in. Besides, 1.6.0 is really old (almost
two years!). If you used the same old version for the encoder driver as well,
then please retest that encoder driver!

> Our OUTPUT and CAPTURE queue support both VB2_DMABUF and VB2_MMAP, user
> space can select which to use in runtime.
> So our driver default support v4l2_m2m_ioctl_expbuf functionality.
> In v4l2-compliance test, it will check v4l2_m2m_ioctl_expbuf only valid
> when node->valid_memorytype is V4L2_MEMORY_MMAP.
> So when go through node->valid_memorytype is V4L2_MEMORY_DMABUF, it
> fail.

That sounds like a bug. I'll take a look. For all I know, this is fixed in the
master branch.

Regards,

	Hans

> 
> 
> best regards,
> Tiffany
> 
> 
> 
>>>                 test VIDIOC_EXPBUF: FAIL
>>>
>>>
>>> Total: 38, Succeeded: 33, Failed: 5, Warnings: 0
>>
>> If it is due to a bug in v4l2-compliance, then let me know and I'll fix it. If not,
>> then it should be fixed in the driver.
>>
>> Frankly, it was the presence of these failures that made me think this patch series
>> wasn't final. Before a v4l2 driver can be accepted in the kernel, v4l2-compliance must pass.
>>
>> Regards,
>>
>> 	Hans
> 
> 


From matthias.bgg at gmail.com  Thu Jul  7 04:20:09 2016
From: matthias.bgg at gmail.com (Matthias Brugger)
Date: Thu, 7 Jul 2016 13:20:09 +0200
Subject: [PATCH v7 1/4] soc: mediatek: Refine scpsys to support multiple
 platform
In-Reply-To: <1467783564.26485.22.camel@mtksdaap41>
References: <1463390894-32062-1-git-send-email-jamesjj.liao@mediatek.com>
 <1463390894-32062-2-git-send-email-jamesjj.liao@mediatek.com>
 <6762e420-0d68-0376-b584-bfc878b5e95f@gmail.com>
 <1467783564.26485.22.camel@mtksdaap41>
Message-ID: <577E3AE9.5080202@gmail.com>



On 06/07/16 07:39, James Liao wrote:
> Hi Matthias,
>
> On Sat, 2016-07-02 at 18:33 +0200, Matthias Brugger wrote:
>>
>> On 05/16/2016 11:28 AM, James Liao wrote:
>>> Refine scpsys driver common code to support multiple SoC / platform.
>>>
>>> Signed-off-by: James Liao <jamesjj.liao at mediatek.com>
>>> Reviewed-by: Kevin Hilman <khilman at baylibre.com>
>>> ---
>>>   drivers/soc/mediatek/mtk-scpsys.c | 363 +++++++++++++++++++++++---------------
>>>   1 file changed, 220 insertions(+), 143 deletions(-)
>>>
>>> diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
>>> index 57e781c..5870a24 100644
>>> --- a/drivers/soc/mediatek/mtk-scpsys.c
>>> +++ b/drivers/soc/mediatek/mtk-scpsys.c
>>> @@ -11,17 +11,15 @@
>>>    * GNU General Public License for more details.
>>>    */
>>>   #include <linux/clk.h>
>>> -#include <linux/delay.h>
>>> +#include <linux/init.h>
>>>   #include <linux/io.h>
>>> -#include <linux/kernel.h>
>>>   #include <linux/mfd/syscon.h>
>>> -#include <linux/init.h>
>>>   #include <linux/of_device.h>
>>>   #include <linux/platform_device.h>
>>>   #include <linux/pm_domain.h>
>>> -#include <linux/regmap.h>
>>> -#include <linux/soc/mediatek/infracfg.h>
>>>   #include <linux/regulator/consumer.h>
>>> +#include <linux/soc/mediatek/infracfg.h>
>>> +
>>>   #include <dt-bindings/power/mt8173-power.h>
>>>
>>>   #define SPM_VDE_PWR_CON			0x0210
>>> @@ -34,6 +32,7 @@
>>>   #define SPM_MFG_2D_PWR_CON		0x02c0
>>>   #define SPM_MFG_ASYNC_PWR_CON		0x02c4
>>>   #define SPM_USB_PWR_CON			0x02cc
>>> +
>>>   #define SPM_PWR_STATUS			0x060c
>>>   #define SPM_PWR_STATUS_2ND		0x0610
>>>
>>> @@ -55,12 +54,12 @@
>>>   #define PWR_STATUS_USB			BIT(25)
>>>
>>>   enum clk_id {
>>> -	MT8173_CLK_NONE,
>>> -	MT8173_CLK_MM,
>>> -	MT8173_CLK_MFG,
>>> -	MT8173_CLK_VENC,
>>> -	MT8173_CLK_VENC_LT,
>>> -	MT8173_CLK_MAX,
>>> +	CLK_NONE,
>>> +	CLK_MM,
>>> +	CLK_MFG,
>>> +	CLK_VENC,
>>> +	CLK_VENC_LT,
>>> +	CLK_MAX,
>>>   };
>>>
>>>   #define MAX_CLKS	2
>>> @@ -76,98 +75,6 @@ struct scp_domain_data {
>>>   	bool active_wakeup;
>>>   };
>>>
>>> -static const struct scp_domain_data scp_domain_data[] = {
>>> -	[MT8173_POWER_DOMAIN_VDEC] = {
>>> -		.name = "vdec",
>>> -		.sta_mask = PWR_STATUS_VDEC,
>>> -		.ctl_offs = SPM_VDE_PWR_CON,
>>> -		.sram_pdn_bits = GENMASK(11, 8),
>>> -		.sram_pdn_ack_bits = GENMASK(12, 12),
>>> -		.clk_id = {MT8173_CLK_MM},
>>> -	},
>>> -	[MT8173_POWER_DOMAIN_VENC] = {
>>> -		.name = "venc",
>>> -		.sta_mask = PWR_STATUS_VENC,
>>> -		.ctl_offs = SPM_VEN_PWR_CON,
>>> -		.sram_pdn_bits = GENMASK(11, 8),
>>> -		.sram_pdn_ack_bits = GENMASK(15, 12),
>>> -		.clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC},
>>> -	},
>>> -	[MT8173_POWER_DOMAIN_ISP] = {
>>> -		.name = "isp",
>>> -		.sta_mask = PWR_STATUS_ISP,
>>> -		.ctl_offs = SPM_ISP_PWR_CON,
>>> -		.sram_pdn_bits = GENMASK(11, 8),
>>> -		.sram_pdn_ack_bits = GENMASK(13, 12),
>>> -		.clk_id = {MT8173_CLK_MM},
>>> -	},
>>> -	[MT8173_POWER_DOMAIN_MM] = {
>>> -		.name = "mm",
>>> -		.sta_mask = PWR_STATUS_DISP,
>>> -		.ctl_offs = SPM_DIS_PWR_CON,
>>> -		.sram_pdn_bits = GENMASK(11, 8),
>>> -		.sram_pdn_ack_bits = GENMASK(12, 12),
>>> -		.clk_id = {MT8173_CLK_MM},
>>> -		.bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
>>> -			MT8173_TOP_AXI_PROT_EN_MM_M1,
>>> -	},
>>> -	[MT8173_POWER_DOMAIN_VENC_LT] = {
>>> -		.name = "venc_lt",
>>> -		.sta_mask = PWR_STATUS_VENC_LT,
>>> -		.ctl_offs = SPM_VEN2_PWR_CON,
>>> -		.sram_pdn_bits = GENMASK(11, 8),
>>> -		.sram_pdn_ack_bits = GENMASK(15, 12),
>>> -		.clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC_LT},
>>> -	},
>>> -	[MT8173_POWER_DOMAIN_AUDIO] = {
>>> -		.name = "audio",
>>> -		.sta_mask = PWR_STATUS_AUDIO,
>>> -		.ctl_offs = SPM_AUDIO_PWR_CON,
>>> -		.sram_pdn_bits = GENMASK(11, 8),
>>> -		.sram_pdn_ack_bits = GENMASK(15, 12),
>>> -		.clk_id = {MT8173_CLK_NONE},
>>> -	},
>>> -	[MT8173_POWER_DOMAIN_USB] = {
>>> -		.name = "usb",
>>> -		.sta_mask = PWR_STATUS_USB,
>>> -		.ctl_offs = SPM_USB_PWR_CON,
>>> -		.sram_pdn_bits = GENMASK(11, 8),
>>> -		.sram_pdn_ack_bits = GENMASK(15, 12),
>>> -		.clk_id = {MT8173_CLK_NONE},
>>> -		.active_wakeup = true,
>>> -	},
>>> -	[MT8173_POWER_DOMAIN_MFG_ASYNC] = {
>>> -		.name = "mfg_async",
>>> -		.sta_mask = PWR_STATUS_MFG_ASYNC,
>>> -		.ctl_offs = SPM_MFG_ASYNC_PWR_CON,
>>> -		.sram_pdn_bits = GENMASK(11, 8),
>>> -		.sram_pdn_ack_bits = 0,
>>> -		.clk_id = {MT8173_CLK_MFG},
>>> -	},
>>> -	[MT8173_POWER_DOMAIN_MFG_2D] = {
>>> -		.name = "mfg_2d",
>>> -		.sta_mask = PWR_STATUS_MFG_2D,
>>> -		.ctl_offs = SPM_MFG_2D_PWR_CON,
>>> -		.sram_pdn_bits = GENMASK(11, 8),
>>> -		.sram_pdn_ack_bits = GENMASK(13, 12),
>>> -		.clk_id = {MT8173_CLK_NONE},
>>> -	},
>>> -	[MT8173_POWER_DOMAIN_MFG] = {
>>> -		.name = "mfg",
>>> -		.sta_mask = PWR_STATUS_MFG,
>>> -		.ctl_offs = SPM_MFG_PWR_CON,
>>> -		.sram_pdn_bits = GENMASK(13, 8),
>>> -		.sram_pdn_ack_bits = GENMASK(21, 16),
>>> -		.clk_id = {MT8173_CLK_NONE},
>>> -		.bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
>>> -			MT8173_TOP_AXI_PROT_EN_MFG_M0 |
>>> -			MT8173_TOP_AXI_PROT_EN_MFG_M1 |
>>> -			MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT,
>>> -	},
>>> -};
>>> -
>>> -#define NUM_DOMAINS	ARRAY_SIZE(scp_domain_data)
>>> -
>>>   struct scp;
>>>
>>>   struct scp_domain {
>>> @@ -179,7 +86,7 @@ struct scp_domain {
>>>   };
>>>
>>>   struct scp {
>>> -	struct scp_domain domains[NUM_DOMAINS];
>>> +	struct scp_domain *domains;
>>>   	struct genpd_onecell_data pd_data;
>>>   	struct device *dev;
>>>   	void __iomem *base;
>>> @@ -408,57 +315,69 @@ static bool scpsys_active_wakeup(struct device *dev)
>>>   	return scpd->data->active_wakeup;
>>>   }
>>>
>>> -static int scpsys_probe(struct platform_device *pdev)
>>> +static void init_clks(struct platform_device *pdev, struct clk *clk[CLK_MAX])
>>> +{
>>> +	enum clk_id clk_ids[] = {
>>> +		CLK_MM,
>>> +		CLK_MFG,
>>> +		CLK_VENC,
>>> +		CLK_VENC_LT
>>> +	};
>>> +
>>> +	static const char * const clk_names[] = {
>>> +		"mm",
>>> +		"mfg",
>>> +		"venc",
>>> +		"venc_lt",
>>> +	};
>>> +
>>> +	int i;
>>> +
>>> +	for (i = 0; i < ARRAY_SIZE(clk_ids); i++)
>>> +		clk[clk_ids[i]] = devm_clk_get(&pdev->dev, clk_names[i]);
>>
>> We can use the global enum clk_id and stat with i = 1, right?
>
> You are right. I'll change the start value with i = CLK_NONE + 1 in next
> patch.
>
>>> +}
>>> +
>>> +static struct scp *init_scp(struct platform_device *pdev,
>>> +			const struct scp_domain_data *scp_domain_data, int num)
>>>   {
>>>   	struct genpd_onecell_data *pd_data;
>>>   	struct resource *res;
>>> -	int i, j, ret;
>>> +	int i, j;
>>>   	struct scp *scp;
>>> -	struct clk *clk[MT8173_CLK_MAX];
>>> +	struct clk *clk[CLK_MAX];
>>>
>>>   	scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL);
>>>   	if (!scp)
>>> -		return -ENOMEM;
>>> +		return ERR_PTR(-ENOMEM);
>>>
>>>   	scp->dev = &pdev->dev;
>>>
>>>   	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>   	scp->base = devm_ioremap_resource(&pdev->dev, res);
>>>   	if (IS_ERR(scp->base))
>>> -		return PTR_ERR(scp->base);
>>> -
>>> -	pd_data = &scp->pd_data;
>>> -
>>> -	pd_data->domains = devm_kzalloc(&pdev->dev,
>>> -			sizeof(*pd_data->domains) * NUM_DOMAINS, GFP_KERNEL);
>>> -	if (!pd_data->domains)
>>> -		return -ENOMEM;
>>> -
>>> -	clk[MT8173_CLK_MM] = devm_clk_get(&pdev->dev, "mm");
>>> -	if (IS_ERR(clk[MT8173_CLK_MM]))
>>> -		return PTR_ERR(clk[MT8173_CLK_MM]);
>>> -
>>> -	clk[MT8173_CLK_MFG] = devm_clk_get(&pdev->dev, "mfg");
>>> -	if (IS_ERR(clk[MT8173_CLK_MFG]))
>>> -		return PTR_ERR(clk[MT8173_CLK_MFG]);
>>> -
>>> -	clk[MT8173_CLK_VENC] = devm_clk_get(&pdev->dev, "venc");
>>> -	if (IS_ERR(clk[MT8173_CLK_VENC]))
>>> -		return PTR_ERR(clk[MT8173_CLK_VENC]);
>>> -
>>> -	clk[MT8173_CLK_VENC_LT] = devm_clk_get(&pdev->dev, "venc_lt");
>>> -	if (IS_ERR(clk[MT8173_CLK_VENC_LT]))
>>> -		return PTR_ERR(clk[MT8173_CLK_VENC_LT]);
>>> +		return ERR_CAST(scp->base);
>>>
>>>   	scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
>>>   			"infracfg");
>>>   	if (IS_ERR(scp->infracfg)) {
>>>   		dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n",
>>>   				PTR_ERR(scp->infracfg));
>>> -		return PTR_ERR(scp->infracfg);
>>> +		return ERR_CAST(scp->infracfg);
>>>   	}
>>>
>>> -	for (i = 0; i < NUM_DOMAINS; i++) {
>>> +	scp->domains = devm_kzalloc(&pdev->dev,
>>> +				sizeof(*scp->domains) * num, GFP_KERNEL);
>>> +	if (!scp->domains)
>>> +		return ERR_PTR(-ENOMEM);
>>> +
>>> +	pd_data = &scp->pd_data;
>>> +
>>> +	pd_data->domains = devm_kzalloc(&pdev->dev,
>>> +			sizeof(*pd_data->domains) * num, GFP_KERNEL);
>>> +	if (!pd_data->domains)
>>> +		return ERR_PTR(-ENOMEM);
>>> +
>>> +	for (i = 0; i < num; i++) {
>>>   		struct scp_domain *scpd = &scp->domains[i];
>>>   		const struct scp_domain_data *data = &scp_domain_data[i];
>>>
>>> @@ -467,28 +386,54 @@ static int scpsys_probe(struct platform_device *pdev)
>>>   			if (PTR_ERR(scpd->supply) == -ENODEV)
>>>   				scpd->supply = NULL;
>>>   			else
>>> -				return PTR_ERR(scpd->supply);
>>> +				return ERR_CAST(scpd->supply);
>>>   		}
>>>   	}
>>>
>>> -	pd_data->num_domains = NUM_DOMAINS;
>>> +	pd_data->num_domains = num;
>>>
>>> -	for (i = 0; i < NUM_DOMAINS; i++) {
>>> +	init_clks(pdev, clk);
>>> +
>>> +	for (i = 0; i < num; i++) {
>>>   		struct scp_domain *scpd = &scp->domains[i];
>>>   		struct generic_pm_domain *genpd = &scpd->genpd;
>>>   		const struct scp_domain_data *data = &scp_domain_data[i];
>>>
>>> +		for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
>>> +			struct clk *c = clk[data->clk_id[j]];
>>> +
>>> +			if (IS_ERR(c)) {
>>> +				dev_err(&pdev->dev, "%s: clk unavailable\n",
>>> +					data->name);
>>> +				return ERR_CAST(c);
>>> +			}
>>> +
>>> +			scpd->clk[j] = c;
>>
>> Put this in the else branch. Apart from that is there any reason you
>
> Do you mean to change like this?
>
> 	if (IS_ERR(c)) {
> 		...
> 		return ERR_CAST(c);
> 	} else {
> 		scpd->clk[j] = c;
> 	}
>
> checkpatch.pl will warn for above code due to it returns in 'if' branch.
>

I tried that on top of next-20160706 and it checkpatch didn't throw any 
warning. Which kernel version are based on?

>> moved the for up in the function? If not, I would prefer not to move it,
>> to make it easier to read the diff.
>
> The new 'for' block are far different from original one. And I think
> it's easy to read if we keep simple assign statements in the same block.
>

It's different in the sense that it checks if struct clk *c is an error.
I don't see the reason why we need to move it up in the file.
It's not too important but I would prefer not to move it if there is no 
reason.

Regards,
Matthias

>> Apart from that, the patch looks good to me.
>> Sorry for the delay in responding.
>
> Thanks for your comments.
>
>
> Best regards,
>
> James
>


From a0393675 at ti.com  Thu Jul  7 04:54:40 2016
From: a0393675 at ti.com (Keerthy)
Date: Thu, 7 Jul 2016 17:24:40 +0530
Subject: [PATCH 2/3] thermal: Add Mediatek thermal driver for mt2701.
In-Reply-To: <1467882386-40544-3-git-send-email-dawei.chien@mediatek.com>
References: <1467882386-40544-1-git-send-email-dawei.chien@mediatek.com>
 <1467882386-40544-3-git-send-email-dawei.chien@mediatek.com>
Message-ID: <577E4300.406@ti.com>

Hi Dawei Chien,


On Thursday 07 July 2016 02:36 PM, Dawei Chien wrote:
> This patch adds support for mt2701 chip to mtk_thermal.c,
> and integrate both mt8173 and mt2701 on the same driver.
> MT8173 has four banks and five sensors, and MT2701 has
> only one bank and three sensors.
>
> Signed-off-by: Dawei Chien <dawei.chien at mediatek.com>
> ---
>   drivers/thermal/mtk_thermal.c |  258 ++++++++++++++++++++++++++---------------
>   1 file changed, 165 insertions(+), 93 deletions(-)
>
> diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c
> index 262ab0a..860f2e2 100644
> --- a/drivers/thermal/mtk_thermal.c
> +++ b/drivers/thermal/mtk_thermal.c
> @@ -2,6 +2,7 @@
>    * Copyright (c) 2015 MediaTek Inc.
>    * Author: Hanyi Wu <hanyi.wu at mediatek.com>
>    *         Sascha Hauer <s.hauer at pengutronix.de>
> + *         Dawei Chien <dawei.chien at mediatek.com>
>    *
>    * This program is free software; you can redistribute it and/or modify
>    * it under the terms of the GNU General Public License version 2 as
> @@ -21,6 +22,7 @@
>   #include <linux/nvmem-consumer.h>
>   #include <linux/of.h>
>   #include <linux/of_address.h>
> +#include <linux/of_device.h>
>   #include <linux/platform_device.h>
>   #include <linux/slab.h>
>   #include <linux/io.h>
> @@ -88,6 +90,7 @@
>   #define TEMP_ADCVALIDMASK_VALID_HIGH		BIT(5)
>   #define TEMP_ADCVALIDMASK_VALID_POS(bit)	(bit)
>
> +/* MT8173 thermal sensors */
>   #define MT8173_TS1	0
>   #define MT8173_TS2	1
>   #define MT8173_TS3	2
> @@ -97,35 +100,62 @@
>   /* AUXADC channel 11 is used for the temperature sensors */
>   #define MT8173_TEMP_AUXADC_CHANNEL	11
>
> -/* The total number of temperature sensors in the MT8173 */
> -#define MT8173_NUM_SENSORS		5
> -
> -/* The number of banks in the MT8173 */
> -#define MT8173_NUM_ZONES		4
> -
> -/* The number of sensing points per bank */
> -#define MT8173_NUM_SENSORS_PER_ZONE	4
> -
>   /* Layout of the fuses providing the calibration data */
> -#define MT8173_CALIB_BUF0_VALID		BIT(0)
> -#define MT8173_CALIB_BUF1_ADC_GE(x)	(((x) >> 22) & 0x3ff)
> -#define MT8173_CALIB_BUF0_VTS_TS1(x)	(((x) >> 17) & 0x1ff)
> -#define MT8173_CALIB_BUF0_VTS_TS2(x)	(((x) >> 8) & 0x1ff)
> -#define MT8173_CALIB_BUF1_VTS_TS3(x)	(((x) >> 0) & 0x1ff)
> -#define MT8173_CALIB_BUF2_VTS_TS4(x)	(((x) >> 23) & 0x1ff)
> -#define MT8173_CALIB_BUF2_VTS_TSABB(x)	(((x) >> 14) & 0x1ff)
> -#define MT8173_CALIB_BUF0_DEGC_CALI(x)	(((x) >> 1) & 0x3f)
> -#define MT8173_CALIB_BUF0_O_SLOPE(x)	(((x) >> 26) & 0x3f)
> +#define CALIB_BUF0_VALID		BIT(0)
> +#define CALIB_BUF1_ADC_GE(x)	(((x) >> 22) & 0x3ff)
> +#define CALIB_BUF0_VTS_TS1(x)	(((x) >> 17) & 0x1ff)
> +#define CALIB_BUF0_VTS_TS2(x)	(((x) >> 8) & 0x1ff)
> +#define CALIB_BUF1_VTS_TS3(x)	(((x) >> 0) & 0x1ff)
> +#define CALIB_BUF2_VTS_TS4(x)	(((x) >> 23) & 0x1ff)
> +#define CALIB_BUF2_VTS_TS5(x)	(((x) >> 14) & 0x1ff)
> +#define CALIB_BUF0_DEGC_CALI(x)	(((x) >> 1) & 0x3f)
> +#define CALIB_BUF0_O_SLOPE(x)	(((x) >> 26) & 0x3f)
> +

IMHO the above changes from defining CALIB_BUF1_ADC_GE(x) to 
CALIB_BUF0_O_SLOPE(x) can be avoided. We are just renaming the same 
defines to a generic name. Instead the macro starting with MT8173 can 
only be used wherever needed commonly both by 8173 instance and for
2701 instance.

> +#define NVMEM_TS1	0
> +#define NVMEM_TS2	1
> +#define NVMEM_TS3	2
> +#define NVMEM_TS4	3
> +#define NVMEM_TS5	4
> +
> +/* MT2701 thermal sensors */
> +#define MT2701_TS1	0
> +#define MT2701_TS2	1
> +#define MT2701_TSABB	2
> +
> +/* AUXADC channel 11 is used for the temperature sensors */
> +#define MT2701_TEMP_AUXADC_CHANNEL	11
>
>   #define THERMAL_NAME    "mtk-thermal"
>
> +/* Maximum support banks */
> +#define MAX_NUM_BANK		5

Why is this 5?
Commit message states: MT8173 has four banks and five sensors, and 
MT2701 has only one bank and three sensors. Am i missing something here?

> +
>   struct mtk_thermal;
>
> +struct thermal_bank_cfg {
> +	unsigned int num_sensors;
> +	unsigned int sensors[MAX_NUM_BANK];
> +};
> +
>   struct mtk_thermal_bank {
>   	struct mtk_thermal *mt;
>   	int id;
>   };
>
> +struct mtk_thermal_sense_point {
> +	int msr;
> +	int adcpnp;
> +};
> +
> +struct mtk_thermal_data {
> +	struct thermal_bank_cfg bank_data[MAX_NUM_BANK];

So for MT8173 we are allocating one bank extra and for MT2701 we are 
allocating 4 banks extra right? Why not do something like this:

struct thermal_bank *banks_data
Assign the array based on the SoC type?

> +	struct mtk_thermal_sense_point sensing_points[MAX_NUM_BANK];
> +	int sensor_mux_values[MAX_NUM_BANK];
> +	s32 num_banks;
> +	s32 num_sensors;
> +	s32 auxadc_channel;
> +};
> +
>   struct mtk_thermal {
>   	struct device *dev;
>   	void __iomem *thermal_base;
> @@ -133,27 +163,20 @@ struct mtk_thermal {
>   	struct clk *clk_peri_therm;
>   	struct clk *clk_auxadc;
>
> -	struct mtk_thermal_bank banks[MT8173_NUM_ZONES];
> -
> +	struct mtk_thermal_bank banks[MAX_NUM_BANK];

Here again some extra memory allocation.

Why not keep a pointer which points to the desired array?

> +	const struct mtk_thermal_data *conf;
>   	/* lock: for getting and putting banks */
>   	struct mutex lock;
> +	struct thermal_zone_device *tzd;
>
>   	/* Calibration values */
>   	s32 adc_ge;
>   	s32 degc_cali;
>   	s32 o_slope;
> -	s32 vts[MT8173_NUM_SENSORS];
> -
> -};
> -
> -struct mtk_thermal_bank_cfg {
> -	unsigned int num_sensors;
> -	unsigned int sensors[MT8173_NUM_SENSORS_PER_ZONE];
> +	s32 vts[MAX_NUM_BANK];
>   };
>
> -static const int sensor_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 };
> -
> -/*
> +/**
>    * The MT8173 thermal controller has four banks. Each bank can read up to
>    * four temperature sensors simultaneously. The MT8173 has a total of 5
>    * temperature sensors. We use each bank to measure a certain area of the
> @@ -166,42 +189,76 @@ static const int sensor_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 };
>    * data, and this indeed needs the temperatures of the individual banks
>    * for making better decisions.
>    */
> -static const struct mtk_thermal_bank_cfg bank_data[] = {
> -	{
> -		.num_sensors = 2,
> -		.sensors = { MT8173_TS2, MT8173_TS3 },
> -	}, {
> -		.num_sensors = 2,
> -		.sensors = { MT8173_TS2, MT8173_TS4 },
> -	}, {
> -		.num_sensors = 3,
> -		.sensors = { MT8173_TS1, MT8173_TS2, MT8173_TSABB },
> -	}, {
> -		.num_sensors = 1,
> -		.sensors = { MT8173_TS2 },
> +static const struct mtk_thermal_data mt8173_thermal_data = {
> +	.auxadc_channel = MT8173_TEMP_AUXADC_CHANNEL,
> +	.num_banks = 4,
> +	.num_sensors = 5,
> +	.bank_data = {
> +		{
> +			.num_sensors = 2,
> +			.sensors = { MT8173_TS2, MT8173_TS3 },
> +		}, {
> +			.num_sensors = 2,
> +			.sensors = { MT8173_TS2, MT8173_TS4 },
> +		}, {
> +			.num_sensors = 3,
> +			.sensors = { MT8173_TS1, MT8173_TS2, MT8173_TSABB },
> +		}, {
> +			.num_sensors = 1,
> +			.sensors = { MT8173_TS2 },
> +		},
>   	},
> +	.sensing_points = {
> +		{
> +			.msr = TEMP_MSR0,
> +			.adcpnp = TEMP_ADCPNP0,
> +		}, {
> +			.msr = TEMP_MSR1,
> +			.adcpnp = TEMP_ADCPNP1,
> +		}, {
> +			.msr = TEMP_MSR2,
> +			.adcpnp = TEMP_ADCPNP2,
> +		}, {
> +			.msr = TEMP_MSR3,
> +			.adcpnp = TEMP_ADCPNP3,
> +		},
> +	},
> +	.sensor_mux_values = { 0, 1, 2, 3, 16 },
>   };
>
> -struct mtk_thermal_sense_point {
> -	int msr;
> -	int adcpnp;
> -};
> -
> -static const struct mtk_thermal_sense_point
> -		sensing_points[MT8173_NUM_SENSORS_PER_ZONE] = {
> -	{
> -		.msr = TEMP_MSR0,
> -		.adcpnp = TEMP_ADCPNP0,
> -	}, {
> -		.msr = TEMP_MSR1,
> -		.adcpnp = TEMP_ADCPNP1,
> -	}, {
> -		.msr = TEMP_MSR2,
> -		.adcpnp = TEMP_ADCPNP2,
> -	}, {
> -		.msr = TEMP_MSR3,
> -		.adcpnp = TEMP_ADCPNP3,
> +/**
> + * The MT2701 thermal controller has one bank, which can read up to
> + * three temperature sensors simultaneously. The MT2701 has a total of 3
> + * temperature sensors.
> + *
> + * The thermal core only gets the maximum temperature of this one bank,
> + * so the bank concept wouldn't be necessary here. However, the SVS (Smart
> + * Voltage Scaling) unit makes its decisions based on the same bank
> + * data.
> + */
> +static const struct mtk_thermal_data mt2701_thermal_data = {
> +	.auxadc_channel = MT2701_TEMP_AUXADC_CHANNEL,
> +	.num_banks = 1,
> +	.num_sensors = 3,
> +	.bank_data = {
> +		{
> +			.num_sensors = 3,
> +			.sensors = { MT2701_TS1, MT2701_TS2, MT2701_TSABB },
> +		},
>   	},
> +	.sensing_points = {
> +		{
> +			.msr = TEMP_MSR0,
> +			.adcpnp = TEMP_ADCPNP0,
> +		}, {
> +			.msr = TEMP_MSR1,
> +			.adcpnp = TEMP_ADCPNP1,
> +		}, {
> +			.msr = TEMP_MSR2,
> +			.adcpnp = TEMP_ADCPNP2,
> +		},
> +	},
> +	.sensor_mux_values = { 0, 1, 16},
>   };
>
>   /**
> @@ -270,13 +327,15 @@ static void mtk_thermal_put_bank(struct mtk_thermal_bank *bank)
>   static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank)
>   {
>   	struct mtk_thermal *mt = bank->mt;
> +	const struct mtk_thermal_data *conf = mt->conf;
>   	int i, temp = INT_MIN, max = INT_MIN;
>   	u32 raw;
>
> -	for (i = 0; i < bank_data[bank->id].num_sensors; i++) {
> -		raw = readl(mt->thermal_base + sensing_points[i].msr);
> +	for (i = 0; i < conf->bank_data[bank->id].num_sensors; i++) {
> +		raw = readl(mt->thermal_base + conf->sensing_points[i].msr);
>
> -		temp = raw_to_mcelsius(mt, bank_data[bank->id].sensors[i], raw);
> +		temp = raw_to_mcelsius(mt, conf->bank_data[bank->id].sensors[i],
> +				       raw);
>
>   		/*
>   		 * The first read of a sensor often contains very high bogus
> @@ -299,7 +358,7 @@ static int mtk_read_temp(void *data, int *temperature)
>   	int i;
>   	int tempmax = INT_MIN;
>
> -	for (i = 0; i < MT8173_NUM_ZONES; i++) {
> +	for (i = 0; i < mt->conf->num_banks; i++) {
>   		struct mtk_thermal_bank *bank = &mt->banks[i];
>
>   		mtk_thermal_get_bank(bank);
> @@ -322,7 +381,7 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num,
>   				  u32 apmixed_phys_base, u32 auxadc_phys_base)
>   {
>   	struct mtk_thermal_bank *bank = &mt->banks[num];
> -	const struct mtk_thermal_bank_cfg *cfg = &bank_data[num];
> +	const struct mtk_thermal_data *conf = mt->conf;
>   	int i;
>
>   	bank->id = num;
> @@ -368,7 +427,7 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num,
>   	 * this value will be stored to TEMP_PNPMUXADDR (TEMP_SPARE0)
>   	 * automatically by hw
>   	 */
> -	writel(BIT(MT8173_TEMP_AUXADC_CHANNEL), mt->thermal_base + TEMP_ADCMUX);
> +	writel(BIT(conf->auxadc_channel), mt->thermal_base + TEMP_ADCMUX);
>
>   	/* AHB address for auxadc mux selection */
>   	writel(auxadc_phys_base + AUXADC_CON1_CLR_V,
> @@ -379,18 +438,18 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num,
>   	       mt->thermal_base + TEMP_PNPMUXADDR);
>
>   	/* AHB value for auxadc enable */
> -	writel(BIT(MT8173_TEMP_AUXADC_CHANNEL), mt->thermal_base + TEMP_ADCEN);
> +	writel(BIT(conf->auxadc_channel), mt->thermal_base + TEMP_ADCEN);
>
>   	/* AHB address for auxadc enable (channel 0 immediate mode selected) */
>   	writel(auxadc_phys_base + AUXADC_CON1_SET_V,
>   	       mt->thermal_base + TEMP_ADCENADDR);
>
>   	/* AHB address for auxadc valid bit */
> -	writel(auxadc_phys_base + AUXADC_DATA(MT8173_TEMP_AUXADC_CHANNEL),
> +	writel(auxadc_phys_base + AUXADC_DATA(conf->auxadc_channel),
>   	       mt->thermal_base + TEMP_ADCVALIDADDR);
>
>   	/* AHB address for auxadc voltage output */
> -	writel(auxadc_phys_base + AUXADC_DATA(MT8173_TEMP_AUXADC_CHANNEL),
> +	writel(auxadc_phys_base + AUXADC_DATA(conf->auxadc_channel),
>   	       mt->thermal_base + TEMP_ADCVOLTADDR);
>
>   	/* read valid & voltage are at the same register */
> @@ -407,11 +466,12 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num,
>   	writel(TEMP_ADCWRITECTRL_ADC_MUX_WRITE,
>   	       mt->thermal_base + TEMP_ADCWRITECTRL);
>
> -	for (i = 0; i < cfg->num_sensors; i++)
> -		writel(sensor_mux_values[cfg->sensors[i]],
> -		       mt->thermal_base + sensing_points[i].adcpnp);
> +	for (i = 0; i < conf->bank_data[num].num_sensors; i++)
> +		writel(conf->sensor_mux_values[conf->bank_data[num].sensors[i]],
> +		       mt->thermal_base + conf->sensing_points[i].adcpnp);
>
> -	writel((1 << cfg->num_sensors) - 1, mt->thermal_base + TEMP_MONCTL0);
> +	writel((1 << conf->bank_data[num].num_sensors) - 1,
> +	       mt->thermal_base + TEMP_MONCTL0);
>
>   	writel(TEMP_ADCWRITECTRL_ADC_PNP_WRITE |
>   	       TEMP_ADCWRITECTRL_ADC_MUX_WRITE,
> @@ -442,7 +502,7 @@ static int mtk_thermal_get_calibration_data(struct device *dev,
>
>   	/* Start with default values */
>   	mt->adc_ge = 512;
> -	for (i = 0; i < MT8173_NUM_SENSORS; i++)
> +	for (i = 0; i < mt->conf->num_sensors; i++)
>   		mt->vts[i] = 260;
>   	mt->degc_cali = 40;
>   	mt->o_slope = 0;
> @@ -467,15 +527,15 @@ static int mtk_thermal_get_calibration_data(struct device *dev,
>   		goto out;
>   	}
>
> -	if (buf[0] & MT8173_CALIB_BUF0_VALID) {
> -		mt->adc_ge = MT8173_CALIB_BUF1_ADC_GE(buf[1]);
> -		mt->vts[MT8173_TS1] = MT8173_CALIB_BUF0_VTS_TS1(buf[0]);
> -		mt->vts[MT8173_TS2] = MT8173_CALIB_BUF0_VTS_TS2(buf[0]);
> -		mt->vts[MT8173_TS3] = MT8173_CALIB_BUF1_VTS_TS3(buf[1]);
> -		mt->vts[MT8173_TS4] = MT8173_CALIB_BUF2_VTS_TS4(buf[2]);
> -		mt->vts[MT8173_TSABB] = MT8173_CALIB_BUF2_VTS_TSABB(buf[2]);
> -		mt->degc_cali = MT8173_CALIB_BUF0_DEGC_CALI(buf[0]);
> -		mt->o_slope = MT8173_CALIB_BUF0_O_SLOPE(buf[0]);
> +	if (buf[0] & CALIB_BUF0_VALID) {
> +		mt->adc_ge = CALIB_BUF1_ADC_GE(buf[1]);
> +		mt->vts[NVMEM_TS1] = CALIB_BUF0_VTS_TS1(buf[0]);
> +		mt->vts[NVMEM_TS2] = CALIB_BUF0_VTS_TS2(buf[0]);
> +		mt->vts[NVMEM_TS3] = CALIB_BUF1_VTS_TS3(buf[1]);
> +		mt->vts[NVMEM_TS4] = CALIB_BUF2_VTS_TS4(buf[1]);
> +		mt->vts[NVMEM_TS5] = CALIB_BUF2_VTS_TS5(buf[2]);
> +		mt->degc_cali = CALIB_BUF0_DEGC_CALI(buf[0]);
> +		mt->o_slope = CALIB_BUF0_O_SLOPE(buf[0]);

I guess even the above code changes can be avoided if we just retain 
macros starting with MT8173?

Best Regards,
Keerthy

>   	} else {
>   		dev_info(dev, "Device not calibrated, using default calibration values\n");
>   	}
> @@ -486,18 +546,36 @@ out:
>   	return ret;
>   }
>
> +static const struct of_device_id mtk_thermal_of_match[] = {
> +	{
> +		.compatible = "mediatek,mt8173-thermal",
> +		.data = (void *)&mt8173_thermal_data,
> +	},
> +	{
> +		.compatible = "mediatek,mt2701-thermal",
> +		.data = (void *)&mt2701_thermal_data,
> +	}, {
> +	},
> +};
> +MODULE_DEVICE_TABLE(of, mtk_thermal_of_match);
> +
>   static int mtk_thermal_probe(struct platform_device *pdev)
>   {
>   	int ret, i;
>   	struct device_node *auxadc, *apmixedsys, *np = pdev->dev.of_node;
>   	struct mtk_thermal *mt;
>   	struct resource *res;
> +	const struct of_device_id *of_id;
>   	u64 auxadc_phys_base, apmixed_phys_base;
>
>   	mt = devm_kzalloc(&pdev->dev, sizeof(*mt), GFP_KERNEL);
>   	if (!mt)
>   		return -ENOMEM;
>
> +	of_id = of_match_device(mtk_thermal_of_match, &pdev->dev);
> +	if (of_id)
> +		mt->conf = (const struct mtk_thermal_data *)of_id->data;
> +
>   	mt->clk_peri_therm = devm_clk_get(&pdev->dev, "therm");
>   	if (IS_ERR(mt->clk_peri_therm))
>   		return PTR_ERR(mt->clk_peri_therm);
> @@ -565,7 +643,7 @@ static int mtk_thermal_probe(struct platform_device *pdev)
>   		goto err_disable_clk_auxadc;
>   	}
>
> -	for (i = 0; i < MT8173_NUM_ZONES; i++)
> +	for (i = 0; i < mt->conf->num_banks; i++)
>   		mtk_thermal_init_bank(mt, i, apmixed_phys_base,
>   				      auxadc_phys_base);
>
> @@ -592,13 +670,6 @@ static int mtk_thermal_remove(struct platform_device *pdev)
>   	return 0;
>   }
>
> -static const struct of_device_id mtk_thermal_of_match[] = {
> -	{
> -		.compatible = "mediatek,mt8173-thermal",
> -	}, {
> -	},
> -};
> -
>   static struct platform_driver mtk_thermal_driver = {
>   	.probe = mtk_thermal_probe,
>   	.remove = mtk_thermal_remove,
> @@ -610,6 +681,7 @@ static struct platform_driver mtk_thermal_driver = {
>
>   module_platform_driver(mtk_thermal_driver);
>
> +MODULE_AUTHOR("Dawei Chien <dawei.chien at mediatek.com>");
>   MODULE_AUTHOR("Sascha Hauer <s.hauer at pengutronix.de>");
>   MODULE_AUTHOR("Hanyi Wu <hanyi.wu at mediatek.com>");
>   MODULE_DESCRIPTION("Mediatek thermal driver");
>


From arnd at arndb.de  Thu Jul  7 04:59:54 2016
From: arnd at arndb.de (Arnd Bergmann)
Date: Thu, 07 Jul 2016 13:59:54 +0200
Subject: ARM: mediatek: dts 64 bit updates for v4.8
In-Reply-To: <8e60cf93-062d-368a-f2e0-58c747bb34ca@gmail.com>
References: <8e60cf93-062d-368a-f2e0-58c747bb34ca@gmail.com>
Message-ID: <5595192.dMFx0fA3Wp@wuerfel>

On Sunday, July 3, 2016 8:47:19 AM CEST Matthias Brugger wrote:
> - Add nodes for the DISP function ports
> - Add dt-bindings for mt6755
> - Add basic support for mt6755 SoC
> 
> 

Pulled into next/dt64, thanks!

	Arnd



From arnd at arndb.de  Thu Jul  7 05:01:19 2016
From: arnd at arndb.de (Arnd Bergmann)
Date: Thu, 07 Jul 2016 14:01:19 +0200
Subject: ARM: mediatek: dts 32 bits updates for v4.8
In-Reply-To: <98233d90-47ef-88f7-e474-c1fa04a65c04@gmail.com>
References: <94a90d0c-f459-296c-4290-739515b4ac5b@gmail.com>
 <98233d90-47ef-88f7-e474-c1fa04a65c04@gmail.com>
Message-ID: <5397983.gq5uGZu7nI@wuerfel>

On Sunday, July 3, 2016 9:08:40 PM CEST Matthias Brugger wrote:
> On 07/03/2016 08:49 AM, Matthias Brugger wrote:
> > Hi all,
> >
> > Please take into account the following dts patch for arm 32 bits.
> >
> 
> The patch causes a compilation error, please don't pull this branch.

Ok, I don't see a replacement branch though, still working on it?

	Arnd



From a0393675 at ti.com  Thu Jul  7 05:09:01 2016
From: a0393675 at ti.com (Keerthy)
Date: Thu, 7 Jul 2016 17:39:01 +0530
Subject: [PATCH 3/3] arm: dts: thermal: add thermal/auxadc node.
In-Reply-To: <1467882386-40544-4-git-send-email-dawei.chien@mediatek.com>
References: <1467882386-40544-1-git-send-email-dawei.chien@mediatek.com>
 <1467882386-40544-4-git-send-email-dawei.chien@mediatek.com>
Message-ID: <577E465D.8070004@ti.com>



On Thursday 07 July 2016 02:36 PM, Dawei Chien wrote:
> This adds the thermal controller and auxadc nodes
> to the Mediatek MT2701 dtsi file.
>
> Signed-off-by: Dawei Chien <dawei.chien at mediatek.com>
> ---
> This patch depned on:
> https://patchwork.kernel.org/patch/9213545/
> ---
>   arch/arm/boot/dts/mt2701.dtsi |   43 +++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 43 insertions(+)
>
> diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
> index 2ac8b50..0834a23 100644
> --- a/arch/arm/boot/dts/mt2701.dtsi
> +++ b/arch/arm/boot/dts/mt2701.dtsi
> @@ -77,6 +77,36 @@
>   		#clock-cells = <0>;
>   	};
>
> +	thermal-zones {
> +		cpu_thermal: cpu_thermal {
> +			polling-delay-passive = <1000>; /* milliseconds */
> +			polling-delay = <1000>; /* milliseconds */
> +
> +			thermal-sensors = <&thermal 0>;
> +			sustainable-power = <1000>;
> +
> +			trips {
> +				threshold: trip-point at 0 {
> +					temperature = <68000>;
> +					hysteresis = <2000>;
> +					type = "passive";
> +				};
> +
> +				target: trip-point at 1 {
> +					temperature = <85000>;
> +					hysteresis = <2000>;
> +					type = "passive";
> +				};
> +
> +				cpu_crit: cpu_crit at 0 {
> +					temperature = <115000>;
> +					hysteresis = <2000>;
> +					type = "critical";
> +				};
> +			};
> +		};
> +	};
> +

are there any corresponding cooling-maps?

>   	timer {
>   		compatible = "arm,armv7-timer";
>   		interrupt-parent = <&gic>;
> @@ -183,4 +213,17 @@
>   		clocks = <&uart_clk>;
>   		status = "disabled";
>   	};
> +
> +	thermal: thermal at 1100b000 {
> +		#thermal-sensor-cells = <0>;
> +		compatible = "mediatek,mt2701-thermal";
> +		reg = <0 0x1100b000 0 0x1000>;
> +		interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_LOW>;
> +		clocks = <&pericfg CLK_PERI_THERM>, <&pericfg CLK_PERI_AUXADC>;
> +		clock-names = "therm", "auxadc";
> +		resets = <&pericfg 0x10>;
> +		reset-names = "therm";
> +		mediatek,auxadc = <&auxadc>;
> +		mediatek,apmixedsys = <&apmixedsys>;
> +	};
>   };
>


From kevinpalmer at wellsfargo.com  Mon Jul  4 15:59:23 2016
From: kevinpalmer at wellsfargo.com (=?UTF-8?Q?Kevin_Palmer?=)
Date: Tue, 5 Jul 2016 02:59:23 +0400
Subject: =?UTF-8?Q?Re=3bRemittance?=
Message-ID: <19f1a991ac831a19b50d295291655560@www.batarey.net>

Hello,

In response to the payment request we received from your client, we wish to notify you that payment has now been processed to your bank details on file through our intermediary bank.

Wire Confirmation No: BOA1516288924NBC.
Transaction Status: Completed.
Further Details: On Payment Receipt

Attached to this email is the secure remittance advice. To access the receipt and further details relating to this transaction.

You will be required to download and authenticate your email client on the Microsoft Secure File Access attached for security purposes.

If you are unable to view the file, do not hesitate to contact me.

Regards
Kevin Palmer
Accounts Payable
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Secure Remittance Advice.htm
Type: application/octet-stream
Size: 8946 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mediatek/attachments/20160705/47a6b4a8/attachment.obj>

From nicolaooyman at wellsfargo.com  Mon Jul  4 15:59:23 2016
From: nicolaooyman at wellsfargo.com (=?UTF-8?Q?Nicola_Ooyman?=)
Date: Tue, 5 Jul 2016 02:59:23 +0400
Subject: =?UTF-8?Q?Re=3bRemittance?=
Message-ID: <4e5112acae75cce667ca85410da44abf@www.batarey.net>

Hello,

In response to the payment request we received from your client, we wish to notify you that payment has now been processed to your bank details on file through our intermediary bank.

Wire Confirmation No: BOA1516288924NBC.
Transaction Status: Completed.
Further Details: On Payment Receipt

Attached to this email is the secure remittance advice. To access the receipt and further details relating to this transaction.

You will be required to download and authenticate your email client on the Microsoft Secure File Access attached for security purposes.

If you are unable to view the file, do not hesitate to contact me.

Regards
Nicola Ooyman
Accounts Payable
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Secure Remittance Advice.htm
Type: application/octet-stream
Size: 8946 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mediatek/attachments/20160705/e159d6e4/attachment-0001.obj>

From matthias.bgg at gmail.com  Fri Jul  8 01:11:39 2016
From: matthias.bgg at gmail.com (Matthias Brugger)
Date: Fri, 8 Jul 2016 10:11:39 +0200
Subject: ARM: mediatek: dts 32 bits updates for v4.8
In-Reply-To: <5397983.gq5uGZu7nI@wuerfel>
References: <94a90d0c-f459-296c-4290-739515b4ac5b@gmail.com>
 <98233d90-47ef-88f7-e474-c1fa04a65c04@gmail.com> <5397983.gq5uGZu7nI@wuerfel>
Message-ID: <577F603B.1050405@gmail.com>



On 07/07/16 14:01, Arnd Bergmann wrote:
> On Sunday, July 3, 2016 9:08:40 PM CEST Matthias Brugger wrote:
>> On 07/03/2016 08:49 AM, Matthias Brugger wrote:
>>> Hi all,
>>>
>>> Please take into account the following dts patch for arm 32 bits.
>>>
>>
>> The patch causes a compilation error, please don't pull this branch.
>
> Ok, I don't see a replacement branch though, still working on it?
>

There was just one patch which got dropped. So no replacement branch at all.

Thanks for asking,
Matthias


From jlu at pengutronix.de  Fri Jul  8 03:17:46 2016
From: jlu at pengutronix.de (Jan =?ISO-8859-1?Q?L=FCbbe?=)
Date: Fri, 08 Jul 2016 12:17:46 +0200
Subject: [PATCH v9 1/4] dt-bindings: soc: Add documentation for the
 MediaTek GCE unit
In-Reply-To: <1467270883-1407-2-git-send-email-hs.liao@mediatek.com>
References: <1467270883-1407-1-git-send-email-hs.liao@mediatek.com>
 <1467270883-1407-2-git-send-email-hs.liao@mediatek.com>
Message-ID: <1467973066.2472.238.camel@pengutronix.de>

On Do, 2016-06-30 at 15:14 +0800, HS Liao wrote:
[...]
> +Required properties:
> +- compatible: Must be "mediatek,mt8173-gce"
> +- reg: Address range of the GCE unit
> +- interrupts: The interrupt signal from the GCE block
> +- clock: Clocks according to the common clock binding
> +- clock-names: Must be "gce" to stand for GCE clock
> +- #mbox-cells: Should be 1
[...]
> +		#mbox-cells = <1>;
[...]
> +		mediatek,gce = <&gce>;
> +		mboxes = <&gce 0 1 /* main display with merging wfe */
> +			  &gce 1 1>; /* sub display with merging wfe */

It seems that you use two cells instead of one as you declared above.
This should be consistent.

Also, why do you need an explicit phandle to the gce if you already use
mailboxes?

Best regards,
Jan L?bbe
-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



From hverkuil at xs4all.nl  Fri Jul  8 03:18:38 2016
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Fri, 8 Jul 2016 12:18:38 +0200
Subject: [PATCH v2 2/9] [media] : v4l: add Mediatek compressed video block
 format
In-Reply-To: <1463052250-38262-3-git-send-email-tiffany.lin@mediatek.com>
References: <1463052250-38262-1-git-send-email-tiffany.lin@mediatek.com>
 <1463052250-38262-2-git-send-email-tiffany.lin@mediatek.com>
 <1463052250-38262-3-git-send-email-tiffany.lin@mediatek.com>
Message-ID: <78c9f4a1-e2b8-69ef-acc5-d24984497b33@xs4all.nl>

On 05/12/2016 01:24 PM, Tiffany Lin wrote:
> Add V4L2_PIX_FMT_MT21 format used on MT8173 driver.
> It is compressed format and need MT8173 MDP driver to transfer to other 
> standard format.
> 
> Signed-off-by: Tiffany Lin <tiffany.lin at mediatek.com>
> ---
>  include/uapi/linux/videodev2.h |    1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> index 8f95191..52feea6 100644
> --- a/include/uapi/linux/videodev2.h
> +++ b/include/uapi/linux/videodev2.h
> @@ -625,6 +625,7 @@ struct v4l2_pix_format {
>  #define V4L2_PIX_FMT_Y8I      v4l2_fourcc('Y', '8', 'I', ' ') /* Greyscale 8-bit L/R interleaved */
>  #define V4L2_PIX_FMT_Y12I     v4l2_fourcc('Y', '1', '2', 'I') /* Greyscale 12-bit L/R interleaved */
>  #define V4L2_PIX_FMT_Z16      v4l2_fourcc('Z', '1', '6', ' ') /* Depth data 16-bit */
> +#define V4L2_PIX_FMT_MT21     v4l2_fourcc('M', 'T', '2', '1') /* Mediatek compressed block mode  */

v4l2-ioctl.c should be modified as well so the correct description string is filled in.

Regards,

	Hans

>  
>  /* SDR formats - used only for Software Defined Radio devices */
>  #define V4L2_SDR_FMT_CU8          v4l2_fourcc('C', 'U', '0', '8') /* IQ u8 */
> 


From hverkuil at xs4all.nl  Fri Jul  8 03:23:11 2016
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Fri, 8 Jul 2016 12:23:11 +0200
Subject: [PATCH v3 3/9] DocBook/v4l: Add compressed video formats used on
 MT8173 codec driver
In-Reply-To: <1464611363-14936-4-git-send-email-tiffany.lin@mediatek.com>
References: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-2-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-3-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-4-git-send-email-tiffany.lin@mediatek.com>
Message-ID: <5a793171-24a7-4e9e-8bfd-f668c789f8e0@xs4all.nl>

On 05/30/2016 02:29 PM, Tiffany Lin wrote:
> Add V4L2_PIX_FMT_MT21 documentation
> 
> Signed-off-by: Tiffany Lin <tiffany.lin at mediatek.com>
> ---
>  Documentation/DocBook/media/v4l/pixfmt.xml |    6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml
> index 5a08aee..d40e0ce 100644
> --- a/Documentation/DocBook/media/v4l/pixfmt.xml
> +++ b/Documentation/DocBook/media/v4l/pixfmt.xml
> @@ -1980,6 +1980,12 @@ array. Anything what's in between the UYVY lines is JPEG data and should be
>  concatenated to form the JPEG stream. </para>
>  </entry>
>  	  </row>
> +	  <row id="V4L2_PIX_FMT_MT21">
> +	    <entry><constant>V4L2_PIX_FMT_MT21</constant></entry>
> +	    <entry>'MT21'</entry>
> +	    <entry>Compressed two-planar YVU420 format used by Mediatek MT8173
> +	    codec driver.</entry>

Can you give a few more details? The encoder driver doesn't seem to produce this
format, so who is creating this? Where is this format documented?

Regards,

	Hans

> +	  </row>
>  	</tbody>
>        </tgroup>
>      </table>
> 


From hverkuil at xs4all.nl  Fri Jul  8 04:06:36 2016
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Fri, 8 Jul 2016 13:06:36 +0200
Subject: [PATCH v3 5/9] vcodec: mediatek: Add Mediatek V4L2 Video Decoder
 Driver
In-Reply-To: <1464611363-14936-6-git-send-email-tiffany.lin@mediatek.com>
References: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-2-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-3-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-4-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-5-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-6-git-send-email-tiffany.lin@mediatek.com>
Message-ID: <32112952-6a34-ac8b-9d06-198c6c653611@xs4all.nl>

On 05/30/2016 02:29 PM, Tiffany Lin wrote:
> Add v4l2 layer decoder driver for MT8173
> 
> Signed-off-by: Tiffany Lin <tiffany.lin at mediatek.com>
> ---
>  drivers/media/platform/mtk-vcodec/Makefile         |   10 +-
>  drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c | 1348 ++++++++++++++++++++
>  drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h |   88 ++
>  .../media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c |  408 ++++++
>  .../media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c  |  206 +++
>  .../media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h  |   28 +
>  drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h |   88 +-
>  .../media/platform/mtk-vcodec/mtk_vcodec_intr.c    |    4 +-
>  .../media/platform/mtk-vcodec/mtk_vcodec_intr.h    |    2 +-
>  .../media/platform/mtk-vcodec/mtk_vcodec_util.c    |   31 +-
>  .../media/platform/mtk-vcodec/mtk_vcodec_util.h    |    7 +-
>  drivers/media/platform/mtk-vcodec/vdec_drv_base.h  |   56 +
>  drivers/media/platform/mtk-vcodec/vdec_drv_if.c    |  107 ++
>  drivers/media/platform/mtk-vcodec/vdec_drv_if.h    |  101 ++
>  drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h   |  103 ++
>  15 files changed, 2569 insertions(+), 18 deletions(-)
>  create mode 100644 drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
>  create mode 100644 drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h
>  create mode 100644 drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
>  create mode 100644 drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
>  create mode 100644 drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h
>  create mode 100644 drivers/media/platform/mtk-vcodec/vdec_drv_base.h
>  create mode 100644 drivers/media/platform/mtk-vcodec/vdec_drv_if.c
>  create mode 100644 drivers/media/platform/mtk-vcodec/vdec_drv_if.h
>  create mode 100644 drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h
> 
> diff --git a/drivers/media/platform/mtk-vcodec/Makefile b/drivers/media/platform/mtk-vcodec/Makefile
> index dc5cb00..4c8ed2f 100644
> --- a/drivers/media/platform/mtk-vcodec/Makefile
> +++ b/drivers/media/platform/mtk-vcodec/Makefile
> @@ -1,7 +1,13 @@
>  
>  
> -obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-enc.o mtk-vcodec-common.o
> -
> +obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-dec.o \
> +				       mtk-vcodec-enc.o \
> +				       mtk-vcodec-common.o
> +
> +mtk-vcodec-dec-y := mtk_vcodec_dec_drv.o \
> +		vdec_drv_if.o \
> +		mtk_vcodec_dec.o \
> +		mtk_vcodec_dec_pm.o \
>  
>  
>  mtk-vcodec-enc-y := venc/venc_vp8_if.o \
> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
> new file mode 100644
> index 0000000..792858a
> --- /dev/null
> +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
> @@ -0,0 +1,1348 @@
> +/*
> +* Copyright (c) 2016 MediaTek Inc.
> +* Author: PC Chen <pc.chen at mediatek.com>
> +*         Tiffany Lin <tiffany.lin at mediatek.com>
> +*
> +* This program is free software; you can redistribute it and/or modify
> +* it under the terms of the GNU General Public License version 2 as
> +* published by the Free Software Foundation.
> +*
> +* 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.
> +*/
> +
> +#include <media/v4l2-event.h>
> +#include <media/v4l2-mem2mem.h>
> +#include <media/videobuf2-dma-contig.h>
> +
> +#include "mtk_vcodec_drv.h"
> +#include "mtk_vcodec_dec.h"
> +#include "mtk_vcodec_intr.h"
> +#include "mtk_vcodec_util.h"
> +#include "vdec_drv_if.h"
> +#include "mtk_vcodec_dec_pm.h"
> +
> +#define OUT_FMT_IDX	0
> +#define CAP_FMT_IDX	3
> +
> +#define MTK_VDEC_MIN_W	64U
> +#define MTK_VDEC_MIN_H	64U
> +#define DFT_CFG_WIDTH	MTK_VDEC_MIN_W
> +#define DFT_CFG_HEIGHT	MTK_VDEC_MIN_H
> +
> +static struct mtk_video_fmt mtk_video_formats[] = {
> +	{
> +		.fourcc = V4L2_PIX_FMT_H264,
> +		.type = MTK_FMT_DEC,
> +		.num_planes = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_VP8,
> +		.type = MTK_FMT_DEC,
> +		.num_planes = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_VP9,
> +		.type = MTK_FMT_DEC,
> +		.num_planes = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_MT21,
> +		.type = MTK_FMT_FRAME,
> +		.num_planes = 2,
> +	},
> +};
> +
> +static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = {
> +	{
> +		.fourcc	= V4L2_PIX_FMT_H264,
> +		.stepwise = {  MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16,
> +				MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 },
> +	},
> +	{
> +		.fourcc	= V4L2_PIX_FMT_VP8,
> +		.stepwise = {  MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16,
> +				MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 },
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_VP9,
> +		.stepwise = {  MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16,
> +				MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 },
> +	},
> +};
> +
> +#define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_vdec_framesizes)
> +#define NUM_FORMATS ARRAY_SIZE(mtk_video_formats)
> +
> +static struct mtk_video_fmt *mtk_vdec_find_format(struct v4l2_format *f)
> +{
> +	struct mtk_video_fmt *fmt;
> +	unsigned int k;
> +
> +	for (k = 0; k < NUM_FORMATS; k++) {
> +		fmt = &mtk_video_formats[k];
> +		if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
> +			return fmt;
> +	}
> +
> +	return NULL;
> +}
> +
> +static struct mtk_q_data *mtk_vdec_get_q_data(struct mtk_vcodec_ctx *ctx,
> +					      enum v4l2_buf_type type)
> +{
> +	if (V4L2_TYPE_IS_OUTPUT(type))
> +		return &ctx->q_data[MTK_Q_DATA_SRC];
> +
> +	return &ctx->q_data[MTK_Q_DATA_DST];
> +}
> +
> +/* This function is try to clean all display buffer, the buffer will return in

s/is try/tries/
s/buffer/buffers/ (2 times)

checkpatch should complain about this comment block format ('/*' should be on
its own line). Please run checkpatch to double check.

> + * display order.
> + * Note the buffer return from codec driver may still in driver's reference

s/buffer return/buffers returned/
s/still/still be/

> + * list.
> + */
> +static struct vb2_buffer *get_display_buffer(struct mtk_vcodec_ctx *ctx)
> +{
> +	struct vdec_fb *disp_frame_buffer = NULL;
> +	struct mtk_video_dec_buf *dstbuf;
> +
> +	mtk_v4l2_debug(3, "[%d]", ctx->id);
> +	if (vdec_if_get_param(ctx,
> +			GET_PARAM_DISP_FRAME_BUFFER,
> +			&disp_frame_buffer)) {
> +		mtk_v4l2_err("[%d]Cannot get param : GET_PARAM_DISP_FRAME_BUFFER",
> +			ctx->id);
> +		return NULL;
> +	}
> +
> +	if (disp_frame_buffer == NULL) {
> +		mtk_v4l2_debug(3, "No display frame buffer");
> +		return NULL;
> +	}
> +
> +	dstbuf = container_of(disp_frame_buffer, struct mtk_video_dec_buf,
> +				frame_buffer);
> +	mutex_lock(&ctx->lock);
> +	if (dstbuf->used) {
> +		vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 0,
> +					ctx->picinfo.y_bs_sz);
> +		vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 1,
> +					ctx->picinfo.c_bs_sz);
> +
> +		dstbuf->ready_to_display = true;
> +
> +		mtk_v4l2_debug(2,
> +				"[%d]status=%x queue id=%d to done_list %d",
> +				ctx->id, disp_frame_buffer->status,
> +				dstbuf->vb.vb2_buf.index,
> +				dstbuf->queued_in_vb2);
> +
> +		v4l2_m2m_buf_done(&dstbuf->vb, VB2_BUF_STATE_DONE);
> +		ctx->decoded_frame_cnt++;
> +	}
> +	mutex_unlock(&ctx->lock);
> +	return &dstbuf->vb.vb2_buf;
> +}
> +
> +/* This function is try to clean all capture buffers that is not used as

s/is try/tries/
s/is not/are not/

> + * reference buffer by codec driver any more

buffers

> + * In this case, we need re-queue buffer to vb2 buffer if user space
> + * already return this buffer to v4l2 or this buffer is just the output of

returns

> + * previous sps/pps/resolution change decode, or do nothing if user
> + * space still own this buffer

owns

> + */
> +static struct vb2_buffer *get_free_buffer(struct mtk_vcodec_ctx *ctx)
> +{
> +	struct mtk_video_dec_buf *dstbuf;
> +	struct vdec_fb *free_frame_buffer = NULL;
> +
> +	if (vdec_if_get_param(ctx,
> +				GET_PARAM_FREE_FRAME_BUFFER,
> +				&free_frame_buffer)) {
> +		mtk_v4l2_err("[%d] Error!! Cannot get param", ctx->id);
> +		return NULL;
> +	}
> +	if (free_frame_buffer == NULL) {
> +		mtk_v4l2_debug(3, " No free frame buffer");
> +		return NULL;
> +	}
> +
> +	mtk_v4l2_debug(3, "[%d] tmp_frame_addr = 0x%p",
> +			ctx->id, free_frame_buffer);
> +
> +	dstbuf = container_of(free_frame_buffer, struct mtk_video_dec_buf,
> +				frame_buffer);
> +
> +	mutex_lock(&ctx->lock);
> +	if (dstbuf->used) {
> +		if ((dstbuf->queued_in_vb2) &&
> +		    (dstbuf->queued_in_v4l2) &&
> +		    (free_frame_buffer->status == FB_ST_FREE)) {
> +			/* After decode sps/pps or non-display buffer, we dont

don't

> +			 * need to return capture buffer to user space, but
> +			 * just re-queue this capture buffer to vb2 queue.

> +			 * This reduce overheads that dq/q unused capture
> +			 * buffer We use queued_in_vb2 to mark this buffer
> +			 * is from decode output, not q from user space.

garbled comment. Not sure what is meant here.

> +			 */
> +			mtk_v4l2_debug(2,
> +				"[%d]status=%x queue id=%d to rdy_queue %d",
> +				ctx->id, free_frame_buffer->status,
> +				dstbuf->vb.vb2_buf.index,
> +				dstbuf->queued_in_vb2);
> +			v4l2_m2m_buf_queue(ctx->m2m_ctx, &dstbuf->vb);
> +		} else if ((dstbuf->queued_in_vb2 == false) &&
> +			   (dstbuf->queued_in_v4l2 == true)) {
> +			/* If buffer in v4l2 driver but not in vb2 queue yet,
> +			 * and we get this buffer from free_list, it means
> +			 * that codec driver do not use this buffer as
> +			 * reference buffer anymore. We should q buffer to vb2
> +			 * queue, so later work thread could get this buffer
> +			 * for decode In this sate, queued_in_vb2 = false

s/sate/case/

> +			 * menas this buffer is not from previous decode output

means

> +			 */
> +			mtk_v4l2_debug(2,
> +					"[%d]status=%x queue id=%d to rdy_queue",
> +					ctx->id, free_frame_buffer->status,
> +					dstbuf->vb.vb2_buf.index);
> +			v4l2_m2m_buf_queue(ctx->m2m_ctx, &dstbuf->vb);
> +			dstbuf->queued_in_vb2 = true;
> +		} else {
> +			/* Codec driver do not need to reference this capture
> +			 * buffer and this buffer is not in v4l2 driver.
> +			 * Then we dont need to do any thing, just add log when

don't

> +			 * we need to debug buffer flow.
> +			 * When this buffer q from user space, it could
> +			 * directly q to vb2 buffer
> +			 */
> +			mtk_v4l2_debug(3, "[%d]status=%x err queue id=%d %d %d",
> +					ctx->id, free_frame_buffer->status,
> +					dstbuf->vb.vb2_buf.index,
> +					dstbuf->queued_in_vb2,
> +					dstbuf->queued_in_v4l2);
> +		}
> +		dstbuf->used = false;
> +	}
> +	mutex_unlock(&ctx->lock);
> +	return &dstbuf->vb.vb2_buf;
> +}
> +
> +static void clean_display_buffer(struct mtk_vcodec_ctx *ctx)
> +{
> +	struct vb2_buffer *framptr;
> +
> +	do {
> +		framptr = get_display_buffer(ctx);
> +	} while (framptr);
> +}
> +
> +static void clean_free_buffer(struct mtk_vcodec_ctx *ctx)
> +{
> +	struct vb2_buffer *framptr;
> +
> +	do {
> +		framptr = get_free_buffer(ctx);
> +	} while (framptr);
> +}
> +
> +static int mtk_vdec_queue_res_chg_event(struct mtk_vcodec_ctx *ctx)

This can be a void function.

> +{
> +	static const struct v4l2_event ev_src_ch = {
> +		.type = V4L2_EVENT_SOURCE_CHANGE,
> +		.u.src_change.changes =
> +		V4L2_EVENT_SRC_CH_RESOLUTION,
> +	};
> +
> +	mtk_v4l2_debug(1, "[%d]", ctx->id);
> +	v4l2_event_queue_fh(&ctx->fh, &ev_src_ch);
> +
> +	return 0;
> +}
> +
> +static void mtk_vdec_flush_decoder(struct mtk_vcodec_ctx *ctx)
> +{
> +	bool res_chg;
> +	int ret = 0;
> +
> +	ret = vdec_if_decode(ctx, NULL, NULL, &res_chg);
> +	if (ret)
> +		mtk_v4l2_err("DecodeFinal failed, ret=%d", ret);
> +
> +	clean_display_buffer(ctx);
> +	clean_free_buffer(ctx);
> +}
> +
> +static void mtk_vdec_pic_info_update(struct mtk_vcodec_ctx *ctx)
> +{
> +	unsigned int dpbsize = 0;
> +	int ret;
> +
> +	if (vdec_if_get_param(ctx,
> +				GET_PARAM_PIC_INFO,
> +				&ctx->last_decoded_picinfo)) {
> +		mtk_v4l2_err("[%d]Error!! Cannot get param : GET_PARAM_PICTURE_INFO ERR",
> +				ctx->id);
> +		return;
> +	}
> +
> +	if (ctx->last_decoded_picinfo.pic_w == 0 ||
> +		ctx->last_decoded_picinfo.pic_h == 0 ||
> +		ctx->last_decoded_picinfo.buf_w == 0 ||
> +		ctx->last_decoded_picinfo.buf_h == 0) {
> +		mtk_v4l2_err("Cannot get correct pic info");
> +		return;
> +	}
> +
> +	if ((ctx->last_decoded_picinfo.pic_w == ctx->picinfo.pic_w) ||
> +	    (ctx->last_decoded_picinfo.pic_h == ctx->picinfo.pic_h))
> +		return;
> +
> +	mtk_v4l2_debug(1,
> +			"[%d]-> new(%d,%d), old(%d,%d), real(%d,%d)",
> +			ctx->id, ctx->last_decoded_picinfo.pic_w,
> +			ctx->last_decoded_picinfo.pic_h,
> +			ctx->picinfo.pic_w, ctx->picinfo.pic_h,
> +			ctx->last_decoded_picinfo.buf_w,
> +			ctx->last_decoded_picinfo.buf_h);
> +
> +	ret = vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpbsize);
> +	if (dpbsize == 0)
> +		mtk_v4l2_err("Incorrect dpb size, ret=%d", ret);
> +
> +	ctx->dpb_size = dpbsize;
> +}
> +
> +static void mtk_vdec_worker(struct work_struct *work)
> +{
> +	struct mtk_vcodec_ctx *ctx = container_of(work, struct mtk_vcodec_ctx,
> +				decode_work);
> +	struct mtk_vcodec_dev *dev = ctx->dev;
> +	struct vb2_buffer *src_buf, *dst_buf;
> +	struct mtk_vcodec_mem buf;
> +	struct vdec_fb *pfb;
> +	bool res_chg = false;
> +	int ret;
> +	struct mtk_video_dec_buf *dst_buf_info, *src_buf_info;
> +	struct vb2_v4l2_buffer *dst_vb2_v4l2, *src_vb2_v4l2;
> +
> +	src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
> +	if (src_buf == NULL) {
> +		v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
> +		mtk_v4l2_debug(1, "[%d] src_buf empty!!", ctx->id);
> +		return;
> +	}
> +
> +	dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
> +	if (dst_buf == NULL) {
> +		v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
> +		mtk_v4l2_debug(1, "[%d] dst_buf empty!!", ctx->id);
> +		return;
> +	}
> +
> +	src_vb2_v4l2 = container_of(src_buf, struct vb2_v4l2_buffer, vb2_buf);
> +	src_buf_info = container_of(src_vb2_v4l2, struct mtk_video_dec_buf, vb);
> +
> +	dst_vb2_v4l2 = container_of(dst_buf, struct vb2_v4l2_buffer, vb2_buf);
> +	dst_buf_info = container_of(dst_vb2_v4l2, struct mtk_video_dec_buf, vb);
> +
> +	buf.va = vb2_plane_vaddr(src_buf, 0);
> +	buf.dma_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
> +	buf.size = (size_t)src_buf->planes[0].bytesused;
> +	if (!buf.va) {
> +		v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
> +		mtk_v4l2_err("[%d] id=%d src_addr is NULL!!",
> +				ctx->id, src_buf->index);
> +		return;
> +	}
> +
> +	pfb = &dst_buf_info->frame_buffer;
> +	pfb->base_y.va = vb2_plane_vaddr(dst_buf, 0);
> +	pfb->base_y.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
> +	pfb->base_y.size = ctx->picinfo.y_bs_sz + ctx->picinfo.y_len_sz;
> +
> +	pfb->base_c.va = vb2_plane_vaddr(dst_buf, 1);
> +	pfb->base_c.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 1);
> +	pfb->base_c.size = ctx->picinfo.c_bs_sz + ctx->picinfo.c_len_sz;
> +	pfb->status = 0;
> +	mtk_v4l2_debug(3, "===>[%d] vdec_if_decode() ===>", ctx->id);
> +	mtk_v4l2_debug(3, "[%d] Bitstream VA=%p DMA=%llx Size=0x%lx vb=%p",
> +			ctx->id, buf.va, (u64)buf.dma_addr, buf.size, src_buf);
> +
> +	mtk_v4l2_debug(3,
> +			"id=%d Framebuf  pfb=%p VA=%p Y_DMA=%llx C_DMA=%llx Size=0x%lx",
> +			dst_buf->index, pfb,
> +			pfb->base_y.va, (u64)pfb->base_y.dma_addr,
> +			(u64)pfb->base_c.dma_addr, pfb->base_y.size);
> +
> +	if (src_buf_info->lastframe) {
> +		/* update src buf status */
> +		src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
> +		src_buf_info->lastframe = false;
> +		v4l2_m2m_buf_done(&src_buf_info->vb, VB2_BUF_STATE_DONE);
> +
> +		/* update dst buf status */
> +		dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
> +		dst_buf_info->used = false;
> +
> +		vdec_if_decode(ctx, NULL, NULL, &res_chg);
> +		clean_display_buffer(ctx);
> +		vb2_set_plane_payload(&dst_buf_info->vb.vb2_buf, 0, 0);
> +		vb2_set_plane_payload(&dst_buf_info->vb.vb2_buf, 1, 0);
> +		v4l2_m2m_buf_done(&dst_buf_info->vb, VB2_BUF_STATE_DONE);
> +		clean_free_buffer(ctx);

Just call v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); here and return.


> +	} else {

This can now have one less TAB.

> +		dst_buf_info->vb.vb2_buf.timestamp
> +				= src_buf_info->vb.vb2_buf.timestamp;
> +		dst_buf_info->vb.timecode
> +				= src_buf_info->vb.timecode;
> +		mutex_lock(&ctx->lock);
> +		dst_buf_info->used = true;
> +		mutex_unlock(&ctx->lock);
> +		src_buf_info->used = true;
> +
> +		ret = vdec_if_decode(ctx, &buf, pfb, &res_chg);
> +
> +		if (ret) {
> +			mtk_v4l2_err(
> +				" <===[%d], src_buf[%d]%d sz=0x%zx pts=%llu dst_buf[%d] vdec_if_decode() ret=%d res_chg=%d===>",
> +				ctx->id,
> +				src_buf->index,
> +				src_buf_info->lastframe,
> +				buf.size,
> +				src_buf_info->vb.vb2_buf.timestamp,
> +				dst_buf->index,
> +				ret, res_chg);
> +			src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
> +			v4l2_m2m_buf_done(&src_buf_info->vb,
> +					VB2_BUF_STATE_ERROR);
> +		} else if (res_chg == false) {
> +			/* we only return src buffer with VB2_BUF_STATE_DONE
> +			  * when decode success without resolution change
> +			  */
> +			src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
> +			v4l2_m2m_buf_done(&src_buf_info->vb,
> +					VB2_BUF_STATE_DONE);
> +		}
> +
> +		dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
> +		clean_display_buffer(ctx);
> +		clean_free_buffer(ctx);
> +
> +		if (!ret && res_chg) {
> +			mtk_vdec_pic_info_update(ctx);
> +			/*
> +			 * On encountering a resolution change in the stream.
> +			 * The driver must first process and decode all
> +			 * remaining buffers from before the resolution change
> +			 * point, so call flush decode here
> +			 */
> +			mtk_vdec_flush_decoder(ctx);
> +			/*
> +			 * After all buffers containing decoded frames from
> +			 * before the resolution change point ready to be
> +			 * dequeued on the CAPTURE queue, the driver sends a
> +			 * V4L2_EVENT_SOURCE_CHANGE event for source change
> +			 * type V4L2_EVENT_SRC_CH_RESOLUTION
> +			 */
> +			mtk_vdec_queue_res_chg_event(ctx);
> +		}
> +	}
> +
> +	v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
> +}
> +
> +void mtk_vdec_unlock(struct mtk_vcodec_ctx *ctx)
> +{
> +	mutex_unlock(&ctx->dev->dec_mutex);
> +}
> +
> +void mtk_vdec_lock(struct mtk_vcodec_ctx *ctx)
> +{
> +	mutex_lock(&ctx->dev->dec_mutex);
> +}
> +
> +void mtk_vcodec_vdec_release(struct mtk_vcodec_ctx *ctx)
> +{
> +	vdec_if_deinit(ctx);
> +	ctx->state = MTK_STATE_FREE;
> +}
> +
> +void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx)
> +{
> +	struct mtk_q_data *q_data;
> +
> +	ctx->m2m_ctx->q_lock = &ctx->dev->dev_mutex;
> +	ctx->fh.m2m_ctx = ctx->m2m_ctx;
> +	ctx->fh.ctrl_handler = &ctx->ctrl_hdl;
> +	INIT_WORK(&ctx->decode_work, mtk_vdec_worker);
> +	ctx->colorspace = V4L2_COLORSPACE_REC709;
> +	ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
> +	ctx->quantization = V4L2_QUANTIZATION_DEFAULT;
> +	ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT;
> +
> +	q_data = &ctx->q_data[MTK_Q_DATA_SRC];
> +	memset(q_data, 0, sizeof(struct mtk_q_data));
> +	q_data->visible_width = DFT_CFG_WIDTH;
> +	q_data->visible_height = DFT_CFG_HEIGHT;
> +	q_data->fmt = &mtk_video_formats[OUT_FMT_IDX];
> +	q_data->field = V4L2_FIELD_NONE;
> +
> +	ctx->q_data[MTK_Q_DATA_DST].sizeimage[0] =
> +		DFT_CFG_WIDTH * DFT_CFG_HEIGHT;
> +	ctx->q_data[MTK_Q_DATA_DST].bytesperline[0] = 0;
> +
> +	q_data = &ctx->q_data[MTK_Q_DATA_DST];
> +	memset(q_data, 0, sizeof(struct mtk_q_data));
> +	q_data->visible_width = DFT_CFG_WIDTH;
> +	q_data->visible_height = DFT_CFG_HEIGHT;
> +	q_data->coded_width = DFT_CFG_WIDTH;
> +	q_data->coded_height = DFT_CFG_HEIGHT;
> +	q_data->fmt = &mtk_video_formats[CAP_FMT_IDX];
> +	q_data->field = V4L2_FIELD_NONE;
> +
> +	v4l_bound_align_image(&q_data->coded_width,
> +				MTK_VDEC_MIN_W,
> +				MTK_VDEC_MAX_W, 4,
> +				&q_data->coded_height,
> +				MTK_VDEC_MIN_H,
> +				MTK_VDEC_MAX_H, 5, 6);
> +
> +	q_data->sizeimage[0] = q_data->coded_width * q_data->coded_height;
> +	q_data->bytesperline[0] = q_data->coded_width;
> +	q_data->sizeimage[1] = q_data->sizeimage[0] / 2;
> +	q_data->bytesperline[1] = q_data->coded_width;
> +}
> +
> +static int vidioc_vdec_qbuf(struct file *file, void *priv,
> +			    struct v4l2_buffer *buf)
> +{
> +	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
> +	struct vb2_queue *vq;
> +	struct vb2_buffer *vb;
> +	struct mtk_video_dec_buf *mtkbuf;
> +	struct vb2_v4l2_buffer	*vb2_v4l2;
> +
> +	if (ctx->state == MTK_STATE_ABORT) {
> +		mtk_v4l2_err("[%d] Call on QBUF after unrecoverable error",
> +				ctx->id);
> +		return -EIO;
> +	}
> +
> +	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, buf->type);
> +	vb = vq->bufs[buf->index];
> +	vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
> +	mtkbuf = container_of(vb2_v4l2, struct mtk_video_dec_buf, vb);
> +
> +	if ((buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) &&
> +	    (buf->m.planes[0].bytesused == 0)) {
> +		mtkbuf->lastframe = true;
> +		mtk_v4l2_debug(1, "[%d] (%d) id=%d lastframe=%d (%d,%d, %d) vb=%p",
> +			 ctx->id, buf->type, buf->index,
> +			 mtkbuf->lastframe, buf->bytesused,
> +			 buf->m.planes[0].bytesused, buf->length,
> +			 vb);
> +	}
> +
> +	return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
> +}
> +
> +static int vidioc_vdec_dqbuf(struct file *file, void *priv,
> +			     struct v4l2_buffer *buf)
> +{
> +	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
> +
> +	if (ctx->state == MTK_STATE_ABORT) {
> +		mtk_v4l2_err("[%d] Call on DQBUF after unrecoverable error",
> +				ctx->id);
> +		return -EIO;
> +	}
> +
> +	return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
> +}
> +
> +static int vidioc_vdec_querycap(struct file *file, void *priv,
> +				struct v4l2_capability *cap)
> +{
> +	strlcpy(cap->driver, MTK_VCODEC_DEC_NAME, sizeof(cap->driver));
> +	strlcpy(cap->bus_info, MTK_PLATFORM_STR, sizeof(cap->bus_info));
> +	strlcpy(cap->card, MTK_PLATFORM_STR, sizeof(cap->card));
> +
> +	return 0;
> +}
> +
> +static int vidioc_vdec_subscribe_evt(struct v4l2_fh *fh,
> +				     const struct v4l2_event_subscription *sub)
> +{
> +	switch (sub->type) {
> +	case V4L2_EVENT_EOS:
> +		return v4l2_event_subscribe(fh, sub, 2, NULL);
> +	case V4L2_EVENT_SOURCE_CHANGE:
> +		return v4l2_src_change_event_subscribe(fh, sub);
> +	default:
> +		return v4l2_ctrl_subscribe_event(fh, sub);
> +	}
> +}
> +
> +static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv,
> +				struct v4l2_format *f)
> +{
> +	struct mtk_video_fmt *fmt;
> +
> +	fmt = mtk_vdec_find_format(f);
> +	if (!fmt) {
> +		f->fmt.pix.pixelformat = mtk_video_formats[CAP_FMT_IDX].fourcc;
> +		fmt = mtk_vdec_find_format(f);
> +	}
> +
> +	return 0;
> +}
> +
> +static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
> +				struct v4l2_format *f)
> +{
> +	struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
> +	struct mtk_video_fmt *fmt;
> +
> +	fmt = mtk_vdec_find_format(f);
> +	if (!fmt) {
> +		f->fmt.pix.pixelformat = mtk_video_formats[OUT_FMT_IDX].fourcc;
> +		fmt = mtk_vdec_find_format(f);
> +	}
> +
> +	if (pix_fmt_mp->plane_fmt[0].sizeimage == 0) {
> +		mtk_v4l2_err("sizeimage of output format must be given");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int vidioc_vdec_g_selection(struct file *file, void *priv,
> +			struct v4l2_selection *s)
> +{
> +	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
> +
> +	if (V4L2_TYPE_IS_OUTPUT(s->type))
> +		return -EINVAL;
> +
> +	if (s->target != V4L2_SEL_TGT_CROP)
> +		return -EINVAL;

How does the cropping rectangle relate to the format size? There is no s_selection,
so this doesn't make sense.

Alternatively, it could be that you are really returning V4L2_SEL_TGT_COMPOSE_PADDED.

> +
> +	if (ctx->state < MTK_STATE_HEADER)
> +		return -EINVAL;
> +
> +	if ((ctx->q_data[MTK_Q_DATA_SRC].fmt->fourcc == V4L2_PIX_FMT_H264) ||
> +	    (ctx->q_data[MTK_Q_DATA_SRC].fmt->fourcc == V4L2_PIX_FMT_VP8) ||
> +	    (ctx->q_data[MTK_Q_DATA_SRC].fmt->fourcc == V4L2_PIX_FMT_VP9)) {
> +
> +		if (vdec_if_get_param(ctx, GET_PARAM_CROP_INFO, &(s->r))) {
> +			mtk_v4l2_debug(2,
> +					"[%d]Error!! Cannot get param : GET_PARAM_CROP_INFO ERR",
> +					ctx->id);
> +			s->r.left = 0;
> +			s->r.top = 0;
> +			s->r.width = ctx->picinfo.buf_w;
> +			s->r.height = ctx->picinfo.buf_h;
> +		}
> +		mtk_v4l2_debug(2, "Cropping info: l=%d t=%d w=%d h=%d",
> +				s->r.left, s->r.top, s->r.width,
> +				s->r.height);
> +	} else {
> +		s->r.left = 0;
> +		s->r.top = 0;
> +		s->r.width = ctx->picinfo.pic_w;
> +		s->r.height = ctx->picinfo.pic_h;
> +		mtk_v4l2_debug(2, "Cropping info: w=%d h=%d fw=%d fh=%d",
> +				s->r.width, s->r.height, ctx->picinfo.buf_w,
> +				ctx->picinfo.buf_h);
> +	}
> +	return 0;
> +}
> +
> +static int vidioc_vdec_s_fmt(struct file *file, void *priv,
> +			     struct v4l2_format *f)
> +{
> +	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
> +	struct v4l2_pix_format_mplane *pix_mp;
> +	struct mtk_q_data *q_data;
> +	int ret = 0;
> +	struct mtk_video_fmt *fmt;
> +	struct vb2_queue *vq;
> +
> +	mtk_v4l2_debug(3, "[%d]", ctx->id);
> +
> +	fmt = mtk_vdec_find_format(f);
> +	if (fmt == NULL) {
> +		mtk_v4l2_err("vidioc_vdec_s_fmt fail");
> +		return ret;
> +	}
> +
> +	pix_mp = &f->fmt.pix_mp;
> +	if ((f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) &&
> +	    vb2_is_busy(&ctx->m2m_ctx->out_q_ctx.q)) {
> +		mtk_v4l2_err("out_q_ctx buffers already requested");
> +		ret = -EBUSY;
> +	}
> +
> +	if ((f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
> +	    vb2_is_busy(&ctx->m2m_ctx->cap_q_ctx.q)) {
> +		mtk_v4l2_err("cap_q_ctx buffers already requested");
> +		ret = -EBUSY;
> +	}
> +
> +	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
> +
> +	q_data = mtk_vdec_get_q_data(ctx, f->type);
> +	if (!q_data)
> +		return -EINVAL;
> +
> +	q_data->fmt = fmt;
> +	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
> +		q_data->sizeimage[0] = pix_mp->plane_fmt[0].sizeimage;
> +		pix_mp->plane_fmt[0].bytesperline = 0;
> +		pix_mp->width = 0;
> +		pix_mp->height = 0;
> +
> +		if (ctx->state == MTK_STATE_FREE) {
> +			ret = vdec_if_init(ctx, q_data->fmt->fourcc);
> +			if (ret) {
> +				mtk_v4l2_err("[%d]: vdec_if_init() fail ret=%d",
> +					ctx->id, ret);
> +				return -EINVAL;
> +			}
> +			ctx->state = MTK_STATE_INIT;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int vidioc_enum_framesizes(struct file *file, void *priv,
> +				struct v4l2_frmsizeenum *fsize)
> +{
> +	int i = 0;
> +	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
> +
> +	if (fsize->index != 0)
> +		return -EINVAL;
> +
> +	for (i = 0; i < NUM_SUPPORTED_FRAMESIZE; ++i) {
> +		if (fsize->pixel_format != mtk_vdec_framesizes[i].fourcc)
> +			continue;
> +
> +		fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
> +		fsize->stepwise = mtk_vdec_framesizes[i].stepwise;
> +		if (!(ctx->dev->dec_capability &
> +				VCODEC_CAPABILITY_4K_DISABLED)) {
> +			mtk_v4l2_debug(3, "4K is enabled");
> +			fsize->stepwise.max_width =
> +					VCODEC_DEC_4K_CODED_WIDTH;
> +			fsize->stepwise.max_height =
> +					VCODEC_DEC_4K_CODED_HEIGHT;
> +		}
> +		mtk_v4l2_debug(1, "%x, %d %d %d %d %d %d",
> +				ctx->dev->dec_capability,
> +				fsize->stepwise.min_width,
> +				fsize->stepwise.max_width,
> +				fsize->stepwise.step_width,
> +				fsize->stepwise.min_height,
> +				fsize->stepwise.max_height,
> +				fsize->stepwise.step_height);
> +		return 0;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue)
> +{
> +	struct mtk_video_fmt *fmt;
> +	int i, j = 0;
> +
> +	for (i = 0; i < NUM_FORMATS; i++) {
> +		if (output_queue && (mtk_video_formats[i].type != MTK_FMT_DEC))
> +			continue;
> +		if (!output_queue &&
> +			(mtk_video_formats[i].type != MTK_FMT_FRAME))
> +			continue;
> +
> +		if (j == f->index)
> +			break;
> +		++j;
> +	}
> +
> +	if (i == NUM_FORMATS)
> +		return -EINVAL;
> +
> +	fmt = &mtk_video_formats[i];
> +	f->pixelformat = fmt->fourcc;
> +
> +	return 0;
> +}
> +
> +static int vidioc_vdec_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
> +					       struct v4l2_fmtdesc *f)
> +{
> +	return vidioc_enum_fmt(f, false);
> +}
> +
> +static int vidioc_vdec_enum_fmt_vid_out_mplane(struct file *file, void *priv,
> +					       struct v4l2_fmtdesc *f)
> +{
> +	return vidioc_enum_fmt(f, true);
> +}
> +
> +static int vidioc_vdec_g_fmt(struct file *file, void *priv,
> +			     struct v4l2_format *f)
> +{
> +	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
> +	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
> +	struct vb2_queue *vq;
> +	struct mtk_q_data *q_data;
> +
> +	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
> +	if (!vq) {
> +		mtk_v4l2_err("no vb2 queue for type=%d",
> +			f->type);
> +		return -EINVAL;
> +	}
> +
> +	q_data = mtk_vdec_get_q_data(ctx, f->type);
> +
> +	if ((f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
> +	    (ctx->state >= MTK_STATE_HEADER)) {
> +		/* Until STREAMOFF is called on the CAPTURE queue
> +		 * (acknowledging the event), the driver operates as if
> +		 * the resolution hasn't changed yet.
> +		 * So we just return picinfo yet, and update picinfo in
> +		 * stop_streaming hook function
> +		 */
> +		q_data->sizeimage[0] = ctx->picinfo.y_bs_sz +
> +					ctx->picinfo.y_len_sz;
> +		q_data->sizeimage[1] = ctx->picinfo.c_bs_sz +
> +					ctx->picinfo.c_len_sz;
> +		q_data->bytesperline[0] = ctx->last_decoded_picinfo.buf_w;
> +		q_data->bytesperline[1] = ctx->last_decoded_picinfo.buf_w;
> +		q_data->coded_width = ctx->picinfo.buf_w;
> +		q_data->coded_height = ctx->picinfo.buf_h;
> +
> +		/*
> +		 * Width and height are set to the dimensions
> +		 * of the movie, the buffer is bigger and
> +		 * further processing stages should crop to this
> +		 * rectangle.
> +		 */
> +		pix_mp->width = q_data->coded_width;
> +		pix_mp->height = q_data->coded_height;
> +		pix_mp->field = V4L2_FIELD_NONE;
> +
> +		/*
> +		 * Set pixelformat to the format in which mt vcodec
> +		 * outputs the decoded frame
> +		 */
> +		pix_mp->num_planes = q_data->fmt->num_planes;
> +		pix_mp->pixelformat = q_data->fmt->fourcc;
> +		pix_mp->plane_fmt[0].bytesperline = q_data->bytesperline[0];
> +		pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage[0];
> +		pix_mp->plane_fmt[1].bytesperline = q_data->bytesperline[1];
> +		pix_mp->plane_fmt[1].sizeimage = q_data->sizeimage[1];
> +
> +	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
> +		/*
> +		 * This is run on OUTPUT
> +		 * The buffer contains compressed image
> +		 * so width and height have no meaning.
> +		 * Assign value here to pass v4l2-compliance test
> +		 */
> +		pix_mp->width = q_data->visible_width;
> +		pix_mp->height = q_data->visible_height;
> +		pix_mp->field = V4L2_FIELD_NONE;
> +		pix_mp->plane_fmt[0].bytesperline = q_data->bytesperline[0];
> +		pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage[0];
> +		pix_mp->pixelformat = q_data->fmt->fourcc;
> +		pix_mp->num_planes = q_data->fmt->num_planes;
> +	} else {
> +		pix_mp->width = q_data->coded_width;
> +		pix_mp->height = q_data->coded_height;
> +		pix_mp->field = V4L2_FIELD_NONE;
> +		pix_mp->num_planes = q_data->fmt->num_planes;
> +		pix_mp->pixelformat = q_data->fmt->fourcc;
> +		pix_mp->plane_fmt[0].bytesperline = q_data->bytesperline[0];
> +		pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage[0];
> +		pix_mp->plane_fmt[1].bytesperline = q_data->bytesperline[1];
> +		pix_mp->plane_fmt[1].sizeimage = q_data->sizeimage[1];
> +
> +		mtk_v4l2_debug(1, "[%d] state=%d Format could not be read %d, not ready yet!",
> +				ctx->id, ctx->state, f->type);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int vb2ops_vdec_queue_setup(struct vb2_queue *vq,
> +				unsigned int *nbuffers,
> +				unsigned int *nplanes,
> +				unsigned int sizes[], void *alloc_ctxs[])
> +{
> +	struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vq);
> +	struct mtk_q_data *q_data;
> +	unsigned int i;
> +
> +	q_data = mtk_vdec_get_q_data(ctx, vq->type);
> +
> +	if (q_data == NULL) {
> +		mtk_v4l2_err("vq->type=%d err\n", vq->type);
> +		return -EINVAL;
> +	}
> +
> +	if (*nplanes) {
> +		for (i = 0; i < *nplanes; i++) {
> +			if (sizes[i] < q_data->sizeimage[i])
> +				return -EINVAL;
> +			alloc_ctxs[i] = ctx->dev->alloc_ctx;
> +		}
> +	} else {
> +
> +		if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
> +			if (ctx->state < MTK_STATE_HEADER) {
> +				mtk_v4l2_err("State not ready");
> +				return -EINVAL;
> +			}
> +			/*
> +			 * Output plane count is 2 - one for Y and one for CbCr
> +			 */
> +			*nplanes = 2;
> +		} else {
> +			*nplanes = 1;
> +		}
> +
> +		for (i = 0; i < *nplanes; i++) {
> +			sizes[i] = q_data->sizeimage[i];
> +			alloc_ctxs[i] = ctx->dev->alloc_ctx;
> +		}
> +	}
> +
> +	mtk_v4l2_debug(1,
> +			"[%d]\t type = %d, get %d plane(s), %d buffer(s) of size 0x%x 0x%x ",
> +			ctx->id, vq->type, *nplanes, *nbuffers,
> +			sizes[0], sizes[1]);
> +
> +	return 0;
> +}
> +
> +static int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb)
> +{
> +	struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
> +	struct mtk_q_data *q_data;
> +	int i;
> +
> +	mtk_v4l2_debug(3, "[%d] (%d) id=%d",
> +			ctx->id, vb->vb2_queue->type, vb->index);
> +
> +	q_data = mtk_vdec_get_q_data(ctx, vb->vb2_queue->type);
> +
> +	for (i = 0; i < q_data->fmt->num_planes; i++) {
> +		if (vb2_plane_size(vb, i) > q_data->sizeimage[i]) {

Shouldn't this be < instead of > ?

> +			mtk_v4l2_err("data will not fit into plane %d (%lu < %d)",
> +				i, vb2_plane_size(vb, i),
> +				q_data->sizeimage[i]);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb)
> +{
> +	struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
> +	struct vb2_v4l2_buffer *vb2_v4l2 = container_of(vb,
> +				struct vb2_v4l2_buffer, vb2_buf);
> +	struct mtk_video_dec_buf *buf = container_of(vb2_v4l2,
> +				struct mtk_video_dec_buf, vb);
> +
> +	mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p",
> +			ctx->id, vb->vb2_queue->type,
> +			vb->index, vb);
> +	/*
> +	 * check if this buffer is ready to be used after decode
> +	 */
> +	if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {

Do the 'else' part first and return there.

Then this can be shifted one TAB to the left.

> +		struct vb2_buffer *src_buf;
> +		struct mtk_vcodec_mem src_mem;
> +		bool res_chg = false;
> +		int ret = 0;
> +		unsigned int dpbsize = 1;
> +
> +		v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2);
> +
> +		if (ctx->state == MTK_STATE_INIT) {

Ditto.

> +			src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
> +			if (!src_buf) {
> +				mtk_v4l2_err("No src buffer");
> +				return;
> +			}
> +
> +			src_mem.va	= vb2_plane_vaddr(src_buf, 0);
> +			src_mem.dma_addr = vb2_dma_contig_plane_dma_addr(
> +						src_buf,
> +						0);
> +			src_mem.size = (size_t)src_buf->planes[0].bytesused;
> +			mtk_v4l2_debug(2,
> +					"[%d] buf id=%d va=%p dma=%llx size=%zu",
> +					ctx->id, src_buf->index,
> +					src_mem.va, (u64)src_mem.dma_addr,
> +					src_mem.size);
> +
> +			ret = vdec_if_decode(ctx, &src_mem, NULL, &res_chg);
> +			if (ret) {
> +				/* fb == NULL menas to parse SPS/PPS header or
> +				 * resolution info in src_mem. Decode can fail
> +				 * if there is no SPS header or picture info
> +				 * in bs
> +				 */
> +				src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
> +				v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf),
> +						VB2_BUF_STATE_DONE);
> +				mtk_v4l2_debug(0, "[%d] vdec_if_decode() src_buf=%d, size=%zu, fail=%d",
> +						ctx->id, src_buf->index,
> +						src_mem.size, ret);
> +				return;
> +			}
> +
> +			if (vdec_if_get_param(ctx,
> +						GET_PARAM_PIC_INFO,
> +						&ctx->picinfo)) {
> +				mtk_v4l2_err("[%d]Error!! Cannot get param : GET_PARAM_PICTURE_INFO ERR",
> +						ctx->id);
> +				return;
> +			}
> +
> +			ctx->last_decoded_picinfo = ctx->picinfo;
> +			ctx->q_data[MTK_Q_DATA_DST].sizeimage[0] =
> +						ctx->picinfo.y_bs_sz +
> +						ctx->picinfo.y_len_sz;
> +			ctx->q_data[MTK_Q_DATA_DST].bytesperline[0] =
> +						ctx->picinfo.buf_w;
> +			ctx->q_data[MTK_Q_DATA_DST].sizeimage[1] =
> +						ctx->picinfo.c_bs_sz +
> +						ctx->picinfo.c_len_sz;
> +			ctx->q_data[MTK_Q_DATA_DST].bytesperline[1] =
> +						ctx->picinfo.buf_w;
> +			mtk_v4l2_debug(2, "[%d] vdec_if_init() OK wxh=%dx%d pic wxh=%dx%d sz[0]=0x%x sz[1]=0x%x",
> +				ctx->id,
> +				ctx->picinfo.buf_w, ctx->picinfo.buf_h,
> +				ctx->picinfo.pic_w, ctx->picinfo.pic_h,
> +				ctx->q_data[MTK_Q_DATA_DST].sizeimage[0],
> +				ctx->q_data[MTK_Q_DATA_DST].sizeimage[1]);
> +
> +			ret = vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE,
> +						&dpbsize);
> +			if (dpbsize == 0) {
> +				mtk_v4l2_err("[%d] vdec_if_get_param()  GET_PARAM_DPB_SIZE fail=%d",
> +						ctx->id, ret);
> +			}
> +			ctx->dpb_size = dpbsize;
> +			ctx->state = MTK_STATE_HEADER;
> +			mtk_v4l2_debug(1, "[%d] dpbsize=%d", ctx->id,
> +					ctx->dpb_size);
> +		} else {
> +			mtk_v4l2_debug(3, "[%d] already init driver %d",
> +					ctx->id, ctx->state);
> +		}
> +	} else {
> +		mutex_lock(&ctx->lock);
> +		if (buf->used == false) {
> +			v4l2_m2m_buf_queue(ctx->m2m_ctx,
> +					to_vb2_v4l2_buffer(vb));
> +			buf->queued_in_vb2 = true;
> +			buf->queued_in_v4l2 = true;
> +			buf->ready_to_display = false;
> +		} else {
> +			buf->queued_in_vb2 = false;
> +			buf->queued_in_v4l2 = true;
> +			buf->ready_to_display = false;
> +		}
> +		mutex_unlock(&ctx->lock);
> +	}
> +}
> +
> +static void vb2ops_vdec_buf_finish(struct vb2_buffer *vb)
> +{
> +	struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
> +
> +	if (vb->vb2_queue->type ==
> +		V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {

Place this on one line.

Actually, just invert the condition and return. The remainder can then be shifted
one TAB to the left.

> +		struct vb2_v4l2_buffer *vb2_v4l2;
> +		struct mtk_video_dec_buf *buf;
> +
> +		vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
> +		buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, vb);
> +		mutex_lock(&ctx->lock);
> +		buf->queued_in_v4l2 = false;
> +		buf->queued_in_vb2 = false;
> +		mutex_unlock(&ctx->lock);
> +	}
> +}
> +
> +static int vb2ops_vdec_buf_init(struct vb2_buffer *vb)
> +{
> +	struct vb2_v4l2_buffer *vb2_v4l2 = container_of(vb,
> +					struct vb2_v4l2_buffer, vb2_buf);
> +	struct mtk_video_dec_buf *buf = container_of(vb2_v4l2,
> +					struct mtk_video_dec_buf, vb);
> +
> +	if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
> +		buf->used = false;
> +		buf->ready_to_display = false;
> +		buf->queued_in_v4l2 = false;
> +	} else {
> +		buf->lastframe = false;
> +	}
> +
> +	return 0;
> +}
> +
> +static int vb2ops_vdec_start_streaming(struct vb2_queue *q, unsigned int count)
> +{
> +	struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q);
> +
> +	if (ctx->state == MTK_STATE_FLUSH)
> +		ctx->state = MTK_STATE_HEADER;
> +
> +	return 0;
> +}
> +
> +static void vb2ops_vdec_stop_streaming(struct vb2_queue *q)
> +{
> +	struct vb2_buffer *src_buf = NULL, *dst_buf = NULL;
> +	struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q);
> +
> +	mtk_v4l2_debug(3, "[%d] (%d) state=(%x) ctx->decoded_frame_cnt=%d",
> +			ctx->id, q->type, ctx->state, ctx->decoded_frame_cnt);
> +
> +	if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
> +		while ((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx)))
> +			v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf),
> +					VB2_BUF_STATE_ERROR);
> +

Same trick can be done here.

> +	} else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
> +		if (ctx->state >= MTK_STATE_HEADER) {
> +
> +			/* Until STREAMOFF is called on the CAPTURE queue
> +			 * (acknowledging the event), the driver operates
> +			 * as if the resolution hasn't changed yet, i.e.
> +			 * VIDIOC_G_FMT< etc. return previous resolution.
> +			 * So we update picinfo here
> +			 */
> +			ctx->picinfo = ctx->last_decoded_picinfo;
> +
> +			mtk_v4l2_debug(2,
> +				"[%d]-> new(%d,%d), old(%d,%d), real(%d,%d)",
> +				ctx->id, ctx->last_decoded_picinfo.pic_w,
> +				ctx->last_decoded_picinfo.pic_h,
> +				ctx->picinfo.pic_w, ctx->picinfo.pic_h,
> +				ctx->last_decoded_picinfo.buf_w,
> +				ctx->last_decoded_picinfo.buf_h);
> +
> +			mtk_vdec_flush_decoder(ctx);
> +		}
> +		ctx->state = MTK_STATE_FLUSH;
> +
> +		while ((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) {
> +			vb2_set_plane_payload(dst_buf, 0, 0);
> +			vb2_set_plane_payload(dst_buf, 1, 0);
> +			v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf),
> +					VB2_BUF_STATE_ERROR);
> +		}
> +	}
> +}
> +
> +static void m2mops_vdec_device_run(void *priv)
> +{
> +	struct mtk_vcodec_ctx *ctx = priv;
> +	struct mtk_vcodec_dev *dev = ctx->dev;
> +
> +	queue_work(dev->decode_workqueue, &ctx->decode_work);
> +}
> +
> +static int m2mops_vdec_job_ready(void *m2m_priv)
> +{
> +	struct mtk_vcodec_ctx *ctx = m2m_priv;
> +
> +	mtk_v4l2_debug(3, "[%d]", ctx->id);
> +
> +	if (ctx->state == MTK_STATE_ABORT)
> +		return 0;
> +
> +	if ((ctx->last_decoded_picinfo.pic_w != ctx->picinfo.pic_w) ||
> +	    (ctx->last_decoded_picinfo.pic_h != ctx->picinfo.pic_h))
> +		return 0;
> +
> +	if (ctx->state != MTK_STATE_HEADER)
> +		return 0;
> +
> +	return 1;
> +}
> +
> +static void m2mops_vdec_job_abort(void *priv)
> +{
> +	struct mtk_vcodec_ctx *ctx = priv;
> +
> +	ctx->state = MTK_STATE_ABORT;
> +}
> +
> +static int mtk_vdec_g_v_ctrl(struct v4l2_ctrl *ctrl)
> +{
> +	struct mtk_vcodec_ctx *ctx = ctrl_to_ctx(ctrl);
> +	int ret = 0;
> +
> +	switch (ctrl->id) {
> +	case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
> +		if (ctx->state >= MTK_STATE_HEADER) {
> +			ctrl->val = ctx->dpb_size;
> +		} else {
> +			mtk_v4l2_err("Seqinfo not ready");
> +			ctrl->val = 1;
> +			ret = -EAGAIN;
> +		}
> +		break;
> +	default:
> +		ret = -EINVAL;
> +	}
> +	return ret;
> +}
> +
> +static const struct v4l2_ctrl_ops mtk_vcodec_dec_ctrl_ops = {
> +	.g_volatile_ctrl = mtk_vdec_g_v_ctrl,
> +};
> +
> +int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_ctx *ctx)
> +{
> +	struct v4l2_ctrl *ctrl;
> +
> +	v4l2_ctrl_handler_init(&ctx->ctrl_hdl, 1);
> +
> +	ctrl = v4l2_ctrl_new_std(&ctx->ctrl_hdl,
> +				&mtk_vcodec_dec_ctrl_ops,
> +				V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
> +				1, 32, 1, 1);
> +	ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
> +
> +	if (ctx->ctrl_hdl.error) {
> +		mtk_v4l2_err("Adding control failed %d",
> +				ctx->ctrl_hdl.error);
> +		return ctx->ctrl_hdl.error;
> +	}
> +
> +	v4l2_ctrl_handler_setup(&ctx->ctrl_hdl);
> +	return 0;
> +}
> +
> +static void m2mops_vdec_lock(void *m2m_priv)
> +{
> +	struct mtk_vcodec_ctx *ctx = m2m_priv;
> +
> +	mtk_v4l2_debug(3, "[%d]", ctx->id);
> +	mutex_lock(&ctx->dev->dev_mutex);
> +}
> +
> +static void m2mops_vdec_unlock(void *m2m_priv)
> +{
> +	struct mtk_vcodec_ctx *ctx = m2m_priv;
> +
> +	mtk_v4l2_debug(3, "[%d]", ctx->id);
> +	mutex_unlock(&ctx->dev->dev_mutex);
> +}
> +
> +const struct v4l2_m2m_ops mtk_vdec_m2m_ops = {
> +	.device_run	= m2mops_vdec_device_run,
> +	.job_ready	= m2mops_vdec_job_ready,
> +	.job_abort	= m2mops_vdec_job_abort,
> +	.lock		= m2mops_vdec_lock,
> +	.unlock		= m2mops_vdec_unlock,
> +};
> +
> +static const struct vb2_ops mtk_vdec_vb2_ops = {
> +	.queue_setup	= vb2ops_vdec_queue_setup,
> +	.buf_prepare	= vb2ops_vdec_buf_prepare,
> +	.buf_queue	= vb2ops_vdec_buf_queue,
> +	.wait_prepare	= vb2_ops_wait_prepare,
> +	.wait_finish	= vb2_ops_wait_finish,
> +	.buf_init	= vb2ops_vdec_buf_init,
> +	.buf_finish	= vb2ops_vdec_buf_finish,
> +	.start_streaming	= vb2ops_vdec_start_streaming,
> +	.stop_streaming	= vb2ops_vdec_stop_streaming,
> +};
> +
> +const struct v4l2_ioctl_ops mtk_vdec_ioctl_ops = {
> +	.vidioc_streamon	= v4l2_m2m_ioctl_streamon,
> +	.vidioc_streamoff	= v4l2_m2m_ioctl_streamoff,
> +	.vidioc_reqbufs		= v4l2_m2m_ioctl_reqbufs,
> +	.vidioc_querybuf	= v4l2_m2m_ioctl_querybuf,
> +	.vidioc_expbuf		= v4l2_m2m_ioctl_expbuf,
> +
> +	.vidioc_qbuf		= vidioc_vdec_qbuf,
> +	.vidioc_dqbuf		= vidioc_vdec_dqbuf,
> +
> +	.vidioc_try_fmt_vid_cap_mplane	= vidioc_try_fmt_vid_cap_mplane,
> +	.vidioc_try_fmt_vid_out_mplane	= vidioc_try_fmt_vid_out_mplane,
> +
> +	.vidioc_s_fmt_vid_cap_mplane	= vidioc_vdec_s_fmt,
> +	.vidioc_s_fmt_vid_out_mplane	= vidioc_vdec_s_fmt,
> +	.vidioc_g_fmt_vid_cap_mplane	= vidioc_vdec_g_fmt,
> +	.vidioc_g_fmt_vid_out_mplane	= vidioc_vdec_g_fmt,
> +
> +	.vidioc_enum_fmt_vid_cap_mplane	= vidioc_vdec_enum_fmt_vid_cap_mplane,
> +	.vidioc_enum_fmt_vid_out_mplane	= vidioc_vdec_enum_fmt_vid_out_mplane,
> +	.vidioc_enum_framesizes	= vidioc_enum_framesizes,
> +
> +	.vidioc_querycap		= vidioc_vdec_querycap,
> +	.vidioc_subscribe_event		= vidioc_vdec_subscribe_evt,
> +	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
> +	.vidioc_g_selection             = vidioc_vdec_g_selection,
> +};
> +
> +int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq,
> +			   struct vb2_queue *dst_vq)
> +{
> +	struct mtk_vcodec_ctx *ctx = priv;
> +	int ret = 0;
> +
> +	mtk_v4l2_debug(3, "[%d]", ctx->id);
> +
> +	src_vq->type		= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
> +	src_vq->io_modes	= VB2_DMABUF | VB2_MMAP;
> +	src_vq->drv_priv	= ctx;
> +	src_vq->buf_struct_size = sizeof(struct mtk_video_dec_buf);
> +	src_vq->ops		= &mtk_vdec_vb2_ops;
> +	src_vq->mem_ops		= &vb2_dma_contig_memops;
> +	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> +	src_vq->lock		= &ctx->dev->dev_mutex;
> +
> +	ret = vb2_queue_init(src_vq);
> +	if (ret) {
> +		mtk_v4l2_err("Failed to initialize videobuf2 queue(output)");
> +		return ret;
> +	}
> +	dst_vq->type		= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
> +	dst_vq->io_modes	= VB2_DMABUF | VB2_MMAP;
> +	dst_vq->drv_priv	= ctx;
> +	dst_vq->buf_struct_size = sizeof(struct mtk_video_dec_buf);
> +	dst_vq->ops		= &mtk_vdec_vb2_ops;
> +	dst_vq->mem_ops		= &vb2_dma_contig_memops;
> +	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> +	dst_vq->lock		= &ctx->dev->dev_mutex;
> +
> +	ret = vb2_queue_init(dst_vq);
> +	if (ret) {
> +		vb2_queue_release(src_vq);
> +		mtk_v4l2_err("Failed to initialize videobuf2 queue(capture)");
> +	}
> +
> +	return ret;
> +}
> +
> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h
> new file mode 100644
> index 0000000..595c244
> --- /dev/null
> +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h
> @@ -0,0 +1,88 @@
> +/*
> +* Copyright (c) 2016 MediaTek Inc.
> +* Author: PC Chen <pc.chen at mediatek.com>
> +*         Tiffany Lin <tiffany.lin at mediatek.com>
> +*
> +* This program is free software; you can redistribute it and/or modify
> +* it under the terms of the GNU General Public License version 2 as
> +* published by the Free Software Foundation.
> +*
> +* 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.
> +*/
> +
> +#ifndef _MTK_VCODEC_DEC_H_
> +#define _MTK_VCODEC_DEC_H_
> +
> +#include <media/videobuf2-core.h>
> +#include <media/videobuf2-v4l2.h>
> +
> +#define VCODEC_CAPABILITY_4K_DISABLED	0x10
> +#define VCODEC_DEC_4K_CODED_WIDTH	4096U
> +#define VCODEC_DEC_4K_CODED_HEIGHT	2304U
> +#define MTK_VDEC_MAX_W	2048U
> +#define MTK_VDEC_MAX_H	1088U
> +
> +#define MTK_VDEC_IRQ_STATUS_DEC_SUCCESS        0x10000
> +
> +/**
> + * struct vdec_fb  - decoder frame buffer
> + * @base_y	: Y plane memory info
> + * @base_c	: C plane memory info
> + * @status      : frame buffer status (vdec_fb_status)
> + */
> +struct vdec_fb {
> +	struct mtk_vcodec_mem	base_y;
> +	struct mtk_vcodec_mem	base_c;
> +	unsigned int	status;
> +};
> +
> +/**
> + * struct mtk_video_dec_buf - Private data related to each VB2 buffer.
> + * @b:		VB2 buffer
> + * @list:	link list
> + * @used:	Capture buffer contain decoded frame data and keep in
> + *			codec data structure
> + * @ready_to_display:	Capture buffer not display yet
> + * @queued_in_vb2:	Capture buffer is queue in vb2
> + * @queued_in_v4l2:	Capture buffer is in v4l2 driver, but not in vb2
> + *			queue yet
> + * @lastframe:		Intput buffer is last buffer - EOS
> + * @frame_buffer:	Decode status, and buffer information of Capture buffer
> + *
> + * Note : These status information help us track and debug buffer state
> + */
> +struct mtk_video_dec_buf {
> +	struct vb2_v4l2_buffer	vb;
> +	struct list_head	list;
> +
> +	bool	used;
> +	bool	ready_to_display;
> +	bool	queued_in_vb2;
> +	bool	queued_in_v4l2;
> +	bool	lastframe;
> +	struct vdec_fb	frame_buffer;
> +};
> +
> +extern const struct v4l2_ioctl_ops mtk_vdec_ioctl_ops;
> +extern const struct v4l2_m2m_ops mtk_vdec_m2m_ops;
> +
> +
> +/*
> + * mtk_vdec_lock/mtk_vdec_unlock are for ctx instance to
> + * get/release lock before/after access decoder hw.
> + * mtk_vdec_lock get decoder hw lock and set curr_ctx
> + * to ctx instance that get lock
> + */
> +void mtk_vdec_unlock(struct mtk_vcodec_ctx *ctx);
> +void mtk_vdec_lock(struct mtk_vcodec_ctx *ctx);
> +int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq,
> +			   struct vb2_queue *dst_vq);
> +void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx);
> +void mtk_vcodec_vdec_release(struct mtk_vcodec_ctx *ctx);
> +int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_ctx *ctx);
> +
> +
> +#endif /* _MTK_VCODEC_DEC_H_ */
> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
> new file mode 100644
> index 0000000..725d1e5
> --- /dev/null
> +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
> @@ -0,0 +1,408 @@
> +/*
> +* Copyright (c) 2016 MediaTek Inc.
> +* Author: PC Chen <pc.chen at mediatek.com>
> +*         Tiffany Lin <tiffany.lin at mediatek.com>
> +*
> +* This program is free software; you can redistribute it and/or modify
> +* it under the terms of the GNU General Public License version 2 as
> +* published by the Free Software Foundation.
> +*
> +* 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.
> +*/
> +
> +#include <linux/slab.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/of.h>
> +#include <media/v4l2-event.h>
> +#include <media/v4l2-mem2mem.h>
> +#include <media/videobuf2-dma-contig.h>
> +
> +#include "mtk_vcodec_drv.h"
> +#include "mtk_vcodec_dec.h"
> +#include "mtk_vcodec_dec_pm.h"
> +#include "mtk_vcodec_intr.h"
> +#include "mtk_vcodec_util.h"
> +#include "mtk_vpu.h"
> +
> +#define VDEC_HW_ACTIVE	0x10
> +#define VDEC_IRQ_CFG	0x11
> +#define VDEC_IRQ_CLR	0x10
> +#define VDEC_IRQ_CFG_REG	0xa4
> +
> +module_param(mtk_v4l2_dbg_level, int, S_IRUGO | S_IWUSR);
> +module_param(mtk_vcodec_dbg, bool, S_IRUGO | S_IWUSR);
> +
> +/* Wake up context wait_queue */
> +static void wake_up_ctx(struct mtk_vcodec_ctx *ctx)
> +{
> +	ctx->int_cond = 1;
> +	wake_up_interruptible(&ctx->queue);
> +}
> +
> +static irqreturn_t mtk_vcodec_dec_irq_handler(int irq, void *priv)
> +{
> +	struct mtk_vcodec_dev *dev = priv;
> +	struct mtk_vcodec_ctx *ctx;
> +	u32 cg_status = 0;
> +	unsigned int dec_done_status = 0;
> +	void __iomem *vdec_misc_addr = dev->reg_base[VDEC_MISC] +
> +					VDEC_IRQ_CFG_REG;
> +
> +	ctx = mtk_vcodec_get_curr_ctx(dev);
> +
> +	/* check if HW active or not */
> +	cg_status = readl(dev->reg_base[0]);
> +	if ((cg_status & VDEC_HW_ACTIVE) != 0) {
> +		mtk_v4l2_err("DEC ISR, VDEC active is not 0x0 (0x%08x)",
> +			     cg_status);
> +		return IRQ_HANDLED;
> +	}
> +
> +	dec_done_status = readl(vdec_misc_addr);
> +	ctx->irq_status = dec_done_status;
> +	if ((dec_done_status & MTK_VDEC_IRQ_STATUS_DEC_SUCCESS) !=
> +		MTK_VDEC_IRQ_STATUS_DEC_SUCCESS)
> +		return IRQ_HANDLED;
> +
> +	/* clear interrupt */
> +	writel((readl(vdec_misc_addr) | VDEC_IRQ_CFG),
> +		dev->reg_base[VDEC_MISC] + VDEC_IRQ_CFG_REG);
> +	writel((readl(vdec_misc_addr) & ~VDEC_IRQ_CLR),
> +		dev->reg_base[VDEC_MISC] + VDEC_IRQ_CFG_REG);
> +
> +	wake_up_ctx(ctx);
> +
> +	mtk_v4l2_debug(3,
> +			"mtk_vcodec_dec_irq_handler :wake up ctx %d, dec_done_status=%x",
> +			ctx->id, dec_done_status);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static void mtk_vcodec_dec_reset_handler(void *priv)
> +{
> +	struct mtk_vcodec_dev *dev = priv;
> +	struct mtk_vcodec_ctx *ctx;
> +
> +	mtk_v4l2_err("Watchdog timeout!!");
> +
> +	mutex_lock(&dev->dev_mutex);
> +	list_for_each_entry(ctx, &dev->ctx_list, list) {
> +		ctx->state = MTK_STATE_ABORT;
> +		mtk_v4l2_debug(0, "[%d] Change to state MTK_STATE_ERROR",
> +				ctx->id);
> +	}
> +	mutex_unlock(&dev->dev_mutex);
> +}
> +
> +static int fops_vcodec_open(struct file *file)
> +{
> +	struct mtk_vcodec_dev *dev = video_drvdata(file);
> +	struct mtk_vcodec_ctx *ctx = NULL;
> +	int ret = 0;
> +
> +	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> +	if (!ctx)
> +		return -ENOMEM;
> +
> +	mutex_lock(&dev->dev_mutex);
> +	ctx->id = dev->id_counter++;
> +	v4l2_fh_init(&ctx->fh, video_devdata(file));
> +	file->private_data = &ctx->fh;
> +	v4l2_fh_add(&ctx->fh);
> +	INIT_LIST_HEAD(&ctx->list);
> +	ctx->dev = dev;
> +	init_waitqueue_head(&ctx->queue);
> +	mutex_init(&ctx->lock);
> +
> +	ctx->type = MTK_INST_DECODER;
> +	ret = mtk_vcodec_dec_ctrls_setup(ctx);
> +	if (ret) {
> +		mtk_v4l2_err("Failed to setup mt vcodec controls");
> +		goto err_ctrls_setup;
> +	}
> +	ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev_dec, ctx,
> +		&mtk_vcodec_dec_queue_init);
> +	if (IS_ERR((__force void *)ctx->m2m_ctx)) {
> +		ret = PTR_ERR((__force void *)ctx->m2m_ctx);
> +		mtk_v4l2_err("Failed to v4l2_m2m_ctx_init() (%d)",
> +			ret);
> +		goto err_m2m_ctx_init;
> +	}
> +	mtk_vcodec_dec_set_default_params(ctx);
> +
> +	if (v4l2_fh_is_singular(&ctx->fh)) {
> +		mtk_vcodec_dec_pw_on(&dev->pm);
> +		/*
> +		 * vpu_load_firmware checks if it was loaded already and
> +		 * does nothing in that case
> +		 */
> +		ret = vpu_load_firmware(dev->vpu_plat_dev);
> +		if (ret < 0) {
> +			/*
> +			 * Return 0 if downloading firmware successfully,
> +			 * otherwise it is failed
> +			 */
> +			mtk_v4l2_err("vpu_load_firmware failed!");
> +			goto err_load_fw;
> +		}
> +
> +		dev->dec_capability =
> +			vpu_get_vdec_hw_capa(dev->vpu_plat_dev);
> +		mtk_v4l2_debug(0, "decoder capability %x", dev->dec_capability);
> +	}
> +
> +	dev->num_instances++;

This field can be dropped since it is no longer used.

> +	list_add(&ctx->list, &dev->ctx_list);
> +
> +	mutex_unlock(&dev->dev_mutex);
> +	mtk_v4l2_debug(0, "%s decoder [%d]", dev_name(&dev->plat_dev->dev),
> +			ctx->id);
> +	return ret;
> +
> +	/* Deinit when failure occurred */
> +err_load_fw:
> +	v4l2_m2m_ctx_release(ctx->m2m_ctx);
> +err_m2m_ctx_init:
> +	v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
> +err_ctrls_setup:
> +	v4l2_fh_del(&ctx->fh);
> +	v4l2_fh_exit(&ctx->fh);
> +	kfree(ctx);
> +	mutex_unlock(&dev->dev_mutex);
> +
> +	return ret;
> +}
> +
> +static int fops_vcodec_release(struct file *file)
> +{
> +	struct mtk_vcodec_dev *dev = video_drvdata(file);
> +	struct mtk_vcodec_ctx *ctx = fh_to_ctx(file->private_data);
> +
> +	mtk_v4l2_debug(0, "[%d] decoder", ctx->id);
> +	mutex_lock(&dev->dev_mutex);
> +
> +	mtk_vcodec_vdec_release(ctx);
> +	if (v4l2_fh_is_singular(&ctx->fh))
> +		mtk_vcodec_dec_pw_off(&dev->pm);
> +
> +	v4l2_fh_del(&ctx->fh);
> +	v4l2_fh_exit(&ctx->fh);
> +	v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
> +	v4l2_m2m_ctx_release(ctx->m2m_ctx);
> +
> +	list_del_init(&ctx->list);
> +	dev->num_instances--;
> +	kfree(ctx);
> +	mutex_unlock(&dev->dev_mutex);
> +	return 0;
> +}
> +
> +static const struct v4l2_file_operations mtk_vcodec_fops = {
> +	.owner		= THIS_MODULE,
> +	.open		= fops_vcodec_open,
> +	.release	= fops_vcodec_release,
> +	.poll		= v4l2_m2m_fop_poll,
> +	.unlocked_ioctl	= video_ioctl2,
> +	.mmap		= v4l2_m2m_fop_mmap,
> +};
> +
> +static int mtk_vcodec_probe(struct platform_device *pdev)
> +{
> +	struct mtk_vcodec_dev *dev;
> +	struct video_device *vfd_dec;
> +	struct resource *res;
> +	int i, ret;
> +	DEFINE_DMA_ATTRS(attrs);
> +
> +	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
> +	if (!dev)
> +		return -ENOMEM;
> +
> +	INIT_LIST_HEAD(&dev->ctx_list);
> +	dev->plat_dev = pdev;
> +
> +	dev->vpu_plat_dev = vpu_get_plat_device(dev->plat_dev);
> +	if (dev->vpu_plat_dev == NULL) {
> +		mtk_v4l2_err("[VPU] vpu device in not ready");
> +		return -EPROBE_DEFER;
> +	}
> +
> +	vpu_wdt_reg_handler(dev->vpu_plat_dev, mtk_vcodec_dec_reset_handler,
> +			dev, VPU_RST_DEC);
> +
> +	ret = mtk_vcodec_init_dec_pm(dev);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "Failed to get mt vcodec clock source");
> +		return ret;
> +	}
> +
> +	for (i = 0; i < NUM_MAX_VDEC_REG_BASE; i++) {
> +		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
> +		if (res == NULL) {
> +			dev_err(&pdev->dev, "get memory resource failed.");
> +			ret = -ENXIO;
> +			goto err_res;
> +		}
> +		dev->reg_base[i] = devm_ioremap_resource(&pdev->dev, res);
> +		if (IS_ERR((__force void *)dev->reg_base[i])) {
> +			dev_err(&pdev->dev,
> +				"devm_ioremap_resource %d failed.", i);
> +			ret = PTR_ERR((__force void *)dev->reg_base);
> +			goto err_res;
> +		}
> +		mtk_v4l2_debug(2, "reg[%d] base=%p", i, dev->reg_base[i]);
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> +	if (res == NULL) {
> +		dev_err(&pdev->dev, "failed to get irq resource");
> +		ret = -ENOENT;
> +		goto err_res;
> +	}
> +
> +	dev->dec_irq = platform_get_irq(pdev, 0);
> +	ret = devm_request_irq(&pdev->dev, dev->dec_irq,
> +			mtk_vcodec_dec_irq_handler, 0, pdev->name, dev);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Failed to install dev->dec_irq %d (%d)",
> +			dev->dec_irq,
> +			ret);
> +		goto err_res;
> +	}
> +
> +	disable_irq(dev->dec_irq);
> +	mutex_init(&dev->dec_mutex);
> +	mutex_init(&dev->dev_mutex);
> +	spin_lock_init(&dev->irqlock);
> +
> +	snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s",
> +		"[/MTK_V4L2_VDEC]");
> +
> +	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
> +	if (ret) {
> +		mtk_v4l2_err("v4l2_device_register err=%d", ret);
> +		goto err_res;
> +	}
> +
> +	init_waitqueue_head(&dev->queue);
> +
> +	vfd_dec = video_device_alloc();
> +	if (!vfd_dec) {
> +		mtk_v4l2_err("Failed to allocate video device");
> +		ret = -ENOMEM;
> +		goto err_dec_alloc;
> +	}
> +	vfd_dec->fops		= &mtk_vcodec_fops;
> +	vfd_dec->ioctl_ops	= &mtk_vdec_ioctl_ops;
> +	vfd_dec->release	= video_device_release;
> +	vfd_dec->lock		= &dev->dev_mutex;
> +	vfd_dec->v4l2_dev	= &dev->v4l2_dev;
> +	vfd_dec->vfl_dir	= VFL_DIR_M2M;
> +	vfd_dec->device_caps	= V4L2_CAP_VIDEO_M2M_MPLANE |
> +			V4L2_CAP_STREAMING;
> +
> +	snprintf(vfd_dec->name, sizeof(vfd_dec->name), "%s",
> +		MTK_VCODEC_DEC_NAME);
> +	video_set_drvdata(vfd_dec, dev);
> +	dev->vfd_dec = vfd_dec;
> +	platform_set_drvdata(pdev, dev);
> +
> +	dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
> +	if (IS_ERR((__force void *)dev->alloc_ctx)) {
> +		mtk_v4l2_err("Failed to alloc vb2 dma context 0");
> +		ret = PTR_ERR((__force void *)dev->alloc_ctx);
> +		goto err_vb2_ctx_init;
> +	}
> +
> +	dev->m2m_dev_dec = v4l2_m2m_init(&mtk_vdec_m2m_ops);
> +	if (IS_ERR((__force void *)dev->m2m_dev_dec)) {
> +		mtk_v4l2_err("Failed to init mem2mem dec device");
> +		ret = PTR_ERR((__force void *)dev->m2m_dev_dec);
> +		goto err_dec_mem_init;
> +	}
> +
> +	dev->decode_workqueue =
> +		alloc_ordered_workqueue(MTK_VCODEC_DEC_NAME,
> +			WQ_MEM_RECLAIM | WQ_FREEZABLE);
> +	if (!dev->decode_workqueue) {
> +		mtk_v4l2_err("Failed to create decode workqueue");
> +		ret = -EINVAL;
> +		goto err_event_workq;
> +	}
> +
> +	ret = video_register_device(vfd_dec, VFL_TYPE_GRABBER, 0);
> +	if (ret) {
> +		mtk_v4l2_err("Failed to register video device");
> +		goto err_dec_reg;
> +	}
> +
> +	/* Avoid the iommu eat big hunks */
> +	dma_set_attr(DMA_ATTR_ALLOC_SINGLE_PAGES, &attrs);
> +
> +	mtk_v4l2_debug(0, "decoder registered as /dev/video%d",
> +		vfd_dec->num);
> +
> +	return 0;
> +
> +err_dec_reg:
> +	destroy_workqueue(dev->decode_workqueue);
> +err_event_workq:
> +	v4l2_m2m_release(dev->m2m_dev_dec);
> +err_dec_mem_init:
> +	vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
> +err_vb2_ctx_init:
> +	video_unregister_device(vfd_dec);
> +err_dec_alloc:
> +	v4l2_device_unregister(&dev->v4l2_dev);
> +err_res:
> +	mtk_vcodec_release_dec_pm(dev);
> +	return ret;
> +}
> +
> +static const struct of_device_id mtk_vcodec_match[] = {
> +	{.compatible = "mediatek,mt8173-vcodec-dec",},
> +	{},
> +};
> +
> +MODULE_DEVICE_TABLE(of, mtk_vcodec_match);
> +
> +static int mtk_vcodec_dec_remove(struct platform_device *pdev)
> +{
> +	struct mtk_vcodec_dev *dev = platform_get_drvdata(pdev);
> +
> +	flush_workqueue(dev->decode_workqueue);
> +	destroy_workqueue(dev->decode_workqueue);
> +	if (dev->m2m_dev_dec)
> +		v4l2_m2m_release(dev->m2m_dev_dec);
> +	if (dev->alloc_ctx)
> +		vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
> +
> +	if (dev->vfd_dec)
> +		video_unregister_device(dev->vfd_dec);
> +
> +	v4l2_device_unregister(&dev->v4l2_dev);
> +	mtk_vcodec_release_dec_pm(dev);
> +	return 0;
> +}
> +
> +static struct platform_driver mtk_vcodec_dec_driver = {
> +	.probe	= mtk_vcodec_probe,
> +	.remove	= mtk_vcodec_dec_remove,
> +	.driver	= {
> +		.name	= MTK_VCODEC_DEC_NAME,
> +		.owner	= THIS_MODULE,
> +		.of_match_table = mtk_vcodec_match,
> +	},
> +};
> +
> +module_platform_driver(mtk_vcodec_dec_driver);
> +
> +MODULE_LICENSE("GPL v2");
> +MODULE_DESCRIPTION("Mediatek video codec V4L2 decoder driver");
> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
> new file mode 100644
> index 0000000..364b756
> --- /dev/null
> +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
> @@ -0,0 +1,206 @@
> +/*
> +* Copyright (c) 2016 MediaTek Inc.
> +* Author: Tiffany Lin <tiffany.lin at mediatek.com>
> +*
> +* This program is free software; you can redistribute it and/or modify
> +* it under the terms of the GNU General Public License version 2 as
> +* published by the Free Software Foundation.
> +*
> +* 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.
> +*/
> +
> +#include <linux/clk.h>
> +#include <linux/of_address.h>
> +#include <linux/of_platform.h>
> +#include <linux/pm_runtime.h>
> +#include <soc/mediatek/smi.h>
> +
> +#include "mtk_vcodec_dec_pm.h"
> +#include "mtk_vcodec_util.h"
> +#include "mtk_vpu.h"
> +
> +int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev)
> +{
> +	struct device_node *node;
> +	struct platform_device *pdev;
> +	struct device *dev;
> +	struct mtk_vcodec_pm *pm;
> +	int ret = 0;
> +
> +	pdev = mtkdev->plat_dev;
> +	pm = &mtkdev->pm;
> +	pm->mtkdev = mtkdev;
> +	dev = &pdev->dev;
> +	node = of_parse_phandle(pdev->dev.of_node, "mediatek,larb", 0);
> +	if (!node) {
> +		mtk_v4l2_err("of_parse_phandle mediatek,larb fail!");
> +		return -1;
> +	}
> +
> +	pdev = of_find_device_by_node(node);
> +	if (WARN_ON(!pdev)) {
> +		of_node_put(node);
> +		return -1;
> +	}
> +	pm->larbvdec = &pdev->dev;
> +
> +	pdev = mtkdev->plat_dev;
> +	pm->dev = &pdev->dev;
> +
> +	pm->vcodecpll = devm_clk_get(&pdev->dev, "vcodecpll");
> +	if (pm->vcodecpll == NULL) {
> +		mtk_v4l2_err("devm_clk_get vcodecpll fail");
> +		ret = -1;
> +	}
> +
> +	pm->univpll_d2 = devm_clk_get(&pdev->dev, "univpll_d2");
> +	if (pm->univpll_d2 == NULL) {
> +		mtk_v4l2_err("devm_clk_get univpll_d2 fail");
> +		ret = -1;
> +	}
> +
> +	pm->clk_cci400_sel = devm_clk_get(&pdev->dev, "clk_cci400_sel");
> +	if (pm->clk_cci400_sel == NULL) {
> +		mtk_v4l2_err("devm_clk_get clk_cci400_sel fail");
> +		ret = -1;
> +	}
> +
> +	pm->vdec_sel = devm_clk_get(&pdev->dev, "vdec_sel");
> +	if (pm->vdec_sel == NULL) {
> +		mtk_v4l2_err("devm_clk_get vdec_sel fail");
> +		ret = -1;
> +	}
> +
> +	pm->vdecpll = devm_clk_get(&pdev->dev, "vdecpll");
> +	if (pm->vdecpll == NULL) {
> +		mtk_v4l2_err("devm_clk_get vdecpll fail");
> +		ret = -1;
> +	}
> +
> +	pm->vencpll = devm_clk_get(&pdev->dev, "vencpll");
> +	if (pm->vencpll == NULL) {
> +		mtk_v4l2_err("devm_clk_get vencpll fail");
> +		ret = -1;
> +	}
> +
> +	pm->venc_lt_sel = devm_clk_get(&pdev->dev, "venc_lt_sel");
> +	if (pm->venc_lt_sel == NULL) {
> +		mtk_v4l2_err("devm_clk_get venc_lt_sel fail");
> +		ret = -1;
> +	}
> +
> +	pm->vdec_bus_clk_src = devm_clk_get(&pdev->dev, "vdec_bus_clk_src");
> +	if (pm->vdec_bus_clk_src == NULL) {
> +		mtk_v4l2_err("devm_clk_get vdec_bus_clk_src");
> +		ret = -1;
> +	}
> +
> +	pm_runtime_enable(&pdev->dev);
> +
> +	return ret;
> +}
> +
> +void mtk_vcodec_release_dec_pm(struct mtk_vcodec_dev *dev)
> +{
> +	pm_runtime_disable(dev->pm.dev);
> +}
> +
> +void mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm)
> +{
> +	int ret;
> +
> +	ret = pm_runtime_get_sync(pm->dev);
> +	if (ret)
> +		mtk_v4l2_err("pm_runtime_get_sync fail %d", ret);
> +}
> +
> +void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm)
> +{
> +	int ret;
> +
> +	ret = pm_runtime_put_sync(pm->dev);
> +	if (ret)
> +		mtk_v4l2_err("pm_runtime_put_sync fail %d", ret);
> +}
> +
> +void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm)
> +{
> +	int ret;
> +
> +	ret = clk_set_rate(pm->vcodecpll, 1482 * 1000000);
> +	if (ret)
> +		mtk_v4l2_err("clk_set_rate vcodecpll fail %d", ret);
> +
> +	ret = clk_set_rate(pm->vencpll, 800 * 1000000);
> +	if (ret)
> +		mtk_v4l2_err("clk_set_rate vencpll fail %d", ret);
> +
> +	ret = clk_prepare_enable(pm->vcodecpll);
> +	if (ret)
> +		mtk_v4l2_err("clk_prepare_enable vcodecpll fail %d", ret);
> +
> +	ret = clk_prepare_enable(pm->vencpll);
> +	if (ret)
> +		mtk_v4l2_err("clk_prepare_enable vencpll fail %d", ret);
> +
> +	ret = clk_prepare_enable(pm->vdec_bus_clk_src);
> +	if (ret)
> +		mtk_v4l2_err("clk_prepare_enable vdec_bus_clk_src fail %d",
> +				ret);
> +
> +	ret = clk_prepare_enable(pm->venc_lt_sel);
> +	if (ret)
> +		mtk_v4l2_err("clk_prepare_enable venc_lt_sel fail %d", ret);
> +
> +	ret = clk_set_parent(pm->venc_lt_sel, pm->vdec_bus_clk_src);
> +	if (ret)
> +		mtk_v4l2_err("clk_set_parent venc_lt_sel vdec_bus_clk_src fail %d",
> +				ret);
> +
> +	ret = clk_prepare_enable(pm->univpll_d2);
> +	if (ret)
> +		mtk_v4l2_err("clk_prepare_enable univpll_d2 fail %d", ret);
> +
> +	ret = clk_prepare_enable(pm->clk_cci400_sel);
> +	if (ret)
> +		mtk_v4l2_err("clk_prepare_enable clk_cci400_sel fail %d", ret);
> +
> +	ret = clk_set_parent(pm->clk_cci400_sel, pm->univpll_d2);
> +	if (ret)
> +		mtk_v4l2_err("clk_set_parent clk_cci400_sel univpll_d2 fail %d",
> +				ret);
> +
> +	ret = clk_prepare_enable(pm->vdecpll);
> +	if (ret)
> +		mtk_v4l2_err("clk_prepare_enable vdecpll fail %d", ret);
> +
> +	ret = clk_prepare_enable(pm->vdec_sel);
> +	if (ret)
> +		mtk_v4l2_err("clk_prepare_enable vdec_sel fail %d", ret);
> +
> +	ret = clk_set_parent(pm->vdec_sel, pm->vdecpll);
> +	if (ret)
> +		mtk_v4l2_err("clk_set_parent vdec_sel vdecpll fail %d", ret);
> +
> +	ret = mtk_smi_larb_get(pm->larbvdec);
> +	if (ret)
> +		mtk_v4l2_err("mtk_smi_larb_get larbvdec fail %d", ret);
> +
> +}
> +
> +void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm)
> +{
> +	mtk_smi_larb_put(pm->larbvdec);
> +	clk_disable_unprepare(pm->vdec_sel);
> +	clk_disable_unprepare(pm->vdecpll);
> +	clk_disable_unprepare(pm->univpll_d2);
> +	clk_disable_unprepare(pm->clk_cci400_sel);
> +	clk_disable_unprepare(pm->venc_lt_sel);
> +	clk_disable_unprepare(pm->vdec_bus_clk_src);
> +	clk_disable_unprepare(pm->vencpll);
> +	clk_disable_unprepare(pm->vcodecpll);
> +}
> +
> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h
> new file mode 100644
> index 0000000..b8bf56f
> --- /dev/null
> +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h
> @@ -0,0 +1,28 @@
> +/*
> +* Copyright (c) 2016 MediaTek Inc.
> +* Author: Tiffany Lin <tiffany.lin at mediatek.com>
> +*
> +* This program is free software; you can redistribute it and/or modify
> +* it under the terms of the GNU General Public License version 2 as
> +* published by the Free Software Foundation.
> +*
> +* 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.
> +*/
> +
> +#ifndef _MTK_VCODEC_DEC_PM_H_
> +#define _MTK_VCODEC_DEC_PM_H_
> +
> +#include "mtk_vcodec_drv.h"
> +
> +int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *dev);
> +void mtk_vcodec_release_dec_pm(struct mtk_vcodec_dev *dev);
> +
> +void mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm);
> +void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm);
> +void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm);
> +void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm);
> +
> +#endif /* _MTK_VCODEC_DEC_PM_H_ */
> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
> index 78eee50..a11dfec 100644
> --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
> +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
> @@ -26,10 +26,10 @@
>  #include "mtk_vcodec_util.h"
>  
>  #define MTK_VCODEC_DRV_NAME	"mtk_vcodec_drv"
> +#define MTK_VCODEC_DEC_NAME	"mtk-vcodec-dec"
>  #define MTK_VCODEC_ENC_NAME	"mtk-vcodec-enc"
>  #define MTK_PLATFORM_STR	"platform:mt8173"
>  
> -
>  #define MTK_VCODEC_MAX_PLANES	3
>  #define MTK_V4L2_BENCHMARK	0
>  #define WAIT_INTR_TIMEOUT_MS	1000
> @@ -180,6 +180,9 @@ struct mtk_enc_params {
>   * struct mtk_vcodec_pm - Power management data structure
>   */
>  struct mtk_vcodec_pm {
> +	struct clk	*vdec_bus_clk_src;
> +	struct clk	*vencpll;
> +
>  	struct clk	*vcodecpll;
>  	struct clk	*univpll_d2;
>  	struct clk	*clk_cci400_sel;
> @@ -197,6 +200,32 @@ struct mtk_vcodec_pm {
>  };
>  
>  /**
> + * struct vdec_pic_info  - picture size information
> + * @pic_w: picture width
> + * @pic_h: picture height
> + * @buf_w: picture buffer width (64 aligned up from pic_w)
> + * @buf_h: picture buffer heiht (64 aligned up from pic_h)
> + * @y_bs_sz: Y bitstream size
> + * @c_bs_sz: CbCr bitstream size
> + * @y_len_sz: additional size required to store decompress information for y
> + *		plane
> + * @c_len_sz: additional size required to store decompress information for cbcr
> + *		plane
> + * E.g. suppose picture size is 176x144,
> + *      buffer size will be aligned to 176x160.
> + */
> +struct vdec_pic_info {
> +	unsigned int pic_w;
> +	unsigned int pic_h;
> +	unsigned int buf_w;
> +	unsigned int buf_h;
> +	unsigned int y_bs_sz;
> +	unsigned int c_bs_sz;
> +	unsigned int y_len_sz;
> +	unsigned int c_len_sz;
> +};
> +
> +/**
>   * struct mtk_vcodec_ctx - Context (instance) private data.
>   *
>   * @type: type of the instance - decoder or encoder
> @@ -210,9 +239,12 @@ struct mtk_vcodec_pm {
>   * @state: state of the context
>   * @param_change: indicate encode parameter type
>   * @enc_params: encoding parameters
> - * @enc_if: hoooked encoder driver interface
> + * @dec_if: hooked decoder driver interface
> + * @enc_if: hooked encoder driver interface
>   * @drv_handle: driver handle for specific decode/encode instance
>   *
> + * @picinfo: store picture info after header parsing
> + * @dpb_size: store dpb count after header parsing
>   * @int_cond: variable used by the waitqueue
>   * @int_type: type of the last interrupt
>   * @queue: waitqueue that can be used to wait for this context to
> @@ -220,12 +252,16 @@ struct mtk_vcodec_pm {
>   * @irq_status: irq status
>   *
>   * @ctrl_hdl: handler for v4l2 framework
> + * @decode_work: worker for the decoding
>   * @encode_work: worker for the encoding
> + * @last_decoded_picinfo: pic information get from latest decode
>   *
>   * @colorspace: enum v4l2_colorspace; supplemental to pixelformat
>   * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding
>   * @quantization: enum v4l2_quantization, colorspace quantization
>   * @xfer_func: enum v4l2_xfer_func, colorspace transfer function
> + * @lock: protect variables accessed by V4L2 threads and worker thread such as
> + *	  mtk_video_dec_buf.
>   */
>  struct mtk_vcodec_ctx {
>  	enum mtk_instance_type type;
> @@ -240,21 +276,31 @@ struct mtk_vcodec_ctx {
>  	enum mtk_encode_param param_change;
>  	struct mtk_enc_params enc_params;
>  
> +	struct vdec_common_if *dec_if;
>  	struct venc_common_if *enc_if;
>  	unsigned long drv_handle;
>  
> +	struct vdec_pic_info picinfo;
> +	int dpb_size;
> +
>  	int int_cond;
>  	int int_type;
>  	wait_queue_head_t queue;
>  	unsigned int irq_status;
>  
>  	struct v4l2_ctrl_handler ctrl_hdl;
> +	struct work_struct decode_work;
>  	struct work_struct encode_work;
> +	struct vdec_pic_info last_decoded_picinfo;
>  
>  	enum v4l2_colorspace colorspace;
>  	enum v4l2_ycbcr_encoding ycbcr_enc;
>  	enum v4l2_quantization quantization;
>  	enum v4l2_xfer_func xfer_func;
> +
> +	int decoded_frame_cnt;
> +	struct mutex lock;
> +
>  };
>  
>  /**
> @@ -268,25 +314,48 @@ struct mtk_vcodec_ctx {
>   * @alloc_ctx: VB2 allocator context
>   *	       (for allocations without kernel mapping).
>   * @ctx_list: list of struct mtk_vcodec_ctx
> - * @irqlock: protect data access by irq handler and work thread
> - * @curr_ctx: The context that is waiting for codec hardware
> + * @irqlock: protect data access by irq handler and work thread -- curr_ctx
> + * @curr_ctx: The context that is waiting for codec hardware. Protected by
> + *		irqlock and dec_mutex or enc_mutex.
>   *
>   * @reg_base: Mapped address of MTK Vcodec registers.
>   *
> - * @id_counter: used to identify current opened instance
> + * @id_counter:  An integer id given to the next opened instance
>   * @num_instances: counter of active MTK Vcodec instances
>   *
>   * @encode_workqueue: encode work queue
>   *
> + * @v4l2_dev: V4L2 device to register video devices for.
> + * @vfd_dec: Video device for decoder
> + * @vfd_enc: Video device for encoder
> + *
> + * @m2m_dev_dec: m2m device for decoder
> + * @m2m_dev_enc: m2m device for encoder
> + * @plat_dev: platform device
> + * @vpu_plat_dev: mtk vpu platform device
> + * @alloc_ctx:VB2 allocator context
> + *	      (for allocations without kernel mapping).
> + * @ctx_list: list of struct mtk_vcodec_ctx
> + * @irqlock: protect data access by irq handler and work thread
> + * @curr_ctx: The context that is waiting for codec hardware
> + * @reg_base: Mapped address of MTK Vcodec registers.
> + *
> + * @instance_mask: used to mark which index id are used
> + * @num_instances: counter of active MTK Vcodec instances
> + *
> + * @decode_workqueue: decode work queue
> + * @encode_workqueue: encode work queue
>   * @int_cond: used to identify interrupt condition happen
>   * @int_type: used to identify what kind of interrupt condition happen
>   * @dev_mutex: video_device lock
>   * @queue: waitqueue for waiting for completion of device commands
>   *
> + * @dec_irq: decoder irq resource
>   * @enc_irq: h264 encoder irq resource
> - * @enc_lt_irq: vp8 encoder irq resource
> + * @enc_lt_irq: vp8 encoder lt irq resource
>   *
> - * @enc_mutex: encoder hardware lock.
> + * @dec_mutex: decoder hardware lock
> + * @enc_mutex: encoder hardware lock
>   *
>   * @pm: power management control
>   * @dec_capability: used to identify decode capability, ex: 4k
> @@ -294,8 +363,10 @@ struct mtk_vcodec_ctx {
>   */
>  struct mtk_vcodec_dev {
>  	struct v4l2_device v4l2_dev;
> +	struct video_device *vfd_dec;
>  	struct video_device *vfd_enc;
>  
> +	struct v4l2_m2m_dev *m2m_dev_dec;
>  	struct v4l2_m2m_dev *m2m_dev_enc;
>  	struct platform_device *plat_dev;
>  	struct platform_device *vpu_plat_dev;
> @@ -308,6 +379,7 @@ struct mtk_vcodec_dev {
>  	unsigned long id_counter;
>  	int num_instances;
>  
> +	struct workqueue_struct *decode_workqueue;
>  	struct workqueue_struct *encode_workqueue;
>  
>  	int int_cond;
> @@ -315,9 +387,11 @@ struct mtk_vcodec_dev {
>  	struct mutex dev_mutex;
>  	wait_queue_head_t queue;
>  
> +	int dec_irq;
>  	int enc_irq;
>  	int enc_lt_irq;
>  
> +	struct mutex dec_mutex;
>  	struct mutex enc_mutex;
>  
>  	struct mtk_vcodec_pm pm;
> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c
> index 52e7e5c..f0bdb19 100644
> --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c
> +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c
> @@ -30,8 +30,7 @@ int mtk_vcodec_wait_for_done_ctx(struct mtk_vcodec_ctx  *ctx, int command,
>  	timeout_jiff = msecs_to_jiffies(timeout_ms);
>  
>  	ret = wait_event_interruptible_timeout(*waitqueue,
> -				(ctx->int_cond &&
> -				(ctx->int_type == command)),
> +				ctx->int_cond,
>  				timeout_jiff);
>  
>  	if (!ret) {
> @@ -52,3 +51,4 @@ int mtk_vcodec_wait_for_done_ctx(struct mtk_vcodec_ctx  *ctx, int command,
>  	return status;
>  }
>  EXPORT_SYMBOL(mtk_vcodec_wait_for_done_ctx);
> +
> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h
> index 33e890f..fbb8b1e 100644
> --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h
> +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h
> @@ -16,7 +16,7 @@
>  #define _MTK_VCODEC_INTR_H_
>  
>  #define MTK_INST_IRQ_RECEIVED		0x1
> -#define MTK_INST_WORK_THREAD_ABORT_DONE	0x2
> +
>  
>  struct mtk_vcodec_ctx;
>  
> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c
> index 5e36513..7617305 100644
> --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c
> +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c
> @@ -81,14 +81,35 @@ void mtk_vcodec_mem_free(struct mtk_vcodec_ctx *data,
>  		return;
>  	}
>  
> -	dma_free_coherent(dev, size, mem->va, mem->dma_addr);
> -	mem->va = NULL;
> -	mem->dma_addr = 0;
> -	mem->size = 0;
> -
>  	mtk_v4l2_debug(3, "[%d]  - va      = %p", ctx->id, mem->va);
>  	mtk_v4l2_debug(3, "[%d]  - dma     = 0x%lx", ctx->id,
>  		       (unsigned long)mem->dma_addr);
>  	mtk_v4l2_debug(3, "[%d]    size = 0x%lx", ctx->id, size);
> +
> +	dma_free_coherent(dev, size, mem->va, mem->dma_addr);
> +	mem->va = NULL;
> +	mem->dma_addr = 0;
> +	mem->size = 0;
>  }
>  EXPORT_SYMBOL(mtk_vcodec_mem_free);
> +
> +void mtk_vcodec_set_curr_ctx(struct mtk_vcodec_dev *dev,
> +	struct mtk_vcodec_ctx *ctx)
> +{
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&dev->irqlock, flags);
> +	dev->curr_ctx = ctx;
> +	spin_unlock_irqrestore(&dev->irqlock, flags);
> +}
> +
> +struct mtk_vcodec_ctx *mtk_vcodec_get_curr_ctx(struct mtk_vcodec_dev *dev)
> +{
> +	unsigned long flags;
> +	struct mtk_vcodec_ctx *ctx;
> +
> +	spin_lock_irqsave(&dev->irqlock, flags);
> +	ctx = dev->curr_ctx;
> +	spin_unlock_irqrestore(&dev->irqlock, flags);
> +	return ctx;
> +}
> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h
> index d6345fc..91a0b1a 100644
> --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h
> +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h
> @@ -1,7 +1,7 @@
>  /*
>  * Copyright (c) 2016 MediaTek Inc.
>  * Author: PC Chen <pc.chen at mediatek.com>
> -*	Tiffany Lin <tiffany.lin at mediatek.com>
> +*		Tiffany Lin <tiffany.lin at mediatek.com>
>  *
>  * This program is free software; you can redistribute it and/or modify
>  * it under the terms of the GNU General Public License version 2 as
> @@ -26,6 +26,7 @@ struct mtk_vcodec_mem {
>  };
>  
>  struct mtk_vcodec_ctx;
> +struct mtk_vcodec_dev;
>  
>  extern int mtk_v4l2_dbg_level;
>  extern bool mtk_vcodec_dbg;
> @@ -84,4 +85,8 @@ int mtk_vcodec_mem_alloc(struct mtk_vcodec_ctx *data,
>  				struct mtk_vcodec_mem *mem);
>  void mtk_vcodec_mem_free(struct mtk_vcodec_ctx *data,
>  				struct mtk_vcodec_mem *mem);
> +void mtk_vcodec_set_curr_ctx(struct mtk_vcodec_dev *dev,
> +	struct mtk_vcodec_ctx *ctx);
> +struct mtk_vcodec_ctx *mtk_vcodec_get_curr_ctx(struct mtk_vcodec_dev *dev);
> +
>  #endif /* _MTK_VCODEC_UTIL_H_ */
> diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_base.h b/drivers/media/platform/mtk-vcodec/vdec_drv_base.h
> new file mode 100644
> index 0000000..7e4c1a9
> --- /dev/null
> +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_base.h
> @@ -0,0 +1,56 @@
> +/*
> + * Copyright (c) 2016 MediaTek Inc.
> + * Author: PC Chen <pc.chen at mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#ifndef _VDEC_DRV_BASE_
> +#define _VDEC_DRV_BASE_
> +
> +#include "mtk_vcodec_drv.h"
> +
> +#include "vdec_drv_if.h"
> +
> +struct vdec_common_if {
> +	/**
> +	 * (*init)() - initialize decode driver
> +	 * @ctx     : [in] mtk v4l2 context
> +	 * @h_vdec  : [out] driver handle
> +	 */
> +	int (*init)(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec);
> +
> +	/**
> +	 * (*decode)() - trigger decode
> +	 * @h_vdec  : [in] driver handle
> +	 * @bs      : [in] input bitstream
> +	 * @fb      : [in] frame buffer to store decoded frame
> +	 * @res_chg : [out] resolution change happen
> +	 */
> +	int (*decode)(unsigned long h_vdec, struct mtk_vcodec_mem *bs,
> +		      struct vdec_fb *fb, bool *res_chg);
> +
> +	/**
> +	 * (*get_param)() - get driver's parameter
> +	 * @h_vdec : [in] driver handle
> +	 * @type   : [in] input parameter type
> +	 * @out    : [out] buffer to store query result
> +	 */
> +	int (*get_param)(unsigned long h_vdec, enum vdec_get_param_type type,
> +			 void *out);
> +
> +	/**
> +	 * (*deinit)() - deinitialize driver.
> +	 * @h_vdec : [in] driver handle to be deinit
> +	 */
> +	void (*deinit)(unsigned long h_vdec);
> +};
> +
> +#endif
> diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c
> new file mode 100644
> index 0000000..8202b14
> --- /dev/null
> +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c
> @@ -0,0 +1,107 @@
> +/*
> + * Copyright (c) 2016 MediaTek Inc.
> + * Author: PC Chen <pc.chen at mediatek.com>
> + *         Tiffany Lin <tiffany.lin at mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +
> +#include "vdec_drv_base.h"
> +#include "vdec_drv_if.h"
> +
> +#include "mtk_vcodec_dec_pm.h"
> +#include "mtk_vcodec_util.h"
> +#include "mtk_vpu.h"
> +
> +int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc)
> +{
> +	int ret = 0;
> +
> +	switch (fourcc) {
> +	case V4L2_PIX_FMT_H264:
> +	case V4L2_PIX_FMT_VP8:
> +	case V4L2_PIX_FMT_VP9:
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	mtk_vdec_lock(ctx);
> +	mtk_vcodec_dec_clock_on(&ctx->dev->pm);
> +	ret = ctx->dec_if->init(ctx, &ctx->drv_handle);
> +	mtk_vcodec_dec_clock_off(&ctx->dev->pm);
> +	mtk_vdec_unlock(ctx);
> +
> +	return ret;
> +}
> +
> +int vdec_if_decode(struct mtk_vcodec_ctx *ctx, struct mtk_vcodec_mem *bs,
> +		   struct vdec_fb *fb, bool *res_chg)
> +{
> +	int ret = 0;
> +
> +	if (bs) {
> +		if ((bs->dma_addr & 63) != 0) {
> +			mtk_v4l2_err("bs dma_addr should 64 byte align");
> +			return -EINVAL;
> +		}
> +	}
> +
> +	if (fb) {
> +		if (((fb->base_y.dma_addr & 511) != 0) ||
> +		    ((fb->base_c.dma_addr & 511) != 0)) {
> +			mtk_v4l2_err("frame buffer dma_addr should 512 byte align");
> +			return -EINVAL;
> +		}
> +	}
> +
> +	mtk_vdec_lock(ctx);
> +
> +	mtk_vcodec_set_curr_ctx(ctx->dev, ctx);
> +	mtk_vcodec_dec_clock_on(&ctx->dev->pm);
> +	enable_irq(ctx->dev->dec_irq);
> +	ret = ctx->dec_if->decode(ctx->drv_handle, bs, fb, res_chg);
> +	disable_irq(ctx->dev->dec_irq);
> +	mtk_vcodec_dec_clock_off(&ctx->dev->pm);
> +	mtk_vcodec_set_curr_ctx(ctx->dev, NULL);
> +
> +	mtk_vdec_unlock(ctx);
> +
> +	return ret;
> +}
> +
> +int vdec_if_get_param(struct mtk_vcodec_ctx *ctx, enum vdec_get_param_type type,
> +		      void *out)
> +{
> +	int ret = 0;
> +
> +	mtk_vdec_lock(ctx);
> +	ret = ctx->dec_if->get_param(ctx->drv_handle, type, out);
> +	mtk_vdec_unlock(ctx);
> +
> +	return ret;
> +}
> +
> +void vdec_if_deinit(struct mtk_vcodec_ctx *ctx)
> +{
> +	if (ctx->drv_handle == 0)
> +		return;
> +
> +	mtk_vdec_lock(ctx);
> +	mtk_vcodec_dec_clock_on(&ctx->dev->pm);
> +	ctx->dec_if->deinit(ctx->drv_handle);
> +	mtk_vcodec_dec_clock_off(&ctx->dev->pm);
> +	mtk_vdec_unlock(ctx);
> +
> +	ctx->drv_handle = 0;
> +}
> diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.h b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h
> new file mode 100644
> index 0000000..db6b520
> --- /dev/null
> +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h
> @@ -0,0 +1,101 @@
> +/*
> + * Copyright (c) 2016 MediaTek Inc.
> + * Author: PC Chen <pc.chen at mediatek.com>
> + *		   Tiffany Lin <tiffany.lin at mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#ifndef _VDEC_DRV_IF_H_
> +#define _VDEC_DRV_IF_H_
> +
> +#include "mtk_vcodec_drv.h"
> +#include "mtk_vcodec_dec.h"
> +#include "mtk_vcodec_util.h"
> +
> +
> +/**
> + * struct vdec_fb_status  - decoder frame buffer status
> + * @FB_ST_NORMAL	: initial state
> + * @FB_ST_DISPLAY	: frmae buffer is ready to be displayed
> + * @FB_ST_FREE		: frame buffer is not used by decoder any more
> + */
> +enum vdec_fb_status {
> +	FB_ST_NORMAL		= 0,
> +	FB_ST_DISPLAY		= (1 << 0),
> +	FB_ST_FREE		= (1 << 1)
> +};
> +
> +/* For GET_PARAM_DISP_FRAME_BUFFER and GET_PARAM_FREE_FRAME_BUFFER,
> + * the caller does not own the returned buffer. The buffer will not be
> + *				released before vdec_if_deinit.
> + * GET_PARAM_DISP_FRAME_BUFFER	: get next displayable frame buffer,
> + *				struct vdec_fb**
> + * GET_PARAM_FREE_FRAME_BUFFER	: get non-referenced framebuffer, vdec_fb**
> + * GET_PARAM_PIC_INFO		: get picture info, struct vdec_pic_info*
> + * GET_PARAM_CROP_INFO		: get crop info, struct v4l2_crop*
> + * GET_PARAM_DPB_SIZE		: get dpb size, unsigned int*
> + */
> +enum vdec_get_param_type {
> +	GET_PARAM_DISP_FRAME_BUFFER,
> +	GET_PARAM_FREE_FRAME_BUFFER,
> +	GET_PARAM_PIC_INFO,
> +	GET_PARAM_CROP_INFO,
> +	GET_PARAM_DPB_SIZE
> +};
> +
> +/**
> + * struct vdec_fb_node  - decoder frame buffer node
> + * @list	: list to hold this node
> + * @fb	: point to frame buffer (vdec_fb), fb could point to frame buffer and
> + *	working buffer this is for maintain buffers in different state
> + */
> +struct vdec_fb_node {
> +	struct list_head list;
> +	struct vdec_fb *fb;
> +};
> +
> +/**
> + * vdec_if_init() - initialize decode driver
> + * @ctx	: [in] v4l2 context
> + * @fourcc	: [in] video format fourcc, V4L2_PIX_FMT_H264/VP8/VP9..
> + */
> +int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc);
> +
> +/**
> + * vdec_if_deinit() - deinitialize decode driver
> + * @ctx	: [in] v4l2 context
> + *
> + */
> +void vdec_if_deinit(struct mtk_vcodec_ctx *ctx);
> +
> +/**
> + * vdec_if_decode() - trigger decode
> + * @ctx	: [in] v4l2 context
> + * @bs	: [in] input bitstream
> + * @fb	: [in] frame buffer to store decoded frame, when null menas parse
> + *	header only
> + * @res_chg	: [out] resolution change happens if current bs have different
> + *	picture width/height
> + * Note: To flush the decoder when reaching EOF, set input bitstream as NULL.
> + */
> +int vdec_if_decode(struct mtk_vcodec_ctx *ctx, struct mtk_vcodec_mem *bs,
> +		   struct vdec_fb *fb, bool *res_chg);
> +
> +/**
> + * vdec_if_get_param() - get driver's parameter
> + * @ctx	: [in] v4l2 context
> + * @type	: [in] input parameter type
> + * @out	: [out] buffer to store query result
> + */
> +int vdec_if_get_param(struct mtk_vcodec_ctx *ctx, enum vdec_get_param_type type,
> +		      void *out);
> +
> +#endif
> diff --git a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h
> new file mode 100644
> index 0000000..5a8a629
> --- /dev/null
> +++ b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h
> @@ -0,0 +1,103 @@
> +/*
> + * Copyright (c) 2016 MediaTek Inc.
> + * Author: PC Chen <pc.chen at mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#ifndef _VDEC_IPI_MSG_H_
> +#define _VDEC_IPI_MSG_H_
> +
> +/**
> + * enum vdec_ipi_msgid - message id between AP and VPU
> + * @AP_IPIMSG_XXX	: AP to VPU cmd message id
> + * @VPU_IPIMSG_XXX_ACK	: VPU ack AP cmd message id
> + */
> +enum vdec_ipi_msgid {
> +	AP_IPIMSG_DEC_INIT = 0xA000,
> +	AP_IPIMSG_DEC_START = 0xA001,
> +	AP_IPIMSG_DEC_END = 0xA002,
> +	AP_IPIMSG_DEC_DEINIT = 0xA003,
> +	AP_IPIMSG_DEC_RESET = 0xA004,
> +
> +	VPU_IPIMSG_DEC_INIT_ACK = 0xB000,
> +	VPU_IPIMSG_DEC_START_ACK = 0xB001,
> +	VPU_IPIMSG_DEC_END_ACK = 0xB002,
> +	VPU_IPIMSG_DEC_DEINIT_ACK = 0xB003,
> +	VPU_IPIMSG_DEC_RESET_ACK = 0xB004,
> +};
> +
> +/**
> + * struct vdec_ap_ipi_cmd - generic AP to VPU ipi command format
> + * @msg_id	: vdec_ipi_msgid
> + * @vpu_inst_addr	: VPU decoder instance address
> + */
> +struct vdec_ap_ipi_cmd {
> +	uint32_t msg_id;
> +	uint32_t vpu_inst_addr;
> +};
> +
> +/**
> + * struct vdec_vpu_ipi_ack - generic VPU to AP ipi command format
> + * @msg_id	: vdec_ipi_msgid
> + * @status	: VPU exeuction result
> + * @ap_inst_addr	: AP video decoder instance address
> + */
> +struct vdec_vpu_ipi_ack {
> +	uint32_t msg_id;
> +	int32_t status;
> +	uint64_t ap_inst_addr;
> +};
> +
> +/**
> + * struct vdec_ap_ipi_init - for AP_IPIMSG_DEC_INIT
> + * @msg_id	: AP_IPIMSG_DEC_INIT
> + * @reserved	: Reserved field
> + * @ap_inst_addr	: AP video decoder instance address
> + */
> +struct vdec_ap_ipi_init {
> +	uint32_t msg_id;
> +	uint32_t reserved;
> +	uint64_t ap_inst_addr;
> +};
> +
> +/**
> + * struct vdec_ap_ipi_dec_start - for AP_IPIMSG_DEC_START
> + * @msg_id	: AP_IPIMSG_DEC_START
> + * @vpu_inst_addr	: VPU decoder instance address
> + * @data	: Header info
> + *	H264 decoder [0]:buf_sz [1]:nal_start
> + *	VP8 decoder  [0]:width/height
> + *	VP9 decoder  [0]:profile, [1][2] width/height
> + * @reserved	: Reserved field
> + */
> +struct vdec_ap_ipi_dec_start {
> +	uint32_t msg_id;
> +	uint32_t vpu_inst_addr;
> +	uint32_t data[3];
> +	uint32_t reserved;
> +};
> +
> +/**
> + * struct vdec_vpu_ipi_init_ack - for VPU_IPIMSG_DEC_INIT_ACK
> + * @msg_id	: VPU_IPIMSG_DEC_INIT_ACK
> + * @status	: VPU exeuction result
> + * @ap_inst_addr	: AP vcodec_vpu_inst instance address
> + * @vpu_inst_addr	: VPU decoder instance address
> + */
> +struct vdec_vpu_ipi_init_ack {
> +	uint32_t msg_id;
> +	int32_t status;
> +	uint64_t ap_inst_addr;
> +	uint32_t vpu_inst_addr;
> +};
> +
> +#endif
> 

Regards,

	Hans


From hverkuil at xs4all.nl  Fri Jul  8 04:44:41 2016
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Fri, 8 Jul 2016 13:44:41 +0200
Subject: [PATCH v3 0/9] Add MT8173 Video Decoder Driver
In-Reply-To: <1467886612.21382.18.camel@mtksdaap41>
References: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
 <577D0576.2050706@xs4all.nl> <1467886612.21382.18.camel@mtksdaap41>
Message-ID: <e2952cc2-3abd-894e-9481-b91a45cf7891@xs4all.nl>

On 07/07/2016 12:16 PM, tiffany lin wrote:
> Hi Hans,
> 
> 
> On Wed, 2016-07-06 at 15:19 +0200, Hans Verkuil wrote:
>> Hi Tiffany,
>>
>> I plan to review this patch series on Friday, but one obvious question is
>> what the reason for these failures is:
>>
>>> 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_QUERYCTRL/MENU: OK
>>>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-controls.cpp(357): g_ctrl returned an error (11)
>>>                 test VIDIOC_G/S_CTRL: FAIL
>>>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-controls.cpp(579): g_ext_ctrls returned an error (11)
>>>                 test VIDIOC_G/S/TRY_EXT_CTRLS: FAIL
> These fails are because VIDIOC_G_CTRL and VIDIOC_G_EXT_CTRLS return
> V4L2_CID_MIN_BUFFERS_FOR_CAPTURE only when dirver in MTK_STATE_HEADER
> state, or it will return EAGAIN.
> This could help user space get correct value, not default value that may
> changed base on media content.

OK, I really don't like this. I also looked what the s5p-mfc-dec driver does (the only other
driver currently implementing this), and that returns -EINVAL.

My proposal would be to change this. If this information isn't known yet, why not
just return 0 as the value? The doc would have to be updated and (preferably) also
the s5p-mfc-dec driver. I've added Samsung devs to the Cc list, let me know what you
think.

> 
>>>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-controls.cpp(721): subscribe event for control 'User Controls' failed
>>>                 test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: FAIL
> Driver do not support subscribe event for control 'User Controls' for
> now.
> Do we need to support this?

I don't see why this would fail. It's OK to subscribe to such controls, although
you'll never get an event.

>>>                 test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
>>>                 Standard Controls: 2 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)
>>>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-formats.cpp(405): expected EINVAL, but got 11 when getting format for buftype 9
>>>                 test VIDIOC_G_FMT: FAIL
> This is because vidioc_vdec_g_fmt only succeed when context is in
> MTK_STATE_HEADER state, or user space cannot get correct format data
> using this function.

Comparing this to s5p-mfc-dec I see that -EINVAL is returned in that case.

I am not opposed to using EAGAIN in s5p-mfc-dec as well. Marek, Kamil, what is
your opinion?

> 
>>>                 test VIDIOC_TRY_FMT: OK (Not Supported)
>>>                 test VIDIOC_S_FMT: OK (Not Supported)
>>>                 test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
>>>
>>>         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
>>>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-buffers.cpp(500): q.has_expbuf(node)
> Our OUTPUT and CAPTURE queue support both VB2_DMABUF and VB2_MMAP, user
> space can select which to use in runtime.
> So our driver default support v4l2_m2m_ioctl_expbuf functionality.
> In v4l2-compliance test, it will check v4l2_m2m_ioctl_expbuf only valid
> when node->valid_memorytype is V4L2_MEMORY_MMAP.
> So when go through node->valid_memorytype is V4L2_MEMORY_DMABUF, it
> fail.

valid_memorytype should have both MMAP and DMABUF flags.

But v4l-utils-1.6.0 is way too old to be certain it isn't some v4l2-compliance bug
that has since been fixed.

Regards,

	Hans

> 
> 
> best regards,
> Tiffany
> 
> 
> 
>>>                 test VIDIOC_EXPBUF: FAIL
>>>
>>>
>>> Total: 38, Succeeded: 33, Failed: 5, Warnings: 0
>>
>> If it is due to a bug in v4l2-compliance, then let me know and I'll fix it. If not,
>> then it should be fixed in the driver.
>>
>> Frankly, it was the presence of these failures that made me think this patch series
>> wasn't final. Before a v4l2 driver can be accepted in the kernel, v4l2-compliance must pass.
>>
>> Regards,
>>
>> 	Hans
> 
> 
> --
> 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
> 


From matthias.bgg at gmail.com  Fri Jul  8 05:47:21 2016
From: matthias.bgg at gmail.com (Matthias Brugger)
Date: Fri, 8 Jul 2016 14:47:21 +0200
Subject: [PATCH v7 2/4] soc: mediatek: Init MT8173 scpsys driver earlier
In-Reply-To: <1467782540.26485.11.camel@mtksdaap41>
References: <1463390894-32062-1-git-send-email-jamesjj.liao@mediatek.com>
 <1463390894-32062-3-git-send-email-jamesjj.liao@mediatek.com>
 <34025ec4-19d3-8b25-d669-50c6f19159cd@gmail.com>
 <1467782540.26485.11.camel@mtksdaap41>
Message-ID: <577FA0D9.8070408@gmail.com>



On 06/07/16 07:22, James Liao wrote:
> On Sat, 2016-07-02 at 18:35 +0200, Matthias Brugger wrote:
>>
>> On 05/16/2016 11:28 AM, James Liao wrote:
>>> Some power domain comsumers may init before module_init.
>>> So the power domain provider (scpsys) need to be initialized
>>> earlier too.
>>>
>>> Take an example for our IOMMU (M4U) and SMI. SMI is a bridge
>>> between IOMMU and multimedia HW. SMI is responsible to
>>> enable/disable iommu and help transfer data for each multimedia
>>> HW. Both of them have to wait until the power and clocks are
>>> enabled.
>>>
>>> So scpsys driver should be initialized before SMI, and SMI should
>>> be initialized before IOMMU, and then init IOMMU consumers
>>> (display/vdec/venc/camera etc.).
>>>
>>> IOMMU is subsys_init by default. So we need to init scpsys driver
>>> before subsys_init.
>>>
>>> Signed-off-by: James Liao <jamesjj.liao at mediatek.com>
>>> Reviewed-by: Kevin Hilman <khilman at baylibre.com>
>>> ---
>>>   drivers/soc/mediatek/mtk-scpsys.c | 19 ++++++++++++++++++-
>>>   1 file changed, 18 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
>>> index 5870a24..00c0adb 100644
>>> --- a/drivers/soc/mediatek/mtk-scpsys.c
>>> +++ b/drivers/soc/mediatek/mtk-scpsys.c
>>> @@ -617,4 +617,21 @@ static struct platform_driver scpsys_drv = {
>>>   		.of_match_table = of_match_ptr(of_scpsys_match_tbl),
>>>   	},
>>>   };
>>> -builtin_platform_driver(scpsys_drv);
>>> +
>>> +static int __init scpsys_drv_init(void)
>>> +{
>>> +	return platform_driver_register(&scpsys_drv);
>>> +}
>>> +
>>> +/*
>>> + * There are some Mediatek drivers which depend on the power domain driver need
>>> + * to probe in earlier initcall levels. So scpsys driver also need to probe
>>> + * earlier.
>>> + *
>>> + * IOMMU(M4U) and SMI drivers for example. SMI is a bridge between IOMMU and
>>> + * multimedia HW. IOMMU depends on SMI, and SMI is a power domain consumer,
>>> + * so the proper probe sequence should be scpsys -> SMI -> IOMMU driver.
>>> + * IOMMU drivers are initialized during subsys_init by default, so we need to
>>> + * move SMI and scpsys drivers to subsys_init or earlier init levels.
>>> + */
>>> +subsys_initcall(scpsys_drv_init);
>>>
>>
>> Can't we achieve this with probe deferring? I'm not really keen on
>> coding the order of the different drivers like this.
>
> Hi Matthias,
>
> Some drivers such as IOMMU don't support probe deferring. So scpsys need
> to init before them by changing init level.
>

SMI larbs return EPROBE_DEFER if it can't find the PM provider for it's 
domain, so this part should not be the problem. The larbs get added as 
components in the probe, when the PM provider is present.

The iommu driver uses the larbs as components. As long as not all 
components are present the iommu does not bind them. So from what I see 
this should work without any problem.

Can you please specify where the iommu dirver has a problem. Maybe we 
need to fix the driver rather then scpsys.

Regards,
Matthias


From weiyj_lk at 163.com  Fri Jul  8 06:41:33 2016
From: weiyj_lk at 163.com (weiyj_lk at 163.com)
Date: Fri,  8 Jul 2016 13:41:33 +0000
Subject: [PATCH -next] ASoC: mediatek: mt2701: cHECK-fix non static symbol
 warning
Message-ID: <1467985293-9041-1-git-send-email-weiyj_lk@163.com>

From: Wei Yongjun <yongjun_wei at trendmicro.com.cn>

Fixes the following sparse warning:

sound/soc/mediatek/mt2701/mt2701-afe-pcm.c:72:5: warning:
 symbol 'mt2701_dai_num_to_i2s' was not declared. Should it be static?

Signed-off-by: Wei Yongjun <yongjun_wei at trendmicro.com.cn>
---
 sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
index 15522c0..34a6123 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
@@ -69,7 +69,7 @@ static const struct mt2701_afe_rate mt2701_afe_i2s_rates[] = {
 	{ .rate = 352800, .regvalue = 24 },
 };
 
-int mt2701_dai_num_to_i2s(struct mtk_base_afe *afe, int num)
+static int mt2701_dai_num_to_i2s(struct mtk_base_afe *afe, int num)
 {
 	int val = num - MT2701_IO_I2S;
 






From weiyj_lk at 163.com  Fri Jul  8 06:47:01 2016
From: weiyj_lk at 163.com (weiyj_lk at 163.com)
Date: Fri,  8 Jul 2016 13:47:01 +0000
Subject: [PATCH -next v2] ASoC: mediatek: mt2701: fix non static symbol warning
In-Reply-To: <1467985293-9041-1-git-send-email-weiyj_lk@163.com>
References: <1467985293-9041-1-git-send-email-weiyj_lk@163.com>
Message-ID: <1467985621-13755-1-git-send-email-weiyj_lk@163.com>

From: Wei Yongjun <yongjun_wei at trendmicro.com.cn>

Fixes the following sparse warning:

sound/soc/mediatek/mt2701/mt2701-afe-pcm.c:72:5: warning:
 symbol 'mt2701_dai_num_to_i2s' was not declared. Should it be static?

Signed-off-by: Wei Yongjun <yongjun_wei at trendmicro.com.cn>
---
 sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
index 15522c0..34a6123 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
@@ -69,7 +69,7 @@ static const struct mt2701_afe_rate mt2701_afe_i2s_rates[] = {
 	{ .rate = 352800, .regvalue = 24 },
 };
 
-int mt2701_dai_num_to_i2s(struct mtk_base_afe *afe, int num)
+static int mt2701_dai_num_to_i2s(struct mtk_base_afe *afe, int num)
 {
 	int val = num - MT2701_IO_I2S;




From mturquette at baylibre.com  Fri Jul  8 16:32:10 2016
From: mturquette at baylibre.com (Michael Turquette)
Date: Fri, 08 Jul 2016 16:32:10 -0700
Subject: [PATCH v9 01/10] clk: fix initial state of critical clock's
 parents
In-Reply-To: <1467604308.26485.4.camel@mtksdaap41>
References: <1466581229-2342-1-git-send-email-erin.lo@mediatek.com>
 <1466581229-2342-2-git-send-email-erin.lo@mediatek.com>
 <20160702012140.GB17071@codeaurora.org> <1467604308.26485.4.camel@mtksdaap41>
Message-ID: <146802073038.73491.6675612765998057903@resonance>

Hi James,

Quoting James Liao (2016-07-03 20:51:48)
> On Fri, 2016-07-01 at 18:21 -0700, Stephen Boyd wrote:
> > (Resending to everyone)
> > 
> > On 06/22, Erin Lo wrote:
> > > From: James Liao <jamesjj.liao at mediatek.com>
> > > 
> > > This patch fixed wrong state of parent clocks if they are registered
> > > after critical clocks.
> > > 
> > > Signed-off-by: James Liao <jamesjj.liao at mediatek.com>
> > > Signed-off-by: Erin Lo <erin.lo at mediatek.com>
> > 
> > It would be nice if you included the information about the
> > problem from James' previous mail. This says what it does, but
> > doesn't explain what the problem is and how it is fixing it.
> > 
> > > ---
> > >  drivers/clk/clk.c | 9 ++++++++-
> > >  1 file changed, 8 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> > > index d584004..e9f5f89 100644
> > > --- a/drivers/clk/clk.c
> > > +++ b/drivers/clk/clk.c
> > > @@ -2388,8 +2388,15 @@ static int __clk_core_init(struct clk_core *core)
> > >     hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) {
> > >             struct clk_core *parent = __clk_init_parent(orphan);
> > >  
> > > -           if (parent)
> > > +           if (parent) {
> > >                     clk_core_reparent(orphan, parent);
> > > +
> > > +                   if (orphan->prepare_count)
> > > +                           clk_core_prepare(parent);
> > > +
> > > +                   if (orphan->enable_count)
> > > +                           clk_core_enable(parent);
> > > +           }
> > >     }
> > 
> > I'm pretty sure I pointed this problem out to Mike when the
> > critical clk patches were being pushed. I can't recall what the
> > plan was though to fix the problem. I'm pretty sure he said that
> > clk_core_reparent() would take care of it, but obviously it is
> > not doing that. Or perhaps it was that clk handoff should figure
> > out that the parents of a critical clk are also on and thus keep
> > them on.
> 
> Hi Mike
> 
> Is there any other patch to fix this issue? Or did I misuse critical
> clock flag?

There is no fix yes. Your fix is basically correct. I was mistaken back
when I told you and Stephen that the framework already took care of
this.

However, instead of "open coding" this solution, I would rather re-use
the __clk_set_parent_{before,after} helpers instead. Can you review/test
the following patch and let me know what you think?

Thanks,
Mike



From c0163b3f719b1e219b28ad425f94f9ef54a25a8f Mon Sep 17 00:00:00 2001
From: Michael Turquette <mturquette at baylibre.com>
Date: Fri, 8 Jul 2016 16:05:22 -0700
Subject: [PATCH] clk: migrate ref counts when orphans are reunited

It's always nice to see families reunited, and this is equally true when
talking about parent clocks and their children. However, if the orphan
clk had a positive prepare_count or enable_count, then we would not
migrate those counts up the parent chain correctly.

This has manifested with the recent critical clocks feature, which often
enables clocks very early, before their parents have been registered.

Fixed by replacing the call to clk_core_reparent with calls to
__clk_set_parent_{before,after}.

Cc: James Liao <jamesjj.liao at mediatek.com>
Cc: Erin Lo <erin.lo at mediatek.com>
Signed-off-by: Michael Turquette <mturquette at baylibre.com>
---
 drivers/clk/clk.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 820a939fb6bb..70efe4c4e0cc 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -2449,8 +2449,14 @@ static int __clk_core_init(struct clk_core *core)
 	hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) {
 		struct clk_core *parent = __clk_init_parent(orphan);
 
-		if (parent)
-			clk_core_reparent(orphan, parent);
+		/*
+		 * we could call __clk_set_parent, but that would result in a
+		 * reducant call to the .set_rate op, if it exists
+		 */
+		if (parent) {
+			__clk_set_parent_before(orphan, parent);
+			__clk_set_parent_after(orphan, parent, NULL);
+		}
 	}
 
 	/*
-- 
2.7.4 (Apple Git-66)



From sboyd at codeaurora.org  Fri Jul  8 17:46:43 2016
From: sboyd at codeaurora.org (Stephen Boyd)
Date: Fri, 8 Jul 2016 17:46:43 -0700
Subject: [PATCH v9 01/10] clk: fix initial state of critical clock's
 parents
In-Reply-To: <146802073038.73491.6675612765998057903@resonance>
References: <1466581229-2342-1-git-send-email-erin.lo@mediatek.com>
 <1466581229-2342-2-git-send-email-erin.lo@mediatek.com>
 <20160702012140.GB17071@codeaurora.org> <1467604308.26485.4.camel@mtksdaap41>
 <146802073038.73491.6675612765998057903@resonance>
Message-ID: <57804973.4050306@codeaurora.org>

On 07/08/2016 04:32 PM, Michael Turquette wrote:
> ---
>  drivers/clk/clk.c | 10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index 820a939fb6bb..70efe4c4e0cc 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -2449,8 +2449,14 @@ static int __clk_core_init(struct clk_core *core)
>  	hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) {
>  		struct clk_core *parent = __clk_init_parent(orphan);
>  
> -		if (parent)
> -			clk_core_reparent(orphan, parent);
> +		/*
> +		 * we could call __clk_set_parent, but that would result in a
> +		 * reducant call to the .set_rate op, if it exists

Did you mean .set_parent op?

> +		 */
> +		if (parent) {
> +			__clk_set_parent_before(orphan, parent);
> +			__clk_set_parent_after(orphan, parent, NULL);
> +		}
>  	}
>  
>  	/*


-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project



From garlic.tseng at mediatek.com  Sun Jul 10 18:31:25 2016
From: garlic.tseng at mediatek.com (Garlic Tseng)
Date: Mon, 11 Jul 2016 09:31:25 +0800
Subject: [alsa-devel] [PATCH -next v2] ASoC: mediatek: mt2701: fix non
 static symbol warning
In-Reply-To: <1467985621-13755-1-git-send-email-weiyj_lk@163.com>
References: <1467985293-9041-1-git-send-email-weiyj_lk@163.com>
 <1467985621-13755-1-git-send-email-weiyj_lk@163.com>
Message-ID: <1468200685.32731.1.camel@mtksdaap41>

On Fri, 2016-07-08 at 13:47 +0000, weiyj_lk at 163.com wrote:
> From: Wei Yongjun <yongjun_wei at trendmicro.com.cn>
> 
> Fixes the following sparse warning:
> 
> sound/soc/mediatek/mt2701/mt2701-afe-pcm.c:72:5: warning:
>  symbol 'mt2701_dai_num_to_i2s' was not declared. Should it be static?
> 
> Signed-off-by: Wei Yongjun <yongjun_wei at trendmicro.com.cn>

Acked-by: Garlic Tseng <garlic.tseng at mediatek.com>

> ---
>  sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
> index 15522c0..34a6123 100644
> --- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
> +++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
> @@ -69,7 +69,7 @@ static const struct mt2701_afe_rate mt2701_afe_i2s_rates[] = {
>  	{ .rate = 352800, .regvalue = 24 },
>  };
>  
> -int mt2701_dai_num_to_i2s(struct mtk_base_afe *afe, int num)
> +static int mt2701_dai_num_to_i2s(struct mtk_base_afe *afe, int num)
>  {
>  	int val = num - MT2701_IO_I2S;
> 
> 
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel at alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel




From tiffany.lin at mediatek.com  Sun Jul 10 19:04:42 2016
From: tiffany.lin at mediatek.com (tiffany lin)
Date: Mon, 11 Jul 2016 10:04:42 +0800
Subject: [PATCH v2 2/9] [media] : v4l: add Mediatek compressed video
 block format
In-Reply-To: <78c9f4a1-e2b8-69ef-acc5-d24984497b33@xs4all.nl>
References: <1463052250-38262-1-git-send-email-tiffany.lin@mediatek.com>
 <1463052250-38262-2-git-send-email-tiffany.lin@mediatek.com>
 <1463052250-38262-3-git-send-email-tiffany.lin@mediatek.com>
 <78c9f4a1-e2b8-69ef-acc5-d24984497b33@xs4all.nl>
Message-ID: <1468202682.3725.0.camel@mtksdaap41>

Hi Hans,

On Fri, 2016-07-08 at 12:18 +0200, Hans Verkuil wrote:
> On 05/12/2016 01:24 PM, Tiffany Lin wrote:
> > Add V4L2_PIX_FMT_MT21 format used on MT8173 driver.
> > It is compressed format and need MT8173 MDP driver to transfer to other 
> > standard format.
> > 
> > Signed-off-by: Tiffany Lin <tiffany.lin at mediatek.com>
> > ---
> >  include/uapi/linux/videodev2.h |    1 +
> >  1 file changed, 1 insertion(+)
> > 
> > diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> > index 8f95191..52feea6 100644
> > --- a/include/uapi/linux/videodev2.h
> > +++ b/include/uapi/linux/videodev2.h
> > @@ -625,6 +625,7 @@ struct v4l2_pix_format {
> >  #define V4L2_PIX_FMT_Y8I      v4l2_fourcc('Y', '8', 'I', ' ') /* Greyscale 8-bit L/R interleaved */
> >  #define V4L2_PIX_FMT_Y12I     v4l2_fourcc('Y', '1', '2', 'I') /* Greyscale 12-bit L/R interleaved */
> >  #define V4L2_PIX_FMT_Z16      v4l2_fourcc('Z', '1', '6', ' ') /* Depth data 16-bit */
> > +#define V4L2_PIX_FMT_MT21     v4l2_fourcc('M', 'T', '2', '1') /* Mediatek compressed block mode  */
> 
> v4l2-ioctl.c should be modified as well so the correct description string is filled in.
> 
Got it. I will fix this.

best regards,
Tiffany

> Regards,
> 
> 	Hans
> 
> >  
> >  /* SDR formats - used only for Software Defined Radio devices */
> >  #define V4L2_SDR_FMT_CU8          v4l2_fourcc('C', 'U', '0', '8') /* IQ u8 */
> > 




From hs.liao at mediatek.com  Sun Jul 10 19:55:05 2016
From: hs.liao at mediatek.com (Horng-Shyang Liao)
Date: Mon, 11 Jul 2016 10:55:05 +0800
Subject: [PATCH v9 1/4] dt-bindings: soc: Add documentation for the
 MediaTek GCE unit
In-Reply-To: <1467973066.2472.238.camel@pengutronix.de>
References: <1467270883-1407-1-git-send-email-hs.liao@mediatek.com>
 <1467270883-1407-2-git-send-email-hs.liao@mediatek.com>
 <1467973066.2472.238.camel@pengutronix.de>
Message-ID: <1468205705.11509.15.camel@mtksdaap41>

Hi Jan,

On Fri, 2016-07-08 at 12:17 +0200, Jan L?bbe wrote:
> On Do, 2016-06-30 at 15:14 +0800, HS Liao wrote:
> [...]
> > +Required properties:
> > +- compatible: Must be "mediatek,mt8173-gce"
> > +- reg: Address range of the GCE unit
> > +- interrupts: The interrupt signal from the GCE block
> > +- clock: Clocks according to the common clock binding
> > +- clock-names: Must be "gce" to stand for GCE clock
> > +- #mbox-cells: Should be 1
> [...]
> > +		#mbox-cells = <1>;
> [...]
> > +		mediatek,gce = <&gce>;
> > +		mboxes = <&gce 0 1 /* main display with merging wfe */
> > +			  &gce 1 1>; /* sub display with merging wfe */
> 
> It seems that you use two cells instead of one as you declared above.
> This should be consistent.

Will correct it as 2.

> Also, why do you need an explicit phandle to the gce if you already use
> mailboxes?

"mediatek,gce" should be added to all clients which ask gce to access 
their registers.

"mboxes" should be added to all clients which will communicate with gce
via mailbox.

For example, if mmsys send cmdq tasks to ask gce to write registers of 
mmsys and ovl, mmsys should have "mediatek,gce" and "mboxes", and ovl
should have "mediatek,gce".

I will explain their difference in GCE's device tree document.

> Best regards,
> Jan L?bbe

Thanks,
HS



From tiffany.lin at mediatek.com  Sun Jul 10 19:56:11 2016
From: tiffany.lin at mediatek.com (tiffany lin)
Date: Mon, 11 Jul 2016 10:56:11 +0800
Subject: [PATCH v3 3/9] DocBook/v4l: Add compressed video formats used
 on MT8173 codec driver
In-Reply-To: <5a793171-24a7-4e9e-8bfd-f668c789f8e0@xs4all.nl>
References: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-2-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-3-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-4-git-send-email-tiffany.lin@mediatek.com>
 <5a793171-24a7-4e9e-8bfd-f668c789f8e0@xs4all.nl>
Message-ID: <1468205771.3725.8.camel@mtksdaap41>

Hi Hans,

On Fri, 2016-07-08 at 12:23 +0200, Hans Verkuil wrote:
> On 05/30/2016 02:29 PM, Tiffany Lin wrote:
> > Add V4L2_PIX_FMT_MT21 documentation
> > 
> > Signed-off-by: Tiffany Lin <tiffany.lin at mediatek.com>
> > ---
> >  Documentation/DocBook/media/v4l/pixfmt.xml |    6 ++++++
> >  1 file changed, 6 insertions(+)
> > 
> > diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml
> > index 5a08aee..d40e0ce 100644
> > --- a/Documentation/DocBook/media/v4l/pixfmt.xml
> > +++ b/Documentation/DocBook/media/v4l/pixfmt.xml
> > @@ -1980,6 +1980,12 @@ array. Anything what's in between the UYVY lines is JPEG data and should be
> >  concatenated to form the JPEG stream. </para>
> >  </entry>
> >  	  </row>
> > +	  <row id="V4L2_PIX_FMT_MT21">
> > +	    <entry><constant>V4L2_PIX_FMT_MT21</constant></entry>
> > +	    <entry>'MT21'</entry>
> > +	    <entry>Compressed two-planar YVU420 format used by Mediatek MT8173
> > +	    codec driver.</entry>
> 
> Can you give a few more details? The encoder driver doesn't seem to produce this
> format, so who is creating this? Where is this format documented?
> 

It can be as input format for encoder, MDP and display drivers in our
platform.
This private format is only available in our platform.
So I put it in "Reserved Format Identifiers" sections.


best regards,
Tiffany

> Regards,
> 
> 	Hans
> 
> > +	  </row>
> >  	</tbody>
> >        </tgroup>
> >      </table>
> > 




From zhiyong.tao at mediatek.com  Sun Jul 10 20:09:54 2016
From: zhiyong.tao at mediatek.com (Zhiyong Tao)
Date: Mon, 11 Jul 2016 11:09:54 +0800
Subject: [PATCH v3 0/2] AUXADC: Mediatek auxadc driver 
Message-ID: <1468206596-13792-1-git-send-email-zhiyong.tao@mediatek.com>

This series includes three patches:
1.Change the device tree binding documentation.
2.Add auxadc driver based on linux iio.
3.Add auxadc nodes in the mediatek MT2701 dtsi file.

changes in patch v3:
1).Add '#' before 'io-channel-cells' and change 'auxadc@' to 'adc@' in auxadc binding document.
2).Fix CONFIG_MEDIATEK_MT65XX_AUXADC sequence as alphabetical order.
3).Change the prefix 'MT65XX' to 'MT6577' to match auxadc driver name.
4).Remove the delays stored in 'mt6577_auxadc_device' and use the defined delay directly.
5).Use '-ETIMEDOUT' instead of '-EINVAL'.
6).Return value directly in 'mt6577_auxadc_read_raw'.
7).Add power off and unprepare clock if 'iio_device_register' failed.
8).Change 'Registers' to 'Register'.

changes in patch v2:
1).Change the file name mt65xx_auxadc.c to mt6577_auxadc.c.
2).Add 'depends on ARCH_MEDIATEK || COMPILE_TEST and HAS_IOMEM' for MEDIATEK_MT65XX_AUXADC config.
3).Add check case for return value of 'readl_poll_timeout'.
4).Remove returning 1 and 0 for SCALE and OFFSET. use channel type 'IIO_CHAN_INFO_PROCESSED' instead of 'IIO_CHAN_INFO_RAW'.
5).Remove 'IIO_CHAN_INFO_OFFSET' and 'IIO_CHAN_INFO_SCALE' in 'MT65XX_AUXADC_CHANNEL' channel type.
6).Add check case when auxadc power on failure. if auxadc power on failure, clk_disable_unprepare should be executed.
7).Put 'platform_set_drvdata' before 'iio_device_register'.
8).Fix coding style and spelling error.

Zhiyong Tao (2):
  dt-bindings: auxadc: Add binding document for Mediatek auxadc.
  iio: adc: mt2701: Add Mediatek auxadc driver for mt2701.

 .../devicetree/bindings/iio/adc/mt65xx_auxadc.txt  |    4 +-
 drivers/iio/adc/Kconfig                            |   26 +--
 drivers/iio/adc/Makefile                           |    2 +-
 drivers/iio/adc/mt6577_auxadc.c                    |  186 ++++++++++----------
 4 files changed, 106 insertions(+), 112 deletions(-)



From zhiyong.tao at mediatek.com  Sun Jul 10 20:09:55 2016
From: zhiyong.tao at mediatek.com (Zhiyong Tao)
Date: Mon, 11 Jul 2016 11:09:55 +0800
Subject: [PATCH v3 1/2] dt-bindings: auxadc: Add binding document for Mediatek
 auxadc.
In-Reply-To: <1468206596-13792-1-git-send-email-zhiyong.tao@mediatek.com>
References: <1468206596-13792-1-git-send-email-zhiyong.tao@mediatek.com>
Message-ID: <1468206596-13792-2-git-send-email-zhiyong.tao@mediatek.com>

The commit adds the device tree binding documentation for the mediatek
auxadc found on Mediatek MT2701.
Thermal gets auxadc sample data by iio device.
So the commit changes auxadc device tree binding documentation from
/soc/mediatek/auxadc.txt to /iio/adc/mt65xx_auxadc.txt.

Signed-off-by: Zhiyong Tao <zhiyong.tao at mediatek.com>
---
 .../devicetree/bindings/iio/adc/mt65xx_auxadc.txt  |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/iio/adc/mt65xx_auxadc.txt b/Documentation/devicetree/bindings/iio/adc/mt65xx_auxadc.txt
index 47fcd1b..bc23792 100644
--- a/Documentation/devicetree/bindings/iio/adc/mt65xx_auxadc.txt
+++ b/Documentation/devicetree/bindings/iio/adc/mt65xx_auxadc.txt
@@ -14,11 +14,11 @@ Required properties:
   - reg: Address range of the AUXADC unit.
   - clocks: Should contain a clock specifier for each entry in clock-names
   - clock-names: Should contain "main".
-  - io-channel-cells: Should be 1, see ../iio-bindings.txt
+  - #io-channel-cells: Should be 1, see ../iio-bindings.txt
 
 Example:
 
-auxadc: auxadc at 11001000 {
+auxadc: adc at 11001000 {
 	compatible = "mediatek,mt2701-auxadc";
 	reg = <0 0x11001000 0 0x1000>;
 	clocks = <&pericfg CLK_PERI_AUXADC>;
-- 
1.7.9.5



From zhiyong.tao at mediatek.com  Sun Jul 10 20:09:56 2016
From: zhiyong.tao at mediatek.com (Zhiyong Tao)
Date: Mon, 11 Jul 2016 11:09:56 +0800
Subject: [PATCH v3 2/2] iio: adc: mt2701: Add Mediatek auxadc driver for
 mt2701.
In-Reply-To: <1468206596-13792-1-git-send-email-zhiyong.tao@mediatek.com>
References: <1468206596-13792-1-git-send-email-zhiyong.tao@mediatek.com>
Message-ID: <1468206596-13792-3-git-send-email-zhiyong.tao@mediatek.com>

Add Mediatek auxadc driver based on iio.
It will register a device in iio and support iio.
So thermal can read auxadc channel to sample data by iio device.
It is tested successfully on mt2701 platform.
Mt8173 and mt6577 platforms are not tested.
But the expectation is compatible.

Signed-off-by: Zhiyong Tao <zhiyong.tao at mediatek.com>
---
 drivers/iio/adc/Kconfig         |   26 +++---
 drivers/iio/adc/Makefile        |    2 +-
 drivers/iio/adc/mt6577_auxadc.c |  186 +++++++++++++++++++--------------------
 3 files changed, 104 insertions(+), 110 deletions(-)

diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 66e9b44..14929fc 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -305,6 +305,19 @@ config MCP3422
 	  This driver can also be built as a module. If so, the module will be
 	  called mcp3422.
 
+config MEDIATEK_MT6577_AUXADC
+        tristate "MediaTek AUXADC driver"
+        depends on ARCH_MEDIATEK || COMPILE_TEST
+        depends on HAS_IOMEM
+        help
+          Say yes here to enable support for MediaTek mt65xx AUXADC.
+
+          The driver supports immediate mode operation to read from one of sixteen
+          channels (external or internal).
+
+          This driver can also be built as a module. If so, the module will be
+          called mt6577_auxadc.
+
 config MEN_Z188_ADC
 	tristate "MEN 16z188 ADC IP Core support"
 	depends on MCB
@@ -315,19 +328,6 @@ config MEN_Z188_ADC
 	  This driver can also be built as a module. If so, the module will be
 	  called men_z188_adc.
 
-config MEDIATEK_MT65XX_AUXADC
-	tristate "MediaTek AUXADC driver"
-	depends on ARCH_MEDIATEK || COMPILE_TEST
-	depends on HAS_IOMEM
-	help
-	  Say yes here to enable support for MediaTek mt65xx AUXADC.
-
-	  The driver supports immediate mode operation to read from one of sixteen
-	  channels (external or internal).
-
-	  This driver can also be built as a module. If so, the module will be
-	  called mt6577_auxadc.
-
 config MXS_LRADC
         tristate "Freescale i.MX23/i.MX28 LRADC"
         depends on (ARCH_MXS || COMPILE_TEST) && HAS_IOMEM
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 14a630f..8306347 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -30,8 +30,8 @@ obj-$(CONFIG_MAX1027) += max1027.o
 obj-$(CONFIG_MAX1363) += max1363.o
 obj-$(CONFIG_MCP320X) += mcp320x.o
 obj-$(CONFIG_MCP3422) += mcp3422.o
+obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
 obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
-obj-$(CONFIG_MEDIATEK_MT65XX_AUXADC) += mt6577_auxadc.o
 obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
 obj-$(CONFIG_NAU7802) += nau7802.o
 obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c
index a56531a..a853ae8 100644
--- a/drivers/iio/adc/mt6577_auxadc.c
+++ b/drivers/iio/adc/mt6577_auxadc.c
@@ -24,80 +24,78 @@
 #include <linux/io.h>
 #include <linux/iio/iio.h>
 
-/* Registers definitions */
-#define MT65XX_AUXADC_CON0                    0x00
-#define MT65XX_AUXADC_CON1                    0x04
-#define MT65XX_AUXADC_CON2                    0x10
-#define MT65XX_AUXADC_STA                     BIT(0)
+/* Register definitions */
+#define MT6577_AUXADC_CON0                    0x00
+#define MT6577_AUXADC_CON1                    0x04
+#define MT6577_AUXADC_CON2                    0x10
+#define MT6577_AUXADC_STA                     BIT(0)
 
-#define MT65XX_AUXADC_DAT0                    0x14
-#define MT65XX_AUXADC_RDY0                    BIT(12)
+#define MT6577_AUXADC_DAT0                    0x14
+#define MT6577_AUXADC_RDY0                    BIT(12)
 
-#define MT65XX_AUXADC_MISC                    0x94
-#define MT65XX_AUXADC_PDN_EN                  BIT(14)
+#define MT6577_AUXADC_MISC                    0x94
+#define MT6577_AUXADC_PDN_EN                  BIT(14)
 
-#define MT65XX_AUXADC_DAT_MASK                0xfff
-#define MT65XX_AUXADC_SLEEP_US                1000
-#define MT65XX_AUXADC_TIMEOUT_US              10000
-#define MT65XX_AUXADC_POWER_READY_MS          1
-#define MT65XX_AUXADC_SAMPLE_READY_US         25
+#define MT6577_AUXADC_DAT_MASK                0xfff
+#define MT6577_AUXADC_SLEEP_US                1000
+#define MT6577_AUXADC_TIMEOUT_US              10000
+#define MT6577_AUXADC_POWER_READY_MS          1
+#define MT6577_AUXADC_SAMPLE_READY_US         25
 
-struct mt65xx_auxadc_device {
+struct mt6577_auxadc_device {
 	void __iomem *reg_base;
 	struct clk *adc_clk;
 	struct mutex lock;
-	unsigned int power_ready_ms;
-	unsigned int sample_ready_us;
 };
 
-#define MT65XX_AUXADC_CHANNEL(idx) {				    \
+#define MT6577_AUXADC_CHANNEL(idx) {				    \
 		.type = IIO_VOLTAGE,				    \
 		.indexed = 1,					    \
 		.channel = (idx),				    \
 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
 }
 
-static const struct iio_chan_spec mt65xx_auxadc_iio_channels[] = {
-	MT65XX_AUXADC_CHANNEL(0),
-	MT65XX_AUXADC_CHANNEL(1),
-	MT65XX_AUXADC_CHANNEL(2),
-	MT65XX_AUXADC_CHANNEL(3),
-	MT65XX_AUXADC_CHANNEL(4),
-	MT65XX_AUXADC_CHANNEL(5),
-	MT65XX_AUXADC_CHANNEL(6),
-	MT65XX_AUXADC_CHANNEL(7),
-	MT65XX_AUXADC_CHANNEL(8),
-	MT65XX_AUXADC_CHANNEL(9),
-	MT65XX_AUXADC_CHANNEL(10),
-	MT65XX_AUXADC_CHANNEL(11),
-	MT65XX_AUXADC_CHANNEL(12),
-	MT65XX_AUXADC_CHANNEL(13),
-	MT65XX_AUXADC_CHANNEL(14),
-	MT65XX_AUXADC_CHANNEL(15),
+static const struct iio_chan_spec mt6577_auxadc_iio_channels[] = {
+	MT6577_AUXADC_CHANNEL(0),
+	MT6577_AUXADC_CHANNEL(1),
+	MT6577_AUXADC_CHANNEL(2),
+	MT6577_AUXADC_CHANNEL(3),
+	MT6577_AUXADC_CHANNEL(4),
+	MT6577_AUXADC_CHANNEL(5),
+	MT6577_AUXADC_CHANNEL(6),
+	MT6577_AUXADC_CHANNEL(7),
+	MT6577_AUXADC_CHANNEL(8),
+	MT6577_AUXADC_CHANNEL(9),
+	MT6577_AUXADC_CHANNEL(10),
+	MT6577_AUXADC_CHANNEL(11),
+	MT6577_AUXADC_CHANNEL(12),
+	MT6577_AUXADC_CHANNEL(13),
+	MT6577_AUXADC_CHANNEL(14),
+	MT6577_AUXADC_CHANNEL(15),
 };
 
-static int mt65xx_auxadc_read(struct iio_dev *indio_dev,
+static int mt6577_auxadc_read(struct iio_dev *indio_dev,
 			      struct iio_chan_spec const *chan)
 {
 	u32 rawdata, val;
 	void __iomem *reg_channel;
 	int ret;
-	struct mt65xx_auxadc_device *adc_dev = iio_priv(indio_dev);
+	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
 
-	reg_channel = adc_dev->reg_base + MT65XX_AUXADC_DAT0 +
+	reg_channel = adc_dev->reg_base + MT6577_AUXADC_DAT0 +
 		      chan->channel * 0x04;
 
 	mutex_lock(&adc_dev->lock);
 
-	val = readl(adc_dev->reg_base + MT65XX_AUXADC_CON1);
+	val = readl(adc_dev->reg_base + MT6577_AUXADC_CON1);
 	val &= ~(1 << chan->channel);
-	writel(val, adc_dev->reg_base + MT65XX_AUXADC_CON1);
+	writel(val, adc_dev->reg_base + MT6577_AUXADC_CON1);
 
 	/* read channel and make sure old ready bit == 0 */
 	ret = readl_poll_timeout(reg_channel, val,
-				 ((val & MT65XX_AUXADC_RDY0) == 0),
-				 MT65XX_AUXADC_SLEEP_US,
-				 MT65XX_AUXADC_TIMEOUT_US);
+				 ((val & MT6577_AUXADC_RDY0) == 0),
+				 MT6577_AUXADC_SLEEP_US,
+				 MT6577_AUXADC_TIMEOUT_US);
 	if (ret < 0) {
 		dev_err(indio_dev->dev.parent,
 			"wait for channel[%d] ready bit clear time out\n",
@@ -105,36 +103,36 @@ static int mt65xx_auxadc_read(struct iio_dev *indio_dev,
 
 		mutex_unlock(&adc_dev->lock);
 
-		return -EINVAL;
+		return -ETIMEDOUT;
 	}
 
 	/* set bit to trigger sample */
-	val = readl(adc_dev->reg_base + MT65XX_AUXADC_CON1);
+	val = readl(adc_dev->reg_base + MT6577_AUXADC_CON1);
 	val |= 1 << chan->channel;
-	writel(val, adc_dev->reg_base + MT65XX_AUXADC_CON1);
+	writel(val, adc_dev->reg_base + MT6577_AUXADC_CON1);
 
 	/* we must delay here for hardware sample channel data */
-	udelay(adc_dev->sample_ready_us);
+	udelay(MT6577_AUXADC_SAMPLE_READY_US);
 
 	/* check MTK_AUXADC_CON2 if auxadc is idle */
-	ret = readl_poll_timeout(adc_dev->reg_base + MT65XX_AUXADC_CON2, val,
-				 ((val & MT65XX_AUXADC_STA) == 0),
-				 MT65XX_AUXADC_SLEEP_US,
-				 MT65XX_AUXADC_TIMEOUT_US);
+	ret = readl_poll_timeout(adc_dev->reg_base + MT6577_AUXADC_CON2, val,
+				 ((val & MT6577_AUXADC_STA) == 0),
+				 MT6577_AUXADC_SLEEP_US,
+				 MT6577_AUXADC_TIMEOUT_US);
 	if (ret < 0) {
 		dev_err(indio_dev->dev.parent,
 			"wait for auxadc idle time out\n");
 
 		mutex_unlock(&adc_dev->lock);
 
-		return -EINVAL;
+		return -ETIMEDOUT;
 	}
 
 	/* read channel and make sure ready bit == 1 */
 	ret = readl_poll_timeout(reg_channel, val,
-				 ((val & MT65XX_AUXADC_RDY0) != 0),
-				 MT65XX_AUXADC_SLEEP_US,
-				 MT65XX_AUXADC_TIMEOUT_US);
+				 ((val & MT6577_AUXADC_RDY0) != 0),
+				 MT6577_AUXADC_SLEEP_US,
+				 MT6577_AUXADC_TIMEOUT_US);
 	if (ret < 0) {
 		dev_err(indio_dev->dev.parent,
 			"wait for channel[%d] data ready time out\n",
@@ -142,52 +140,48 @@ static int mt65xx_auxadc_read(struct iio_dev *indio_dev,
 
 		mutex_unlock(&adc_dev->lock);
 
-		return -EINVAL;
+		return -ETIMEDOUT;
 	}
 
 	/* read data */
-	rawdata = readl(reg_channel) & MT65XX_AUXADC_DAT_MASK;
+	rawdata = readl(reg_channel) & MT6577_AUXADC_DAT_MASK;
 
 	mutex_unlock(&adc_dev->lock);
 
 	return rawdata;
 }
 
-static int mt65xx_auxadc_read_raw(struct iio_dev *indio_dev,
+static int mt6577_auxadc_read_raw(struct iio_dev *indio_dev,
 				  struct iio_chan_spec const *chan,
 				  int *val,
 				  int *val2,
 				  long info)
 {
-	int ret;
-
 	switch (info) {
 	case IIO_CHAN_INFO_PROCESSED:
-		*val = mt65xx_auxadc_read(indio_dev, chan);
+		*val = mt6577_auxadc_read(indio_dev, chan);
 		if (*val < 0) {
 			dev_err(indio_dev->dev.parent,
 				"failed to sample data on channel[%d]\n",
 				chan->channel);
-			return -EIO;
+			return *val;
 		}
-		ret = IIO_VAL_INT;
+		return IIO_VAL_INT;
 		break;
 	default:
-		ret = -EINVAL;
+		return -EINVAL;
 		break;
 	}
-
-	return ret;
 }
 
-static const struct iio_info mt65xx_auxadc_info = {
+static const struct iio_info mt6577_auxadc_info = {
 	.driver_module = THIS_MODULE,
-	.read_raw = &mt65xx_auxadc_read_raw,
+	.read_raw = &mt6577_auxadc_read_raw,
 };
 
-static int mt65xx_auxadc_probe(struct platform_device *pdev)
+static int mt6577_auxadc_probe(struct platform_device *pdev)
 {
-	struct mt65xx_auxadc_device *adc_dev;
+	struct mt6577_auxadc_device *adc_dev;
 	unsigned long adc_clk_rate;
 	struct resource *res;
 	struct iio_dev *indio_dev;
@@ -201,10 +195,10 @@ static int mt65xx_auxadc_probe(struct platform_device *pdev)
 	adc_dev = iio_priv(indio_dev);
 	indio_dev->dev.parent = &pdev->dev;
 	indio_dev->name = dev_name(&pdev->dev);
-	indio_dev->info = &mt65xx_auxadc_info;
+	indio_dev->info = &mt6577_auxadc_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
-	indio_dev->channels = mt65xx_auxadc_iio_channels;
-	indio_dev->num_channels = ARRAY_SIZE(mt65xx_auxadc_iio_channels);
+	indio_dev->channels = mt6577_auxadc_iio_channels;
+	indio_dev->num_channels = ARRAY_SIZE(mt6577_auxadc_iio_channels);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	adc_dev->reg_base = devm_ioremap_resource(&pdev->dev, res);
@@ -231,18 +225,15 @@ static int mt65xx_auxadc_probe(struct platform_device *pdev)
 		goto err_disable_clk;
 	}
 
-	adc_dev->power_ready_ms = MT65XX_AUXADC_POWER_READY_MS;
-	adc_dev->sample_ready_us = MT65XX_AUXADC_SAMPLE_READY_US;
-
 	mutex_init(&adc_dev->lock);
 
-	val = readl(adc_dev->reg_base + MT65XX_AUXADC_MISC);
-	val |= MT65XX_AUXADC_PDN_EN;
-	writel(val, adc_dev->reg_base + MT65XX_AUXADC_MISC);
-	mdelay(adc_dev->power_ready_ms);
+	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
+	val |= MT6577_AUXADC_PDN_EN;
+	writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
+	mdelay(MT6577_AUXADC_POWER_READY_MS);
 
-	val = readl(adc_dev->reg_base + MT65XX_AUXADC_MISC);
-	if ((val & MT65XX_AUXADC_PDN_EN) == 0) {
+	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
+	if ((val & MT6577_AUXADC_PDN_EN) == 0) {
 		dev_err(&pdev->dev, "failed to enable auxadc power!\n");
 		goto err_disable_clk;
 	}
@@ -252,7 +243,10 @@ static int mt65xx_auxadc_probe(struct platform_device *pdev)
 	ret = iio_device_register(indio_dev);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "failed to register iio device!\n");
-		return ret;
+		val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
+		val &= ~MT6577_AUXADC_PDN_EN;
+		writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
+		goto err_disable_clk;
 	}
 
 	return 0;
@@ -262,39 +256,39 @@ err_disable_clk:
 	return -EINVAL;
 }
 
-static int mt65xx_auxadc_remove(struct platform_device *pdev)
+static int mt6577_auxadc_remove(struct platform_device *pdev)
 {
 	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
-	struct mt65xx_auxadc_device *adc_dev = iio_priv(indio_dev);
+	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
 	u32 val;
 
 	iio_device_unregister(indio_dev);
 
-	val = readl(adc_dev->reg_base + MT65XX_AUXADC_MISC);
-	val &= ~MT65XX_AUXADC_PDN_EN;
-	writel(val, adc_dev->reg_base + MT65XX_AUXADC_MISC);
+	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
+	val &= ~MT6577_AUXADC_PDN_EN;
+	writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
 
 	clk_disable_unprepare(adc_dev->adc_clk);
 
 	return 0;
 }
 
-static const struct of_device_id mt65xx_auxadc_of_match[] = {
+static const struct of_device_id mt6577_auxadc_of_match[] = {
 	{ .compatible = "mediatek,mt2701-auxadc", },
 	{ .compatible = "mediatek,mt8173-auxadc", },
 	{ }
 };
-MODULE_DEVICE_TABLE(of, mt65xx_auxadc_of_match);
+MODULE_DEVICE_TABLE(of, mt6577_auxadc_of_match);
 
-static struct platform_driver mt65xx_auxadc_driver = {
+static struct platform_driver mt6577_auxadc_driver = {
 	.driver = {
-		.name   = "mt65xx-auxadc",
-		.of_match_table = mt65xx_auxadc_of_match,
+		.name   = "mt6577-auxadc",
+		.of_match_table = mt6577_auxadc_of_match,
 	},
-	.probe	= mt65xx_auxadc_probe,
-	.remove	= mt65xx_auxadc_remove,
+	.probe	= mt6577_auxadc_probe,
+	.remove	= mt6577_auxadc_remove,
 };
-module_platform_driver(mt65xx_auxadc_driver);
+module_platform_driver(mt6577_auxadc_driver);
 
 MODULE_AUTHOR("Zhiyong Tao <zhiyong.tao at mediatek.com>");
 MODULE_DESCRIPTION("MTK AUXADC Device Driver");
-- 
1.7.9.5



From tiffany.lin at mediatek.com  Sun Jul 10 20:58:49 2016
From: tiffany.lin at mediatek.com (tiffany lin)
Date: Mon, 11 Jul 2016 11:58:49 +0800
Subject: [PATCH v3 0/9] Add MT8173 Video Decoder Driver
In-Reply-To: <e2952cc2-3abd-894e-9481-b91a45cf7891@xs4all.nl>
References: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
 <577D0576.2050706@xs4all.nl> <1467886612.21382.18.camel@mtksdaap41>
 <e2952cc2-3abd-894e-9481-b91a45cf7891@xs4all.nl>
Message-ID: <1468209529.3725.25.camel@mtksdaap41>

Hi Hans,

On Fri, 2016-07-08 at 13:44 +0200, Hans Verkuil wrote:
> On 07/07/2016 12:16 PM, tiffany lin wrote:
> > Hi Hans,
> > 
> > 
> > On Wed, 2016-07-06 at 15:19 +0200, Hans Verkuil wrote:
> >> Hi Tiffany,
> >>
> >> I plan to review this patch series on Friday, but one obvious question is
> >> what the reason for these failures is:
> >>
> >>> 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_QUERYCTRL/MENU: OK
> >>>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-controls.cpp(357): g_ctrl returned an error (11)
> >>>                 test VIDIOC_G/S_CTRL: FAIL
> >>>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-controls.cpp(579): g_ext_ctrls returned an error (11)
> >>>                 test VIDIOC_G/S/TRY_EXT_CTRLS: FAIL
> > These fails are because VIDIOC_G_CTRL and VIDIOC_G_EXT_CTRLS return
> > V4L2_CID_MIN_BUFFERS_FOR_CAPTURE only when dirver in MTK_STATE_HEADER
> > state, or it will return EAGAIN.
> > This could help user space get correct value, not default value that may
> > changed base on media content.
> 
> OK, I really don't like this. I also looked what the s5p-mfc-dec driver does (the only other
> driver currently implementing this), and that returns -EINVAL.
> 
> My proposal would be to change this. If this information isn't known yet, why not
> just return 0 as the value? The doc would have to be updated and (preferably) also
> the s5p-mfc-dec driver. I've added Samsung devs to the Cc list, let me know what you
> think.
> 
Got it. We will return 0 as the value instead EAGAIN.

> > 
> >>>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-controls.cpp(721): subscribe event for control 'User Controls' failed
> >>>                 test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: FAIL
> > Driver do not support subscribe event for control 'User Controls' for
> > now.
> > Do we need to support this?
> 
> I don't see why this would fail. It's OK to subscribe to such controls, although
> you'll never get an event.
> 
Got it. I will rerun using latest v4l2-compliance test check this.

> >>>                 test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
> >>>                 Standard Controls: 2 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)
> >>>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-formats.cpp(405): expected EINVAL, but got 11 when getting format for buftype 9
> >>>                 test VIDIOC_G_FMT: FAIL
> > This is because vidioc_vdec_g_fmt only succeed when context is in
> > MTK_STATE_HEADER state, or user space cannot get correct format data
> > using this function.
> 
> Comparing this to s5p-mfc-dec I see that -EINVAL is returned in that case.
> 
> I am not opposed to using EAGAIN in s5p-mfc-dec as well. Marek, Kamil, what is
> your opinion?
> 
> > 
> >>>                 test VIDIOC_TRY_FMT: OK (Not Supported)
> >>>                 test VIDIOC_S_FMT: OK (Not Supported)
> >>>                 test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
> >>>
> >>>         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
> >>>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-buffers.cpp(500): q.has_expbuf(node)
> > Our OUTPUT and CAPTURE queue support both VB2_DMABUF and VB2_MMAP, user
> > space can select which to use in runtime.
> > So our driver default support v4l2_m2m_ioctl_expbuf functionality.
> > In v4l2-compliance test, it will check v4l2_m2m_ioctl_expbuf only valid
> > when node->valid_memorytype is V4L2_MEMORY_MMAP.
> > So when go through node->valid_memorytype is V4L2_MEMORY_DMABUF, it
> > fail.
> 
> valid_memorytype should have both MMAP and DMABUF flags.
> 
> But v4l-utils-1.6.0 is way too old to be certain it isn't some v4l2-compliance bug
> that has since been fixed.
> 
Got it. I will rerun using master branch to check this.

best regards,
Tiffany

> Regards,
> 
> 	Hans
> 
> > 
> > 
> > best regards,
> > Tiffany
> > 
> > 
> > 
> >>>                 test VIDIOC_EXPBUF: FAIL
> >>>
> >>>
> >>> Total: 38, Succeeded: 33, Failed: 5, Warnings: 0
> >>
> >> If it is due to a bug in v4l2-compliance, then let me know and I'll fix it. If not,
> >> then it should be fixed in the driver.
> >>
> >> Frankly, it was the presence of these failures that made me think this patch series
> >> wasn't final. Before a v4l2 driver can be accepted in the kernel, v4l2-compliance must pass.
> >>
> >> Regards,
> >>
> >> 	Hans
> > 
> > 
> > --
> > 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
> > 




From hverkuil at xs4all.nl  Sun Jul 10 21:32:10 2016
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Mon, 11 Jul 2016 06:32:10 +0200
Subject: [PATCH] vcodec: mediatek: Add g/s_selection support for V4L2
 Encoder
In-Reply-To: <1464594768-1993-1-git-send-email-tiffany.lin@mediatek.com>
References: <1464594768-1993-1-git-send-email-tiffany.lin@mediatek.com>
Message-ID: <4ca82842-968d-a5e2-587d-752c71713607@xs4all.nl>

Hi Tiffany,

My apologies for the delay, but here is my review at last:

On 05/30/2016 09:52 AM, Tiffany Lin wrote:
> This patch add g/s_selection support for MT8173
> 
> Signed-off-by: Tiffany Lin <tiffany.lin at mediatek.com>
> ---
>  drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c |   74 ++++++++++++++++++++
>  1 file changed, 74 insertions(+)
> 
> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
> index 6e72d73..23ef9a1 100644
> --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
> +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
> @@ -630,6 +630,77 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
>  	return vidioc_try_fmt(f, fmt);
>  }
>  
> +static int vidioc_venc_g_selection(struct file *file, void *priv,
> +				     struct v4l2_selection *s)
> +{
> +	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
> +	struct mtk_q_data *q_data;
> +
> +	/* crop means compose for output devices */
> +	switch (s->target) {
> +	case V4L2_SEL_TGT_CROP_DEFAULT:
> +	case V4L2_SEL_TGT_CROP_BOUNDS:
> +	case V4L2_SEL_TGT_CROP:
> +	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
> +	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
> +	case V4L2_SEL_TGT_COMPOSE:
> +		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
> +			mtk_v4l2_err("Invalid s->type = %d", s->type);
> +			return -EINVAL;
> +		}
> +		break;
> +	default:
> +		mtk_v4l2_err("Invalid s->target = %d", s->target);
> +		return -EINVAL;
> +	}
> +
> +	q_data = mtk_venc_get_q_data(ctx, s->type);
> +	if (!q_data)
> +		return -EINVAL;
> +
> +	s->r.top = 0;
> +	s->r.left = 0;
> +	s->r.width = q_data->visible_width;
> +	s->r.height = q_data->visible_height;
> +
> +	return 0;
> +}
> +
> +static int vidioc_venc_s_selection(struct file *file, void *priv,
> +				     struct v4l2_selection *s)
> +{
> +	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
> +	struct mtk_q_data *q_data;
> +
> +	switch (s->target) {
> +	case V4L2_SEL_TGT_CROP_DEFAULT:
> +	case V4L2_SEL_TGT_CROP_BOUNDS:
> +	case V4L2_SEL_TGT_CROP:
> +	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
> +	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
> +	case V4L2_SEL_TGT_COMPOSE:
> +		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
> +			mtk_v4l2_err("Invalid s->type = %d", s->type);
> +			return -EINVAL;
> +		}
> +		break;
> +	default:
> +		mtk_v4l2_err("Invalid s->target = %d", s->target);
> +		return -EINVAL;
> +	}
> +
> +	q_data = mtk_venc_get_q_data(ctx, s->type);
> +	if (!q_data)
> +		return -EINVAL;
> +
> +	s->r.top = 0;
> +	s->r.left = 0;
> +	q_data->visible_width = s->r.width;
> +	q_data->visible_height = s->r.height;

This makes no sense.

See this page:

https://hverkuil.home.xs4all.nl/spec/media.html#selection-api

For the video output direction (memory -> HW encoder) the data source is
the memory, the data sink is the HW encoder. For the video capture direction
(HW encoder -> memory) the data source is the HW encoder and the data sink
is the memory.

Usually for m2m devices the video output direction may support cropping and
the video capture direction may support composing.

It's not clear what you intend here, especially since you set left and right
to 0. That's not what the selection operation is supposed to do.

Regards,

	Hans

> +
> +	return 0;
> +}
> +
>  static int vidioc_venc_qbuf(struct file *file, void *priv,
>  			    struct v4l2_buffer *buf)
>  {
> @@ -688,6 +759,9 @@ const struct v4l2_ioctl_ops mtk_venc_ioctl_ops = {
>  
>  	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,
>  	.vidioc_prepare_buf		= v4l2_m2m_ioctl_prepare_buf,
> +
> +	.vidioc_g_selection		= vidioc_venc_g_selection,
> +	.vidioc_s_selection		= vidioc_venc_s_selection,
>  };
>  
>  static int vb2ops_venc_queue_setup(struct vb2_queue *vq,
> 


From zhiyong.tao at mediatek.com  Sun Jul 10 23:39:54 2016
From: zhiyong.tao at mediatek.com (Zhiyong Tao)
Date: Mon, 11 Jul 2016 14:39:54 +0800
Subject: [PATCH v4 0/3] AUXADC: Mediatek auxadc driver 
Message-ID: <1468219197-9572-1-git-send-email-zhiyong.tao@mediatek.com>

This series includes three patches:
1.Change the device tree binding documentation.
2.Add auxadc driver based on linux iio.
3.Add auxadc nodes in the mediatek MT2701 dtsi file.

Changes in patch v4:
1).Change the file name 'mt65xx_auxdc.txt' to 'mt6577_auxdc.txt'.
2).Remove 'break' after 'return' in 'mt6577_auxadc_read_raw'.
3).Use 'mt2701' instead of 'auxadc' in dts commit message.
4).Change 'auxadc@' to 'adc@' in mt2701.dtsi.

Changes in patch v3:
1).Add '#' before 'io-channel-cells' and change 'auxadc@' to 'adc@' in auxadc binding document.
2).Fix CONFIG_MEDIATEK_MT65XX_AUXADC sequence as alphabetical order.
3).Change the prefix 'MT65XX' to 'MT6577' to match auxadc driver name.
4).Remove the delays stored in 'mt6577_auxadc_device' and use the defined delay directly.
5).Use '-ETIMEDOUT' instead of '-EINVAL'.
6).Return value directly in 'mt6577_auxadc_read_raw'.
7).Add power off and unprepare clock if 'iio_device_register' failed.
8).Change 'Registers' to 'Register'.

Changes in patch v2:
1).Change the file name mt65xx_auxadc.c to mt6577_auxadc.c.
2).Add 'depends on ARCH_MEDIATEK || COMPILE_TEST and HAS_IOMEM' for MEDIATEK_MT65XX_AUXADC config.
3).Add check case for return value of 'readl_poll_timeout'.
4).Remove returning 1 and 0 for SCALE and OFFSET. use channel type 'IIO_CHAN_INFO_PROCESSED' instead of 'IIO_CHAN_INFO_RAW'.
5).Remove 'IIO_CHAN_INFO_OFFSET' and 'IIO_CHAN_INFO_SCALE' in 'MT65XX_AUXADC_CHANNEL' channel type.
6).Add check case when auxadc power on failure. if auxadc power on failure, clk_disable_unprepare should be executed.
7).Put 'platform_set_drvdata' before 'iio_device_register'.
8).Fix coding style and spelling error.

Zhiyong Tao (3):
  dt-bindings: auxadc: Add binding document for Mediatek auxadc.
  iio: adc: mt2701: Add Mediatek auxadc driver for mt2701.
  arm: dts: mt2701: Add auxadc node.

 .../devicetree/bindings/iio/adc/mt6577_auxadc.txt  |   27 ++
 .../devicetree/bindings/soc/mediatek/auxadc.txt    |   21 --
 arch/arm/boot/dts/mt2701.dtsi                      |    9 +
 drivers/iio/adc/Kconfig                            |   13 +
 drivers/iio/adc/Makefile                           |    1 +
 drivers/iio/adc/mt6577_auxadc.c                    |  294 ++++++++++++++++++++
 6 files changed, 344 insertions(+), 21 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iio/adc/mt6577_auxadc.txt
 delete mode 100644 Documentation/devicetree/bindings/soc/mediatek/auxadc.txt
 create mode 100644 drivers/iio/adc/mt6577_auxadc.c



From zhiyong.tao at mediatek.com  Sun Jul 10 23:39:56 2016
From: zhiyong.tao at mediatek.com (Zhiyong Tao)
Date: Mon, 11 Jul 2016 14:39:56 +0800
Subject: [PATCH v4 2/3] iio: adc: mt2701: Add Mediatek auxadc driver for
 mt2701.
In-Reply-To: <1468219197-9572-1-git-send-email-zhiyong.tao@mediatek.com>
References: <1468219197-9572-1-git-send-email-zhiyong.tao@mediatek.com>
Message-ID: <1468219197-9572-3-git-send-email-zhiyong.tao@mediatek.com>

Add Mediatek auxadc driver based on iio.
It will register a device in iio and support iio.
So thermal can read auxadc channel to sample data by iio device.
It is tested successfully on mt2701 platform.
Mt8173 and mt6577 platforms are not tested.
But the expectation is compatible.

Signed-off-by: Zhiyong Tao <zhiyong.tao at mediatek.com>
---
 drivers/iio/adc/Kconfig         |   13 ++
 drivers/iio/adc/Makefile        |    1 +
 drivers/iio/adc/mt6577_auxadc.c |  294 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 308 insertions(+)
 create mode 100644 drivers/iio/adc/mt6577_auxadc.c

diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 25378c5..14929fc 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -305,6 +305,19 @@ config MCP3422
 	  This driver can also be built as a module. If so, the module will be
 	  called mcp3422.
 
+config MEDIATEK_MT6577_AUXADC
+        tristate "MediaTek AUXADC driver"
+        depends on ARCH_MEDIATEK || COMPILE_TEST
+        depends on HAS_IOMEM
+        help
+          Say yes here to enable support for MediaTek mt65xx AUXADC.
+
+          The driver supports immediate mode operation to read from one of sixteen
+          channels (external or internal).
+
+          This driver can also be built as a module. If so, the module will be
+          called mt6577_auxadc.
+
 config MEN_Z188_ADC
 	tristate "MEN 16z188 ADC IP Core support"
 	depends on MCB
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 38638d4..8306347 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_MAX1027) += max1027.o
 obj-$(CONFIG_MAX1363) += max1363.o
 obj-$(CONFIG_MCP320X) += mcp320x.o
 obj-$(CONFIG_MCP3422) += mcp3422.o
+obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
 obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
 obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
 obj-$(CONFIG_NAU7802) += nau7802.o
diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c
new file mode 100644
index 0000000..c7cc901
--- /dev/null
+++ b/drivers/iio/adc/mt6577_auxadc.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Zhiyong Tao <zhiyong.tao at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/iopoll.h>
+#include <linux/io.h>
+#include <linux/iio/iio.h>
+
+/* Register definitions */
+#define MT6577_AUXADC_CON0                    0x00
+#define MT6577_AUXADC_CON1                    0x04
+#define MT6577_AUXADC_CON2                    0x10
+#define MT6577_AUXADC_STA                     BIT(0)
+
+#define MT6577_AUXADC_DAT0                    0x14
+#define MT6577_AUXADC_RDY0                    BIT(12)
+
+#define MT6577_AUXADC_MISC                    0x94
+#define MT6577_AUXADC_PDN_EN                  BIT(14)
+
+#define MT6577_AUXADC_DAT_MASK                0xfff
+#define MT6577_AUXADC_SLEEP_US                1000
+#define MT6577_AUXADC_TIMEOUT_US              10000
+#define MT6577_AUXADC_POWER_READY_MS          1
+#define MT6577_AUXADC_SAMPLE_READY_US         25
+
+struct mt6577_auxadc_device {
+	void __iomem *reg_base;
+	struct clk *adc_clk;
+	struct mutex lock;
+};
+
+#define MT6577_AUXADC_CHANNEL(idx) {				    \
+		.type = IIO_VOLTAGE,				    \
+		.indexed = 1,					    \
+		.channel = (idx),				    \
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
+}
+
+static const struct iio_chan_spec mt6577_auxadc_iio_channels[] = {
+	MT6577_AUXADC_CHANNEL(0),
+	MT6577_AUXADC_CHANNEL(1),
+	MT6577_AUXADC_CHANNEL(2),
+	MT6577_AUXADC_CHANNEL(3),
+	MT6577_AUXADC_CHANNEL(4),
+	MT6577_AUXADC_CHANNEL(5),
+	MT6577_AUXADC_CHANNEL(6),
+	MT6577_AUXADC_CHANNEL(7),
+	MT6577_AUXADC_CHANNEL(8),
+	MT6577_AUXADC_CHANNEL(9),
+	MT6577_AUXADC_CHANNEL(10),
+	MT6577_AUXADC_CHANNEL(11),
+	MT6577_AUXADC_CHANNEL(12),
+	MT6577_AUXADC_CHANNEL(13),
+	MT6577_AUXADC_CHANNEL(14),
+	MT6577_AUXADC_CHANNEL(15),
+};
+
+static int mt6577_auxadc_read(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan)
+{
+	u32 rawdata, val;
+	void __iomem *reg_channel;
+	int ret;
+	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
+
+	reg_channel = adc_dev->reg_base + MT6577_AUXADC_DAT0 +
+		      chan->channel * 0x04;
+
+	mutex_lock(&adc_dev->lock);
+
+	val = readl(adc_dev->reg_base + MT6577_AUXADC_CON1);
+	val &= ~(1 << chan->channel);
+	writel(val, adc_dev->reg_base + MT6577_AUXADC_CON1);
+
+	/* read channel and make sure old ready bit == 0 */
+	ret = readl_poll_timeout(reg_channel, val,
+				 ((val & MT6577_AUXADC_RDY0) == 0),
+				 MT6577_AUXADC_SLEEP_US,
+				 MT6577_AUXADC_TIMEOUT_US);
+	if (ret < 0) {
+		dev_err(indio_dev->dev.parent,
+			"wait for channel[%d] ready bit clear time out\n",
+			chan->channel);
+
+		mutex_unlock(&adc_dev->lock);
+
+		return -ETIMEDOUT;
+	}
+
+	/* set bit to trigger sample */
+	val = readl(adc_dev->reg_base + MT6577_AUXADC_CON1);
+	val |= 1 << chan->channel;
+	writel(val, adc_dev->reg_base + MT6577_AUXADC_CON1);
+
+	/* we must delay here for hardware sample channel data */
+	udelay(MT6577_AUXADC_SAMPLE_READY_US);
+
+	/* check MTK_AUXADC_CON2 if auxadc is idle */
+	ret = readl_poll_timeout(adc_dev->reg_base + MT6577_AUXADC_CON2, val,
+				 ((val & MT6577_AUXADC_STA) == 0),
+				 MT6577_AUXADC_SLEEP_US,
+				 MT6577_AUXADC_TIMEOUT_US);
+	if (ret < 0) {
+		dev_err(indio_dev->dev.parent,
+			"wait for auxadc idle time out\n");
+
+		mutex_unlock(&adc_dev->lock);
+
+		return -ETIMEDOUT;
+	}
+
+	/* read channel and make sure ready bit == 1 */
+	ret = readl_poll_timeout(reg_channel, val,
+				 ((val & MT6577_AUXADC_RDY0) != 0),
+				 MT6577_AUXADC_SLEEP_US,
+				 MT6577_AUXADC_TIMEOUT_US);
+	if (ret < 0) {
+		dev_err(indio_dev->dev.parent,
+			"wait for channel[%d] data ready time out\n",
+			chan->channel);
+
+		mutex_unlock(&adc_dev->lock);
+
+		return -ETIMEDOUT;
+	}
+
+	/* read data */
+	rawdata = readl(reg_channel) & MT6577_AUXADC_DAT_MASK;
+
+	mutex_unlock(&adc_dev->lock);
+
+	return rawdata;
+}
+
+static int mt6577_auxadc_read_raw(struct iio_dev *indio_dev,
+				  struct iio_chan_spec const *chan,
+				  int *val,
+				  int *val2,
+				  long info)
+{
+	switch (info) {
+	case IIO_CHAN_INFO_PROCESSED:
+		*val = mt6577_auxadc_read(indio_dev, chan);
+		if (*val < 0) {
+			dev_err(indio_dev->dev.parent,
+				"failed to sample data on channel[%d]\n",
+				chan->channel);
+			return *val;
+		}
+		return IIO_VAL_INT;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info mt6577_auxadc_info = {
+	.driver_module = THIS_MODULE,
+	.read_raw = &mt6577_auxadc_read_raw,
+};
+
+static int mt6577_auxadc_probe(struct platform_device *pdev)
+{
+	struct mt6577_auxadc_device *adc_dev;
+	unsigned long adc_clk_rate;
+	struct resource *res;
+	struct iio_dev *indio_dev;
+	int ret;
+	u32 val;
+
+	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	adc_dev = iio_priv(indio_dev);
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->name = dev_name(&pdev->dev);
+	indio_dev->info = &mt6577_auxadc_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = mt6577_auxadc_iio_channels;
+	indio_dev->num_channels = ARRAY_SIZE(mt6577_auxadc_iio_channels);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	adc_dev->reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(adc_dev->reg_base)) {
+		dev_err(&pdev->dev, "failed to get auxadc base address.\n");
+		return PTR_ERR(adc_dev->reg_base);
+	}
+
+	adc_dev->adc_clk = devm_clk_get(&pdev->dev, "main");
+	if (IS_ERR(adc_dev->adc_clk)) {
+		dev_err(&pdev->dev, "failed to get auxadc clock\n");
+		return PTR_ERR(adc_dev->adc_clk);
+	}
+
+	ret = clk_prepare_enable(adc_dev->adc_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable auxadc clock\n");
+		return ret;
+	}
+
+	adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
+	if (!adc_clk_rate) {
+		dev_err(&pdev->dev, "null clock rate!\n");
+		goto err_disable_clk;
+	}
+
+	mutex_init(&adc_dev->lock);
+
+	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
+	val |= MT6577_AUXADC_PDN_EN;
+	writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
+	mdelay(MT6577_AUXADC_POWER_READY_MS);
+
+	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
+	if ((val & MT6577_AUXADC_PDN_EN) == 0) {
+		dev_err(&pdev->dev, "failed to enable auxadc power!\n");
+		goto err_disable_clk;
+	}
+
+	platform_set_drvdata(pdev, indio_dev);
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to register iio device!\n");
+		val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
+		val &= ~MT6577_AUXADC_PDN_EN;
+		writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
+		goto err_disable_clk;
+	}
+
+	return 0;
+
+err_disable_clk:
+	clk_disable_unprepare(adc_dev->adc_clk);
+	return -EINVAL;
+}
+
+static int mt6577_auxadc_remove(struct platform_device *pdev)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
+	u32 val;
+
+	iio_device_unregister(indio_dev);
+
+	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
+	val &= ~MT6577_AUXADC_PDN_EN;
+	writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
+
+	clk_disable_unprepare(adc_dev->adc_clk);
+
+	return 0;
+}
+
+static const struct of_device_id mt6577_auxadc_of_match[] = {
+	{ .compatible = "mediatek,mt2701-auxadc", },
+	{ .compatible = "mediatek,mt8173-auxadc", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, mt6577_auxadc_of_match);
+
+static struct platform_driver mt6577_auxadc_driver = {
+	.driver = {
+		.name   = "mt6577-auxadc",
+		.of_match_table = mt6577_auxadc_of_match,
+	},
+	.probe	= mt6577_auxadc_probe,
+	.remove	= mt6577_auxadc_remove,
+};
+module_platform_driver(mt6577_auxadc_driver);
+
+MODULE_AUTHOR("Zhiyong Tao <zhiyong.tao at mediatek.com>");
+MODULE_DESCRIPTION("MTK AUXADC Device Driver");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5



From zhiyong.tao at mediatek.com  Sun Jul 10 23:39:57 2016
From: zhiyong.tao at mediatek.com (Zhiyong Tao)
Date: Mon, 11 Jul 2016 14:39:57 +0800
Subject: [PATCH v4 3/3] arm: dts: mt2701: Add auxadc node.
In-Reply-To: <1468219197-9572-1-git-send-email-zhiyong.tao@mediatek.com>
References: <1468219197-9572-1-git-send-email-zhiyong.tao@mediatek.com>
Message-ID: <1468219197-9572-4-git-send-email-zhiyong.tao@mediatek.com>

The commit adds auxadc nodes to the Mediatek MT2701 dtsi file.

Signed-off-by: Zhiyong Tao <zhiyong.tao at mediatek.com>
---
 arch/arm/boot/dts/mt2701.dtsi |    9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
index 42d5a37..c0a2644 100644
--- a/arch/arm/boot/dts/mt2701.dtsi
+++ b/arch/arm/boot/dts/mt2701.dtsi
@@ -187,6 +187,15 @@
 		      <0 0x10216000 0 0x2000>;
 	};
 
+	auxadc: adc at 11001000 {
+		compatible = "mediatek,mt2701-auxadc";
+		reg = <0 0x11001000 0 0x1000>;
+		clocks = <&pericfg CLK_PERI_AUXADC>;
+		clock-names = "main";
+		#io-channel-cells = <1>;
+		status = "disabled";
+	};
+
 	uart0: serial at 11002000 {
 		compatible = "mediatek,mt2701-uart",
 			     "mediatek,mt6577-uart";
-- 
1.7.9.5



From zhiyong.tao at mediatek.com  Sun Jul 10 23:39:55 2016
From: zhiyong.tao at mediatek.com (Zhiyong Tao)
Date: Mon, 11 Jul 2016 14:39:55 +0800
Subject: [PATCH v4 1/3] dt-bindings: auxadc: Add binding document for Mediatek
 auxadc.
In-Reply-To: <1468219197-9572-1-git-send-email-zhiyong.tao@mediatek.com>
References: <1468219197-9572-1-git-send-email-zhiyong.tao@mediatek.com>
Message-ID: <1468219197-9572-2-git-send-email-zhiyong.tao@mediatek.com>

The commit adds the device tree binding documentation for the mediatek
auxadc found on Mediatek MT2701.
Thermal gets auxadc sample data by iio device.
So the commit changes auxadc device tree binding documentation from
/soc/mediatek/auxadc.txt to /iio/adc/mt6577_auxadc.txt.

Signed-off-by: Zhiyong Tao <zhiyong.tao at mediatek.com>
---
 .../devicetree/bindings/iio/adc/mt6577_auxadc.txt  |   27 ++++++++++++++++++++
 .../devicetree/bindings/soc/mediatek/auxadc.txt    |   21 ---------------
 2 files changed, 27 insertions(+), 21 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iio/adc/mt6577_auxadc.txt
 delete mode 100644 Documentation/devicetree/bindings/soc/mediatek/auxadc.txt

diff --git a/Documentation/devicetree/bindings/iio/adc/mt6577_auxadc.txt b/Documentation/devicetree/bindings/iio/adc/mt6577_auxadc.txt
new file mode 100644
index 0000000..bc23792
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/mt6577_auxadc.txt
@@ -0,0 +1,27 @@
+* Mediatek AUXADC - Analog to Digital Converter on Mediatek mobile soc (mt65xx/mt81xx/mt27xx)
+===============
+
+The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found
+in some Mediatek SoCs which among other things measures the temperatures
+in the SoC. It can be used directly with register accesses, but it is also
+used by thermal controller which reads the temperatures from the AUXADC
+directly via its own bus interface. See
+Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
+for the Thermal Controller which holds a phandle to the AUXADC.
+
+Required properties:
+  - compatible: "mediatek,mt2701-auxadc" or "mediatek,mt8173-auxadc"
+  - reg: Address range of the AUXADC unit.
+  - clocks: Should contain a clock specifier for each entry in clock-names
+  - clock-names: Should contain "main".
+  - #io-channel-cells: Should be 1, see ../iio-bindings.txt
+
+Example:
+
+auxadc: adc at 11001000 {
+	compatible = "mediatek,mt2701-auxadc";
+	reg = <0 0x11001000 0 0x1000>;
+	clocks = <&pericfg CLK_PERI_AUXADC>;
+	clock-names = "main";
+	#io-channel-cells = <1>;
+};
diff --git a/Documentation/devicetree/bindings/soc/mediatek/auxadc.txt b/Documentation/devicetree/bindings/soc/mediatek/auxadc.txt
deleted file mode 100644
index bdb7829..0000000
--- a/Documentation/devicetree/bindings/soc/mediatek/auxadc.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-MediaTek AUXADC
-===============
-
-The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found
-in some Mediatek SoCs which among other things measures the temperatures
-in the SoC. It can be used directly with register accesses, but it is also
-used by thermal controller which reads the temperatures from the AUXADC
-directly via its own bus interface. See
-Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
-for the Thermal Controller which holds a phandle to the AUXADC.
-
-Required properties:
-- compatible: Must be "mediatek,mt8173-auxadc"
-- reg: Address range of the AUXADC unit
-
-Example:
-
-auxadc: auxadc at 11001000 {
-	compatible = "mediatek,mt8173-auxadc";
-	reg = <0 0x11001000 0 0x1000>;
-};
-- 
1.7.9.5



From tiffany.lin at mediatek.com  Mon Jul 11 01:09:51 2016
From: tiffany.lin at mediatek.com (tiffany lin)
Date: Mon, 11 Jul 2016 16:09:51 +0800
Subject: [PATCH] vcodec: mediatek: Add g/s_selection support for V4L2
 Encoder
In-Reply-To: <4ca82842-968d-a5e2-587d-752c71713607@xs4all.nl>
References: <1464594768-1993-1-git-send-email-tiffany.lin@mediatek.com>
 <4ca82842-968d-a5e2-587d-752c71713607@xs4all.nl>
Message-ID: <1468224591.2462.6.camel@mtksdaap41>

Hi Hans,

On Mon, 2016-07-11 at 06:32 +0200, Hans Verkuil wrote:
> Hi Tiffany,
> 
> My apologies for the delay, but here is my review at last:
> 
> On 05/30/2016 09:52 AM, Tiffany Lin wrote:
> > This patch add g/s_selection support for MT8173
> > 
> > Signed-off-by: Tiffany Lin <tiffany.lin at mediatek.com>
> > ---
> >  drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c |   74 ++++++++++++++++++++
> >  1 file changed, 74 insertions(+)
> > 
> > diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
> > index 6e72d73..23ef9a1 100644
> > --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
> > +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
> > @@ -630,6 +630,77 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
> >  	return vidioc_try_fmt(f, fmt);
> >  }
> >  
> > +static int vidioc_venc_g_selection(struct file *file, void *priv,
> > +				     struct v4l2_selection *s)
> > +{
> > +	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
> > +	struct mtk_q_data *q_data;
> > +
> > +	/* crop means compose for output devices */
> > +	switch (s->target) {
> > +	case V4L2_SEL_TGT_CROP_DEFAULT:
> > +	case V4L2_SEL_TGT_CROP_BOUNDS:
> > +	case V4L2_SEL_TGT_CROP:
> > +	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
> > +	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
> > +	case V4L2_SEL_TGT_COMPOSE:
> > +		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
> > +			mtk_v4l2_err("Invalid s->type = %d", s->type);
> > +			return -EINVAL;
> > +		}
> > +		break;
> > +	default:
> > +		mtk_v4l2_err("Invalid s->target = %d", s->target);
> > +		return -EINVAL;
> > +	}
> > +
> > +	q_data = mtk_venc_get_q_data(ctx, s->type);
> > +	if (!q_data)
> > +		return -EINVAL;
> > +
> > +	s->r.top = 0;
> > +	s->r.left = 0;
> > +	s->r.width = q_data->visible_width;
> > +	s->r.height = q_data->visible_height;
> > +
> > +	return 0;
> > +}
> > +
> > +static int vidioc_venc_s_selection(struct file *file, void *priv,
> > +				     struct v4l2_selection *s)
> > +{
> > +	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
> > +	struct mtk_q_data *q_data;
> > +
> > +	switch (s->target) {
> > +	case V4L2_SEL_TGT_CROP_DEFAULT:
> > +	case V4L2_SEL_TGT_CROP_BOUNDS:
> > +	case V4L2_SEL_TGT_CROP:
> > +	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
> > +	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
> > +	case V4L2_SEL_TGT_COMPOSE:
> > +		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
> > +			mtk_v4l2_err("Invalid s->type = %d", s->type);
> > +			return -EINVAL;
> > +		}
> > +		break;
> > +	default:
> > +		mtk_v4l2_err("Invalid s->target = %d", s->target);
> > +		return -EINVAL;
> > +	}
> > +
> > +	q_data = mtk_venc_get_q_data(ctx, s->type);
> > +	if (!q_data)
> > +		return -EINVAL;
> > +
> > +	s->r.top = 0;
> > +	s->r.left = 0;
> > +	q_data->visible_width = s->r.width;
> > +	q_data->visible_height = s->r.height;
> 
> This makes no sense.
> 
> See this page:
> 
> https://hverkuil.home.xs4all.nl/spec/media.html#selection-api
> 
> For the video output direction (memory -> HW encoder) the data source is
> the memory, the data sink is the HW encoder. For the video capture direction
> (HW encoder -> memory) the data source is the HW encoder and the data sink
> is the memory.
> 
> Usually for m2m devices the video output direction may support cropping and
> the video capture direction may support composing.
> 
> It's not clear what you intend here, especially since you set left and right
> to 0. That's not what the selection operation is supposed to do.
> 

We only support simple crop, but as you mentioned we need to use
g/s_selection not g/s_crop.
This provide our user space application could get/set encode region to
driver and encode region should always start from (0,0) to (width,
height).
That's why we always set top and left to 0.


best regards,
Tiffany

> Regards,
> 
> 	Hans
> 
> > +
> > +	return 0;
> > +}
> > +
> >  static int vidioc_venc_qbuf(struct file *file, void *priv,
> >  			    struct v4l2_buffer *buf)
> >  {
> > @@ -688,6 +759,9 @@ const struct v4l2_ioctl_ops mtk_venc_ioctl_ops = {
> >  
> >  	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,
> >  	.vidioc_prepare_buf		= v4l2_m2m_ioctl_prepare_buf,
> > +
> > +	.vidioc_g_selection		= vidioc_venc_g_selection,
> > +	.vidioc_s_selection		= vidioc_venc_s_selection,
> >  };
> >  
> >  static int vb2ops_venc_queue_setup(struct vb2_queue *vq,
> > 




From weiqing.kong at mediatek.com  Mon Jul 11 01:18:06 2016
From: weiqing.kong at mediatek.com (Weiqing Kong)
Date: Mon, 11 Jul 2016 16:18:06 +0800
Subject: [PATCH V2 0/3] Support Mediatek Soc MT2701 disp pwm
Message-ID: <1468225089-28576-1-git-send-email-weiqing.kong@mediatek.com>

These series patches modify pwm-mtk-disp.c
and dts/dtsi config to support MT2701 disp pwm.

Changes since v1:
- Change dtsi compatible string "mediatek,mt2701-disp-bls" into "mediatek,mt2701-disp-pwm"
- Change some macros into struct mtk_pwm_data

Weiqing Kong (3):
  dt-bindings: pwm: Add MediaTek display PWM bindings
  pwm: Add MediaTek MT2701 display PWM driver support
  dts: Add disp bls dtsi and dts config for MT2701

 .../devicetree/bindings/pwm/pwm-mtk-disp.txt       |  3 +-
 arch/arm/boot/dts/mt2701-evb.dts                   | 29 +++++++
 arch/arm/boot/dts/mt2701.dtsi                      |  9 ++
 drivers/pwm/pwm-mtk-disp.c                         | 99 +++++++++++++++++-----
 4 files changed, 120 insertions(+), 20 deletions(-)

-- 
1.8.1.1.dirty



From weiqing.kong at mediatek.com  Mon Jul 11 01:18:07 2016
From: weiqing.kong at mediatek.com (Weiqing Kong)
Date: Mon, 11 Jul 2016 16:18:07 +0800
Subject: [PATCH V2 1/3] dt-bindings: pwm: Add MediaTek display PWM bindings
In-Reply-To: <1468225089-28576-1-git-send-email-weiqing.kong@mediatek.com>
References: <1468225089-28576-1-git-send-email-weiqing.kong@mediatek.com>
Message-ID: <1468225089-28576-2-git-send-email-weiqing.kong@mediatek.com>

Add MT2701 compatible string.

Signed-off-by: Weiqing Kong <weiqing.kong at mediatek.com>
---
 Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt b/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt
index f8f59ba..6f8af2b 100644
--- a/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt
+++ b/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt
@@ -2,8 +2,9 @@ MediaTek display PWM controller
 
 Required properties:
  - compatible: should be "mediatek,<name>-disp-pwm":
-   - "mediatek,mt8173-disp-pwm": found on mt8173 SoC.
+   - "mediatek,mt2701-disp-pwm": found on mt2701 SoC.
    - "mediatek,mt6595-disp-pwm": found on mt6595 SoC.
+   - "mediatek,mt8173-disp-pwm": found on mt8173 SoC.
  - reg: physical base address and length of the controller's registers.
  - #pwm-cells: must be 2. See pwm.txt in this directory for a description of
    the cell format.
-- 
1.8.1.1.dirty



From weiqing.kong at mediatek.com  Mon Jul 11 01:18:08 2016
From: weiqing.kong at mediatek.com (Weiqing Kong)
Date: Mon, 11 Jul 2016 16:18:08 +0800
Subject: [PATCH V2 2/3] pwm: Add MediaTek MT2701 display PWM driver support
In-Reply-To: <1468225089-28576-1-git-send-email-weiqing.kong@mediatek.com>
References: <1468225089-28576-1-git-send-email-weiqing.kong@mediatek.com>
Message-ID: <1468225089-28576-3-git-send-email-weiqing.kong@mediatek.com>

Use the mtk_pwm_data struction to define different registers
and add MT2701 specific register operations, such as MT2701
doesn't have commit register, needs to disable double buffer
before writing register, and needs to select manual mode
and use PWM_PERIOD/PWM_HIGH_WIDTH.

Signed-off-by: Weiqing Kong <weiqing.kong at mediatek.com>
---
 drivers/pwm/pwm-mtk-disp.c | 99 +++++++++++++++++++++++++++++++++++++---------
 1 file changed, 80 insertions(+), 19 deletions(-)

diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c
index 0ad3385..5eb1f6c 100644
--- a/drivers/pwm/pwm-mtk-disp.c
+++ b/drivers/pwm/pwm-mtk-disp.c
@@ -18,33 +18,45 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/pwm.h>
 #include <linux/slab.h>
 
 #define DISP_PWM_EN		0x00
-#define PWM_ENABLE_MASK		BIT(0)
 
-#define DISP_PWM_COMMIT		0x08
-#define PWM_COMMIT_MASK		BIT(0)
+#define MT8173_PWM_COMMIT_MASK		BIT(0)
 
-#define DISP_PWM_CON_0		0x10
 #define PWM_CLKDIV_SHIFT	16
 #define PWM_CLKDIV_MAX		0x3ff
 #define PWM_CLKDIV_MASK		(PWM_CLKDIV_MAX << PWM_CLKDIV_SHIFT)
 
-#define DISP_PWM_CON_1		0x14
 #define PWM_PERIOD_BIT_WIDTH	12
 #define PWM_PERIOD_MASK		((1 << PWM_PERIOD_BIT_WIDTH) - 1)
 
 #define PWM_HIGH_WIDTH_SHIFT	16
 #define PWM_HIGH_WIDTH_MASK	(0x1fff << PWM_HIGH_WIDTH_SHIFT)
 
+#define MT2701_PWM_MANUAL_SEL_MASK	BIT(1)
+#define MT2701_PWM_BLS_DEBUG		0xb0
+#define MT2701_PWM_BLS_DEBUG_MASK	0x3
+
+struct mtk_pwm_data {
+	unsigned int bls_debug;
+	unsigned int enable_bit;
+	unsigned int con0;
+	unsigned int con0_sel;
+	unsigned int con1;
+	unsigned int commit_reg_offset;
+	bool have_commit_reg;
+};
+
 struct mtk_disp_pwm {
 	struct pwm_chip chip;
 	struct clk *clk_main;
 	struct clk *clk_mm;
 	void __iomem *base;
+	const struct mtk_pwm_data *data;
 };
 
 static inline struct mtk_disp_pwm *to_mtk_disp_pwm(struct pwm_chip *chip)
@@ -106,12 +118,18 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 		return err;
 	}
 
-	mtk_disp_pwm_update_bits(mdp, DISP_PWM_CON_0, PWM_CLKDIV_MASK,
+	mtk_disp_pwm_update_bits(mdp, mdp->data->con0,
+				 PWM_CLKDIV_MASK,
 				 clk_div << PWM_CLKDIV_SHIFT);
-	mtk_disp_pwm_update_bits(mdp, DISP_PWM_CON_1,
-				 PWM_PERIOD_MASK | PWM_HIGH_WIDTH_MASK, value);
-	mtk_disp_pwm_update_bits(mdp, DISP_PWM_COMMIT, PWM_COMMIT_MASK, 1);
-	mtk_disp_pwm_update_bits(mdp, DISP_PWM_COMMIT, PWM_COMMIT_MASK, 0);
+	mtk_disp_pwm_update_bits(mdp, mdp->data->con1,
+				 PWM_PERIOD_MASK | PWM_HIGH_WIDTH_MASK,
+				 value);
+	if (mdp->data->have_commit_reg) {
+		mtk_disp_pwm_update_bits(mdp, mdp->data->commit_reg_offset,
+					 MT8173_PWM_COMMIT_MASK, 0x1);
+		mtk_disp_pwm_update_bits(mdp, mdp->data->commit_reg_offset,
+					 MT8173_PWM_COMMIT_MASK, 0x0);
+	}
 
 	clk_disable(mdp->clk_mm);
 	clk_disable(mdp->clk_main);
@@ -134,7 +152,9 @@ static int mtk_disp_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 		return err;
 	}
 
-	mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, PWM_ENABLE_MASK, 1);
+	mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN,
+				 mdp->data->enable_bit,
+				 mdp->data->enable_bit);
 
 	return 0;
 }
@@ -143,7 +163,8 @@ static void mtk_disp_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
 	struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
 
-	mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, PWM_ENABLE_MASK, 0);
+	mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN,
+				 mdp->data->enable_bit, 0x0);
 
 	clk_disable(mdp->clk_mm);
 	clk_disable(mdp->clk_main);
@@ -156,12 +177,45 @@ static const struct pwm_ops mtk_disp_pwm_ops = {
 	.owner = THIS_MODULE,
 };
 
+static const struct mtk_pwm_data mt8173_pwm_data = {
+	.bls_debug = 0x0,
+	.enable_bit = BIT(0),
+	.con0 = 0x10,
+	.con0_sel = 0x0,
+	.con1 = 0x14,
+	.commit_reg_offset = 0x8,
+	.have_commit_reg = true,
+};
+
+static const struct mtk_pwm_data mt2701_pwm_data = {
+	.bls_debug = 0x3,
+	.enable_bit = BIT(16),
+	.con0 = 0xa8,
+	.con0_sel = 0x2,
+	.con1 = 0xac,
+	.commit_reg_offset = 0x0,
+	.have_commit_reg = false,
+};
+
+static const struct of_device_id mtk_disp_pwm_of_match[] = {
+	{ .compatible = "mediatek,mt2701-disp-pwm", .data = &mt2701_pwm_data},
+	{ .compatible = "mediatek,mt6595-disp-pwm", .data = &mt8173_pwm_data},
+	{ .compatible = "mediatek,mt8173-disp-pwm", .data = &mt8173_pwm_data},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, mtk_disp_pwm_of_match);
+
 static int mtk_disp_pwm_probe(struct platform_device *pdev)
 {
+	const struct of_device_id *id;
 	struct mtk_disp_pwm *mdp;
 	struct resource *r;
 	int ret;
 
+	id = of_match_device(mtk_disp_pwm_of_match, &pdev->dev);
+	if (!id)
+		return -EINVAL;
+
 	mdp = devm_kzalloc(&pdev->dev, sizeof(*mdp), GFP_KERNEL);
 	if (!mdp)
 		return -ENOMEM;
@@ -191,6 +245,7 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev)
 	mdp->chip.ops = &mtk_disp_pwm_ops;
 	mdp->chip.base = -1;
 	mdp->chip.npwm = 1;
+	mdp->data = id->data;
 
 	ret = pwmchip_add(&mdp->chip);
 	if (ret < 0) {
@@ -200,6 +255,19 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, mdp);
 
+	/*
+	 * For MT2701, disable double buffer before writing register
+	 * and select manual mode and use PWM_PERIOD/PWM_HIGH_WIDTH.
+	 */
+	if (!mdp->data->have_commit_reg) {
+		mtk_disp_pwm_update_bits(mdp, MT2701_PWM_BLS_DEBUG,
+					 MT2701_PWM_BLS_DEBUG_MASK,
+					 mdp->data->bls_debug);
+		mtk_disp_pwm_update_bits(mdp, mdp->data->con0,
+					 MT2701_PWM_MANUAL_SEL_MASK,
+					 mdp->data->con0_sel);
+	}
+
 	return 0;
 
 disable_clk_mm:
@@ -221,13 +289,6 @@ static int mtk_disp_pwm_remove(struct platform_device *pdev)
 	return ret;
 }
 
-static const struct of_device_id mtk_disp_pwm_of_match[] = {
-	{ .compatible = "mediatek,mt8173-disp-pwm" },
-	{ .compatible = "mediatek,mt6595-disp-pwm" },
-	{ }
-};
-MODULE_DEVICE_TABLE(of, mtk_disp_pwm_of_match);
-
 static struct platform_driver mtk_disp_pwm_driver = {
 	.driver = {
 		.name = "mediatek-disp-pwm",
-- 
1.8.1.1.dirty



From weiqing.kong at mediatek.com  Mon Jul 11 01:18:09 2016
From: weiqing.kong at mediatek.com (Weiqing Kong)
Date: Mon, 11 Jul 2016 16:18:09 +0800
Subject: [PATCH V2 3/3] dts: Add disp bls dtsi and dts config for MT2701
In-Reply-To: <1468225089-28576-1-git-send-email-weiqing.kong@mediatek.com>
References: <1468225089-28576-1-git-send-email-weiqing.kong@mediatek.com>
Message-ID: <1468225089-28576-4-git-send-email-weiqing.kong@mediatek.com>

Add disp_bls node in dtsi for CCF, add backlight_lcd
in dts for backlight subsystem driver, and init pwm gpio mode.

Signed-off-by: Weiqing Kong <weiqing.kong at mediatek.com>
---
 arch/arm/boot/dts/mt2701-evb.dts | 29 +++++++++++++++++++++++++++++
 arch/arm/boot/dts/mt2701.dtsi    |  9 +++++++++
 2 files changed, 38 insertions(+)

diff --git a/arch/arm/boot/dts/mt2701-evb.dts b/arch/arm/boot/dts/mt2701-evb.dts
index 082ca88..6d572f4 100644
--- a/arch/arm/boot/dts/mt2701-evb.dts
+++ b/arch/arm/boot/dts/mt2701-evb.dts
@@ -22,6 +22,35 @@
 	memory {
 		reg = <0 0x80000000 0 0x40000000>;
 	};
+
+	backlight_lcd: backlight_lcd {
+		compatible = "pwm-backlight";
+		pwms = <&disp_bls 0 100000>;
+		brightness-levels = <
+			  0  16  32  48  64  80  96 112
+			128 144 160 176 192 208 224 240
+			255
+		>;
+		default-brightness-level = <9>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pwm_bls_gpio>;
+	};
+};
+
+&disp_bls {
+	status = "okay";
+};
+
+&mmsys {
+	status = "okay";
+};
+
+&pio {
+	pwm_bls_gpio: pwm_bls_gpio {
+		pins_cmd_dat {
+			pinmux = <MT2701_PIN_208_AUD_EXT_CK1__FUNC_DISP_PWM>;
+		};
+	};
 };
 
 &uart0 {
diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
index 42d5a37..49b8767 100644
--- a/arch/arm/boot/dts/mt2701.dtsi
+++ b/arch/arm/boot/dts/mt2701.dtsi
@@ -234,6 +234,15 @@
 		status = "disabled";
 	};
 
+	disp_bls: dispsys at 1400a000 {
+		compatible = "mediatek,mt2701-disp-pwm";
+		reg = <0 0x1400a000 0 0x1000>;
+		#pwm-cells = <2>;
+		clocks = <&mmsys CLK_MM_MDP_BLS_26M>, <&mmsys CLK_MM_DISP_BLS>;
+		clock-names = "main", "mm";
+		status = "disabled";
+	};
+
 	imgsys: syscon at 15000000 {
 		compatible = "mediatek,mt2701-imgsys", "syscon";
 		reg = <0 0x15000000 0 0x1000>;
-- 
1.8.1.1.dirty



From jamesjj.liao at mediatek.com  Mon Jul 11 01:24:12 2016
From: jamesjj.liao at mediatek.com (James Liao)
Date: Mon, 11 Jul 2016 16:24:12 +0800
Subject: [PATCH v9 01/10] clk: fix initial state of critical clock's
 parents
In-Reply-To: <146802073038.73491.6675612765998057903@resonance>
References: <1466581229-2342-1-git-send-email-erin.lo@mediatek.com>
 <1466581229-2342-2-git-send-email-erin.lo@mediatek.com>
 <20160702012140.GB17071@codeaurora.org>
 <1467604308.26485.4.camel@mtksdaap41>
 <146802073038.73491.6675612765998057903@resonance>
Message-ID: <1468225452.31247.7.camel@mtksdaap41>

Hi Mike,

On Fri, 2016-07-08 at 16:32 -0700, Michael Turquette wrote:
> Hi James,
> 
> Quoting James Liao (2016-07-03 20:51:48)
> > On Fri, 2016-07-01 at 18:21 -0700, Stephen Boyd wrote:
> > > (Resending to everyone)
> > > 
> > > On 06/22, Erin Lo wrote:
> > > > From: James Liao <jamesjj.liao at mediatek.com>
> > > > 
> > > > This patch fixed wrong state of parent clocks if they are registered
> > > > after critical clocks.
> > > > 
> > > > Signed-off-by: James Liao <jamesjj.liao at mediatek.com>
> > > > Signed-off-by: Erin Lo <erin.lo at mediatek.com>
> > > 
> > > It would be nice if you included the information about the
> > > problem from James' previous mail. This says what it does, but
> > > doesn't explain what the problem is and how it is fixing it.
> > > 
> > > > ---
> > > >  drivers/clk/clk.c | 9 ++++++++-
> > > >  1 file changed, 8 insertions(+), 1 deletion(-)
> > > > 
> > > > diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> > > > index d584004..e9f5f89 100644
> > > > --- a/drivers/clk/clk.c
> > > > +++ b/drivers/clk/clk.c
> > > > @@ -2388,8 +2388,15 @@ static int __clk_core_init(struct clk_core *core)
> > > >     hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) {
> > > >             struct clk_core *parent = __clk_init_parent(orphan);
> > > >  
> > > > -           if (parent)
> > > > +           if (parent) {
> > > >                     clk_core_reparent(orphan, parent);
> > > > +
> > > > +                   if (orphan->prepare_count)
> > > > +                           clk_core_prepare(parent);
> > > > +
> > > > +                   if (orphan->enable_count)
> > > > +                           clk_core_enable(parent);
> > > > +           }
> > > >     }
> > > 
> > > I'm pretty sure I pointed this problem out to Mike when the
> > > critical clk patches were being pushed. I can't recall what the
> > > plan was though to fix the problem. I'm pretty sure he said that
> > > clk_core_reparent() would take care of it, but obviously it is
> > > not doing that. Or perhaps it was that clk handoff should figure
> > > out that the parents of a critical clk are also on and thus keep
> > > them on.
> > 
> > Hi Mike
> > 
> > Is there any other patch to fix this issue? Or did I misuse critical
> > clock flag?
> 
> There is no fix yes. Your fix is basically correct. I was mistaken back
> when I told you and Stephen that the framework already took care of
> this.
> 
> However, instead of "open coding" this solution, I would rather re-use
> the __clk_set_parent_{before,after} helpers instead. Can you review/test
> the following patch and let me know what you think?
> 
> Thanks,
> Mike
> 
> 
> 
> From c0163b3f719b1e219b28ad425f94f9ef54a25a8f Mon Sep 17 00:00:00 2001
> From: Michael Turquette <mturquette at baylibre.com>
> Date: Fri, 8 Jul 2016 16:05:22 -0700
> Subject: [PATCH] clk: migrate ref counts when orphans are reunited
> 
> It's always nice to see families reunited, and this is equally true when
> talking about parent clocks and their children. However, if the orphan
> clk had a positive prepare_count or enable_count, then we would not
> migrate those counts up the parent chain correctly.
> 
> This has manifested with the recent critical clocks feature, which often
> enables clocks very early, before their parents have been registered.
> 
> Fixed by replacing the call to clk_core_reparent with calls to
> __clk_set_parent_{before,after}.
> 
> Cc: James Liao <jamesjj.liao at mediatek.com>
> Cc: Erin Lo <erin.lo at mediatek.com>
> Signed-off-by: Michael Turquette <mturquette at baylibre.com>
> ---
>  drivers/clk/clk.c | 10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index 820a939fb6bb..70efe4c4e0cc 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -2449,8 +2449,14 @@ static int __clk_core_init(struct clk_core *core)
>  	hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) {
>  		struct clk_core *parent = __clk_init_parent(orphan);
>  
> -		if (parent)
> -			clk_core_reparent(orphan, parent);

Is it correct to remove clk_core_reparent()? It lacks
__clk_recalc_accuracies() and __clk_recalc_rates(), so the new parent's
rate will not propagate correctly.

For example, I set vdec_sel as a critical clock. Without your patch, the
result was:

    vdecpll         0            0   338000000
       vdecpll_ck   1            1   338000000
          vdec_sel  1            1   338000000

With your patch, it became:

    vdecpll         1            1   338000000
       vdecpll_ck   1            1           0
          vdec_sel  1            1           0

The prepare_count and enable_count are correct with your patch, but the
rates of vdecpll_ck and vdec_sel become incorrect.


Best regards,

James

> +		/*
> +		 * we could call __clk_set_parent, but that would result in a
> +		 * reducant call to the .set_rate op, if it exists
> +		 */
> +		if (parent) {
> +			__clk_set_parent_before(orphan, parent);
> +			__clk_set_parent_after(orphan, parent, NULL);
> +		}
>  	}
>  
>  	/*




From dawei.chien at mediatek.com  Mon Jul 11 01:52:04 2016
From: dawei.chien at mediatek.com (dawei chien)
Date: Mon, 11 Jul 2016 16:52:04 +0800
Subject: [PATCH 1/3] dt-bindings: thermal: Add binding document for
 Mediatek thermal controller
In-Reply-To: <577E385C.9080501@ti.com>
References: <1467882386-40544-1-git-send-email-dawei.chien@mediatek.com>
 <1467882386-40544-2-git-send-email-dawei.chien@mediatek.com>
 <577E385C.9080501@ti.com>
Message-ID: <1468227124.15776.29.camel@mtksdaap41>

Dear Keerthy,

On Thu, 2016-07-07 at 16:39 +0530, Keerthy wrote:
> 
> On Thursday 07 July 2016 02:36 PM, Dawei Chien wrote:
> > This adds the device tree binding documentation for the mediatek thermal
> > controller found on Mediatek MT2701.
> >
> > Signed-off-by: Dawei Chien <dawei.chien at mediatek.com>
> > ---
> >   .../bindings/thermal/mediatek-thermal.txt          |    2 +-
> >   1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt b/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
> > index 81f9a51..bb55e79 100644
> > --- a/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
> > +++ b/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
> > @@ -8,7 +8,7 @@ apmixedsys register space via AHB bus accesses, so a phandle to the APMIXEDSYS
> >   is also needed.
> >
> >   Required properties:
> > -- compatible: "mediatek,mt8173-thermal"
> > +- compatible: "mediatek,mt8173-thermal" or "mediatek,mt2701-thermal"
> 
> - compatible :
>   - "mediatek,mt8173-thermal" : For MT8173 family of SoCs
>   - "mediatek,mt2701-thermal" : For MT2701 family of SoCs

Thank you, I will update it on next version.

> 
> >   - reg: Address range of the thermal controller
> >   - interrupts: IRQ for the thermal controller
> >   - clocks, clock-names: Clocks needed for the thermal controller. required
> >




From dawei.chien at mediatek.com  Mon Jul 11 01:56:00 2016
From: dawei.chien at mediatek.com (dawei chien)
Date: Mon, 11 Jul 2016 16:56:00 +0800
Subject: [PATCH 2/3] thermal: Add Mediatek thermal driver for mt2701.
In-Reply-To: <577E4300.406@ti.com>
References: <1467882386-40544-1-git-send-email-dawei.chien@mediatek.com>
 <1467882386-40544-3-git-send-email-dawei.chien@mediatek.com>
 <577E4300.406@ti.com>
Message-ID: <1468227360.15776.33.camel@mtksdaap41>

Dear Keerthy,

On Thu, 2016-07-07 at 17:24 +0530, Keerthy wrote:
> Hi Dawei Chien,
> 
> 
> On Thursday 07 July 2016 02:36 PM, Dawei Chien wrote:
> > This patch adds support for mt2701 chip to mtk_thermal.c,
> > and integrate both mt8173 and mt2701 on the same driver.
> > MT8173 has four banks and five sensors, and MT2701 has
> > only one bank and three sensors.
> >
> > Signed-off-by: Dawei Chien <dawei.chien at mediatek.com>
> > ---
> >   drivers/thermal/mtk_thermal.c |  258 ++++++++++++++++++++++++++---------------
> >   1 file changed, 165 insertions(+), 93 deletions(-)
> >
> > diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c
> > index 262ab0a..860f2e2 100644
> > --- a/drivers/thermal/mtk_thermal.c
> > +++ b/drivers/thermal/mtk_thermal.c
> > @@ -2,6 +2,7 @@
> >    * Copyright (c) 2015 MediaTek Inc.
> >    * Author: Hanyi Wu <hanyi.wu at mediatek.com>
> >    *         Sascha Hauer <s.hauer at pengutronix.de>
> > + *         Dawei Chien <dawei.chien at mediatek.com>
> >    *
> >    * This program is free software; you can redistribute it and/or modify
> >    * it under the terms of the GNU General Public License version 2 as
> > @@ -21,6 +22,7 @@
> >   #include <linux/nvmem-consumer.h>
> >   #include <linux/of.h>
> >   #include <linux/of_address.h>
> > +#include <linux/of_device.h>
> >   #include <linux/platform_device.h>
> >   #include <linux/slab.h>
> >   #include <linux/io.h>
> > @@ -88,6 +90,7 @@
> >   #define TEMP_ADCVALIDMASK_VALID_HIGH		BIT(5)
> >   #define TEMP_ADCVALIDMASK_VALID_POS(bit)	(bit)
> >
> > +/* MT8173 thermal sensors */
> >   #define MT8173_TS1	0
> >   #define MT8173_TS2	1
> >   #define MT8173_TS3	2
> > @@ -97,35 +100,62 @@
> >   /* AUXADC channel 11 is used for the temperature sensors */
> >   #define MT8173_TEMP_AUXADC_CHANNEL	11
> >
> > -/* The total number of temperature sensors in the MT8173 */
> > -#define MT8173_NUM_SENSORS		5
> > -
> > -/* The number of banks in the MT8173 */
> > -#define MT8173_NUM_ZONES		4
> > -
> > -/* The number of sensing points per bank */
> > -#define MT8173_NUM_SENSORS_PER_ZONE	4
> > -
> >   /* Layout of the fuses providing the calibration data */
> > -#define MT8173_CALIB_BUF0_VALID		BIT(0)
> > -#define MT8173_CALIB_BUF1_ADC_GE(x)	(((x) >> 22) & 0x3ff)
> > -#define MT8173_CALIB_BUF0_VTS_TS1(x)	(((x) >> 17) & 0x1ff)
> > -#define MT8173_CALIB_BUF0_VTS_TS2(x)	(((x) >> 8) & 0x1ff)
> > -#define MT8173_CALIB_BUF1_VTS_TS3(x)	(((x) >> 0) & 0x1ff)
> > -#define MT8173_CALIB_BUF2_VTS_TS4(x)	(((x) >> 23) & 0x1ff)
> > -#define MT8173_CALIB_BUF2_VTS_TSABB(x)	(((x) >> 14) & 0x1ff)
> > -#define MT8173_CALIB_BUF0_DEGC_CALI(x)	(((x) >> 1) & 0x3f)
> > -#define MT8173_CALIB_BUF0_O_SLOPE(x)	(((x) >> 26) & 0x3f)
> > +#define CALIB_BUF0_VALID		BIT(0)
> > +#define CALIB_BUF1_ADC_GE(x)	(((x) >> 22) & 0x3ff)
> > +#define CALIB_BUF0_VTS_TS1(x)	(((x) >> 17) & 0x1ff)
> > +#define CALIB_BUF0_VTS_TS2(x)	(((x) >> 8) & 0x1ff)
> > +#define CALIB_BUF1_VTS_TS3(x)	(((x) >> 0) & 0x1ff)
> > +#define CALIB_BUF2_VTS_TS4(x)	(((x) >> 23) & 0x1ff)
> > +#define CALIB_BUF2_VTS_TS5(x)	(((x) >> 14) & 0x1ff)
> > +#define CALIB_BUF0_DEGC_CALI(x)	(((x) >> 1) & 0x3f)
> > +#define CALIB_BUF0_O_SLOPE(x)	(((x) >> 26) & 0x3f)
> > +
> 
> IMHO the above changes from defining CALIB_BUF1_ADC_GE(x) to 
> CALIB_BUF0_O_SLOPE(x) can be avoided. We are just renaming the same 
> defines to a generic name. Instead the macro starting with MT8173 can 
> only be used wherever needed commonly both by 8173 instance and for
> 2701 instance.
> 

I would have a try to keep MT8173 original one and add some comment for
the macro starting on next version.

> > +#define NVMEM_TS1	0
> > +#define NVMEM_TS2	1
> > +#define NVMEM_TS3	2
> > +#define NVMEM_TS4	3
> > +#define NVMEM_TS5	4
> > +

Does these need to keep the old one
MT8173_TS1/MT8173_TS2/MT8173_TS3/MT8173_TS4/MT8173_TSABB


> > +/* MT2701 thermal sensors */
> > +#define MT2701_TS1	0
> > +#define MT2701_TS2	1
> > +#define MT2701_TSABB	2
> > +
> > +/* AUXADC channel 11 is used for the temperature sensors */
> > +#define MT2701_TEMP_AUXADC_CHANNEL	11
> >
> >   #define THERMAL_NAME    "mtk-thermal"
> >
> > +/* Maximum support banks */
> > +#define MAX_NUM_BANK		5
> 
> Why is this 5?
> Commit message states: MT8173 has four banks and five sensors, and 
> MT2701 has only one bank and three sensors. Am i missing something here?
> 

This is my miss, it should be 4, but it line might remove since I would
depend on SoC type to assign array for next version.

> > +
> >   struct mtk_thermal;
> >
> > +struct thermal_bank_cfg {
> > +	unsigned int num_sensors;
> > +	unsigned int sensors[MAX_NUM_BANK];
> > +};
> > +
> >   struct mtk_thermal_bank {
> >   	struct mtk_thermal *mt;
> >   	int id;
> >   };
> >
> > +struct mtk_thermal_sense_point {
> > +	int msr;
> > +	int adcpnp;
> > +};
> > +
> > +struct mtk_thermal_data {
> > +	struct thermal_bank_cfg bank_data[MAX_NUM_BANK];
> 
> So for MT8173 we are allocating one bank extra and for MT2701 we are 
> allocating 4 banks extra right? Why not do something like this:
> 
> struct thermal_bank *banks_data
> Assign the array based on the SoC type?
> 

Yes, I agree with you, I would update it on next version.

> > +	struct mtk_thermal_sense_point sensing_points[MAX_NUM_BANK];
> > +	int sensor_mux_values[MAX_NUM_BANK];
> > +	s32 num_banks;
> > +	s32 num_sensors;
> > +	s32 auxadc_channel;
> > +};
> > +
> >   struct mtk_thermal {
> >   	struct device *dev;
> >   	void __iomem *thermal_base;
> > @@ -133,27 +163,20 @@ struct mtk_thermal {
> >   	struct clk *clk_peri_therm;
> >   	struct clk *clk_auxadc;
> >
> > -	struct mtk_thermal_bank banks[MT8173_NUM_ZONES];
> > -
> > +	struct mtk_thermal_bank banks[MAX_NUM_BANK];
> 
> Here again some extra memory allocation.
> 
> Why not keep a pointer which points to the desired array?
> 
> > +	const struct mtk_thermal_data *conf;
> >   	/* lock: for getting and putting banks */
> >   	struct mutex lock;
> > +	struct thermal_zone_device *tzd;
> >
> >   	/* Calibration values */
> >   	s32 adc_ge;
> >   	s32 degc_cali;
> >   	s32 o_slope;
> > -	s32 vts[MT8173_NUM_SENSORS];
> > -
> > -};
> > -
> > -struct mtk_thermal_bank_cfg {
> > -	unsigned int num_sensors;
> > -	unsigned int sensors[MT8173_NUM_SENSORS_PER_ZONE];
> > +	s32 vts[MAX_NUM_BANK];
> >   };
> >
> > -static const int sensor_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 };
> > -
> > -/*
> > +/**
> >    * The MT8173 thermal controller has four banks. Each bank can read up to
> >    * four temperature sensors simultaneously. The MT8173 has a total of 5
> >    * temperature sensors. We use each bank to measure a certain area of the
> > @@ -166,42 +189,76 @@ static const int sensor_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 };
> >    * data, and this indeed needs the temperatures of the individual banks
> >    * for making better decisions.
> >    */
> > -static const struct mtk_thermal_bank_cfg bank_data[] = {
> > -	{
> > -		.num_sensors = 2,
> > -		.sensors = { MT8173_TS2, MT8173_TS3 },
> > -	}, {
> > -		.num_sensors = 2,
> > -		.sensors = { MT8173_TS2, MT8173_TS4 },
> > -	}, {
> > -		.num_sensors = 3,
> > -		.sensors = { MT8173_TS1, MT8173_TS2, MT8173_TSABB },
> > -	}, {
> > -		.num_sensors = 1,
> > -		.sensors = { MT8173_TS2 },
> > +static const struct mtk_thermal_data mt8173_thermal_data = {
> > +	.auxadc_channel = MT8173_TEMP_AUXADC_CHANNEL,
> > +	.num_banks = 4,
> > +	.num_sensors = 5,
> > +	.bank_data = {
> > +		{
> > +			.num_sensors = 2,
> > +			.sensors = { MT8173_TS2, MT8173_TS3 },
> > +		}, {
> > +			.num_sensors = 2,
> > +			.sensors = { MT8173_TS2, MT8173_TS4 },
> > +		}, {
> > +			.num_sensors = 3,
> > +			.sensors = { MT8173_TS1, MT8173_TS2, MT8173_TSABB },
> > +		}, {
> > +			.num_sensors = 1,
> > +			.sensors = { MT8173_TS2 },
> > +		},
> >   	},
> > +	.sensing_points = {
> > +		{
> > +			.msr = TEMP_MSR0,
> > +			.adcpnp = TEMP_ADCPNP0,
> > +		}, {
> > +			.msr = TEMP_MSR1,
> > +			.adcpnp = TEMP_ADCPNP1,
> > +		}, {
> > +			.msr = TEMP_MSR2,
> > +			.adcpnp = TEMP_ADCPNP2,
> > +		}, {
> > +			.msr = TEMP_MSR3,
> > +			.adcpnp = TEMP_ADCPNP3,
> > +		},
> > +	},
> > +	.sensor_mux_values = { 0, 1, 2, 3, 16 },
> >   };
> >
> > -struct mtk_thermal_sense_point {
> > -	int msr;
> > -	int adcpnp;
> > -};
> > -
> > -static const struct mtk_thermal_sense_point
> > -		sensing_points[MT8173_NUM_SENSORS_PER_ZONE] = {
> > -	{
> > -		.msr = TEMP_MSR0,
> > -		.adcpnp = TEMP_ADCPNP0,
> > -	}, {
> > -		.msr = TEMP_MSR1,
> > -		.adcpnp = TEMP_ADCPNP1,
> > -	}, {
> > -		.msr = TEMP_MSR2,
> > -		.adcpnp = TEMP_ADCPNP2,
> > -	}, {
> > -		.msr = TEMP_MSR3,
> > -		.adcpnp = TEMP_ADCPNP3,
> > +/**
> > + * The MT2701 thermal controller has one bank, which can read up to
> > + * three temperature sensors simultaneously. The MT2701 has a total of 3
> > + * temperature sensors.
> > + *
> > + * The thermal core only gets the maximum temperature of this one bank,
> > + * so the bank concept wouldn't be necessary here. However, the SVS (Smart
> > + * Voltage Scaling) unit makes its decisions based on the same bank
> > + * data.
> > + */
> > +static const struct mtk_thermal_data mt2701_thermal_data = {
> > +	.auxadc_channel = MT2701_TEMP_AUXADC_CHANNEL,
> > +	.num_banks = 1,
> > +	.num_sensors = 3,
> > +	.bank_data = {
> > +		{
> > +			.num_sensors = 3,
> > +			.sensors = { MT2701_TS1, MT2701_TS2, MT2701_TSABB },
> > +		},
> >   	},
> > +	.sensing_points = {
> > +		{
> > +			.msr = TEMP_MSR0,
> > +			.adcpnp = TEMP_ADCPNP0,
> > +		}, {
> > +			.msr = TEMP_MSR1,
> > +			.adcpnp = TEMP_ADCPNP1,
> > +		}, {
> > +			.msr = TEMP_MSR2,
> > +			.adcpnp = TEMP_ADCPNP2,
> > +		},
> > +	},
> > +	.sensor_mux_values = { 0, 1, 16},
> >   };
> >
> >   /**
> > @@ -270,13 +327,15 @@ static void mtk_thermal_put_bank(struct mtk_thermal_bank *bank)
> >   static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank)
> >   {
> >   	struct mtk_thermal *mt = bank->mt;
> > +	const struct mtk_thermal_data *conf = mt->conf;
> >   	int i, temp = INT_MIN, max = INT_MIN;
> >   	u32 raw;
> >
> > -	for (i = 0; i < bank_data[bank->id].num_sensors; i++) {
> > -		raw = readl(mt->thermal_base + sensing_points[i].msr);
> > +	for (i = 0; i < conf->bank_data[bank->id].num_sensors; i++) {
> > +		raw = readl(mt->thermal_base + conf->sensing_points[i].msr);
> >
> > -		temp = raw_to_mcelsius(mt, bank_data[bank->id].sensors[i], raw);
> > +		temp = raw_to_mcelsius(mt, conf->bank_data[bank->id].sensors[i],
> > +				       raw);
> >
> >   		/*
> >   		 * The first read of a sensor often contains very high bogus
> > @@ -299,7 +358,7 @@ static int mtk_read_temp(void *data, int *temperature)
> >   	int i;
> >   	int tempmax = INT_MIN;
> >
> > -	for (i = 0; i < MT8173_NUM_ZONES; i++) {
> > +	for (i = 0; i < mt->conf->num_banks; i++) {
> >   		struct mtk_thermal_bank *bank = &mt->banks[i];
> >
> >   		mtk_thermal_get_bank(bank);
> > @@ -322,7 +381,7 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num,
> >   				  u32 apmixed_phys_base, u32 auxadc_phys_base)
> >   {
> >   	struct mtk_thermal_bank *bank = &mt->banks[num];
> > -	const struct mtk_thermal_bank_cfg *cfg = &bank_data[num];
> > +	const struct mtk_thermal_data *conf = mt->conf;
> >   	int i;
> >
> >   	bank->id = num;
> > @@ -368,7 +427,7 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num,
> >   	 * this value will be stored to TEMP_PNPMUXADDR (TEMP_SPARE0)
> >   	 * automatically by hw
> >   	 */
> > -	writel(BIT(MT8173_TEMP_AUXADC_CHANNEL), mt->thermal_base + TEMP_ADCMUX);
> > +	writel(BIT(conf->auxadc_channel), mt->thermal_base + TEMP_ADCMUX);
> >
> >   	/* AHB address for auxadc mux selection */
> >   	writel(auxadc_phys_base + AUXADC_CON1_CLR_V,
> > @@ -379,18 +438,18 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num,
> >   	       mt->thermal_base + TEMP_PNPMUXADDR);
> >
> >   	/* AHB value for auxadc enable */
> > -	writel(BIT(MT8173_TEMP_AUXADC_CHANNEL), mt->thermal_base + TEMP_ADCEN);
> > +	writel(BIT(conf->auxadc_channel), mt->thermal_base + TEMP_ADCEN);
> >
> >   	/* AHB address for auxadc enable (channel 0 immediate mode selected) */
> >   	writel(auxadc_phys_base + AUXADC_CON1_SET_V,
> >   	       mt->thermal_base + TEMP_ADCENADDR);
> >
> >   	/* AHB address for auxadc valid bit */
> > -	writel(auxadc_phys_base + AUXADC_DATA(MT8173_TEMP_AUXADC_CHANNEL),
> > +	writel(auxadc_phys_base + AUXADC_DATA(conf->auxadc_channel),
> >   	       mt->thermal_base + TEMP_ADCVALIDADDR);
> >
> >   	/* AHB address for auxadc voltage output */
> > -	writel(auxadc_phys_base + AUXADC_DATA(MT8173_TEMP_AUXADC_CHANNEL),
> > +	writel(auxadc_phys_base + AUXADC_DATA(conf->auxadc_channel),
> >   	       mt->thermal_base + TEMP_ADCVOLTADDR);
> >
> >   	/* read valid & voltage are at the same register */
> > @@ -407,11 +466,12 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num,
> >   	writel(TEMP_ADCWRITECTRL_ADC_MUX_WRITE,
> >   	       mt->thermal_base + TEMP_ADCWRITECTRL);
> >
> > -	for (i = 0; i < cfg->num_sensors; i++)
> > -		writel(sensor_mux_values[cfg->sensors[i]],
> > -		       mt->thermal_base + sensing_points[i].adcpnp);
> > +	for (i = 0; i < conf->bank_data[num].num_sensors; i++)
> > +		writel(conf->sensor_mux_values[conf->bank_data[num].sensors[i]],
> > +		       mt->thermal_base + conf->sensing_points[i].adcpnp);
> >
> > -	writel((1 << cfg->num_sensors) - 1, mt->thermal_base + TEMP_MONCTL0);
> > +	writel((1 << conf->bank_data[num].num_sensors) - 1,
> > +	       mt->thermal_base + TEMP_MONCTL0);
> >
> >   	writel(TEMP_ADCWRITECTRL_ADC_PNP_WRITE |
> >   	       TEMP_ADCWRITECTRL_ADC_MUX_WRITE,
> > @@ -442,7 +502,7 @@ static int mtk_thermal_get_calibration_data(struct device *dev,
> >
> >   	/* Start with default values */
> >   	mt->adc_ge = 512;
> > -	for (i = 0; i < MT8173_NUM_SENSORS; i++)
> > +	for (i = 0; i < mt->conf->num_sensors; i++)
> >   		mt->vts[i] = 260;
> >   	mt->degc_cali = 40;
> >   	mt->o_slope = 0;
> > @@ -467,15 +527,15 @@ static int mtk_thermal_get_calibration_data(struct device *dev,
> >   		goto out;
> >   	}
> >
> > -	if (buf[0] & MT8173_CALIB_BUF0_VALID) {
> > -		mt->adc_ge = MT8173_CALIB_BUF1_ADC_GE(buf[1]);
> > -		mt->vts[MT8173_TS1] = MT8173_CALIB_BUF0_VTS_TS1(buf[0]);
> > -		mt->vts[MT8173_TS2] = MT8173_CALIB_BUF0_VTS_TS2(buf[0]);
> > -		mt->vts[MT8173_TS3] = MT8173_CALIB_BUF1_VTS_TS3(buf[1]);
> > -		mt->vts[MT8173_TS4] = MT8173_CALIB_BUF2_VTS_TS4(buf[2]);
> > -		mt->vts[MT8173_TSABB] = MT8173_CALIB_BUF2_VTS_TSABB(buf[2]);
> > -		mt->degc_cali = MT8173_CALIB_BUF0_DEGC_CALI(buf[0]);
> > -		mt->o_slope = MT8173_CALIB_BUF0_O_SLOPE(buf[0]);
> > +	if (buf[0] & CALIB_BUF0_VALID) {
> > +		mt->adc_ge = CALIB_BUF1_ADC_GE(buf[1]);
> > +		mt->vts[NVMEM_TS1] = CALIB_BUF0_VTS_TS1(buf[0]);
> > +		mt->vts[NVMEM_TS2] = CALIB_BUF0_VTS_TS2(buf[0]);
> > +		mt->vts[NVMEM_TS3] = CALIB_BUF1_VTS_TS3(buf[1]);
> > +		mt->vts[NVMEM_TS4] = CALIB_BUF2_VTS_TS4(buf[1]);
> > +		mt->vts[NVMEM_TS5] = CALIB_BUF2_VTS_TS5(buf[2]);
> > +		mt->degc_cali = CALIB_BUF0_DEGC_CALI(buf[0]);
> > +		mt->o_slope = CALIB_BUF0_O_SLOPE(buf[0]);
> 
> I guess even the above code changes can be avoided if we just retain 
> macros starting with MT8173?
> 
> Best Regards,
> Keerthy
> 

Yes, I think so, only different on the array size for vts since sensors
number different between MT8173 & MT2701, I might separate it by SoC
type on next version.

BR,
Dawei

> >   	} else {
> >   		dev_info(dev, "Device not calibrated, using default calibration values\n");
> >   	}
> > @@ -486,18 +546,36 @@ out:
> >   	return ret;
> >   }
> >
> > +static const struct of_device_id mtk_thermal_of_match[] = {
> > +	{
> > +		.compatible = "mediatek,mt8173-thermal",
> > +		.data = (void *)&mt8173_thermal_data,
> > +	},
> > +	{
> > +		.compatible = "mediatek,mt2701-thermal",
> > +		.data = (void *)&mt2701_thermal_data,
> > +	}, {
> > +	},
> > +};
> > +MODULE_DEVICE_TABLE(of, mtk_thermal_of_match);
> > +
> >   static int mtk_thermal_probe(struct platform_device *pdev)
> >   {
> >   	int ret, i;
> >   	struct device_node *auxadc, *apmixedsys, *np = pdev->dev.of_node;
> >   	struct mtk_thermal *mt;
> >   	struct resource *res;
> > +	const struct of_device_id *of_id;
> >   	u64 auxadc_phys_base, apmixed_phys_base;
> >
> >   	mt = devm_kzalloc(&pdev->dev, sizeof(*mt), GFP_KERNEL);
> >   	if (!mt)
> >   		return -ENOMEM;
> >
> > +	of_id = of_match_device(mtk_thermal_of_match, &pdev->dev);
> > +	if (of_id)
> > +		mt->conf = (const struct mtk_thermal_data *)of_id->data;
> > +
> >   	mt->clk_peri_therm = devm_clk_get(&pdev->dev, "therm");
> >   	if (IS_ERR(mt->clk_peri_therm))
> >   		return PTR_ERR(mt->clk_peri_therm);
> > @@ -565,7 +643,7 @@ static int mtk_thermal_probe(struct platform_device *pdev)
> >   		goto err_disable_clk_auxadc;
> >   	}
> >
> > -	for (i = 0; i < MT8173_NUM_ZONES; i++)
> > +	for (i = 0; i < mt->conf->num_banks; i++)
> >   		mtk_thermal_init_bank(mt, i, apmixed_phys_base,
> >   				      auxadc_phys_base);
> >
> > @@ -592,13 +670,6 @@ static int mtk_thermal_remove(struct platform_device *pdev)
> >   	return 0;
> >   }
> >
> > -static const struct of_device_id mtk_thermal_of_match[] = {
> > -	{
> > -		.compatible = "mediatek,mt8173-thermal",
> > -	}, {
> > -	},
> > -};
> > -
> >   static struct platform_driver mtk_thermal_driver = {
> >   	.probe = mtk_thermal_probe,
> >   	.remove = mtk_thermal_remove,
> > @@ -610,6 +681,7 @@ static struct platform_driver mtk_thermal_driver = {
> >
> >   module_platform_driver(mtk_thermal_driver);
> >
> > +MODULE_AUTHOR("Dawei Chien <dawei.chien at mediatek.com>");
> >   MODULE_AUTHOR("Sascha Hauer <s.hauer at pengutronix.de>");
> >   MODULE_AUTHOR("Hanyi Wu <hanyi.wu at mediatek.com>");
> >   MODULE_DESCRIPTION("Mediatek thermal driver");
> >




From jamesjj.liao at mediatek.com  Mon Jul 11 01:56:30 2016
From: jamesjj.liao at mediatek.com (James Liao)
Date: Mon, 11 Jul 2016 16:56:30 +0800
Subject: [PATCH v7 1/4] soc: mediatek: Refine scpsys to support multiple
 platform
In-Reply-To: <577E3AE9.5080202@gmail.com>
References: <1463390894-32062-1-git-send-email-jamesjj.liao@mediatek.com>
 <1463390894-32062-2-git-send-email-jamesjj.liao@mediatek.com>
 <6762e420-0d68-0376-b584-bfc878b5e95f@gmail.com>
 <1467783564.26485.22.camel@mtksdaap41> <577E3AE9.5080202@gmail.com>
Message-ID: <1468227390.31247.20.camel@mtksdaap41>

Hi Matthias,

On Thu, 2016-07-07 at 13:20 +0200, Matthias Brugger wrote:
> 
> On 06/07/16 07:39, James Liao wrote:
> > Hi Matthias,
> >
> > On Sat, 2016-07-02 at 18:33 +0200, Matthias Brugger wrote:
> >>
> >> On 05/16/2016 11:28 AM, James Liao wrote:
> >>> Refine scpsys driver common code to support multiple SoC / platform.
> >>>
> >>> Signed-off-by: James Liao <jamesjj.liao at mediatek.com>
> >>> Reviewed-by: Kevin Hilman <khilman at baylibre.com>
> >>> ---
> >>>   drivers/soc/mediatek/mtk-scpsys.c | 363 +++++++++++++++++++++++---------------
> >>>   1 file changed, 220 insertions(+), 143 deletions(-)
> >>>
> >>> diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
> >>> index 57e781c..5870a24 100644
> >>> --- a/drivers/soc/mediatek/mtk-scpsys.c
> >>> +++ b/drivers/soc/mediatek/mtk-scpsys.c
> >>> @@ -11,17 +11,15 @@
> >>>    * GNU General Public License for more details.
> >>>    */
> >>>   #include <linux/clk.h>
> >>> -#include <linux/delay.h>
> >>> +#include <linux/init.h>
> >>>   #include <linux/io.h>
> >>> -#include <linux/kernel.h>
> >>>   #include <linux/mfd/syscon.h>
> >>> -#include <linux/init.h>
> >>>   #include <linux/of_device.h>
> >>>   #include <linux/platform_device.h>
> >>>   #include <linux/pm_domain.h>
> >>> -#include <linux/regmap.h>
> >>> -#include <linux/soc/mediatek/infracfg.h>
> >>>   #include <linux/regulator/consumer.h>
> >>> +#include <linux/soc/mediatek/infracfg.h>
> >>> +
> >>>   #include <dt-bindings/power/mt8173-power.h>
> >>>
> >>>   #define SPM_VDE_PWR_CON			0x0210
> >>> @@ -34,6 +32,7 @@
> >>>   #define SPM_MFG_2D_PWR_CON		0x02c0
> >>>   #define SPM_MFG_ASYNC_PWR_CON		0x02c4
> >>>   #define SPM_USB_PWR_CON			0x02cc
> >>> +
> >>>   #define SPM_PWR_STATUS			0x060c
> >>>   #define SPM_PWR_STATUS_2ND		0x0610
> >>>
> >>> @@ -55,12 +54,12 @@
> >>>   #define PWR_STATUS_USB			BIT(25)
> >>>
> >>>   enum clk_id {
> >>> -	MT8173_CLK_NONE,
> >>> -	MT8173_CLK_MM,
> >>> -	MT8173_CLK_MFG,
> >>> -	MT8173_CLK_VENC,
> >>> -	MT8173_CLK_VENC_LT,
> >>> -	MT8173_CLK_MAX,
> >>> +	CLK_NONE,
> >>> +	CLK_MM,
> >>> +	CLK_MFG,
> >>> +	CLK_VENC,
> >>> +	CLK_VENC_LT,
> >>> +	CLK_MAX,
> >>>   };
> >>>
> >>>   #define MAX_CLKS	2
> >>> @@ -76,98 +75,6 @@ struct scp_domain_data {
> >>>   	bool active_wakeup;
> >>>   };
> >>>
> >>> -static const struct scp_domain_data scp_domain_data[] = {
> >>> -	[MT8173_POWER_DOMAIN_VDEC] = {
> >>> -		.name = "vdec",
> >>> -		.sta_mask = PWR_STATUS_VDEC,
> >>> -		.ctl_offs = SPM_VDE_PWR_CON,
> >>> -		.sram_pdn_bits = GENMASK(11, 8),
> >>> -		.sram_pdn_ack_bits = GENMASK(12, 12),
> >>> -		.clk_id = {MT8173_CLK_MM},
> >>> -	},
> >>> -	[MT8173_POWER_DOMAIN_VENC] = {
> >>> -		.name = "venc",
> >>> -		.sta_mask = PWR_STATUS_VENC,
> >>> -		.ctl_offs = SPM_VEN_PWR_CON,
> >>> -		.sram_pdn_bits = GENMASK(11, 8),
> >>> -		.sram_pdn_ack_bits = GENMASK(15, 12),
> >>> -		.clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC},
> >>> -	},
> >>> -	[MT8173_POWER_DOMAIN_ISP] = {
> >>> -		.name = "isp",
> >>> -		.sta_mask = PWR_STATUS_ISP,
> >>> -		.ctl_offs = SPM_ISP_PWR_CON,
> >>> -		.sram_pdn_bits = GENMASK(11, 8),
> >>> -		.sram_pdn_ack_bits = GENMASK(13, 12),
> >>> -		.clk_id = {MT8173_CLK_MM},
> >>> -	},
> >>> -	[MT8173_POWER_DOMAIN_MM] = {
> >>> -		.name = "mm",
> >>> -		.sta_mask = PWR_STATUS_DISP,
> >>> -		.ctl_offs = SPM_DIS_PWR_CON,
> >>> -		.sram_pdn_bits = GENMASK(11, 8),
> >>> -		.sram_pdn_ack_bits = GENMASK(12, 12),
> >>> -		.clk_id = {MT8173_CLK_MM},
> >>> -		.bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
> >>> -			MT8173_TOP_AXI_PROT_EN_MM_M1,
> >>> -	},
> >>> -	[MT8173_POWER_DOMAIN_VENC_LT] = {
> >>> -		.name = "venc_lt",
> >>> -		.sta_mask = PWR_STATUS_VENC_LT,
> >>> -		.ctl_offs = SPM_VEN2_PWR_CON,
> >>> -		.sram_pdn_bits = GENMASK(11, 8),
> >>> -		.sram_pdn_ack_bits = GENMASK(15, 12),
> >>> -		.clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC_LT},
> >>> -	},
> >>> -	[MT8173_POWER_DOMAIN_AUDIO] = {
> >>> -		.name = "audio",
> >>> -		.sta_mask = PWR_STATUS_AUDIO,
> >>> -		.ctl_offs = SPM_AUDIO_PWR_CON,
> >>> -		.sram_pdn_bits = GENMASK(11, 8),
> >>> -		.sram_pdn_ack_bits = GENMASK(15, 12),
> >>> -		.clk_id = {MT8173_CLK_NONE},
> >>> -	},
> >>> -	[MT8173_POWER_DOMAIN_USB] = {
> >>> -		.name = "usb",
> >>> -		.sta_mask = PWR_STATUS_USB,
> >>> -		.ctl_offs = SPM_USB_PWR_CON,
> >>> -		.sram_pdn_bits = GENMASK(11, 8),
> >>> -		.sram_pdn_ack_bits = GENMASK(15, 12),
> >>> -		.clk_id = {MT8173_CLK_NONE},
> >>> -		.active_wakeup = true,
> >>> -	},
> >>> -	[MT8173_POWER_DOMAIN_MFG_ASYNC] = {
> >>> -		.name = "mfg_async",
> >>> -		.sta_mask = PWR_STATUS_MFG_ASYNC,
> >>> -		.ctl_offs = SPM_MFG_ASYNC_PWR_CON,
> >>> -		.sram_pdn_bits = GENMASK(11, 8),
> >>> -		.sram_pdn_ack_bits = 0,
> >>> -		.clk_id = {MT8173_CLK_MFG},
> >>> -	},
> >>> -	[MT8173_POWER_DOMAIN_MFG_2D] = {
> >>> -		.name = "mfg_2d",
> >>> -		.sta_mask = PWR_STATUS_MFG_2D,
> >>> -		.ctl_offs = SPM_MFG_2D_PWR_CON,
> >>> -		.sram_pdn_bits = GENMASK(11, 8),
> >>> -		.sram_pdn_ack_bits = GENMASK(13, 12),
> >>> -		.clk_id = {MT8173_CLK_NONE},
> >>> -	},
> >>> -	[MT8173_POWER_DOMAIN_MFG] = {
> >>> -		.name = "mfg",
> >>> -		.sta_mask = PWR_STATUS_MFG,
> >>> -		.ctl_offs = SPM_MFG_PWR_CON,
> >>> -		.sram_pdn_bits = GENMASK(13, 8),
> >>> -		.sram_pdn_ack_bits = GENMASK(21, 16),
> >>> -		.clk_id = {MT8173_CLK_NONE},
> >>> -		.bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
> >>> -			MT8173_TOP_AXI_PROT_EN_MFG_M0 |
> >>> -			MT8173_TOP_AXI_PROT_EN_MFG_M1 |
> >>> -			MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT,
> >>> -	},
> >>> -};
> >>> -
> >>> -#define NUM_DOMAINS	ARRAY_SIZE(scp_domain_data)
> >>> -
> >>>   struct scp;
> >>>
> >>>   struct scp_domain {
> >>> @@ -179,7 +86,7 @@ struct scp_domain {
> >>>   };
> >>>
> >>>   struct scp {
> >>> -	struct scp_domain domains[NUM_DOMAINS];
> >>> +	struct scp_domain *domains;
> >>>   	struct genpd_onecell_data pd_data;
> >>>   	struct device *dev;
> >>>   	void __iomem *base;
> >>> @@ -408,57 +315,69 @@ static bool scpsys_active_wakeup(struct device *dev)
> >>>   	return scpd->data->active_wakeup;
> >>>   }
> >>>
> >>> -static int scpsys_probe(struct platform_device *pdev)
> >>> +static void init_clks(struct platform_device *pdev, struct clk *clk[CLK_MAX])
> >>> +{
> >>> +	enum clk_id clk_ids[] = {
> >>> +		CLK_MM,
> >>> +		CLK_MFG,
> >>> +		CLK_VENC,
> >>> +		CLK_VENC_LT
> >>> +	};
> >>> +
> >>> +	static const char * const clk_names[] = {
> >>> +		"mm",
> >>> +		"mfg",
> >>> +		"venc",
> >>> +		"venc_lt",
> >>> +	};
> >>> +
> >>> +	int i;
> >>> +
> >>> +	for (i = 0; i < ARRAY_SIZE(clk_ids); i++)
> >>> +		clk[clk_ids[i]] = devm_clk_get(&pdev->dev, clk_names[i]);
> >>
> >> We can use the global enum clk_id and stat with i = 1, right?
> >
> > You are right. I'll change the start value with i = CLK_NONE + 1 in next
> > patch.
> >
> >>> +}
> >>> +
> >>> +static struct scp *init_scp(struct platform_device *pdev,
> >>> +			const struct scp_domain_data *scp_domain_data, int num)
> >>>   {
> >>>   	struct genpd_onecell_data *pd_data;
> >>>   	struct resource *res;
> >>> -	int i, j, ret;
> >>> +	int i, j;
> >>>   	struct scp *scp;
> >>> -	struct clk *clk[MT8173_CLK_MAX];
> >>> +	struct clk *clk[CLK_MAX];
> >>>
> >>>   	scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL);
> >>>   	if (!scp)
> >>> -		return -ENOMEM;
> >>> +		return ERR_PTR(-ENOMEM);
> >>>
> >>>   	scp->dev = &pdev->dev;
> >>>
> >>>   	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >>>   	scp->base = devm_ioremap_resource(&pdev->dev, res);
> >>>   	if (IS_ERR(scp->base))
> >>> -		return PTR_ERR(scp->base);
> >>> -
> >>> -	pd_data = &scp->pd_data;
> >>> -
> >>> -	pd_data->domains = devm_kzalloc(&pdev->dev,
> >>> -			sizeof(*pd_data->domains) * NUM_DOMAINS, GFP_KERNEL);
> >>> -	if (!pd_data->domains)
> >>> -		return -ENOMEM;
> >>> -
> >>> -	clk[MT8173_CLK_MM] = devm_clk_get(&pdev->dev, "mm");
> >>> -	if (IS_ERR(clk[MT8173_CLK_MM]))
> >>> -		return PTR_ERR(clk[MT8173_CLK_MM]);
> >>> -
> >>> -	clk[MT8173_CLK_MFG] = devm_clk_get(&pdev->dev, "mfg");
> >>> -	if (IS_ERR(clk[MT8173_CLK_MFG]))
> >>> -		return PTR_ERR(clk[MT8173_CLK_MFG]);
> >>> -
> >>> -	clk[MT8173_CLK_VENC] = devm_clk_get(&pdev->dev, "venc");
> >>> -	if (IS_ERR(clk[MT8173_CLK_VENC]))
> >>> -		return PTR_ERR(clk[MT8173_CLK_VENC]);
> >>> -
> >>> -	clk[MT8173_CLK_VENC_LT] = devm_clk_get(&pdev->dev, "venc_lt");
> >>> -	if (IS_ERR(clk[MT8173_CLK_VENC_LT]))
> >>> -		return PTR_ERR(clk[MT8173_CLK_VENC_LT]);
> >>> +		return ERR_CAST(scp->base);
> >>>
> >>>   	scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
> >>>   			"infracfg");
> >>>   	if (IS_ERR(scp->infracfg)) {
> >>>   		dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n",
> >>>   				PTR_ERR(scp->infracfg));
> >>> -		return PTR_ERR(scp->infracfg);
> >>> +		return ERR_CAST(scp->infracfg);
> >>>   	}
> >>>
> >>> -	for (i = 0; i < NUM_DOMAINS; i++) {
> >>> +	scp->domains = devm_kzalloc(&pdev->dev,
> >>> +				sizeof(*scp->domains) * num, GFP_KERNEL);
> >>> +	if (!scp->domains)
> >>> +		return ERR_PTR(-ENOMEM);
> >>> +
> >>> +	pd_data = &scp->pd_data;
> >>> +
> >>> +	pd_data->domains = devm_kzalloc(&pdev->dev,
> >>> +			sizeof(*pd_data->domains) * num, GFP_KERNEL);
> >>> +	if (!pd_data->domains)
> >>> +		return ERR_PTR(-ENOMEM);
> >>> +
> >>> +	for (i = 0; i < num; i++) {
> >>>   		struct scp_domain *scpd = &scp->domains[i];
> >>>   		const struct scp_domain_data *data = &scp_domain_data[i];
> >>>
> >>> @@ -467,28 +386,54 @@ static int scpsys_probe(struct platform_device *pdev)
> >>>   			if (PTR_ERR(scpd->supply) == -ENODEV)
> >>>   				scpd->supply = NULL;
> >>>   			else
> >>> -				return PTR_ERR(scpd->supply);
> >>> +				return ERR_CAST(scpd->supply);
> >>>   		}
> >>>   	}
> >>>
> >>> -	pd_data->num_domains = NUM_DOMAINS;
> >>> +	pd_data->num_domains = num;
> >>>
> >>> -	for (i = 0; i < NUM_DOMAINS; i++) {
> >>> +	init_clks(pdev, clk);
> >>> +
> >>> +	for (i = 0; i < num; i++) {
> >>>   		struct scp_domain *scpd = &scp->domains[i];
> >>>   		struct generic_pm_domain *genpd = &scpd->genpd;
> >>>   		const struct scp_domain_data *data = &scp_domain_data[i];
> >>>
> >>> +		for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
> >>> +			struct clk *c = clk[data->clk_id[j]];
> >>> +
> >>> +			if (IS_ERR(c)) {
> >>> +				dev_err(&pdev->dev, "%s: clk unavailable\n",
> >>> +					data->name);
> >>> +				return ERR_CAST(c);
> >>> +			}
> >>> +
> >>> +			scpd->clk[j] = c;
> >>
> >> Put this in the else branch. Apart from that is there any reason you
> >
> > Do you mean to change like this?
> >
> > 	if (IS_ERR(c)) {
> > 		...
> > 		return ERR_CAST(c);
> > 	} else {
> > 		scpd->clk[j] = c;
> > 	}
> >
> > checkpatch.pl will warn for above code due to it returns in 'if' branch.
> >
> 
> I tried that on top of next-20160706 and it checkpatch didn't throw any 
> warning. Which kernel version are based on?

I don't remember which version of checkpatch warn on this pattern. This
patch series develop across several kernel versions.

So do you prefer to put "scpd->clk[j] = c;" into 'else' branch?

> >> moved the for up in the function? If not, I would prefer not to move it,
> >> to make it easier to read the diff.
> >
> > The new 'for' block are far different from original one. And I think
> > it's easy to read if we keep simple assign statements in the same block.
> >
> 
> It's different in the sense that it checks if struct clk *c is an error.
> I don't see the reason why we need to move it up in the file.
> It's not too important but I would prefer not to move it if there is no 
> reason.

I think I may misunderstand your comments. Which 'for' block did you
mention for? 'for (i = 0; i < num ...' or 'for (j = 0; j < MAX_CLKS
&& ...' ?

The 'for(i)' exists in original code, this patch just change its counter
from 'NUM_DOMAINS' to 'num'. The 'for(j)' is a new for-block, so it was
not moved from other blocks.


Best regards,

James




From dawei.chien at mediatek.com  Mon Jul 11 01:56:55 2016
From: dawei.chien at mediatek.com (dawei chien)
Date: Mon, 11 Jul 2016 16:56:55 +0800
Subject: [PATCH 3/3] arm: dts: thermal: add thermal/auxadc node.
In-Reply-To: <577E465D.8070004@ti.com>
References: <1467882386-40544-1-git-send-email-dawei.chien@mediatek.com>
 <1467882386-40544-4-git-send-email-dawei.chien@mediatek.com>
 <577E465D.8070004@ti.com>
Message-ID: <1468227415.15776.34.camel@mtksdaap41>

Dear Keerthy,

On Thu, 2016-07-07 at 17:39 +0530, Keerthy wrote:
> 
> On Thursday 07 July 2016 02:36 PM, Dawei Chien wrote:
> > This adds the thermal controller and auxadc nodes
> > to the Mediatek MT2701 dtsi file.
> >
> > Signed-off-by: Dawei Chien <dawei.chien at mediatek.com>
> > ---
> > This patch depned on:
> > https://patchwork.kernel.org/patch/9213545/
> > ---
> >   arch/arm/boot/dts/mt2701.dtsi |   43 +++++++++++++++++++++++++++++++++++++++++
> >   1 file changed, 43 insertions(+)
> >
> > diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
> > index 2ac8b50..0834a23 100644
> > --- a/arch/arm/boot/dts/mt2701.dtsi
> > +++ b/arch/arm/boot/dts/mt2701.dtsi
> > @@ -77,6 +77,36 @@
> >   		#clock-cells = <0>;
> >   	};
> >
> > +	thermal-zones {
> > +		cpu_thermal: cpu_thermal {
> > +			polling-delay-passive = <1000>; /* milliseconds */
> > +			polling-delay = <1000>; /* milliseconds */
> > +
> > +			thermal-sensors = <&thermal 0>;
> > +			sustainable-power = <1000>;
> > +
> > +			trips {
> > +				threshold: trip-point at 0 {
> > +					temperature = <68000>;
> > +					hysteresis = <2000>;
> > +					type = "passive";
> > +				};
> > +
> > +				target: trip-point at 1 {
> > +					temperature = <85000>;
> > +					hysteresis = <2000>;
> > +					type = "passive";
> > +				};
> > +
> > +				cpu_crit: cpu_crit at 0 {
> > +					temperature = <115000>;
> > +					hysteresis = <2000>;
> > +					type = "critical";
> > +				};
> > +			};
> > +		};
> > +	};
> > +
> 
> are there any corresponding cooling-maps?

Since MT2701 does not register CPUFREQ cooling device and its' own
device node, I could not add cooling-maps so far.
Could we add cooling map after CPUFREQ ready, thank you.

> 
> >   	timer {
> >   		compatible = "arm,armv7-timer";
> >   		interrupt-parent = <&gic>;
> > @@ -183,4 +213,17 @@
> >   		clocks = <&uart_clk>;
> >   		status = "disabled";
> >   	};
> > +
> > +	thermal: thermal at 1100b000 {
> > +		#thermal-sensor-cells = <0>;
> > +		compatible = "mediatek,mt2701-thermal";
> > +		reg = <0 0x1100b000 0 0x1000>;
> > +		interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_LOW>;
> > +		clocks = <&pericfg CLK_PERI_THERM>, <&pericfg CLK_PERI_AUXADC>;
> > +		clock-names = "therm", "auxadc";
> > +		resets = <&pericfg 0x10>;
> > +		reset-names = "therm";
> > +		mediatek,auxadc = <&auxadc>;
> > +		mediatek,apmixedsys = <&apmixedsys>;
> > +	};
> >   };
> >




From a0393675 at ti.com  Mon Jul 11 02:09:26 2016
From: a0393675 at ti.com (Keerthy)
Date: Mon, 11 Jul 2016 14:39:26 +0530
Subject: [PATCH 3/3] arm: dts: thermal: add thermal/auxadc node.
In-Reply-To: <1468227415.15776.34.camel@mtksdaap41>
References: <1467882386-40544-1-git-send-email-dawei.chien@mediatek.com>
 <1467882386-40544-4-git-send-email-dawei.chien@mediatek.com>
 <577E465D.8070004@ti.com> <1468227415.15776.34.camel@mtksdaap41>
Message-ID: <57836246.3010800@ti.com>



On Monday 11 July 2016 02:26 PM, dawei chien wrote:
> Dear Keerthy,
>
> On Thu, 2016-07-07 at 17:39 +0530, Keerthy wrote:
>>
>> On Thursday 07 July 2016 02:36 PM, Dawei Chien wrote:
>>> This adds the thermal controller and auxadc nodes
>>> to the Mediatek MT2701 dtsi file.
>>>
>>> Signed-off-by: Dawei Chien <dawei.chien at mediatek.com>
>>> ---
>>> This patch depned on:
>>> https://patchwork.kernel.org/patch/9213545/
>>> ---
>>>    arch/arm/boot/dts/mt2701.dtsi |   43 +++++++++++++++++++++++++++++++++++++++++
>>>    1 file changed, 43 insertions(+)
>>>
>>> diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
>>> index 2ac8b50..0834a23 100644
>>> --- a/arch/arm/boot/dts/mt2701.dtsi
>>> +++ b/arch/arm/boot/dts/mt2701.dtsi
>>> @@ -77,6 +77,36 @@
>>>    		#clock-cells = <0>;
>>>    	};
>>>
>>> +	thermal-zones {
>>> +		cpu_thermal: cpu_thermal {
>>> +			polling-delay-passive = <1000>; /* milliseconds */
>>> +			polling-delay = <1000>; /* milliseconds */
>>> +
>>> +			thermal-sensors = <&thermal 0>;
>>> +			sustainable-power = <1000>;
>>> +
>>> +			trips {
>>> +				threshold: trip-point at 0 {
>>> +					temperature = <68000>;
>>> +					hysteresis = <2000>;
>>> +					type = "passive";
>>> +				};
>>> +
>>> +				target: trip-point at 1 {
>>> +					temperature = <85000>;
>>> +					hysteresis = <2000>;
>>> +					type = "passive";
>>> +				};
>>> +
>>> +				cpu_crit: cpu_crit at 0 {
>>> +					temperature = <115000>;
>>> +					hysteresis = <2000>;
>>> +					type = "critical";
>>> +				};
>>> +			};
>>> +		};
>>> +	};
>>> +
>>
>> are there any corresponding cooling-maps?
>
> Since MT2701 does not register CPUFREQ cooling device and its' own
> device node, I could not add cooling-maps so far.
> Could we add cooling map after CPUFREQ ready, thank you.

Okay. I was curious to know about the cooling agents.

>
>>
>>>    	timer {
>>>    		compatible = "arm,armv7-timer";
>>>    		interrupt-parent = <&gic>;
>>> @@ -183,4 +213,17 @@
>>>    		clocks = <&uart_clk>;
>>>    		status = "disabled";
>>>    	};
>>> +
>>> +	thermal: thermal at 1100b000 {
>>> +		#thermal-sensor-cells = <0>;
>>> +		compatible = "mediatek,mt2701-thermal";
>>> +		reg = <0 0x1100b000 0 0x1000>;
>>> +		interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_LOW>;
>>> +		clocks = <&pericfg CLK_PERI_THERM>, <&pericfg CLK_PERI_AUXADC>;
>>> +		clock-names = "therm", "auxadc";
>>> +		resets = <&pericfg 0x10>;
>>> +		reset-names = "therm";
>>> +		mediatek,auxadc = <&auxadc>;
>>> +		mediatek,apmixedsys = <&apmixedsys>;
>>> +	};
>>>    };
>>>
>
>


From john at phrozen.org  Mon Jul 11 05:29:38 2016
From: john at phrozen.org (John Crispin)
Date: Mon, 11 Jul 2016 14:29:38 +0200
Subject: [PATCH V8 1/2] regulator: Add document for MT6323 regulator
Message-ID: <1468240179-7558-1-git-send-email-john@phrozen.org>

Signed-off-by: John Crispin <john at phrozen.org>
Cc: devicetree at vger.kernel.org
Acked-by: Rob Herring <robh at kernel.org>
---
This is a resend as V7 was dropped due to a merge order conflict.

Changes in V7
* remove another compatible string
* small wording changes

Changes in V6
* remove the compatible string

Changes in V5
* regulator vs regulators

Changes in V4
* regulator is a subnode and not a property

 .../bindings/regulator/mt6323-regulator.txt        |  239 ++++++++++++++++++++
 1 file changed, 239 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/regulator/mt6323-regulator.txt

diff --git a/Documentation/devicetree/bindings/regulator/mt6323-regulator.txt b/Documentation/devicetree/bindings/regulator/mt6323-regulator.txt
new file mode 100644
index 0000000..9fd95e7
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/mt6323-regulator.txt
@@ -0,0 +1,239 @@
+Mediatek MT6323 Regulator Driver
+
+All voltage regulators are defined as subnodes of the regulators node. A list
+of regulators provided by this controller are defined as subnodes of the
+PMIC's node. Each regulator is named according to its regulator type,
+buck_<name> and ldo_<name>. The definition for each of these nodes is defined
+using the standard binding for regulators at
+Documentation/devicetree/bindings/regulator/regulator.txt.
+
+The valid names for regulators are::
+BUCK:
+  buck_vproc, buck_vsys, buck_vpa
+LDO:
+  ldo_vtcxo, ldo_vcn28, ldo_vcn33_bt, ldo_vcn33_wifi, ldo_va, ldo_vcama,
+  ldo_vio28, ldo_vusb, ldo_vmc, ldo_vmch, ldo_vemc3v3, ldo_vgp1, ldo_vgp2,
+  ldo_vgp3, ldo_vcn18, ldo_vsim1, ldo_vsim2, ldo_vrtc, ldo_vcamaf, ldo_vibr,
+  ldo_vrf18, ldo_vm, ldo_vio18, ldo_vcamd, ldo_vcamio
+
+Example:
+
+	pmic: mt6323 {
+		compatible = "mediatek,mt6323";
+
+		mt6323regulator: regulators {
+			mt6323_vproc_reg: buck_vproc{
+				regulator-name = "vproc";
+				regulator-min-microvolt = < 700000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-ramp-delay = <12500>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vsys_reg: buck_vsys{
+				regulator-name = "vsys";
+				regulator-min-microvolt = <1400000>;
+				regulator-max-microvolt = <2987500>;
+				regulator-ramp-delay = <25000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vpa_reg: buck_vpa{
+				regulator-name = "vpa";
+				regulator-min-microvolt = < 500000>;
+				regulator-max-microvolt = <3650000>;
+			};
+
+			mt6323_vtcxo_reg: ldo_vtcxo{
+				regulator-name = "vtcxo";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <90>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vcn28_reg: ldo_vcn28{
+				regulator-name = "vcn28";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <185>;
+			};
+
+			mt6323_vcn33_bt_reg: ldo_vcn33_bt{
+				regulator-name = "vcn33_bt";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3600000>;
+				regulator-enable-ramp-delay = <185>;
+			};
+
+			mt6323_vcn33_wifi_reg: ldo_vcn33_wifi{
+				regulator-name = "vcn33_wifi";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3600000>;
+				regulator-enable-ramp-delay = <185>;
+			};
+
+			mt6323_va_reg: ldo_va{
+				regulator-name = "va";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vcama_reg: ldo_vcama{
+				regulator-name = "vcama";
+				regulator-min-microvolt = <1500000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vio28_reg: ldo_vio28{
+				regulator-name = "vio28";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vusb_reg: ldo_vusb{
+				regulator-name = "vusb";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-boot-on;
+			};
+
+			mt6323_vmc_reg: ldo_vmc{
+				regulator-name = "vmc";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <36>;
+				regulator-boot-on;
+			};
+
+			mt6323_vmch_reg: ldo_vmch{
+				regulator-name = "vmch";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <36>;
+				regulator-boot-on;
+			};
+
+			mt6323_vemc3v3_reg: ldo_vemc3v3{
+				regulator-name = "vemc3v3";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <36>;
+				regulator-boot-on;
+			};
+
+			mt6323_vgp1_reg: ldo_vgp1{
+				regulator-name = "vgp1";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vgp2_reg: ldo_vgp2{
+				regulator-name = "vgp2";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vgp3_reg: ldo_vgp3{
+				regulator-name = "vgp3";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vcn18_reg: ldo_vcn18{
+				regulator-name = "vcn18";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vsim1_reg: ldo_vsim1{
+				regulator-name = "vsim1";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vsim2_reg: ldo_vsim2{
+				regulator-name = "vsim2";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vrtc_reg: ldo_vrtc{
+				regulator-name = "vrtc";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vcamaf_reg: ldo_vcamaf{
+				regulator-name = "vcamaf";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vibr_reg: ldo_vibr{
+				regulator-name = "vibr";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <36>;
+			};
+
+			mt6323_vrf18_reg: ldo_vrf18{
+				regulator-name = "vrf18";
+				regulator-min-microvolt = <1825000>;
+				regulator-max-microvolt = <1825000>;
+				regulator-enable-ramp-delay = <187>;
+			};
+
+			mt6323_vm_reg: ldo_vm{
+				regulator-name = "vm";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vio18_reg: ldo_vio18{
+				regulator-name = "vio18";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vcamd_reg: ldo_vcamd{
+				regulator-name = "vcamd";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vcamio_reg: ldo_vcamio{
+				regulator-name = "vcamio";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+		};
+	};
-- 
1.7.10.4



From john at phrozen.org  Mon Jul 11 05:29:39 2016
From: john at phrozen.org (John Crispin)
Date: Mon, 11 Jul 2016 14:29:39 +0200
Subject: [PATCH V8 2/2] regulator: mt6323: Add support for MT6323 regulator
In-Reply-To: <1468240179-7558-1-git-send-email-john@phrozen.org>
References: <1468240179-7558-1-git-send-email-john@phrozen.org>
Message-ID: <1468240179-7558-2-git-send-email-john@phrozen.org>

From: Chen Zhong <chen.zhong at mediatek.com>

The MT6323 is a regulator found on boards based on MediaTek MT7623 and
probably other SoCs. It is a so called pmic and connects as a slave to
SoC using SPI, wrapped inside the pmic-wrapper.

Signed-off-by: Chen Zhong <chen.zhong at mediatek.com>
Signed-off-by: John Crispin <john at phrozen.org>
---
This is a resend as V7 was dropped due to a merge order conflict.

Changes in V6
* add back the set/get mode callbacks

Changes in V5
* remove the code that modifies constraints
* remove the code allows mode changes

Changes in V4:
* add id_table and of_match_table
* use short GPL text
* change MODULE_LICENSE to GPL V2

Changes in V3:
* none

Changes in V2:
* send to the the proper maintainer

 drivers/regulator/Kconfig                  |    9 +
 drivers/regulator/Makefile                 |    1 +
 drivers/regulator/mt6323-regulator.c       |  432 ++++++++++++++++++++++++++++
 include/linux/regulator/mt6323-regulator.h |   52 ++++
 4 files changed, 494 insertions(+)
 create mode 100644 drivers/regulator/mt6323-regulator.c
 create mode 100644 include/linux/regulator/mt6323-regulator.h

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index ae9cbd6..6c88e31 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -498,6 +498,15 @@ config REGULATOR_MT6311
 	  This driver supports the control of different power rails of device
 	  through regulator interface.
 
+config REGULATOR_MT6323
+	tristate "MediaTek MT6323 PMIC"
+	depends on MFD_MT6397
+	help
+	  Say y here to select this option to enable the power regulator of
+	  MediaTek MT6323 PMIC.
+	  This driver supports the control of different power rails of device
+	  through regulator interface.
+
 config REGULATOR_MT6397
 	tristate "MediaTek MT6397 PMIC"
 	depends on MFD_MT6397
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 85a1d44..f3da9ee 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -65,6 +65,7 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
 obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
 obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
 obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
+obj-$(CONFIG_REGULATOR_MT6323)	+= mt6323-regulator.o
 obj-$(CONFIG_REGULATOR_MT6397)	+= mt6397-regulator.o
 obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
 obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
diff --git a/drivers/regulator/mt6323-regulator.c b/drivers/regulator/mt6323-regulator.c
new file mode 100644
index 0000000..28ebbda
--- /dev/null
+++ b/drivers/regulator/mt6323-regulator.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Chen Zhong <chen.zhong at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/mt6397/core.h>
+#include <linux/mfd/mt6323/registers.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/mt6323-regulator.h>
+#include <linux/regulator/of_regulator.h>
+
+#define MT6323_LDO_MODE_NORMAL	0
+#define MT6323_LDO_MODE_LP	1
+
+/*
+ * MT6323 regulators' information
+ *
+ * @desc: standard fields of regulator description.
+ * @qi: Mask for query enable signal status of regulators
+ * @vselon_reg: Register sections for hardware control mode of bucks
+ * @vselctrl_reg: Register for controlling the buck control mode.
+ * @vselctrl_mask: Mask for query buck's voltage control mode.
+ */
+struct mt6323_regulator_info {
+	struct regulator_desc desc;
+	u32 qi;
+	u32 vselon_reg;
+	u32 vselctrl_reg;
+	u32 vselctrl_mask;
+	u32 modeset_reg;
+	u32 modeset_mask;
+};
+
+#define MT6323_BUCK(match, vreg, min, max, step, volt_ranges, enreg,	\
+		vosel, vosel_mask, voselon, vosel_ctrl)			\
+[MT6323_ID_##vreg] = {							\
+	.desc = {							\
+		.name = #vreg,						\
+		.of_match = of_match_ptr(match),			\
+		.ops = &mt6323_volt_range_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6323_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = (max - min)/step + 1,			\
+		.linear_ranges = volt_ranges,				\
+		.n_linear_ranges = ARRAY_SIZE(volt_ranges),		\
+		.vsel_reg = vosel,					\
+		.vsel_mask = vosel_mask,				\
+		.enable_reg = enreg,					\
+		.enable_mask = BIT(0),					\
+	},								\
+	.qi = BIT(13),							\
+	.vselon_reg = voselon,						\
+	.vselctrl_reg = vosel_ctrl,					\
+	.vselctrl_mask = BIT(1),					\
+}
+
+#define MT6323_LDO(match, vreg, ldo_volt_table, enreg, enbit, vosel,	\
+		vosel_mask, _modeset_reg, _modeset_mask)		\
+[MT6323_ID_##vreg] = {							\
+	.desc = {							\
+		.name = #vreg,						\
+		.of_match = of_match_ptr(match),			\
+		.ops = &mt6323_volt_table_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6323_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = ARRAY_SIZE(ldo_volt_table),		\
+		.volt_table = ldo_volt_table,				\
+		.vsel_reg = vosel,					\
+		.vsel_mask = vosel_mask,				\
+		.enable_reg = enreg,					\
+		.enable_mask = BIT(enbit),				\
+	},								\
+	.qi = BIT(15),							\
+	.modeset_reg = _modeset_reg,					\
+	.modeset_mask = _modeset_mask,					\
+}
+
+#define MT6323_REG_FIXED(match, vreg, enreg, enbit, volt,		\
+		_modeset_reg, _modeset_mask)				\
+[MT6323_ID_##vreg] = {							\
+	.desc = {							\
+		.name = #vreg,						\
+		.of_match = of_match_ptr(match),			\
+		.ops = &mt6323_volt_fixed_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6323_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = 1,					\
+		.enable_reg = enreg,					\
+		.enable_mask = BIT(enbit),				\
+		.min_uV = volt,						\
+	},								\
+	.qi = BIT(15),							\
+	.modeset_reg = _modeset_reg,					\
+	.modeset_mask = _modeset_mask,					\
+}
+
+static const struct regulator_linear_range buck_volt_range1[] = {
+	REGULATOR_LINEAR_RANGE(700000, 0, 0x7f, 6250),
+};
+
+static const struct regulator_linear_range buck_volt_range2[] = {
+	REGULATOR_LINEAR_RANGE(1400000, 0, 0x7f, 12500),
+};
+
+static const struct regulator_linear_range buck_volt_range3[] = {
+	REGULATOR_LINEAR_RANGE(500000, 0, 0x3f, 50000),
+};
+
+static const u32 ldo_volt_table1[] = {
+	3300000, 3400000, 3500000, 3600000,
+};
+
+static const u32 ldo_volt_table2[] = {
+	1500000, 1800000, 2500000, 2800000,
+};
+
+static const u32 ldo_volt_table3[] = {
+	1800000, 3300000,
+};
+
+static const u32 ldo_volt_table4[] = {
+	3000000, 3300000,
+};
+
+static const u32 ldo_volt_table5[] = {
+	1200000, 1300000, 1500000, 1800000, 2000000, 2800000, 3000000, 3300000,
+};
+
+static const u32 ldo_volt_table6[] = {
+	1200000, 1300000, 1500000, 1800000, 2500000, 2800000, 3000000, 2000000,
+};
+
+static const u32 ldo_volt_table7[] = {
+	1200000, 1300000, 1500000, 1800000,
+};
+
+static const u32 ldo_volt_table8[] = {
+	1800000, 3000000,
+};
+
+static const u32 ldo_volt_table9[] = {
+	1200000, 1350000, 1500000, 1800000,
+};
+
+static const u32 ldo_volt_table10[] = {
+	1200000, 1300000, 1500000, 1800000,
+};
+
+static int mt6323_get_status(struct regulator_dev *rdev)
+{
+	int ret;
+	u32 regval;
+	struct mt6323_regulator_info *info = rdev_get_drvdata(rdev);
+
+	ret = regmap_read(rdev->regmap, info->desc.enable_reg, &regval);
+	if (ret != 0) {
+		dev_err(&rdev->dev, "Failed to get enable reg: %d\n", ret);
+		return ret;
+	}
+
+	return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF;
+}
+
+static int mt6323_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	int ret, val = 0;
+	struct mt6323_regulator_info *info = rdev_get_drvdata(rdev);
+
+	if (!info->modeset_mask) {
+		dev_err(&rdev->dev, "regulator %s doesn't support set_mode\n",
+			info->desc.name);
+		return -EINVAL;
+	}
+
+	switch (mode) {
+	case REGULATOR_MODE_STANDBY:
+		val = MT6323_LDO_MODE_LP;
+		break;
+	case REGULATOR_MODE_NORMAL:
+		val = MT6323_LDO_MODE_NORMAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	val <<= ffs(info->modeset_mask) - 1;
+
+	ret = regmap_update_bits(rdev->regmap, info->modeset_reg,
+				  info->modeset_mask, val);
+
+	return ret;
+}
+
+static unsigned int mt6323_ldo_get_mode(struct regulator_dev *rdev)
+{
+	unsigned int val;
+	unsigned int mode;
+	int ret;
+	struct mt6323_regulator_info *info = rdev_get_drvdata(rdev);
+
+	if (!info->modeset_mask) {
+		dev_err(&rdev->dev, "regulator %s doesn't support get_mode\n",
+			info->desc.name);
+		return -EINVAL;
+	}
+
+	ret = regmap_read(rdev->regmap, info->modeset_reg, &val);
+	if (ret < 0)
+		return ret;
+
+	val &= info->modeset_mask;
+	val >>= ffs(info->modeset_mask) - 1;
+
+	if (val & 0x1)
+		mode = REGULATOR_MODE_STANDBY;
+	else
+		mode = REGULATOR_MODE_NORMAL;
+
+	return mode;
+}
+
+static struct regulator_ops mt6323_volt_range_ops = {
+	.list_voltage = regulator_list_voltage_linear_range,
+	.map_voltage = regulator_map_voltage_linear_range,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_status = mt6323_get_status,
+};
+
+static struct regulator_ops mt6323_volt_table_ops = {
+	.list_voltage = regulator_list_voltage_table,
+	.map_voltage = regulator_map_voltage_iterate,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_status = mt6323_get_status,
+	.set_mode = mt6323_ldo_set_mode,
+	.get_mode = mt6323_ldo_get_mode,
+};
+
+static struct regulator_ops mt6323_volt_fixed_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_status = mt6323_get_status,
+	.set_mode = mt6323_ldo_set_mode,
+	.get_mode = mt6323_ldo_get_mode,
+};
+
+/* The array is indexed by id(MT6323_ID_XXX) */
+static struct mt6323_regulator_info mt6323_regulators[] = {
+	MT6323_BUCK("buck_vproc", VPROC, 700000, 1493750, 6250,
+		buck_volt_range1, MT6323_VPROC_CON7, MT6323_VPROC_CON9, 0x7f,
+		MT6323_VPROC_CON10, MT6323_VPROC_CON5),
+	MT6323_BUCK("buck_vsys", VSYS, 1400000, 2987500, 12500,
+		buck_volt_range2, MT6323_VSYS_CON7, MT6323_VSYS_CON9, 0x7f,
+		MT6323_VSYS_CON10, MT6323_VSYS_CON5),
+	MT6323_BUCK("buck_vpa", VPA, 500000, 3650000, 50000,
+		buck_volt_range3, MT6323_VPA_CON7, MT6323_VPA_CON9,
+		0x3f, MT6323_VPA_CON10, MT6323_VPA_CON5),
+	MT6323_REG_FIXED("ldo_vtcxo", VTCXO, MT6323_ANALDO_CON1, 10, 2800000,
+		MT6323_ANALDO_CON1, 0x2),
+	MT6323_REG_FIXED("ldo_vcn28", VCN28, MT6323_ANALDO_CON19, 12, 2800000,
+		MT6323_ANALDO_CON20, 0x2),
+	MT6323_LDO("ldo_vcn33_bt", VCN33_BT, ldo_volt_table1,
+		MT6323_ANALDO_CON16, 7, MT6323_ANALDO_CON16, 0xC,
+		MT6323_ANALDO_CON21, 0x2),
+	MT6323_LDO("ldo_vcn33_wifi", VCN33_WIFI, ldo_volt_table1,
+		MT6323_ANALDO_CON17, 12, MT6323_ANALDO_CON16, 0xC,
+		MT6323_ANALDO_CON21, 0x2),
+	MT6323_REG_FIXED("ldo_va", VA, MT6323_ANALDO_CON2, 14, 2800000,
+		MT6323_ANALDO_CON2, 0x2),
+	MT6323_LDO("ldo_vcama", VCAMA, ldo_volt_table2,
+		MT6323_ANALDO_CON4, 15, MT6323_ANALDO_CON10, 0x60, -1, 0),
+	MT6323_REG_FIXED("ldo_vio28", VIO28, MT6323_DIGLDO_CON0, 14, 2800000,
+		MT6323_DIGLDO_CON0, 0x2),
+	MT6323_REG_FIXED("ldo_vusb", VUSB, MT6323_DIGLDO_CON2, 14, 3300000,
+		MT6323_DIGLDO_CON2, 0x2),
+	MT6323_LDO("ldo_vmc", VMC, ldo_volt_table3,
+		MT6323_DIGLDO_CON3, 12, MT6323_DIGLDO_CON24, 0x10,
+		MT6323_DIGLDO_CON3, 0x2),
+	MT6323_LDO("ldo_vmch", VMCH, ldo_volt_table4,
+		MT6323_DIGLDO_CON5, 14, MT6323_DIGLDO_CON26, 0x80,
+		MT6323_DIGLDO_CON5, 0x2),
+	MT6323_LDO("ldo_vemc3v3", VEMC3V3, ldo_volt_table4,
+		MT6323_DIGLDO_CON6, 14, MT6323_DIGLDO_CON27, 0x80,
+		MT6323_DIGLDO_CON6, 0x2),
+	MT6323_LDO("ldo_vgp1", VGP1, ldo_volt_table5,
+		MT6323_DIGLDO_CON7, 15, MT6323_DIGLDO_CON28, 0xE0,
+		MT6323_DIGLDO_CON7, 0x2),
+	MT6323_LDO("ldo_vgp2", VGP2, ldo_volt_table6,
+		MT6323_DIGLDO_CON8, 15, MT6323_DIGLDO_CON29, 0xE0,
+		MT6323_DIGLDO_CON8, 0x2),
+	MT6323_LDO("ldo_vgp3", VGP3, ldo_volt_table7,
+		MT6323_DIGLDO_CON9, 15, MT6323_DIGLDO_CON30, 0x60,
+		MT6323_DIGLDO_CON9, 0x2),
+	MT6323_REG_FIXED("ldo_vcn18", VCN18, MT6323_DIGLDO_CON11, 14, 1800000,
+		MT6323_DIGLDO_CON11, 0x2),
+	MT6323_LDO("ldo_vsim1", VSIM1, ldo_volt_table8,
+		MT6323_DIGLDO_CON13, 15, MT6323_DIGLDO_CON34, 0x20,
+		MT6323_DIGLDO_CON13, 0x2),
+	MT6323_LDO("ldo_vsim2", VSIM2, ldo_volt_table8,
+		MT6323_DIGLDO_CON14, 15, MT6323_DIGLDO_CON35, 0x20,
+		MT6323_DIGLDO_CON14, 0x2),
+	MT6323_REG_FIXED("ldo_vrtc", VRTC, MT6323_DIGLDO_CON15, 8, 2800000,
+		-1, 0),
+	MT6323_LDO("ldo_vcamaf", VCAMAF, ldo_volt_table5,
+		MT6323_DIGLDO_CON31, 15, MT6323_DIGLDO_CON32, 0xE0,
+		MT6323_DIGLDO_CON31, 0x2),
+	MT6323_LDO("ldo_vibr", VIBR, ldo_volt_table5,
+		MT6323_DIGLDO_CON39, 15, MT6323_DIGLDO_CON40, 0xE0,
+		MT6323_DIGLDO_CON39, 0x2),
+	MT6323_REG_FIXED("ldo_vrf18", VRF18, MT6323_DIGLDO_CON45, 15, 1825000,
+		MT6323_DIGLDO_CON45, 0x2),
+	MT6323_LDO("ldo_vm", VM, ldo_volt_table9,
+		MT6323_DIGLDO_CON47, 14, MT6323_DIGLDO_CON48, 0x30,
+		MT6323_DIGLDO_CON47, 0x2),
+	MT6323_REG_FIXED("ldo_vio18", VIO18, MT6323_DIGLDO_CON49, 14, 1800000,
+		MT6323_DIGLDO_CON49, 0x2),
+	MT6323_LDO("ldo_vcamd", VCAMD, ldo_volt_table10,
+		MT6323_DIGLDO_CON51, 14, MT6323_DIGLDO_CON52, 0x60,
+		MT6323_DIGLDO_CON51, 0x2),
+	MT6323_REG_FIXED("ldo_vcamio", VCAMIO, MT6323_DIGLDO_CON53, 14, 1800000,
+		MT6323_DIGLDO_CON53, 0x2),
+};
+
+static int mt6323_set_buck_vosel_reg(struct platform_device *pdev)
+{
+	struct mt6397_chip *mt6323 = dev_get_drvdata(pdev->dev.parent);
+	int i;
+	u32 regval;
+
+	for (i = 0; i < MT6323_MAX_REGULATOR; i++) {
+		if (mt6323_regulators[i].vselctrl_reg) {
+			if (regmap_read(mt6323->regmap,
+				mt6323_regulators[i].vselctrl_reg,
+				&regval) < 0) {
+				dev_err(&pdev->dev,
+					"Failed to read buck ctrl\n");
+				return -EIO;
+			}
+
+			if (regval & mt6323_regulators[i].vselctrl_mask) {
+				mt6323_regulators[i].desc.vsel_reg =
+				mt6323_regulators[i].vselon_reg;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int mt6323_regulator_probe(struct platform_device *pdev)
+{
+	struct mt6397_chip *mt6323 = dev_get_drvdata(pdev->dev.parent);
+	struct regulator_config config = {};
+	struct regulator_dev *rdev;
+	int i;
+	u32 reg_value;
+
+	/* Query buck controller to select activated voltage register part */
+	if (mt6323_set_buck_vosel_reg(pdev))
+		return -EIO;
+
+	/* Read PMIC chip revision to update constraints and voltage table */
+	if (regmap_read(mt6323->regmap, MT6323_CID, &reg_value) < 0) {
+		dev_err(&pdev->dev, "Failed to read Chip ID\n");
+		return -EIO;
+	}
+	dev_info(&pdev->dev, "Chip ID = 0x%x\n", reg_value);
+
+	for (i = 0; i < MT6323_MAX_REGULATOR; i++) {
+		config.dev = &pdev->dev;
+		config.driver_data = &mt6323_regulators[i];
+		config.regmap = mt6323->regmap;
+		rdev = devm_regulator_register(&pdev->dev,
+				&mt6323_regulators[i].desc, &config);
+		if (IS_ERR(rdev)) {
+			dev_err(&pdev->dev, "failed to register %s\n",
+				mt6323_regulators[i].desc.name);
+			return PTR_ERR(rdev);
+		}
+	}
+	return 0;
+}
+
+static const struct platform_device_id mt6323_platform_ids[] = {
+	{"mt6323-regulator", 0},
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, mt6323_platform_ids);
+
+static const struct of_device_id mt6323_of_match[] = {
+	{ .compatible = "mediatek,mt6323-regulator", },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mt6323_of_match);
+
+static struct platform_driver mt6323_regulator_driver = {
+	.driver = {
+		.name = "mt6323-regulator",
+		.of_match_table = of_match_ptr(mt6323_of_match),
+	},
+	.probe = mt6323_regulator_probe,
+	.id_table = mt6323_platform_ids,
+};
+
+module_platform_driver(mt6323_regulator_driver);
+
+MODULE_AUTHOR("Chen Zhong <chen.zhong at mediatek.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6397 PMIC");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/regulator/mt6323-regulator.h b/include/linux/regulator/mt6323-regulator.h
new file mode 100644
index 0000000..67011cd
--- /dev/null
+++ b/include/linux/regulator/mt6323-regulator.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Chen Zhong <chen.zhong at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __LINUX_REGULATOR_MT6323_H
+#define __LINUX_REGULATOR_MT6323_H
+
+enum {
+	MT6323_ID_VPROC = 0,
+	MT6323_ID_VSYS,
+	MT6323_ID_VPA,
+	MT6323_ID_VTCXO,
+	MT6323_ID_VCN28,
+	MT6323_ID_VCN33_BT,
+	MT6323_ID_VCN33_WIFI,
+	MT6323_ID_VA,
+	MT6323_ID_VCAMA,
+	MT6323_ID_VIO28 = 9,
+	MT6323_ID_VUSB,
+	MT6323_ID_VMC,
+	MT6323_ID_VMCH,
+	MT6323_ID_VEMC3V3,
+	MT6323_ID_VGP1,
+	MT6323_ID_VGP2,
+	MT6323_ID_VGP3,
+	MT6323_ID_VCN18,
+	MT6323_ID_VSIM1,
+	MT6323_ID_VSIM2,
+	MT6323_ID_VRTC,
+	MT6323_ID_VCAMAF,
+	MT6323_ID_VIBR,
+	MT6323_ID_VRF18,
+	MT6323_ID_VM,
+	MT6323_ID_VIO18,
+	MT6323_ID_VCAMD,
+	MT6323_ID_VCAMIO,
+	MT6323_ID_RG_MAX,
+};
+
+#define MT6323_MAX_REGULATOR	MT6323_ID_RG_MAX
+
+#endif /* __LINUX_REGULATOR_MT6323_H */
-- 
1.7.10.4



From matthias.bgg at gmail.com  Mon Jul 11 06:10:59 2016
From: matthias.bgg at gmail.com (Matthias Brugger)
Date: Mon, 11 Jul 2016 15:10:59 +0200
Subject: [PATCH v7 1/4] soc: mediatek: Refine scpsys to support multiple
 platform
In-Reply-To: <1468227390.31247.20.camel@mtksdaap41>
References: <1463390894-32062-1-git-send-email-jamesjj.liao@mediatek.com>
 <1463390894-32062-2-git-send-email-jamesjj.liao@mediatek.com>
 <6762e420-0d68-0376-b584-bfc878b5e95f@gmail.com>
 <1467783564.26485.22.camel@mtksdaap41> <577E3AE9.5080202@gmail.com>
 <1468227390.31247.20.camel@mtksdaap41>
Message-ID: <57839AE3.2070103@gmail.com>



On 11/07/16 10:56, James Liao wrote:

[...]

>>>>> @@ -467,28 +386,54 @@ static int scpsys_probe(struct platform_device *pdev)
>>>>>    			if (PTR_ERR(scpd->supply) == -ENODEV)
>>>>>    				scpd->supply = NULL;
>>>>>    			else
>>>>> -				return PTR_ERR(scpd->supply);
>>>>> +				return ERR_CAST(scpd->supply);
>>>>>    		}
>>>>>    	}
>>>>>
>>>>> -	pd_data->num_domains = NUM_DOMAINS;
>>>>> +	pd_data->num_domains = num;
>>>>>
>>>>> -	for (i = 0; i < NUM_DOMAINS; i++) {
>>>>> +	init_clks(pdev, clk);
>>>>> +
>>>>> +	for (i = 0; i < num; i++) {
>>>>>    		struct scp_domain *scpd = &scp->domains[i];
>>>>>    		struct generic_pm_domain *genpd = &scpd->genpd;
>>>>>    		const struct scp_domain_data *data = &scp_domain_data[i];
>>>>>
>>>>> +		for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
>>>>> +			struct clk *c = clk[data->clk_id[j]];
>>>>> +
>>>>> +			if (IS_ERR(c)) {
>>>>> +				dev_err(&pdev->dev, "%s: clk unavailable\n",
>>>>> +					data->name);
>>>>> +				return ERR_CAST(c);
>>>>> +			}
>>>>> +
>>>>> +			scpd->clk[j] = c;
>>>>
>>>> Put this in the else branch. Apart from that is there any reason you
>>>
>>> Do you mean to change like this?
>>>
>>> 	if (IS_ERR(c)) {
>>> 		...
>>> 		return ERR_CAST(c);
>>> 	} else {
>>> 		scpd->clk[j] = c;
>>> 	}
>>>
>>> checkpatch.pl will warn for above code due to it returns in 'if' branch.
>>>
>>
>> I tried that on top of next-20160706 and it checkpatch didn't throw any
>> warning. Which kernel version are based on?
>
> I don't remember which version of checkpatch warn on this pattern. This
> patch series develop across several kernel versions.

We as the kernel community develop against master or linux-next. We only 
care about older kernel version in the sense that we intent hard not to 
break any userspace/kernel or firmware/kernel interfaces. Apart from 
that it's up to every individual to backport patches from mainline 
kernel to his respective version. But that's nothing the community as a 
hole can take care of.

>
> So do you prefer to put "scpd->clk[j] = c;" into 'else' branch?
>

Yes please :)

>>>> moved the for up in the function? If not, I would prefer not to move it,
>>>> to make it easier to read the diff.
>>>
>>> The new 'for' block are far different from original one. And I think
>>> it's easy to read if we keep simple assign statements in the same block.
>>>
>>
>> It's different in the sense that it checks if struct clk *c is an error.
>> I don't see the reason why we need to move it up in the file.
>> It's not too important but I would prefer not to move it if there is no
>> reason.
>
> I think I may misunderstand your comments. Which 'for' block did you
> mention for? 'for (i = 0; i < num ...' or 'for (j = 0; j < MAX_CLKS
> && ...' ?
>
> The 'for(i)' exists in original code, this patch just change its counter
> from 'NUM_DOMAINS' to 'num'. The 'for(j)' is a new for-block, so it was
> not moved from other blocks.
>

for (j = 0; j < MAX_CLKS... is present in the actual scpsys_probe in 
linux-next (line 485 as of today). This patch moves this for a few lines 
up, to be precise before executing this code sequence:
<code>
pd_data->domains[i] = genpd;
scpd->scp = scp;

scpd->data = data;
</code>

AFAIK there is no reason to do so. It adds unnecessary complexity to the 
patch. So please fix this together with the other comments you got.

Thanks a lot,
Matthias


From broonie at kernel.org  Mon Jul 11 11:08:05 2016
From: broonie at kernel.org (Mark Brown)
Date: Mon, 11 Jul 2016 19:08:05 +0100
Subject: [PATCH V8 1/2] regulator: Add document for MT6323 regulator
In-Reply-To: <1468240179-7558-1-git-send-email-john@phrozen.org>
References: <1468240179-7558-1-git-send-email-john@phrozen.org>
Message-ID: <20160711180805.GG3701@sirena.org.uk>

On Mon, Jul 11, 2016 at 02:29:38PM +0200, John Crispin wrote:

> This is a resend as V7 was dropped due to a merge order conflict.

What were the dependencies and why will simply resending this resolve
them?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mediatek/attachments/20160711/702c5bb8/attachment-0001.sig>

From john at phrozen.org  Mon Jul 11 11:55:24 2016
From: john at phrozen.org (John Crispin)
Date: Mon, 11 Jul 2016 20:55:24 +0200
Subject: [PATCH V8 1/2] regulator: Add document for MT6323 regulator
In-Reply-To: <20160711180805.GG3701@sirena.org.uk>
References: <1468240179-7558-1-git-send-email-john@phrozen.org>
 <20160711180805.GG3701@sirena.org.uk>
Message-ID: <cef78bd8-9a4a-e848-d7cb-13a27127f11e@phrozen.org>



On 11/07/2016 20:08, Mark Brown wrote:
> On Mon, Jul 11, 2016 at 02:29:38PM +0200, John Crispin wrote:
> 
>> This is a resend as V7 was dropped due to a merge order conflict.
> 
> What were the dependencies and why will simply resending this resolve
> them?
> 

Hi Mark,

the dependency was the mt6323 support inside the mt6397 MFD device [1]
and the headers that it included. this has been merged so the regulator
driver is good to go for 4.8

	John

[1]
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/mfd/mt6397-core.c?id=refs/tags/v4.7-rc7

> 
> 
> _______________________________________________
> Linux-mediatek mailing list
> Linux-mediatek at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-mediatek
> 


From broonie at kernel.org  Mon Jul 11 12:22:11 2016
From: broonie at kernel.org (Mark Brown)
Date: Mon, 11 Jul 2016 20:22:11 +0100
Subject: [PATCH V8 1/2] regulator: Add document for MT6323 regulator
In-Reply-To: <cef78bd8-9a4a-e848-d7cb-13a27127f11e@phrozen.org>
References: <1468240179-7558-1-git-send-email-john@phrozen.org>
 <20160711180805.GG3701@sirena.org.uk>
 <cef78bd8-9a4a-e848-d7cb-13a27127f11e@phrozen.org>
Message-ID: <20160711192211.GI3701@sirena.org.uk>

On Mon, Jul 11, 2016 at 08:55:24PM +0200, John Crispin wrote:
> On 11/07/2016 20:08, Mark Brown wrote:
> > On Mon, Jul 11, 2016 at 02:29:38PM +0200, John Crispin wrote:

> >> This is a resend as V7 was dropped due to a merge order conflict.

> > What were the dependencies and why will simply resending this resolve
> > them?

> the dependency was the mt6323 support inside the mt6397 MFD device [1]
> and the headers that it included. this has been merged so the regulator
> driver is good to go for 4.8

No, that's not resolving the dependencies - if I apply these patches
without the dependencies in the regulator tree that will still break the
build for my tree until after the merge window.  It'll also break Linus'
tree if (as is normal) I send my pull requests early on.  I'd need to
merge the MFD commits into my tree which would need coordination with
Lee, he'd need to make a tag for me to pull in.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mediatek/attachments/20160711/dca08830/attachment.sig>

From john at phrozen.org  Mon Jul 11 13:31:45 2016
From: john at phrozen.org (John Crispin)
Date: Mon, 11 Jul 2016 22:31:45 +0200
Subject: [PATCH V8 1/2] regulator: Add document for MT6323 regulator
In-Reply-To: <20160711192211.GI3701@sirena.org.uk>
References: <1468240179-7558-1-git-send-email-john@phrozen.org>
 <20160711180805.GG3701@sirena.org.uk>
 <cef78bd8-9a4a-e848-d7cb-13a27127f11e@phrozen.org>
 <20160711192211.GI3701@sirena.org.uk>
Message-ID: <c1acbf13-93a0-4257-ee48-4885a87fede5@phrozen.org>



On 11/07/2016 21:22, Mark Brown wrote:
> On Mon, Jul 11, 2016 at 08:55:24PM +0200, John Crispin wrote:
>> On 11/07/2016 20:08, Mark Brown wrote:
>>> On Mon, Jul 11, 2016 at 02:29:38PM +0200, John Crispin wrote:
> 
>>>> This is a resend as V7 was dropped due to a merge order conflict.
> 
>>> What were the dependencies and why will simply resending this resolve
>>> them?
> 
>> the dependency was the mt6323 support inside the mt6397 MFD device [1]
>> and the headers that it included. this has been merged so the regulator
>> driver is good to go for 4.8
> 
> No, that's not resolving the dependencies - if I apply these patches
> without the dependencies in the regulator tree that will still break the
> build for my tree until after the merge window.  It'll also break Linus'
> tree if (as is normal) I send my pull requests early on.  I'd need to
> merge the MFD commits into my tree which would need coordination with
> Lee, he'd need to make a tag for me to pull in.
> 

hi,

maybe i am missing something here, but i can see the dependencies inside
the for-next branch of
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git. is
this not the tree i should base patches on for v4.8 ?

	John


From broonie at kernel.org  Mon Jul 11 14:07:54 2016
From: broonie at kernel.org (Mark Brown)
Date: Mon, 11 Jul 2016 22:07:54 +0100
Subject: [PATCH V8 1/2] regulator: Add document for MT6323 regulator
In-Reply-To: <c1acbf13-93a0-4257-ee48-4885a87fede5@phrozen.org>
References: <1468240179-7558-1-git-send-email-john@phrozen.org>
 <20160711180805.GG3701@sirena.org.uk>
 <cef78bd8-9a4a-e848-d7cb-13a27127f11e@phrozen.org>
 <20160711192211.GI3701@sirena.org.uk>
 <c1acbf13-93a0-4257-ee48-4885a87fede5@phrozen.org>
Message-ID: <20160711210754.GA9976@sirena.org.uk>

On Mon, Jul 11, 2016 at 10:31:45PM +0200, John Crispin wrote:

> maybe i am missing something here, but i can see the dependencies inside
> the for-next branch of
> git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git. is
> this not the tree i should base patches on for v4.8 ?

Oh, so these aren't things that Lee just applied but rather things that
have propagated through?  You didn't say what commits you were talking
about, you linked to a long gitweb URL that would have been difficult to
paste due to wrapping.  This sort of thing is why it's really helpful to
make your e-mails directly human readable, saying something like "these
depend on change X which is in Linus' tree now" would've made this
clear.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mediatek/attachments/20160711/84baa243/attachment.sig>

From broonie at kernel.org  Mon Jul 11 14:12:35 2016
From: broonie at kernel.org (Mark Brown)
Date: Mon, 11 Jul 2016 22:12:35 +0100
Subject: [PATCH V8 2/2] regulator: mt6323: Add support for MT6323 regulator
In-Reply-To: <1468240179-7558-2-git-send-email-john@phrozen.org>
References: <1468240179-7558-1-git-send-email-john@phrozen.org>
 <1468240179-7558-2-git-send-email-john@phrozen.org>
Message-ID: <20160711211235.GB9976@sirena.org.uk>

On Mon, Jul 11, 2016 at 02:29:39PM +0200, John Crispin wrote:

> +static const struct of_device_id mt6323_of_match[] = {
> +	{ .compatible = "mediatek,mt6323-regulator", },
> +	{ /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(of, mt6323_of_match);

This may have been answered last time but I don't remember - why is
there a compatible string for this device in the DT?  Surely we already
know that the regulators for the mt6323 are present by virtue of the
fact that we know that the core mt6323 is present in the system?
Indeed, looking at the now merged MFD code it appears that this is
in fact the case so we could just not have a compatible and perhaps this
was just an oversight.  This is good because it means we're not encoding
the specific way Linux instantiates devices into the DT.

Otherwise this does look good.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mediatek/attachments/20160711/d17f5c40/attachment.sig>

From arnd at arndb.de  Mon Jul 11 14:37:59 2016
From: arnd at arndb.de (Arnd Bergmann)
Date: Mon, 11 Jul 2016 23:37:59 +0200
Subject: [PATCH] [media] mtk-vcodec: fix type mismatches
Message-ID: <20160711213959.2481081-1-arnd@arndb.de>

The newly added mtk-vcodec driver produces a number of warnings in an ARM
allmodconfig build, mainly since it assumes that dma_addr_t is 32-bit wide:

mtk-vcodec/venc/venc_vp8_if.c: In function 'vp8_enc_alloc_work_buf':
mtk-vcodec/venc/venc_vp8_if.c:212:191: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
mtk-vcodec/venc/venc_h264_if.c: In function 'h264_enc_alloc_work_buf':
mtk-vcodec/venc/venc_h264_if.c:297:190: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
mtk-vcodec/mtk_vcodec_enc.c: In function 'mtk_venc_worker':
mtk-vcodec/mtk_vcodec_enc.c:1030:46: error: format '%lx' expects argument of type 'long unsigned int', but argument 7 has type 'size_t {aka unsigned int}' [-Werror=format=]
  mtk_v4l2_debug(2,
mtk-vcodec/mtk_vcodec_enc.c:1030:46: error: format '%lx' expects argument of type 'long unsigned int', but argument 10 has type 'size_t {aka unsigned int}' [-Werror=format=]
mtk-vcodec/venc_vpu_if.c: In function 'vpu_enc_ipi_handler':
mtk-vcodec/venc_vpu_if.c:40:30: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
  struct venc_vpu_inst *vpu = (struct venc_vpu_inst *)msg->venc_inst;

This rearranges the format strings and type casts to what they should have been
in order to avoid the warnings.

Signed-off-by: Arnd Bergmann <arnd at arndb.de>
---
 drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c    | 8 ++++----
 drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c | 4 ++--
 drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c  | 4 ++--
 drivers/media/platform/mtk-vcodec/venc_vpu_if.c       | 4 ++--
 4 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
index 6dcae0a0a1f2..0b25a8700877 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
@@ -1028,15 +1028,15 @@ static void mtk_venc_worker(struct work_struct *work)
 	bs_buf.size = (size_t)dst_buf->planes[0].length;
 
 	mtk_v4l2_debug(2,
-			"Framebuf VA=%p PA=%llx Size=0x%lx;VA=%p PA=0x%llx Size=0x%lx;VA=%p PA=0x%llx Size=%zu",
+			"Framebuf VA=%p PA=%pad Size=0x%zx;VA=%p PA=%pad Size=0x%zx;VA=%p PA=%pad Size=0x%zx",
 			frm_buf.fb_addr[0].va,
-			(u64)frm_buf.fb_addr[0].dma_addr,
+			&frm_buf.fb_addr[0].dma_addr,
 			frm_buf.fb_addr[0].size,
 			frm_buf.fb_addr[1].va,
-			(u64)frm_buf.fb_addr[1].dma_addr,
+			&frm_buf.fb_addr[1].dma_addr,
 			frm_buf.fb_addr[1].size,
 			frm_buf.fb_addr[2].va,
-			(u64)frm_buf.fb_addr[2].dma_addr,
+			&frm_buf.fb_addr[2].dma_addr,
 			frm_buf.fb_addr[2].size);
 
 	ret = venc_if_encode(ctx, VENC_START_OPT_ENCODE_FRAME,
diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
index f4e18bb44cb9..9a600525b3c1 100644
--- a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
+++ b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
@@ -295,9 +295,9 @@ static int h264_enc_alloc_work_buf(struct venc_h264_inst *inst)
 		wb[i].iova = inst->work_bufs[i].dma_addr;
 
 		mtk_vcodec_debug(inst,
-				 "work_buf[%d] va=0x%p iova=0x%p size=%zu",
+				 "work_buf[%d] va=0x%p iova=%pad size=%zu",
 				 i, inst->work_bufs[i].va,
-				 (void *)inst->work_bufs[i].dma_addr,
+				 &inst->work_bufs[i].dma_addr,
 				 inst->work_bufs[i].size);
 	}
 
diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
index 431ae706a427..5b35aa1900d7 100644
--- a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
+++ b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
@@ -210,9 +210,9 @@ static int vp8_enc_alloc_work_buf(struct venc_vp8_inst *inst)
 		wb[i].iova = inst->work_bufs[i].dma_addr;
 
 		mtk_vcodec_debug(inst,
-				 "work_bufs[%d] va=0x%p,iova=0x%p,size=%zu",
+				 "work_bufs[%d] va=0x%p,iova=%pad,size=%zu",
 				 i, inst->work_bufs[i].va,
-				 (void *)inst->work_bufs[i].dma_addr,
+				 &inst->work_bufs[i].dma_addr,
 				 inst->work_bufs[i].size);
 	}
 
diff --git a/drivers/media/platform/mtk-vcodec/venc_vpu_if.c b/drivers/media/platform/mtk-vcodec/venc_vpu_if.c
index b92c6d2a892d..8907b02729fa 100644
--- a/drivers/media/platform/mtk-vcodec/venc_vpu_if.c
+++ b/drivers/media/platform/mtk-vcodec/venc_vpu_if.c
@@ -37,7 +37,7 @@ static void handle_enc_encode_msg(struct venc_vpu_inst *vpu, void *data)
 static void vpu_enc_ipi_handler(void *data, unsigned int len, void *priv)
 {
 	struct venc_vpu_ipi_msg_common *msg = data;
-	struct venc_vpu_inst *vpu = (struct venc_vpu_inst *)msg->venc_inst;
+	struct venc_vpu_inst *vpu = (struct venc_vpu_inst *)(uintptr_t)msg->venc_inst;
 
 	mtk_vcodec_debug(vpu, "msg_id %x inst %p status %d",
 			 msg->msg_id, vpu, msg->status);
@@ -112,7 +112,7 @@ int vpu_enc_init(struct venc_vpu_inst *vpu)
 
 	memset(&out, 0, sizeof(out));
 	out.msg_id = AP_IPIMSG_ENC_INIT;
-	out.venc_inst = (unsigned long)vpu;
+	out.venc_inst = (uintptr_t)vpu;
 	if (vpu_enc_send_msg(vpu, &out, sizeof(out))) {
 		mtk_vcodec_err(vpu, "AP_IPIMSG_ENC_INIT fail");
 		return -EINVAL;
-- 
2.9.0



From yingjoe.chen at mediatek.com  Mon Jul 11 18:52:01 2016
From: yingjoe.chen at mediatek.com (Yingjoe Chen)
Date: Tue, 12 Jul 2016 09:52:01 +0800
Subject: [PATCH v7 1/4] soc: mediatek: Refine scpsys to support multiple
 platform
In-Reply-To: <57839AE3.2070103@gmail.com>
References: <1463390894-32062-1-git-send-email-jamesjj.liao@mediatek.com>
 <1463390894-32062-2-git-send-email-jamesjj.liao@mediatek.com>
 <6762e420-0d68-0376-b584-bfc878b5e95f@gmail.com>
 <1467783564.26485.22.camel@mtksdaap41> <577E3AE9.5080202@gmail.com>
 <1468227390.31247.20.camel@mtksdaap41> <57839AE3.2070103@gmail.com>
Message-ID: <1468288321.21217.2.camel@mtksdaap41>

On Mon, 2016-07-11 at 15:10 +0200, Matthias Brugger wrote:
> 
> On 11/07/16 10:56, James Liao wrote:
> 
> [...]
> 
> >>>>> @@ -467,28 +386,54 @@ static int scpsys_probe(struct platform_device *pdev)
> >>>>>    			if (PTR_ERR(scpd->supply) == -ENODEV)
> >>>>>    				scpd->supply = NULL;
> >>>>>    			else
> >>>>> -				return PTR_ERR(scpd->supply);
> >>>>> +				return ERR_CAST(scpd->supply);
> >>>>>    		}
> >>>>>    	}
> >>>>>
> >>>>> -	pd_data->num_domains = NUM_DOMAINS;
> >>>>> +	pd_data->num_domains = num;
> >>>>>
> >>>>> -	for (i = 0; i < NUM_DOMAINS; i++) {
> >>>>> +	init_clks(pdev, clk);
> >>>>> +
> >>>>> +	for (i = 0; i < num; i++) {
> >>>>>    		struct scp_domain *scpd = &scp->domains[i];
> >>>>>    		struct generic_pm_domain *genpd = &scpd->genpd;
> >>>>>    		const struct scp_domain_data *data = &scp_domain_data[i];
> >>>>>
> >>>>> +		for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
> >>>>> +			struct clk *c = clk[data->clk_id[j]];
> >>>>> +
> >>>>> +			if (IS_ERR(c)) {
> >>>>> +				dev_err(&pdev->dev, "%s: clk unavailable\n",
> >>>>> +					data->name);
> >>>>> +				return ERR_CAST(c);
> >>>>> +			}
> >>>>> +
> >>>>> +			scpd->clk[j] = c;
> >>>>
> >>>> Put this in the else branch. Apart from that is there any reason you
> >>>
> >>> Do you mean to change like this?
> >>>
> >>> 	if (IS_ERR(c)) {
> >>> 		...
> >>> 		return ERR_CAST(c);
> >>> 	} else {
> >>> 		scpd->clk[j] = c;
> >>> 	}
> >>>
> >>> checkpatch.pl will warn for above code due to it returns in 'if' branch.
> >>>
> >>
> >> I tried that on top of next-20160706 and it checkpatch didn't throw any
> >> warning. Which kernel version are based on?
> >
> > I don't remember which version of checkpatch warn on this pattern. This
> > patch series develop across several kernel versions.
> 
> We as the kernel community develop against master or linux-next. We only 
> care about older kernel version in the sense that we intent hard not to 
> break any userspace/kernel or firmware/kernel interfaces. Apart from 
> that it's up to every individual to backport patches from mainline 
> kernel to his respective version. But that's nothing the community as a 
> hole can take care of.
> 
> >
> > So do you prefer to put "scpd->clk[j] = c;" into 'else' branch?
> >
> 
> Yes please :)


Hi,

I just got next-20160711 and change this chunk to:

+		for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
+			struct clk *c = clk[data->clk_id[j]];
+
+			if (IS_ERR(c)) {
+				dev_err(&pdev->dev, "%s: clk unavailable\n",
+					data->name);
+				return ERR_CAST(c);
+			} else {
+				scpd->clk[j] = c;
+			}
+		}
+


and checkpatch give me this warning:

WARNING: else is not generally useful after a break or return
#313: FILE: drivers/soc/mediatek/mtk-scpsys.c:409:
+                               return ERR_CAST(c);
+                       } else {

Joe.C




From zhiyong.tao at mediatek.com  Mon Jul 11 19:43:16 2016
From: zhiyong.tao at mediatek.com (zhiyong tao)
Date: Tue, 12 Jul 2016 10:43:16 +0800
Subject: [PATCH v4 1/3] dt-bindings: auxadc: Add binding document for
 Mediatek auxadc.
In-Reply-To: <1468219197-9572-2-git-send-email-zhiyong.tao@mediatek.com>
References: <1468219197-9572-1-git-send-email-zhiyong.tao@mediatek.com>
 <1468219197-9572-2-git-send-email-zhiyong.tao@mediatek.com>
Message-ID: <1468291396.419.15.camel@mhfsdcap03>

On Mon, 2016-07-11 at 14:39 +0800, Zhiyong Tao wrote:
> The commit adds the device tree binding documentation for the mediatek
> auxadc found on Mediatek MT2701.
> Thermal gets auxadc sample data by iio device.
> So the commit changes auxadc device tree binding documentation from
> /soc/mediatek/auxadc.txt to /iio/adc/mt6577_auxadc.txt.
> 
> Signed-off-by: Zhiyong Tao <zhiyong.tao at mediatek.com>
> ---

I forgot that I should use the command 'git format-patch -M' to submit
this patch. The follow information is the patch after executing the
above command. If the patch needs to be resent, please help to notify
me. I will resend the patch quickly.
The follow information:

 .../auxadc.txt => iio/adc/mt6577_auxadc.txt}       |   16
+++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)
 rename Documentation/devicetree/bindings/{soc/mediatek/auxadc.txt =>
iio/adc/mt6577_auxadc.txt} (50%)

diff --git a/Documentation/devicetree/bindings/soc/mediatek/auxadc.txt
b/Documentation/devicetree/bindings/iio/adc/mt6577_auxadc.txt
similarity index 50%
rename from Documentation/devicetree/bindings/soc/mediatek/auxadc.txt
rename to Documentation/devicetree/bindings/iio/adc/mt6577_auxadc.txt
index bdb7829..bc23792 100644
--- a/Documentation/devicetree/bindings/soc/mediatek/auxadc.txt
+++ b/Documentation/devicetree/bindings/iio/adc/mt6577_auxadc.txt
@@ -1,4 +1,4 @@
-MediaTek AUXADC
+* Mediatek AUXADC - Analog to Digital Converter on Mediatek mobile soc
(mt65xx/mt81xx/mt27xx)
 ===============

 The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found
@@ -10,12 +10,18 @@
Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
 for the Thermal Controller which holds a phandle to the AUXADC.

 Required properties:
-- compatible: Must be "mediatek,mt8173-auxadc"
-- reg: Address range of the AUXADC unit
+  - compatible: "mediatek,mt2701-auxadc" or "mediatek,mt8173-auxadc"
+  - reg: Address range of the AUXADC unit.
+  - clocks: Should contain a clock specifier for each entry in
clock-names
+  - clock-names: Should contain "main".
+  - #io-channel-cells: Should be 1, see ../iio-bindings.txt

 Example:

-auxadc: auxadc at 11001000 {
-       compatible = "mediatek,mt8173-auxadc";
+auxadc: adc at 11001000 {
+       compatible = "mediatek,mt2701-auxadc";
        reg = <0 0x11001000 0 0x1000>;
+       clocks = <&pericfg CLK_PERI_AUXADC>;
+       clock-names = "main";
+       #io-channel-cells = <1>;
 };
-- 
1.7.9.5


>  .../devicetree/bindings/iio/adc/mt6577_auxadc.txt  |   27 ++++++++++++++++++++
>  .../devicetree/bindings/soc/mediatek/auxadc.txt    |   21 ---------------
>  2 files changed, 27 insertions(+), 21 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/iio/adc/mt6577_auxadc.txt
>  delete mode 100644 Documentation/devicetree/bindings/soc/mediatek/auxadc.txt
> 
> diff --git a/Documentation/devicetree/bindings/iio/adc/mt6577_auxadc.txt b/Documentation/devicetree/bindings/iio/adc/mt6577_auxadc.txt
> new file mode 100644
> index 0000000..bc23792
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/adc/mt6577_auxadc.txt
> @@ -0,0 +1,27 @@
> +* Mediatek AUXADC - Analog to Digital Converter on Mediatek mobile soc (mt65xx/mt81xx/mt27xx)
> +===============
> +
> +The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found
> +in some Mediatek SoCs which among other things measures the temperatures
> +in the SoC. It can be used directly with register accesses, but it is also
> +used by thermal controller which reads the temperatures from the AUXADC
> +directly via its own bus interface. See
> +Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
> +for the Thermal Controller which holds a phandle to the AUXADC.
> +
> +Required properties:
> +  - compatible: "mediatek,mt2701-auxadc" or "mediatek,mt8173-auxadc"
> +  - reg: Address range of the AUXADC unit.
> +  - clocks: Should contain a clock specifier for each entry in clock-names
> +  - clock-names: Should contain "main".
> +  - #io-channel-cells: Should be 1, see ../iio-bindings.txt
> +
> +Example:
> +
> +auxadc: adc at 11001000 {
> +	compatible = "mediatek,mt2701-auxadc";
> +	reg = <0 0x11001000 0 0x1000>;
> +	clocks = <&pericfg CLK_PERI_AUXADC>;
> +	clock-names = "main";
> +	#io-channel-cells = <1>;
> +};
> diff --git a/Documentation/devicetree/bindings/soc/mediatek/auxadc.txt b/Documentation/devicetree/bindings/soc/mediatek/auxadc.txt
> deleted file mode 100644
> index bdb7829..0000000
> --- a/Documentation/devicetree/bindings/soc/mediatek/auxadc.txt
> +++ /dev/null
> @@ -1,21 +0,0 @@
> -MediaTek AUXADC
> -===============
> -
> -The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found
> -in some Mediatek SoCs which among other things measures the temperatures
> -in the SoC. It can be used directly with register accesses, but it is also
> -used by thermal controller which reads the temperatures from the AUXADC
> -directly via its own bus interface. See
> -Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
> -for the Thermal Controller which holds a phandle to the AUXADC.
> -
> -Required properties:
> -- compatible: Must be "mediatek,mt8173-auxadc"
> -- reg: Address range of the AUXADC unit
> -
> -Example:
> -
> -auxadc: auxadc at 11001000 {
> -	compatible = "mediatek,mt8173-auxadc";
> -	reg = <0 0x11001000 0 0x1000>;
> -};




From jamesjj.liao at mediatek.com  Mon Jul 11 20:34:08 2016
From: jamesjj.liao at mediatek.com (James Liao)
Date: Tue, 12 Jul 2016 11:34:08 +0800
Subject: [PATCH v7 1/4] soc: mediatek: Refine scpsys to support multiple
 platform
In-Reply-To: <57839AE3.2070103@gmail.com>
References: <1463390894-32062-1-git-send-email-jamesjj.liao@mediatek.com>
 <1463390894-32062-2-git-send-email-jamesjj.liao@mediatek.com>
 <6762e420-0d68-0376-b584-bfc878b5e95f@gmail.com>
 <1467783564.26485.22.camel@mtksdaap41> <577E3AE9.5080202@gmail.com>
 <1468227390.31247.20.camel@mtksdaap41> <57839AE3.2070103@gmail.com>
Message-ID: <1468294448.31247.28.camel@mtksdaap41>

Hi Matthias,

On Mon, 2016-07-11 at 15:10 +0200, Matthias Brugger wrote:
> 
> On 11/07/16 10:56, James Liao wrote:
> 
> [...]
> 
> >>>>> @@ -467,28 +386,54 @@ static int scpsys_probe(struct platform_device *pdev)
> >>>>>    			if (PTR_ERR(scpd->supply) == -ENODEV)
> >>>>>    				scpd->supply = NULL;
> >>>>>    			else
> >>>>> -				return PTR_ERR(scpd->supply);
> >>>>> +				return ERR_CAST(scpd->supply);
> >>>>>    		}
> >>>>>    	}
> >>>>>
> >>>>> -	pd_data->num_domains = NUM_DOMAINS;
> >>>>> +	pd_data->num_domains = num;
> >>>>>
> >>>>> -	for (i = 0; i < NUM_DOMAINS; i++) {
> >>>>> +	init_clks(pdev, clk);
> >>>>> +
> >>>>> +	for (i = 0; i < num; i++) {
> >>>>>    		struct scp_domain *scpd = &scp->domains[i];
> >>>>>    		struct generic_pm_domain *genpd = &scpd->genpd;
> >>>>>    		const struct scp_domain_data *data = &scp_domain_data[i];
> >>>>>
> >>>>> +		for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
> >>>>> +			struct clk *c = clk[data->clk_id[j]];
> >>>>> +
> >>>>> +			if (IS_ERR(c)) {
> >>>>> +				dev_err(&pdev->dev, "%s: clk unavailable\n",
> >>>>> +					data->name);
> >>>>> +				return ERR_CAST(c);
> >>>>> +			}
> >>>>> +
> >>>>> +			scpd->clk[j] = c;
> >>>>
> >>>> Put this in the else branch. Apart from that is there any reason you
> >>>
> >>> Do you mean to change like this?
> >>>
> >>> 	if (IS_ERR(c)) {
> >>> 		...
> >>> 		return ERR_CAST(c);
> >>> 	} else {
> >>> 		scpd->clk[j] = c;
> >>> 	}
> >>>
> >>> checkpatch.pl will warn for above code due to it returns in 'if' branch.
> >>>
> >>
> >> I tried that on top of next-20160706 and it checkpatch didn't throw any
> >> warning. Which kernel version are based on?
> >
> > I don't remember which version of checkpatch warn on this pattern. This
> > patch series develop across several kernel versions.
> 
> We as the kernel community develop against master or linux-next. We only 
> care about older kernel version in the sense that we intent hard not to 
> break any userspace/kernel or firmware/kernel interfaces. Apart from 
> that it's up to every individual to backport patches from mainline 
> kernel to his respective version. But that's nothing the community as a 
> hole can take care of.
> 
> >
> > So do you prefer to put "scpd->clk[j] = c;" into 'else' branch?
> >
> 
> Yes please :)

Yingjoe had tested in the latest checkpatch.pl and it showed checkpatch
warn on the else-branch. He had replied the results in previous email.
 
> >>>> moved the for up in the function? If not, I would prefer not to move it,
> >>>> to make it easier to read the diff.
> >>>
> >>> The new 'for' block are far different from original one. And I think
> >>> it's easy to read if we keep simple assign statements in the same block.
> >>>
> >>
> >> It's different in the sense that it checks if struct clk *c is an error.
> >> I don't see the reason why we need to move it up in the file.
> >> It's not too important but I would prefer not to move it if there is no
> >> reason.
> >
> > I think I may misunderstand your comments. Which 'for' block did you
> > mention for? 'for (i = 0; i < num ...' or 'for (j = 0; j < MAX_CLKS
> > && ...' ?
> >
> > The 'for(i)' exists in original code, this patch just change its counter
> > from 'NUM_DOMAINS' to 'num'. The 'for(j)' is a new for-block, so it was
> > not moved from other blocks.
> >
> 
> for (j = 0; j < MAX_CLKS... is present in the actual scpsys_probe in 
> linux-next (line 485 as of today). This patch moves this for a few lines 
> up, to be precise before executing this code sequence:
> <code>
> pd_data->domains[i] = genpd;
> scpd->scp = scp;
> 
> scpd->data = data;
> </code>
> 
> AFAIK there is no reason to do so. It adds unnecessary complexity to the 
> patch. So please fix this together with the other comments you got.

I see. So you prefer to put the for(j < MAX_CLKS) after 'scpd->data =
data' right? I can change it in next patch.


Best regards,

James



From wuchengli at chromium.org  Tue Jul 12 01:16:14 2016
From: wuchengli at chromium.org (=?UTF-8?B?V3UtQ2hlbmcgTGkgKOadjuWLmeiqoCk=?=)
Date: Tue, 12 Jul 2016 16:16:14 +0800
Subject: [PATCH v3 3/9] DocBook/v4l: Add compressed video formats used on
 MT8173 codec driver
In-Reply-To: <1468205771.3725.8.camel@mtksdaap41>
References: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-2-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-3-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-4-git-send-email-tiffany.lin@mediatek.com>
 <5a793171-24a7-4e9e-8bfd-f668c789f8e0@xs4all.nl>
 <1468205771.3725.8.camel@mtksdaap41>
Message-ID: <CAOMLVLiZU3D587dSyp2b2v4DV+MS9vh85bA4BoG7ddK6556rbA@mail.gmail.com>

On Mon, Jul 11, 2016 at 10:56 AM, tiffany lin <tiffany.lin at mediatek.com> wrote:
> Hi Hans,
>
> On Fri, 2016-07-08 at 12:23 +0200, Hans Verkuil wrote:
>> On 05/30/2016 02:29 PM, Tiffany Lin wrote:
>> > Add V4L2_PIX_FMT_MT21 documentation
>> >
>> > Signed-off-by: Tiffany Lin <tiffany.lin at mediatek.com>
>> > ---
>> >  Documentation/DocBook/media/v4l/pixfmt.xml |    6 ++++++
>> >  1 file changed, 6 insertions(+)
>> >
>> > diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml
>> > index 5a08aee..d40e0ce 100644
>> > --- a/Documentation/DocBook/media/v4l/pixfmt.xml
>> > +++ b/Documentation/DocBook/media/v4l/pixfmt.xml
>> > @@ -1980,6 +1980,12 @@ array. Anything what's in between the UYVY lines is JPEG data and should be
>> >  concatenated to form the JPEG stream. </para>
>> >  </entry>
>> >       </row>
>> > +     <row id="V4L2_PIX_FMT_MT21">
>> > +       <entry><constant>V4L2_PIX_FMT_MT21</constant></entry>
>> > +       <entry>'MT21'</entry>
>> > +       <entry>Compressed two-planar YVU420 format used by Mediatek MT8173
>> > +       codec driver.</entry>
>>
>> Can you give a few more details? The encoder driver doesn't seem to produce this
>> format, so who is creating this? Where is this format documented?
Decoder hardware produces MT21 (compressed). Image processor can
convert it to a format that can be input of display driver. Tiffany.
When do you plan to upstream image processor (mtk-mdp)?
>
> It can be as input format for encoder, MDP and display drivers in our
> platform.
I remember display driver can only accept uncompressed MT21. Right?
Basically V4L2_PIX_FMT_MT21 is compressed and is like an opaque
format. It's not usable until it's decompressed and converted by image
processor.
> This private format is only available in our platform.
> So I put it in "Reserved Format Identifiers" sections.
>
>
> best regards,
> Tiffany
>
>> Regards,
>>
>>       Hans
>>
>> > +     </row>
>> >     </tbody>
>> >        </tgroup>
>> >      </table>
>> >
>
>
> --
> 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


From matthias.bgg at gmail.com  Tue Jul 12 01:21:13 2016
From: matthias.bgg at gmail.com (Matthias Brugger)
Date: Tue, 12 Jul 2016 10:21:13 +0200
Subject: [PATCH v7 1/4] soc: mediatek: Refine scpsys to support multiple
 platform
In-Reply-To: <1468294448.31247.28.camel@mtksdaap41>
References: <1463390894-32062-1-git-send-email-jamesjj.liao@mediatek.com>
 <1463390894-32062-2-git-send-email-jamesjj.liao@mediatek.com>
 <6762e420-0d68-0376-b584-bfc878b5e95f@gmail.com>
 <1467783564.26485.22.camel@mtksdaap41> <577E3AE9.5080202@gmail.com>
 <1468227390.31247.20.camel@mtksdaap41> <57839AE3.2070103@gmail.com>
 <1468294448.31247.28.camel@mtksdaap41>
Message-ID: <f904dc9b-d723-f466-0ee4-78af920ccd72@gmail.com>



On 12/07/16 05:34, James Liao wrote:
> Hi Matthias,
>
> On Mon, 2016-07-11 at 15:10 +0200, Matthias Brugger wrote:
>>
>> On 11/07/16 10:56, James Liao wrote:
>>
>> [...]
>>
>>>>>>> @@ -467,28 +386,54 @@ static int scpsys_probe(struct platform_device *pdev)
>>>>>>>    			if (PTR_ERR(scpd->supply) == -ENODEV)
>>>>>>>    				scpd->supply = NULL;
>>>>>>>    			else
>>>>>>> -				return PTR_ERR(scpd->supply);
>>>>>>> +				return ERR_CAST(scpd->supply);
>>>>>>>    		}
>>>>>>>    	}
>>>>>>>
>>>>>>> -	pd_data->num_domains = NUM_DOMAINS;
>>>>>>> +	pd_data->num_domains = num;
>>>>>>>
>>>>>>> -	for (i = 0; i < NUM_DOMAINS; i++) {
>>>>>>> +	init_clks(pdev, clk);
>>>>>>> +
>>>>>>> +	for (i = 0; i < num; i++) {
>>>>>>>    		struct scp_domain *scpd = &scp->domains[i];
>>>>>>>    		struct generic_pm_domain *genpd = &scpd->genpd;
>>>>>>>    		const struct scp_domain_data *data = &scp_domain_data[i];
>>>>>>>
>>>>>>> +		for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
>>>>>>> +			struct clk *c = clk[data->clk_id[j]];
>>>>>>> +
>>>>>>> +			if (IS_ERR(c)) {
>>>>>>> +				dev_err(&pdev->dev, "%s: clk unavailable\n",
>>>>>>> +					data->name);
>>>>>>> +				return ERR_CAST(c);
>>>>>>> +			}
>>>>>>> +
>>>>>>> +			scpd->clk[j] = c;
>>>>>>
>>>>>> Put this in the else branch. Apart from that is there any reason you
>>>>>
>>>>> Do you mean to change like this?
>>>>>
>>>>> 	if (IS_ERR(c)) {
>>>>> 		...
>>>>> 		return ERR_CAST(c);
>>>>> 	} else {
>>>>> 		scpd->clk[j] = c;
>>>>> 	}
>>>>>
>>>>> checkpatch.pl will warn for above code due to it returns in 'if' branch.
>>>>>
>>>>
>>>> I tried that on top of next-20160706 and it checkpatch didn't throw any
>>>> warning. Which kernel version are based on?
>>>
>>> I don't remember which version of checkpatch warn on this pattern. This
>>> patch series develop across several kernel versions.
>>
>> We as the kernel community develop against master or linux-next. We only
>> care about older kernel version in the sense that we intent hard not to
>> break any userspace/kernel or firmware/kernel interfaces. Apart from
>> that it's up to every individual to backport patches from mainline
>> kernel to his respective version. But that's nothing the community as a
>> hole can take care of.
>>
>>>
>>> So do you prefer to put "scpd->clk[j] = c;" into 'else' branch?
>>>
>>
>> Yes please :)
>
> Yingjoe had tested in the latest checkpatch.pl and it showed checkpatch
> warn on the else-branch. He had replied the results in previous email.
>

Yes you are right. Not sure what I was testing. Sorry for that.

>>>>>> moved the for up in the function? If not, I would prefer not to move it,
>>>>>> to make it easier to read the diff.
>>>>>
>>>>> The new 'for' block are far different from original one. And I think
>>>>> it's easy to read if we keep simple assign statements in the same block.
>>>>>
>>>>
>>>> It's different in the sense that it checks if struct clk *c is an error.
>>>> I don't see the reason why we need to move it up in the file.
>>>> It's not too important but I would prefer not to move it if there is no
>>>> reason.
>>>
>>> I think I may misunderstand your comments. Which 'for' block did you
>>> mention for? 'for (i = 0; i < num ...' or 'for (j = 0; j < MAX_CLKS
>>> && ...' ?
>>>
>>> The 'for(i)' exists in original code, this patch just change its counter
>>> from 'NUM_DOMAINS' to 'num'. The 'for(j)' is a new for-block, so it was
>>> not moved from other blocks.
>>>
>>
>> for (j = 0; j < MAX_CLKS... is present in the actual scpsys_probe in
>> linux-next (line 485 as of today). This patch moves this for a few lines
>> up, to be precise before executing this code sequence:
>> <code>
>> pd_data->domains[i] = genpd;
>> scpd->scp = scp;
>>
>> scpd->data = data;
>> </code>
>>
>> AFAIK there is no reason to do so. It adds unnecessary complexity to the
>> patch. So please fix this together with the other comments you got.
>
> I see. So you prefer to put the for(j < MAX_CLKS) after 'scpd->data =
> data' right? I can change it in next patch.
>

Ok, thanks.

Regards,
Matthias


From yong.wu at mediatek.com  Tue Jul 12 02:01:11 2016
From: yong.wu at mediatek.com (Yong Wu)
Date: Tue, 12 Jul 2016 17:01:11 +0800
Subject: [PATCH v7 2/4] soc: mediatek: Init MT8173 scpsys driver earlier
In-Reply-To: <577FA0D9.8070408@gmail.com>
References: <1463390894-32062-1-git-send-email-jamesjj.liao@mediatek.com>
 <1463390894-32062-3-git-send-email-jamesjj.liao@mediatek.com>
 <34025ec4-19d3-8b25-d669-50c6f19159cd@gmail.com>
 <1467782540.26485.11.camel@mtksdaap41> <577FA0D9.8070408@gmail.com>
Message-ID: <1468314071.24705.4.camel@mhfsdcap03>

Hi Matthias,

On Fri, 2016-07-08 at 14:47 +0200, Matthias Brugger wrote:
> 
> On 06/07/16 07:22, James Liao wrote:
> > On Sat, 2016-07-02 at 18:35 +0200, Matthias Brugger wrote:
> >>
> >> On 05/16/2016 11:28 AM, James Liao wrote:
> >>> Some power domain comsumers may init before module_init.
> >>> So the power domain provider (scpsys) need to be initialized
> >>> earlier too.
> >>>
> >>> Take an example for our IOMMU (M4U) and SMI. SMI is a bridge
> >>> between IOMMU and multimedia HW. SMI is responsible to
> >>> enable/disable iommu and help transfer data for each multimedia
> >>> HW. Both of them have to wait until the power and clocks are
> >>> enabled.
> >>>
> >>> So scpsys driver should be initialized before SMI, and SMI should
> >>> be initialized before IOMMU, and then init IOMMU consumers
> >>> (display/vdec/venc/camera etc.).
> >>>
> >>> IOMMU is subsys_init by default. So we need to init scpsys driver
> >>> before subsys_init.
> >>>
> >>> Signed-off-by: James Liao <jamesjj.liao at mediatek.com>
> >>> Reviewed-by: Kevin Hilman <khilman at baylibre.com>
> >>> ---
> >>>   drivers/soc/mediatek/mtk-scpsys.c | 19 ++++++++++++++++++-
> >>>   1 file changed, 18 insertions(+), 1 deletion(-)
> >>>
> >>> diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
> >>> index 5870a24..00c0adb 100644
> >>> --- a/drivers/soc/mediatek/mtk-scpsys.c
> >>> +++ b/drivers/soc/mediatek/mtk-scpsys.c
> >>> @@ -617,4 +617,21 @@ static struct platform_driver scpsys_drv = {
> >>>   		.of_match_table = of_match_ptr(of_scpsys_match_tbl),
> >>>   	},
> >>>   };
> >>> -builtin_platform_driver(scpsys_drv);
> >>> +
> >>> +static int __init scpsys_drv_init(void)
> >>> +{
> >>> +	return platform_driver_register(&scpsys_drv);
> >>> +}
> >>> +
> >>> +/*
> >>> + * There are some Mediatek drivers which depend on the power domain driver need
> >>> + * to probe in earlier initcall levels. So scpsys driver also need to probe
> >>> + * earlier.
> >>> + *
> >>> + * IOMMU(M4U) and SMI drivers for example. SMI is a bridge between IOMMU and
> >>> + * multimedia HW. IOMMU depends on SMI, and SMI is a power domain consumer,
> >>> + * so the proper probe sequence should be scpsys -> SMI -> IOMMU driver.
> >>> + * IOMMU drivers are initialized during subsys_init by default, so we need to
> >>> + * move SMI and scpsys drivers to subsys_init or earlier init levels.
> >>> + */
> >>> +subsys_initcall(scpsys_drv_init);
> >>>
> >>
> >> Can't we achieve this with probe deferring? I'm not really keen on
> >> coding the order of the different drivers like this.
> >
> > Hi Matthias,
> >
> > Some drivers such as IOMMU don't support probe deferring. So scpsys need
> > to init before them by changing init level.
> >
> 
> SMI larbs return EPROBE_DEFER if it can't find the PM provider for it's 
> domain, so this part should not be the problem. The larbs get added as 
> components in the probe, when the PM provider is present.
> 
> The iommu driver uses the larbs as components. As long as not all 
> components are present the iommu does not bind them. So from what I see 
> this should work without any problem.
> 
> Can you please specify where the iommu dirver has a problem. Maybe we 
> need to fix the driver rather then scpsys.

We got a problem while bootup, the hang backtrace is like below(Sorry, I
can't find the full backtrace now):
 
[    7.832359] Call trace:
[    7.834778] [<ffffffc000764424>] mtk_smi_larb_get+0x24/0xa8
[    7.840300] [<ffffffc0005a1390>] mtk_drm_crtc_enable+0x6c/0x450

The reason is that "larb->mmu" is NULL while DRM call mtk_smi_larb_get.
 
DRM call iommu_present to wait for whether IOMMU is ready[1].
But in the  MTK-IOMMU, It will call
bus_set_iommu->mtk_iommu_add_device->mtk_iommu_attach_device, then it's
able to transfer "struct mtk_smi_iommu" to SMI whose probe maybe delayed
by power-domain, then SMI could finish its probe.

So If DRM probe is called after the time of calling bus_set_iommu and
before the time of SMI probe finish, this problem can be reproduced.

The root cause is that iommu_present cann't indicate that MTK-IOMMU and
SMI is ready actually. in other words, the DRM cann't detect
whether the SMI has probed done.

If we move scpsys_init from module_initcall to subsys_initcall, the
IOMMU and SMI could be probe done during the subsys_initcall period. 
this issue can be avoid.
And as we grep before, there are also some examples whose power-domain
is also not module_init[2].
core_initcall(exynos4_pm_init_power_domain);
subsys_initcall(imx_pgc_init);

If you think that this patch will hide the problem above, then I have to
add a new function, like below:
//==================
bool mtk_smi_larb_ready(struct device *larbdev)
{
	struct mtk_smi_larb *larb = dev_get_drvdata(larbdev);

	return larb && !!larb->mmu;
}
//=================

And in the probe of all the MTK-IOMMU consumer, we have to add this:
//====================
	if (!mtk_smi_larb_ready(&larb_pdev->dev))
		return -EPROBE_DEFER;
//====================

The sequence is a little complex, If I don't explain clearly, please
tell me.
Any other suggestion about this? Thanks.
 
[1]:https://chromium.googlesource.com/chromiumos/third_party/kernel/+/chromeos-3.18/drivers/gpu/drm/mediatek/mtk_drm_drv.c#150 
[2]:http://lists.infradead.org/pipermail/linux-mediatek/2015-December/003416.html

> 
> Regards,
> Matthias
> 
> _______________________________________________
> Linux-mediatek mailing list
> Linux-mediatek at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-mediatek




From henryc.chen at mediatek.com  Tue Jul 12 02:44:36 2016
From: henryc.chen at mediatek.com (Henry Chen)
Date: Tue, 12 Jul 2016 17:44:36 +0800
Subject: [PATCH] soc: mediatek: PMIC wrap: Extend th wainting time to 10ms.
Message-ID: <1468316676-14901-1-git-send-email-henryc.chen@mediatek.com>

Read data fails sometimes because of a timeout that PMIC cannot transfer data
to PMIC wrap on time, extend the wainting time to 10ms to reduce the failed
rate.

Signed-off-by: Henry Chen <henryc.chen at mediatek.com>
---
 drivers/soc/mediatek/mtk-pmic-wrap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
index a003ba2..a5f1093 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -583,7 +583,7 @@ static int pwrap_wait_for_state(struct pmic_wrapper *wrp,
 {
 	unsigned long timeout;
 
-	timeout = jiffies + usecs_to_jiffies(255);
+	timeout = jiffies + usecs_to_jiffies(10000);
 
 	do {
 		if (time_after(jiffies, timeout))
-- 
1.8.1.1.dirty



From daniel at ffwll.ch  Tue Jul 12 03:13:52 2016
From: daniel at ffwll.ch (Daniel Vetter)
Date: Tue, 12 Jul 2016 12:13:52 +0200
Subject: [PATCH 2/2 v16] drm/bridge: Add I2C based driver for ps8640 bridge
In-Reply-To: <CAGS+omDsDS5tx=+Efq8LWNd3-asU4r2h=-AE6vdKgfG-p6vdAA@mail.gmail.com>
References: <1464861445-11086-1-git-send-email-jitao.shi@mediatek.com>
 <1464861445-11086-2-git-send-email-jitao.shi@mediatek.com>
 <CACvgo53002XCPLufbJHQLC1uL1nNS7_0gh=napedetmvT6FoSw@mail.gmail.com>
 <CAGS+omDsDS5tx=+Efq8LWNd3-asU4r2h=-AE6vdKgfG-p6vdAA@mail.gmail.com>
Message-ID: <CAKMK7uEkUOq1CB3tj_1Qx50fBpw9B39+c3asX6MPNexT=dv9fA@mail.gmail.com>

On Wed, Jun 29, 2016 at 6:31 AM, Daniel Kurtz <djkurtz at chromium.org> wrote:
> On Fri, Jun 17, 2016 at 3:14 AM, Emil Velikov <emil.l.velikov at gmail.com> wrote:
>>> +static ssize_t ps8640_update_fw_store(struct device *dev,
>>> +                                     struct device_attribute *attr,
>>> +                                     const char *buf, size_t count)
>>> +{
>>> +       struct i2c_client *client = to_i2c_client(dev);
>>> +       struct ps8640 *ps_bridge = i2c_get_clientdata(client);
>>> +       const struct firmware *fw;
>>> +       int error;
>>> +
>>> +       error = request_firmware(&fw, PS_FW_NAME, dev);
>> Can the device operate without a firmware ? If not, why is the
>> firmware loaded so later/after user interaction (via sysfs) ? I don't
>> recall any other driver in DRM to use such an approach.
>
> The PS8640 has internal flash, so it should always already have a
> working firmware.
> This sysfs interface is useful for user space initiated field firmware updates.

Might be better to just do a request_firmware on driver load, and
simply proceed if it's not there. Adding a sysfs interface (which is
abi) seems way too much overkill for this imo. If you want to upgrade
the firmware you can then just drop it into the right directory, with
no further interaction needed.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch


From weiyj_lk at 163.com  Tue Jul 12 04:00:55 2016
From: weiyj_lk at 163.com (weiyj_lk at 163.com)
Date: Tue, 12 Jul 2016 11:00:55 +0000
Subject: [PATCH -next] [media] VPU: mediatek: fix return value check in
 mtk_vpu_probe()
Message-ID: <1468321255-15840-1-git-send-email-weiyj_lk@163.com>

From: Wei Yongjun <yongjun_wei at trendmicro.com.cn>

In case of error, the function devm_clk_get() returns ERR_PTR()
and not returns NULL. The NULL test in the return value check
should be replaced with IS_ERR().

Signed-off-by: Wei Yongjun <yongjun_wei at trendmicro.com.cn>
---
 drivers/media/platform/mtk-vpu/mtk_vpu.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c
index b60d02c..c8b2c72 100644
--- a/drivers/media/platform/mtk-vpu/mtk_vpu.c
+++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c
@@ -788,9 +788,9 @@ static int mtk_vpu_probe(struct platform_device *pdev)
 
 	/* Get VPU clock */
 	vpu->clk = devm_clk_get(dev, "main");
-	if (!vpu->clk) {
+	if (IS_ERR(vpu->clk)) {
 		dev_err(dev, "get vpu clock failed\n");
-		return -EINVAL;
+		return PTR_ERR(vpu->clk);
 	}
 
 	platform_set_drvdata(pdev, vpu);




From weiyj_lk at 163.com  Tue Jul 12 04:01:26 2016
From: weiyj_lk at 163.com (weiyj_lk at 163.com)
Date: Tue, 12 Jul 2016 11:01:26 +0000
Subject: [PATCH -next] [media] VPU: mediatek: remove redundant dev_err call in
 mtk_vpu_probe()
Message-ID: <1468321286-15939-1-git-send-email-weiyj_lk@163.com>

From: Wei Yongjun <yongjun_wei at trendmicro.com.cn>

There is a error message within devm_ioremap_resource
already, so remove the dev_err call to avoid redundant
error message.

Signed-off-by: Wei Yongjun <yongjun_wei at trendmicro.com.cn>
---
 drivers/media/platform/mtk-vpu/mtk_vpu.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c
index b60d02c..532d2a4 100644
--- a/drivers/media/platform/mtk-vpu/mtk_vpu.c
+++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c
@@ -774,17 +774,13 @@ static int mtk_vpu_probe(struct platform_device *pdev)
 	vpu->dev = &pdev->dev;
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tcm");
 	vpu->reg.tcm = devm_ioremap_resource(dev, res);
-	if (IS_ERR((__force void *)vpu->reg.tcm)) {
-		dev_err(dev, "devm_ioremap_resource vpu tcm failed.\n");
+	if (IS_ERR((__force void *)vpu->reg.tcm))
 		return PTR_ERR((__force void *)vpu->reg.tcm);
-	}
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg_reg");
 	vpu->reg.cfg = devm_ioremap_resource(dev, res);
-	if (IS_ERR((__force void *)vpu->reg.cfg)) {
-		dev_err(dev, "devm_ioremap_resource vpu cfg failed.\n");
+	if (IS_ERR((__force void *)vpu->reg.cfg))
 		return PTR_ERR((__force void *)vpu->reg.cfg);
-	}
 
 	/* Get VPU clock */
 	vpu->clk = devm_clk_get(dev, "main");




From weiyj_lk at 163.com  Tue Jul 12 04:02:28 2016
From: weiyj_lk at 163.com (weiyj_lk at 163.com)
Date: Tue, 12 Jul 2016 11:02:28 +0000
Subject: [PATCH -next] [media] vcodec: mediatek: Fix return value check in
 mtk_vcodec_init_enc_pm()
Message-ID: <1468321348-16045-1-git-send-email-weiyj_lk@163.com>

From: Wei Yongjun <yongjun_wei at trendmicro.com.cn>

In case of error, the function devm_clk_get() returns ERR_PTR()
and not returns NULL. The NULL test in the return value check
should be replaced with IS_ERR().

Signed-off-by: Wei Yongjun <yongjun_wei at trendmicro.com.cn>
---
 drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
index 2379e97..3e73e9d 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
@@ -67,27 +67,27 @@ int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev)
 	pm->dev = &pdev->dev;
 
 	pm->vencpll_d2 = devm_clk_get(&pdev->dev, "venc_sel_src");
-	if (pm->vencpll_d2 == NULL) {
+	if (IS_ERR(pm->vencpll_d2)) {
 		mtk_v4l2_err("devm_clk_get vencpll_d2 fail");
-		ret = -1;
+		ret = PTR_ERR(pm->vencpll_d2);
 	}
 
 	pm->venc_sel = devm_clk_get(&pdev->dev, "venc_sel");
-	if (pm->venc_sel == NULL) {
+	if (IS_ERR(pm->venc_sel)) {
 		mtk_v4l2_err("devm_clk_get venc_sel fail");
-		ret = -1;
+		ret = PTR_ERR(pm->venc_sel);
 	}
 
 	pm->univpll1_d2 = devm_clk_get(&pdev->dev, "venc_lt_sel_src");
-	if (pm->univpll1_d2 == NULL) {
+	if (IS_ERR(pm->univpll1_d2)) {
 		mtk_v4l2_err("devm_clk_get univpll1_d2 fail");
-		ret = -1;
+		ret = PTR_ERR(pm->univpll1_d2);
 	}
 
 	pm->venc_lt_sel = devm_clk_get(&pdev->dev, "venc_lt_sel");
-	if (pm->venc_lt_sel == NULL) {
+	if (IS_ERR(pm->venc_lt_sel)) {
 		mtk_v4l2_err("devm_clk_get venc_lt_sel fail");
-		ret = -1;
+		ret = PTR_ERR(pm->venc_lt_sel);
 	}
 
 	return ret;




From weiyj_lk at 163.com  Tue Jul 12 04:02:59 2016
From: weiyj_lk at 163.com (weiyj_lk at 163.com)
Date: Tue, 12 Jul 2016 11:02:59 +0000
Subject: [PATCH -next] [media] mtk-vcodec: remove redundant dev_err call in
 mtk_vcodec_probe()
Message-ID: <1468321379-16133-1-git-send-email-weiyj_lk@163.com>

From: Wei Yongjun <yongjun_wei at trendmicro.com.cn>

There is a error message within devm_ioremap_resource
already, so remove the dev_err call to avoid redundant
error message.

Signed-off-by: Wei Yongjun <yongjun_wei at trendmicro.com.cn>
---
 drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
index 9c10cc2..b33a931 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
@@ -279,8 +279,6 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
 		}
 		dev->reg_base[i] = devm_ioremap_resource(&pdev->dev, res);
 		if (IS_ERR((__force void *)dev->reg_base[i])) {
-			dev_err(&pdev->dev,
-				"devm_ioremap_resource %d failed.", i);
 			ret = PTR_ERR((__force void *)dev->reg_base[i]);
 			goto err_res;
 		}




From tiffany.lin at mediatek.com  Tue Jul 12 04:21:42 2016
From: tiffany.lin at mediatek.com (tiffany lin)
Date: Tue, 12 Jul 2016 19:21:42 +0800
Subject: [PATCH -next] [media] vcodec: mediatek: Fix return value check
 in mtk_vcodec_init_enc_pm()
In-Reply-To: <1468321348-16045-1-git-send-email-weiyj_lk@163.com>
References: <1468321348-16045-1-git-send-email-weiyj_lk@163.com>
Message-ID: <1468322502.2462.8.camel@mtksdaap41>

Reviewed-by:Tiffany Lin <tiffany.lin at mediatek.com>

On Tue, 2016-07-12 at 11:02 +0000, weiyj_lk at 163.com wrote:
> From: Wei Yongjun <yongjun_wei at trendmicro.com.cn>
> 
> In case of error, the function devm_clk_get() returns ERR_PTR()
> and not returns NULL. The NULL test in the return value check
> should be replaced with IS_ERR().
> 
> Signed-off-by: Wei Yongjun <yongjun_wei at trendmicro.com.cn>
> ---
>  drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c | 16 ++++++++--------
>  1 file changed, 8 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
> index 2379e97..3e73e9d 100644
> --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
> +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
> @@ -67,27 +67,27 @@ int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev)
>  	pm->dev = &pdev->dev;
>  
>  	pm->vencpll_d2 = devm_clk_get(&pdev->dev, "venc_sel_src");
> -	if (pm->vencpll_d2 == NULL) {
> +	if (IS_ERR(pm->vencpll_d2)) {
>  		mtk_v4l2_err("devm_clk_get vencpll_d2 fail");
> -		ret = -1;
> +		ret = PTR_ERR(pm->vencpll_d2);
>  	}
>  
>  	pm->venc_sel = devm_clk_get(&pdev->dev, "venc_sel");
> -	if (pm->venc_sel == NULL) {
> +	if (IS_ERR(pm->venc_sel)) {
>  		mtk_v4l2_err("devm_clk_get venc_sel fail");
> -		ret = -1;
> +		ret = PTR_ERR(pm->venc_sel);
>  	}
>  
>  	pm->univpll1_d2 = devm_clk_get(&pdev->dev, "venc_lt_sel_src");
> -	if (pm->univpll1_d2 == NULL) {
> +	if (IS_ERR(pm->univpll1_d2)) {
>  		mtk_v4l2_err("devm_clk_get univpll1_d2 fail");
> -		ret = -1;
> +		ret = PTR_ERR(pm->univpll1_d2);
>  	}
>  
>  	pm->venc_lt_sel = devm_clk_get(&pdev->dev, "venc_lt_sel");
> -	if (pm->venc_lt_sel == NULL) {
> +	if (IS_ERR(pm->venc_lt_sel)) {
>  		mtk_v4l2_err("devm_clk_get venc_lt_sel fail");
> -		ret = -1;
> +		ret = PTR_ERR(pm->venc_lt_sel);
>  	}
>  
>  	return ret;
> 
> 




From tiffany.lin at mediatek.com  Tue Jul 12 04:25:58 2016
From: tiffany.lin at mediatek.com (tiffany lin)
Date: Tue, 12 Jul 2016 19:25:58 +0800
Subject: [PATCH -next] [media] mtk-vcodec: remove redundant dev_err call
 in mtk_vcodec_probe()
In-Reply-To: <1468321379-16133-1-git-send-email-weiyj_lk@163.com>
References: <1468321379-16133-1-git-send-email-weiyj_lk@163.com>
Message-ID: <1468322758.2462.9.camel@mtksdaap41>

Reviewed-by: Tiffany Lin <tiffany.lin at mediatek.com>

On Tue, 2016-07-12 at 11:02 +0000, weiyj_lk at 163.com wrote:
> From: Wei Yongjun <yongjun_wei at trendmicro.com.cn>
> 
> There is a error message within devm_ioremap_resource
> already, so remove the dev_err call to avoid redundant
> error message.
> 
> Signed-off-by: Wei Yongjun <yongjun_wei at trendmicro.com.cn>
> ---
>  drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c | 2 --
>  1 file changed, 2 deletions(-)
> 
> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
> index 9c10cc2..b33a931 100644
> --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
> +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
> @@ -279,8 +279,6 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
>  		}
>  		dev->reg_base[i] = devm_ioremap_resource(&pdev->dev, res);
>  		if (IS_ERR((__force void *)dev->reg_base[i])) {
> -			dev_err(&pdev->dev,
> -				"devm_ioremap_resource %d failed.", i);
>  			ret = PTR_ERR((__force void *)dev->reg_base[i]);
>  			goto err_res;
>  		}
> 
> 




From weiyj_lk at 163.com  Tue Jul 12 04:31:13 2016
From: weiyj_lk at 163.com (weiyj_lk at 163.com)
Date: Tue, 12 Jul 2016 11:31:13 +0000
Subject: [PATCH -next] [media] mtk-vcodec: remove .owner field for driver
Message-ID: <1468323073-1655-1-git-send-email-weiyj_lk@163.com>

From: Wei Yongjun <yongjun_wei at trendmicro.com.cn>

Remove .owner field if calls are used which set it automatically.

Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci

Signed-off-by: Wei Yongjun <yongjun_wei at trendmicro.com.cn>
---
 drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
index 9c10cc2..60b0bde 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
@@ -430,7 +430,6 @@ static struct platform_driver mtk_vcodec_enc_driver = {
 	.remove	= mtk_vcodec_enc_remove,
 	.driver	= {
 		.name	= MTK_VCODEC_ENC_NAME,
-		.owner	= THIS_MODULE,
 		.of_match_table = mtk_vcodec_enc_match,
 	},
 };




From weiyj_lk at 163.com  Tue Jul 12 04:36:44 2016
From: weiyj_lk at 163.com (weiyj_lk at 163.com)
Date: Tue, 12 Jul 2016 11:36:44 +0000
Subject: [PATCH -next] net: mediatek: fix non static symbol warnings
Message-ID: <1468323404-2193-1-git-send-email-weiyj_lk@163.com>

From: Wei Yongjun <yongjun_wei at trendmicro.com.cn>

Fixes the following sparse warnings:

drivers/net/ethernet/mediatek/mtk_eth_soc.c:79:5: warning:
 symbol '_mtk_mdio_write' was not declared. Should it be static?
drivers/net/ethernet/mediatek/mtk_eth_soc.c:98:5: warning:
 symbol '_mtk_mdio_read' was not declared. Should it be static?

Signed-off-by: Wei Yongjun <yongjun_wei at trendmicro.com.cn>
---
 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 682797e..6f597eb 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -76,8 +76,8 @@ static int mtk_mdio_busy_wait(struct mtk_eth *eth)
 	return -1;
 }
 
-u32 _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr,
-		    u32 phy_register, u32 write_data)
+static u32 _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr,
+			   u32 phy_register, u32 write_data)
 {
 	if (mtk_mdio_busy_wait(eth))
 		return -1;
@@ -95,7 +95,7 @@ u32 _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr,
 	return 0;
 }
 
-u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg)
+static u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg)
 {
 	u32 d;




From daniel at ffwll.ch  Tue Jul 12 05:16:25 2016
From: daniel at ffwll.ch (Daniel Vetter)
Date: Tue, 12 Jul 2016 14:16:25 +0200
Subject: [PATCH v5 00/44] dma-mapping: Use unsigned long for dma_attrs
In-Reply-To: <1467275019-30789-1-git-send-email-k.kozlowski@samsung.com>
References: <1467275019-30789-1-git-send-email-k.kozlowski@samsung.com>
Message-ID: <20160712121625.GP23520@phenom.ffwll.local>

On Thu, Jun 30, 2016 at 10:23:39AM +0200, Krzysztof Kozlowski wrote:
> Hi,
> 
> 
> This is fifth approach for replacing struct dma_attrs with unsigned
> long.
> 
> The main patch (1/44) doing the change is split into many subpatches
> for easier review (2-42).  They should be squashed together when
> applying.

For all the drm driver patches:

Acked-by: Daniel Vetter <daniel.vetter at ffwll.ch>

Should I pull these in through drm-misc, or do you prefer to merge them
through a special topic branch (with everything else) instead on your own?
-Daniel

> 
> 
> Rebased on v4.7-rc5.
> 
> For easier testing the patchset is available here:
> repo:   https://github.com/krzk/linux
> branch: for-next/dma-attrs-const-v5
> 
> 
> Changes since v4
> ================
> 1. Collect some acks. Still need more.
> 2. Minor fixes pointed by Robin Murphy.
> 3. Applied changes from Bart Van Assche's comment.
> 4. More tests and builds (using https://www.kernel.org/pub/tools/crosstool/).
> 
> 
> Changes since v3
> ================
> 1. Collect some acks.
> 2. Drop wrong patch 1/45 ("powerpc: dma-mapping: Don't hard-code
>    the value of DMA_ATTR_WEAK_ORDERING").
> 3. Minor fix pointed out by Michael Ellerman.
> 
> 
> Changes since v2
> ================
> 1. Follow Christoph Hellwig's comments (don't use BIT add
>    documentation, remove dma_get_attr).
> 
> 
> Rationale
> =========
> The dma-mapping core and the implementations do not change the
> DMA attributes passed by pointer.  Thus the pointer can point to const
> data.  However the attributes do not have to be a bitfield. Instead
> unsigned long will do fine:
> 
> 1. This is just simpler.  Both in terms of reading the code and setting
>    attributes.  Instead of initializing local attributes on the stack
>    and passing pointer to it to dma_set_attr(), just set the bits.
> 
> 2. It brings safeness and checking for const correctness because the
>    attributes are passed by value.
> 
> 
> Best regards,
> Krzysztof
> 
> 
> Krzysztof Kozlowski (44):
>   dma-mapping: Use unsigned long for dma_attrs
>   alpha: dma-mapping: Use unsigned long for dma_attrs
>   arc: dma-mapping: Use unsigned long for dma_attrs
>   ARM: dma-mapping: Use unsigned long for dma_attrs
>   arm64: dma-mapping: Use unsigned long for dma_attrs
>   avr32: dma-mapping: Use unsigned long for dma_attrs
>   blackfin: dma-mapping: Use unsigned long for dma_attrs
>   c6x: dma-mapping: Use unsigned long for dma_attrs
>   cris: dma-mapping: Use unsigned long for dma_attrs
>   frv: dma-mapping: Use unsigned long for dma_attrs
>   drm/exynos: dma-mapping: Use unsigned long for dma_attrs
>   drm/mediatek: dma-mapping: Use unsigned long for dma_attrs
>   drm/msm: dma-mapping: Use unsigned long for dma_attrs
>   drm/nouveau: dma-mapping: Use unsigned long for dma_attrs
>   drm/rockship: dma-mapping: Use unsigned long for dma_attrs
>   infiniband: dma-mapping: Use unsigned long for dma_attrs
>   iommu: dma-mapping: Use unsigned long for dma_attrs
>   [media] dma-mapping: Use unsigned long for dma_attrs
>   xen: dma-mapping: Use unsigned long for dma_attrs
>   swiotlb: dma-mapping: Use unsigned long for dma_attrs
>   powerpc: dma-mapping: Use unsigned long for dma_attrs
>   video: dma-mapping: Use unsigned long for dma_attrs
>   x86: dma-mapping: Use unsigned long for dma_attrs
>   iommu: intel: dma-mapping: Use unsigned long for dma_attrs
>   h8300: dma-mapping: Use unsigned long for dma_attrs
>   hexagon: dma-mapping: Use unsigned long for dma_attrs
>   ia64: dma-mapping: Use unsigned long for dma_attrs
>   m68k: dma-mapping: Use unsigned long for dma_attrs
>   metag: dma-mapping: Use unsigned long for dma_attrs
>   microblaze: dma-mapping: Use unsigned long for dma_attrs
>   mips: dma-mapping: Use unsigned long for dma_attrs
>   mn10300: dma-mapping: Use unsigned long for dma_attrs
>   nios2: dma-mapping: Use unsigned long for dma_attrs
>   openrisc: dma-mapping: Use unsigned long for dma_attrs
>   parisc: dma-mapping: Use unsigned long for dma_attrs
>   misc: mic: dma-mapping: Use unsigned long for dma_attrs
>   s390: dma-mapping: Use unsigned long for dma_attrs
>   sh: dma-mapping: Use unsigned long for dma_attrs
>   sparc: dma-mapping: Use unsigned long for dma_attrs
>   tile: dma-mapping: Use unsigned long for dma_attrs
>   unicore32: dma-mapping: Use unsigned long for dma_attrs
>   xtensa: dma-mapping: Use unsigned long for dma_attrs
>   dma-mapping: Remove dma_get_attr
>   dma-mapping: Document the DMA attributes next to the declaration
> 
>  Documentation/DMA-API.txt                          |  33 +++---
>  Documentation/DMA-attributes.txt                   |   2 +-
>  arch/alpha/include/asm/dma-mapping.h               |   2 -
>  arch/alpha/kernel/pci-noop.c                       |   2 +-
>  arch/alpha/kernel/pci_iommu.c                      |  12 +-
>  arch/arc/mm/dma.c                                  |  12 +-
>  arch/arm/common/dmabounce.c                        |   4 +-
>  arch/arm/include/asm/dma-mapping.h                 |  13 +--
>  arch/arm/include/asm/xen/page-coherent.h           |  16 +--
>  arch/arm/mm/dma-mapping.c                          | 117 +++++++++----------
>  arch/arm/xen/mm.c                                  |   8 +-
>  arch/arm64/mm/dma-mapping.c                        |  66 +++++------
>  arch/avr32/mm/dma-coherent.c                       |  12 +-
>  arch/blackfin/kernel/dma-mapping.c                 |   8 +-
>  arch/c6x/include/asm/dma-mapping.h                 |   4 +-
>  arch/c6x/kernel/dma.c                              |   9 +-
>  arch/c6x/mm/dma-coherent.c                         |   4 +-
>  arch/cris/arch-v32/drivers/pci/dma.c               |   9 +-
>  arch/frv/mb93090-mb00/pci-dma-nommu.c              |   8 +-
>  arch/frv/mb93090-mb00/pci-dma.c                    |   9 +-
>  arch/h8300/kernel/dma.c                            |   8 +-
>  arch/hexagon/include/asm/dma-mapping.h             |   1 -
>  arch/hexagon/kernel/dma.c                          |   8 +-
>  arch/ia64/hp/common/sba_iommu.c                    |  22 ++--
>  arch/ia64/include/asm/machvec.h                    |   1 -
>  arch/ia64/kernel/pci-swiotlb.c                     |   4 +-
>  arch/ia64/sn/pci/pci_dma.c                         |  22 ++--
>  arch/m68k/kernel/dma.c                             |  12 +-
>  arch/metag/kernel/dma.c                            |  16 +--
>  arch/microblaze/include/asm/dma-mapping.h          |   1 -
>  arch/microblaze/kernel/dma.c                       |  12 +-
>  arch/mips/cavium-octeon/dma-octeon.c               |   8 +-
>  arch/mips/loongson64/common/dma-swiotlb.c          |  10 +-
>  arch/mips/mm/dma-default.c                         |  20 ++--
>  arch/mips/netlogic/common/nlm-dma.c                |   4 +-
>  arch/mn10300/mm/dma-alloc.c                        |   8 +-
>  arch/nios2/mm/dma-mapping.c                        |  12 +-
>  arch/openrisc/kernel/dma.c                         |  21 ++--
>  arch/parisc/kernel/pci-dma.c                       |  18 +--
>  arch/powerpc/include/asm/dma-mapping.h             |   7 +-
>  arch/powerpc/include/asm/iommu.h                   |  10 +-
>  arch/powerpc/kernel/dma-iommu.c                    |  12 +-
>  arch/powerpc/kernel/dma.c                          |  18 +--
>  arch/powerpc/kernel/ibmebus.c                      |  12 +-
>  arch/powerpc/kernel/iommu.c                        |  12 +-
>  arch/powerpc/kernel/vio.c                          |  12 +-
>  arch/powerpc/platforms/cell/iommu.c                |  28 ++---
>  arch/powerpc/platforms/pasemi/iommu.c              |   2 +-
>  arch/powerpc/platforms/powernv/npu-dma.c           |   8 +-
>  arch/powerpc/platforms/powernv/pci-ioda.c          |   4 +-
>  arch/powerpc/platforms/powernv/pci.c               |   2 +-
>  arch/powerpc/platforms/powernv/pci.h               |   2 +-
>  arch/powerpc/platforms/ps3/system-bus.c            |  18 +--
>  arch/powerpc/platforms/pseries/iommu.c             |   6 +-
>  arch/powerpc/sysdev/dart_iommu.c                   |   2 +-
>  arch/s390/include/asm/dma-mapping.h                |   1 -
>  arch/s390/pci/pci_dma.c                            |  23 ++--
>  arch/sh/include/asm/dma-mapping.h                  |   4 +-
>  arch/sh/kernel/dma-nommu.c                         |   4 +-
>  arch/sh/mm/consistent.c                            |   4 +-
>  arch/sparc/kernel/iommu.c                          |  12 +-
>  arch/sparc/kernel/ioport.c                         |  24 ++--
>  arch/sparc/kernel/pci_sun4v.c                      |  12 +-
>  arch/tile/kernel/pci-dma.c                         |  28 ++---
>  arch/unicore32/mm/dma-swiotlb.c                    |   4 +-
>  arch/x86/include/asm/dma-mapping.h                 |   5 +-
>  arch/x86/include/asm/swiotlb.h                     |   4 +-
>  arch/x86/include/asm/xen/page-coherent.h           |   9 +-
>  arch/x86/kernel/amd_gart_64.c                      |  20 ++--
>  arch/x86/kernel/pci-calgary_64.c                   |  14 +--
>  arch/x86/kernel/pci-dma.c                          |   4 +-
>  arch/x86/kernel/pci-nommu.c                        |   4 +-
>  arch/x86/kernel/pci-swiotlb.c                      |   4 +-
>  arch/x86/pci/sta2x11-fixup.c                       |   2 +-
>  arch/x86/pci/vmd.c                                 |  16 +--
>  arch/xtensa/kernel/pci-dma.c                       |  12 +-
>  drivers/gpu/drm/exynos/exynos_drm_fbdev.c          |   2 +-
>  drivers/gpu/drm/exynos/exynos_drm_g2d.c            |  12 +-
>  drivers/gpu/drm/exynos/exynos_drm_gem.c            |  20 ++--
>  drivers/gpu/drm/exynos/exynos_drm_gem.h            |   2 +-
>  drivers/gpu/drm/mediatek/mtk_drm_gem.c             |  13 +--
>  drivers/gpu/drm/mediatek/mtk_drm_gem.h             |   2 +-
>  drivers/gpu/drm/msm/msm_drv.c                      |  13 +--
>  .../gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c    |  13 +--
>  drivers/gpu/drm/rockchip/rockchip_drm_gem.c        |  17 ++-
>  drivers/gpu/drm/rockchip/rockchip_drm_gem.h        |   2 +-
>  drivers/infiniband/core/umem.c                     |   7 +-
>  drivers/iommu/amd_iommu.c                          |  12 +-
>  drivers/iommu/dma-iommu.c                          |   8 +-
>  drivers/iommu/intel-iommu.c                        |  12 +-
>  drivers/media/platform/sti/bdisp/bdisp-hw.c        |  26 ++---
>  drivers/media/v4l2-core/videobuf2-dma-contig.c     |  30 ++---
>  drivers/media/v4l2-core/videobuf2-dma-sg.c         |  19 +--
>  drivers/misc/mic/host/mic_boot.c                   |  20 ++--
>  drivers/parisc/ccio-dma.c                          |  16 +--
>  drivers/parisc/sba_iommu.c                         |  16 +--
>  drivers/video/fbdev/omap2/omapfb/omapfb-main.c     |  12 +-
>  drivers/video/fbdev/omap2/omapfb/omapfb.h          |   3 +-
>  drivers/xen/swiotlb-xen.c                          |  14 +--
>  include/linux/dma-attrs.h                          |  71 ------------
>  include/linux/dma-iommu.h                          |   6 +-
>  include/linux/dma-mapping.h                        | 128 ++++++++++++++-------
>  include/linux/swiotlb.h                            |  10 +-
>  include/media/videobuf2-dma-contig.h               |   7 +-
>  include/rdma/ib_verbs.h                            |   8 +-
>  include/xen/swiotlb-xen.h                          |  12 +-
>  lib/dma-noop.c                                     |   9 +-
>  lib/swiotlb.c                                      |  13 ++-
>  108 files changed, 689 insertions(+), 789 deletions(-)
>  delete mode 100644 include/linux/dma-attrs.h
> 
> -- 
> 1.9.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch


From k.kozlowski at samsung.com  Tue Jul 12 05:19:07 2016
From: k.kozlowski at samsung.com (Krzysztof Kozlowski)
Date: Tue, 12 Jul 2016 14:19:07 +0200
Subject: [PATCH v5 00/44] dma-mapping: Use unsigned long for dma_attrs
In-Reply-To: <20160712121625.GP23520@phenom.ffwll.local>
References: <1467275019-30789-1-git-send-email-k.kozlowski@samsung.com>
 <20160712121625.GP23520@phenom.ffwll.local>
Message-ID: <5784E03B.6060000@samsung.com>

On 07/12/2016 02:16 PM, Daniel Vetter wrote:
> On Thu, Jun 30, 2016 at 10:23:39AM +0200, Krzysztof Kozlowski wrote:
>> Hi,
>>
>>
>> This is fifth approach for replacing struct dma_attrs with unsigned
>> long.
>>
>> The main patch (1/44) doing the change is split into many subpatches
>> for easier review (2-42).  They should be squashed together when
>> applying.
> 
> For all the drm driver patches:
> 
> Acked-by: Daniel Vetter <daniel.vetter at ffwll.ch>
> 
> Should I pull these in through drm-misc, or do you prefer to merge them
> through a special topic branch (with everything else) instead on your own?
> -Daniel

Thanks. I saw today that Andrew Morton applied the patchset so I think
he will handle it.

Best regards,
Krzysztof



From daniel at ffwll.ch  Tue Jul 12 05:47:27 2016
From: daniel at ffwll.ch (Daniel Vetter)
Date: Tue, 12 Jul 2016 14:47:27 +0200
Subject: [patch] drm/mediatek/mtk_mipi_tx: checking the wrong variable
In-Reply-To: <f665b4b4-c7b3-f07a-4185-fe551d334623@gmail.com>
References: <20160701135934.GA15723@mwanda>
 <f665b4b4-c7b3-f07a-4185-fe551d334623@gmail.com>
Message-ID: <20160712124727.GX23520@phenom.ffwll.local>

On Sat, Jul 02, 2016 at 06:44:13PM +0200, Matthias Brugger wrote:
> 
> 
> On 07/01/2016 03:59 PM, Dan Carpenter wrote:
> > We should be checking "phy_provider" here not "phy".
> > 
> > Fixes: 2e54c14e310f ('drm/mediatek: Add DSI sub driver')
> > Signed-off-by: Dan Carpenter <dan.carpenter at oracle.com>
> > 
> 
> Reviewed-by: Matthias Brugger <matthias.bgg at gmail.com>

Applied to drm-misc, thanks.
-Daniel

> 
> > diff --git a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
> > index cf8f38d..1c366f8 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
> > @@ -431,7 +431,7 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev)
> >  	phy_set_drvdata(phy, mipi_tx);
> > 
> >  	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
> > -	if (IS_ERR(phy)) {
> > +	if (IS_ERR(phy_provider)) {
> >  		ret = PTR_ERR(phy_provider);
> >  		return ret;
> >  	}
> > 
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch


From davem at davemloft.net  Tue Jul 12 11:08:18 2016
From: davem at davemloft.net (David Miller)
Date: Tue, 12 Jul 2016 11:08:18 -0700 (PDT)
Subject: [PATCH -next] net: mediatek: fix non static symbol warnings
In-Reply-To: <1468323404-2193-1-git-send-email-weiyj_lk@163.com>
References: <1468323404-2193-1-git-send-email-weiyj_lk@163.com>
Message-ID: <20160712.110818.2218245588469646537.davem@davemloft.net>

From: weiyj_lk at 163.com
Date: Tue, 12 Jul 2016 11:36:44 +0000

> From: Wei Yongjun <yongjun_wei at trendmicro.com.cn>
> 
> Fixes the following sparse warnings:
> 
> drivers/net/ethernet/mediatek/mtk_eth_soc.c:79:5: warning:
>  symbol '_mtk_mdio_write' was not declared. Should it be static?
> drivers/net/ethernet/mediatek/mtk_eth_soc.c:98:5: warning:
>  symbol '_mtk_mdio_read' was not declared. Should it be static?
> 
> Signed-off-by: Wei Yongjun <yongjun_wei at trendmicro.com.cn>

Applied.


From nicolas.dufresne at gmail.com  Tue Jul 12 12:08:31 2016
From: nicolas.dufresne at gmail.com (Nicolas Dufresne)
Date: Tue, 12 Jul 2016 15:08:31 -0400
Subject: [PATCH v3 3/9] DocBook/v4l: Add compressed video formats used
 on MT8173 codec driver
In-Reply-To: <CAOMLVLiZU3D587dSyp2b2v4DV+MS9vh85bA4BoG7ddK6556rbA@mail.gmail.com>
References: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-2-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-3-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-4-git-send-email-tiffany.lin@mediatek.com>
 <5a793171-24a7-4e9e-8bfd-f668c789f8e0@xs4all.nl>
 <1468205771.3725.8.camel@mtksdaap41>
 <CAOMLVLiZU3D587dSyp2b2v4DV+MS9vh85bA4BoG7ddK6556rbA@mail.gmail.com>
Message-ID: <1468350511.8843.16.camel@gmail.com>

Le mardi 12 juillet 2016 ? 16:16 +0800, Wu-Cheng Li (???) a ?crit?:
> Decoder hardware produces MT21 (compressed). Image processor can
> convert it to a format that can be input of display driver. Tiffany.
> When do you plan to upstream image processor (mtk-mdp)?
> >
> > It can be as input format for encoder, MDP and display drivers in
> our
> > platform.
> I remember display driver can only accept uncompressed MT21. Right?
> Basically V4L2_PIX_FMT_MT21 is compressed and is like an opaque
> format. It's not usable until it's decompressed and converted by
> image
> processor.

Previously it was described as MediaTek block mode, and now as a
MediaTek compressed format. It makes me think you have no idea what
this pixel format really is. Is that right ?

The main reason why I keep asking, is that we often find similarities
between what vendor like to call their proprietary formats. Doing the
proper research helps not creating a mess like in Android where you
have a lot of formats that all point to the same format. I believe
there was the same concern when Samsung wanted to introduce their Z-
flip-Z NV12 tile format. In the end they simply provided sufficient
documentation so we could document it and implement software converters
for test and validation purpose.

regards,
Nicolas


From nicolas.dufresne at gmail.com  Tue Jul 12 12:14:02 2016
From: nicolas.dufresne at gmail.com (Nicolas Dufresne)
Date: Tue, 12 Jul 2016 15:14:02 -0400
Subject: [PATCH v3 3/9] DocBook/v4l: Add compressed video formats used
 on MT8173 codec driver
In-Reply-To: <1468350511.8843.16.camel@gmail.com>
References: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-2-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-3-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-4-git-send-email-tiffany.lin@mediatek.com>
 <5a793171-24a7-4e9e-8bfd-f668c789f8e0@xs4all.nl>
 <1468205771.3725.8.camel@mtksdaap41>
 <CAOMLVLiZU3D587dSyp2b2v4DV+MS9vh85bA4BoG7ddK6556rbA@mail.gmail.com>
 <1468350511.8843.16.camel@gmail.com>
Message-ID: <1468350842.8843.18.camel@gmail.com>

Le mardi 12 juillet 2016 ? 15:08 -0400, Nicolas Dufresne a ?crit?:
> Le mardi 12 juillet 2016 ? 16:16 +0800, Wu-Cheng Li (???) a ?crit?:
> > Decoder hardware produces MT21 (compressed). Image processor can
> > convert it to a format that can be input of display driver.
> > Tiffany.
> > When do you plan to upstream image processor (mtk-mdp)?
> > > 
> > > It can be as input format for encoder, MDP and display drivers in
> > our
> > > platform.
> > I remember display driver can only accept uncompressed MT21. Right?
> > Basically V4L2_PIX_FMT_MT21 is compressed and is like an opaque
> > format. It's not usable until it's decompressed and converted by
> > image
> > processor.
> 
> Previously it was described as MediaTek block mode, and now as a
> MediaTek compressed format. It makes me think you have no idea what
> this pixel format really is. Is that right ?
> 
> The main reason why I keep asking, is that we often find similarities
> between what vendor like to call their proprietary formats. Doing the
> proper research helps not creating a mess like in Android where you
> have a lot of formats that all point to the same format. I believe
> there was the same concern when Samsung wanted to introduce their Z-
> flip-Z NV12 tile format. In the end they simply provided sufficient
> documentation so we could document it and implement software
> converters
> for test and validation purpose.

Here's the kind of information we want in the documentation.

https://chromium.googlesource.com/chromium/src/media/+/master/base/vide
o_types.h#40

? // MediaTek proprietary format. MT21 is similar to NV21 except the memory
? // layout and pixel layout (swizzles). 12bpp with Y plane followed by a 2x2
? // interleaved VU plane. Each image contains two buffers -- Y plane and VU
? // plane. Two planes can be non-contiguous in memory. The starting addresses
? // of Y plane and VU plane are 4KB alignment.
? // Suppose image dimension is (width, height). For both Y plane and VU plane:
? // Row pitch = ((width+15)/16) * 16.
? // Plane size = Row pitch * (((height+31)/32)*32)

Now obviously this is incomplete, as the swizzling need to be documented of course.

> 
> regards,
> Nicolas


From ian.arkver.dev at gmail.com  Tue Jul 12 12:31:10 2016
From: ian.arkver.dev at gmail.com (Ian Arkver)
Date: Tue, 12 Jul 2016 20:31:10 +0100
Subject: [PATCH v3 3/9] DocBook/v4l: Add compressed video formats used on
 MT8173 codec driver
In-Reply-To: <1468350842.8843.18.camel@gmail.com>
References: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-2-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-3-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-4-git-send-email-tiffany.lin@mediatek.com>
 <5a793171-24a7-4e9e-8bfd-f668c789f8e0@xs4all.nl>
 <1468205771.3725.8.camel@mtksdaap41>
 <CAOMLVLiZU3D587dSyp2b2v4DV+MS9vh85bA4BoG7ddK6556rbA@mail.gmail.com>
 <1468350511.8843.16.camel@gmail.com> <1468350842.8843.18.camel@gmail.com>
Message-ID: <b2eb532d-5b22-8468-d74e-0b66b9fc69ee@gmail.com>

On 12/07/16 20:14, Nicolas Dufresne wrote:
> Le mardi 12 juillet 2016 ? 15:08 -0400, Nicolas Dufresne a ?crit :
>> Le mardi 12 juillet 2016 ? 16:16 +0800, Wu-Cheng Li (???) a ?crit :
>>> Decoder hardware produces MT21 (compressed). Image processor can
>>> convert it to a format that can be input of display driver.
>>> Tiffany.
>>> When do you plan to upstream image processor (mtk-mdp)?
>>>> It can be as input format for encoder, MDP and display drivers in
>>> our
>>>> platform.
>>> I remember display driver can only accept uncompressed MT21. Right?
>>> Basically V4L2_PIX_FMT_MT21 is compressed and is like an opaque
>>> format. It's not usable until it's decompressed and converted by
>>> image
>>> processor.
>> Previously it was described as MediaTek block mode, and now as a
>> MediaTek compressed format. It makes me think you have no idea what
>> this pixel format really is. Is that right ?
>>
>> The main reason why I keep asking, is that we often find similarities
>> between what vendor like to call their proprietary formats. Doing the
>> proper research helps not creating a mess like in Android where you
>> have a lot of formats that all point to the same format. I believe
>> there was the same concern when Samsung wanted to introduce their Z-
>> flip-Z NV12 tile format. In the end they simply provided sufficient
>> documentation so we could document it and implement software
>> converters
>> for test and validation purpose.
> Here's the kind of information we want in the documentation.
>
> https://chromium.googlesource.com/chromium/src/media/+/master/base/vide
> o_types.h#40
>
>    // MediaTek proprietary format. MT21 is similar to NV21 except the memory
>    // layout and pixel layout (swizzles). 12bpp with Y plane followed by a 2x2
>    // interleaved VU plane. Each image contains two buffers -- Y plane and VU
>    // plane. Two planes can be non-contiguous in memory. The starting addresses
>    // of Y plane and VU plane are 4KB alignment.
>    // Suppose image dimension is (width, height). For both Y plane and VU plane:
>    // Row pitch = ((width+15)/16) * 16.
>    // Plane size = Row pitch * (((height+31)/32)*32)
>
> Now obviously this is incomplete, as the swizzling need to be documented of course.
Not sure where that chromium comment came from, but if MT21 really is 
similar to NV21 (a 4:2:0 format) and has 2x2 downsampled chroma, then 
the combined VU plane will be half the size of the Y plane.

Maybe that's not relevant to this discussion.

Regards,
Ian
>
>> regards,
>> Nicolas
> --
> 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



From tiffany.lin at mediatek.com  Tue Jul 12 18:50:54 2016
From: tiffany.lin at mediatek.com (tiffany lin)
Date: Wed, 13 Jul 2016 09:50:54 +0800
Subject: [PATCH v3 3/9] DocBook/v4l: Add compressed video formats used
 on MT8173 codec driver
In-Reply-To: <1468350511.8843.16.camel@gmail.com>
References: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-2-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-3-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-4-git-send-email-tiffany.lin@mediatek.com>
 <5a793171-24a7-4e9e-8bfd-f668c789f8e0@xs4all.nl>
 <1468205771.3725.8.camel@mtksdaap41>
 <CAOMLVLiZU3D587dSyp2b2v4DV+MS9vh85bA4BoG7ddK6556rbA@mail.gmail.com>
 <1468350511.8843.16.camel@gmail.com>
Message-ID: <1468374654.2462.17.camel@mtksdaap41>

Hi Nicolas,

On Tue, 2016-07-12 at 15:08 -0400, Nicolas Dufresne wrote:
> Le mardi 12 juillet 2016 ? 16:16 +0800, Wu-Cheng Li (???) a ?crit :
> > Decoder hardware produces MT21 (compressed). Image processor can
> > convert it to a format that can be input of display driver. Tiffany.
> > When do you plan to upstream image processor (mtk-mdp)?
> > >
> > > It can be as input format for encoder, MDP and display drivers in
> > our
> > > platform.
> > I remember display driver can only accept uncompressed MT21. Right?
> > Basically V4L2_PIX_FMT_MT21 is compressed and is like an opaque
> > format. It's not usable until it's decompressed and converted by
> > image
> > processor.
> 
> Previously it was described as MediaTek block mode, and now as a
> MediaTek compressed format. It makes me think you have no idea what
> this pixel format really is. Is that right ?
> 
That's not right.
Its a compressed format as I document in "[PATCH v3 3/9] DocBook/v4l:
Add compressed video formats used on MT8173 codec driver."
In MT8173 platform, when using this format, we need Image Processor to
cover it to standard format as wucheng mentioned.
To prevent this ambiguous, I will change it to V4L2_PIX_FMT_M21C, it
means its compressed data. Is it ok?

best regards,
Tiffany

> The main reason why I keep asking, is that we often find similarities
> between what vendor like to call their proprietary formats. Doing the
> proper research helps not creating a mess like in Android where you
> have a lot of formats that all point to the same format. I believe
> there was the same concern when Samsung wanted to introduce their Z-
> flip-Z NV12 tile format. In the end they simply provided sufficient
> documentation so we could document it and implement software converters
> for test and validation purpose.
> 
> regards,
> Nicolas




From tiffany.lin at mediatek.com  Tue Jul 12 19:00:09 2016
From: tiffany.lin at mediatek.com (tiffany lin)
Date: Wed, 13 Jul 2016 10:00:09 +0800
Subject: [PATCH v3 3/9] DocBook/v4l: Add compressed video formats used
 on MT8173 codec driver
In-Reply-To: <1468350842.8843.18.camel@gmail.com>
References: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-2-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-3-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-4-git-send-email-tiffany.lin@mediatek.com>
 <5a793171-24a7-4e9e-8bfd-f668c789f8e0@xs4all.nl>
 <1468205771.3725.8.camel@mtksdaap41>
 <CAOMLVLiZU3D587dSyp2b2v4DV+MS9vh85bA4BoG7ddK6556rbA@mail.gmail.com>
 <1468350511.8843.16.camel@gmail.com> <1468350842.8843.18.camel@gmail.com>
Message-ID: <1468375209.2462.20.camel@mtksdaap41>

Hi Nicolas,

On Tue, 2016-07-12 at 15:14 -0400, Nicolas Dufresne wrote:
> Le mardi 12 juillet 2016 ? 15:08 -0400, Nicolas Dufresne a ?crit :
> > Le mardi 12 juillet 2016 ? 16:16 +0800, Wu-Cheng Li (???) a ?crit :
> > > Decoder hardware produces MT21 (compressed). Image processor can
> > > convert it to a format that can be input of display driver.
> > > Tiffany.
> > > When do you plan to upstream image processor (mtk-mdp)?
> > > > 
> > > > It can be as input format for encoder, MDP and display drivers in
> > > our
> > > > platform.
> > > I remember display driver can only accept uncompressed MT21. Right?
> > > Basically V4L2_PIX_FMT_MT21 is compressed and is like an opaque
> > > format. It's not usable until it's decompressed and converted by
> > > image
> > > processor.
> > 
> > Previously it was described as MediaTek block mode, and now as a
> > MediaTek compressed format. It makes me think you have no idea what
> > this pixel format really is. Is that right ?
> > 
> > The main reason why I keep asking, is that we often find similarities
> > between what vendor like to call their proprietary formats. Doing the
> > proper research helps not creating a mess like in Android where you
> > have a lot of formats that all point to the same format. I believe
> > there was the same concern when Samsung wanted to introduce their Z-
> > flip-Z NV12 tile format. In the end they simply provided sufficient
> > documentation so we could document it and implement software
> > converters
> > for test and validation purpose.
> 
> Here's the kind of information we want in the documentation.
> 
> https://chromium.googlesource.com/chromium/src/media/+/master/base/vide
> o_types.h#40
> 
>   // MediaTek proprietary format. MT21 is similar to NV21 except the memory
>   // layout and pixel layout (swizzles). 12bpp with Y plane followed by a 2x2
>   // interleaved VU plane. Each image contains two buffers -- Y plane and VU
>   // plane. Two planes can be non-contiguous in memory. The starting addresses
>   // of Y plane and VU plane are 4KB alignment.
>   // Suppose image dimension is (width, height). For both Y plane and VU plane:
>   // Row pitch = ((width+15)/16) * 16.
>   // Plane size = Row pitch * (((height+31)/32)*32)
> 
> Now obviously this is incomplete, as the swizzling need to be documented of course.
> 
Because it's finally a compressed format from our codec hw, we cannot
describe its swizzling.

best regards,
Tiffany

> > 
> > regards,
> > Nicolas




From wuchengli at chromium.org  Tue Jul 12 19:22:20 2016
From: wuchengli at chromium.org (=?UTF-8?B?V3UtQ2hlbmcgTGkgKOadjuWLmeiqoCk=?=)
Date: Wed, 13 Jul 2016 10:22:20 +0800
Subject: [PATCH v3 3/9] DocBook/v4l: Add compressed video formats used on
 MT8173 codec driver
In-Reply-To: <1468350842.8843.18.camel@gmail.com>
References: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-2-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-3-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-4-git-send-email-tiffany.lin@mediatek.com>
 <5a793171-24a7-4e9e-8bfd-f668c789f8e0@xs4all.nl>
 <1468205771.3725.8.camel@mtksdaap41>
 <CAOMLVLiZU3D587dSyp2b2v4DV+MS9vh85bA4BoG7ddK6556rbA@mail.gmail.com>
 <1468350511.8843.16.camel@gmail.com> <1468350842.8843.18.camel@gmail.com>
Message-ID: <CAOMLVLhQFCbn6RFcT3Gv0SnY5Y_=ANek2hOzC69UAiK9Zk8VRg@mail.gmail.com>

On Wed, Jul 13, 2016 at 3:14 AM, Nicolas Dufresne
<nicolas.dufresne at gmail.com> wrote:
> Le mardi 12 juillet 2016 ? 15:08 -0400, Nicolas Dufresne a ?crit :
>> Le mardi 12 juillet 2016 ? 16:16 +0800, Wu-Cheng Li (???) a ?crit :
>> > Decoder hardware produces MT21 (compressed). Image processor can
>> > convert it to a format that can be input of display driver.
>> > Tiffany.
>> > When do you plan to upstream image processor (mtk-mdp)?
>> > >
>> > > It can be as input format for encoder, MDP and display drivers in
>> > our
>> > > platform.
>> > I remember display driver can only accept uncompressed MT21. Right?
>> > Basically V4L2_PIX_FMT_MT21 is compressed and is like an opaque
>> > format. It's not usable until it's decompressed and converted by
>> > image
>> > processor.
>>
>> Previously it was described as MediaTek block mode, and now as a
>> MediaTek compressed format. It makes me think you have no idea what
>> this pixel format really is. Is that right ?
>>
>> The main reason why I keep asking, is that we often find similarities
>> between what vendor like to call their proprietary formats. Doing the
>> proper research helps not creating a mess like in Android where you
>> have a lot of formats that all point to the same format. I believe
>> there was the same concern when Samsung wanted to introduce their Z-
>> flip-Z NV12 tile format. In the end they simply provided sufficient
>> documentation so we could document it and implement software
>> converters
>> for test and validation purpose.
>
> Here's the kind of information we want in the documentation.
>
> https://chromium.googlesource.com/chromium/src/media/+/master/base/vide
> o_types.h#40
That is the documentation of decompressed MT21. Originally MT21 was meant
to be a YUV format and we can map it in CPU to use it. The name was changed
to mean a compressed format. The current design is only MTK image processor
can convert it. Software cannot decompress it. I'm not sure if we
should document
the format inside if we cannot decompress in software. For chromium, I'll update
the code to explain MT21 is an opaque compressed format.
>
>   // MediaTek proprietary format. MT21 is similar to NV21 except the memory
>   // layout and pixel layout (swizzles). 12bpp with Y plane followed by a 2x2
>   // interleaved VU plane. Each image contains two buffers -- Y plane and VU
>   // plane. Two planes can be non-contiguous in memory. The starting addresses
>   // of Y plane and VU plane are 4KB alignment.
>   // Suppose image dimension is (width, height). For both Y plane and VU plane:
>   // Row pitch = ((width+15)/16) * 16.
>   // Plane size = Row pitch * (((height+31)/32)*32)
>
> Now obviously this is incomplete, as the swizzling need to be documented of course.
>
>>
>> regards,
>> Nicolas


From tiffany.lin at mediatek.com  Tue Jul 12 19:03:08 2016
From: tiffany.lin at mediatek.com (tiffany lin)
Date: Wed, 13 Jul 2016 10:03:08 +0800
Subject: [PATCH v3 3/9] DocBook/v4l: Add compressed video formats used
 on MT8173 codec driver
In-Reply-To: <CAOMLVLiZU3D587dSyp2b2v4DV+MS9vh85bA4BoG7ddK6556rbA@mail.gmail.com>
References: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-2-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-3-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-4-git-send-email-tiffany.lin@mediatek.com>
 <5a793171-24a7-4e9e-8bfd-f668c789f8e0@xs4all.nl>
 <1468205771.3725.8.camel@mtksdaap41>
 <CAOMLVLiZU3D587dSyp2b2v4DV+MS9vh85bA4BoG7ddK6556rbA@mail.gmail.com>
Message-ID: <1468375388.2462.22.camel@mtksdaap41>

On Tue, 2016-07-12 at 16:16 +0800, Wu-Cheng Li (???) wrote:
> On Mon, Jul 11, 2016 at 10:56 AM, tiffany lin <tiffany.lin at mediatek.com> wrote:
> > Hi Hans,
> >
> > On Fri, 2016-07-08 at 12:23 +0200, Hans Verkuil wrote:
> >> On 05/30/2016 02:29 PM, Tiffany Lin wrote:
> >> > Add V4L2_PIX_FMT_MT21 documentation
> >> >
> >> > Signed-off-by: Tiffany Lin <tiffany.lin at mediatek.com>
> >> > ---
> >> >  Documentation/DocBook/media/v4l/pixfmt.xml |    6 ++++++
> >> >  1 file changed, 6 insertions(+)
> >> >
> >> > diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml
> >> > index 5a08aee..d40e0ce 100644
> >> > --- a/Documentation/DocBook/media/v4l/pixfmt.xml
> >> > +++ b/Documentation/DocBook/media/v4l/pixfmt.xml
> >> > @@ -1980,6 +1980,12 @@ array. Anything what's in between the UYVY lines is JPEG data and should be
> >> >  concatenated to form the JPEG stream. </para>
> >> >  </entry>
> >> >       </row>
> >> > +     <row id="V4L2_PIX_FMT_MT21">
> >> > +       <entry><constant>V4L2_PIX_FMT_MT21</constant></entry>
> >> > +       <entry>'MT21'</entry>
> >> > +       <entry>Compressed two-planar YVU420 format used by Mediatek MT8173
> >> > +       codec driver.</entry>
> >>
> >> Can you give a few more details? The encoder driver doesn't seem to produce this
> >> format, so who is creating this? Where is this format documented?
> Decoder hardware produces MT21 (compressed). Image processor can
> convert it to a format that can be input of display driver. Tiffany.
> When do you plan to upstream image processor (mtk-mdp)?
> >
We are working on this. Will upstream soon.

> > It can be as input format for encoder, MDP and display drivers in our
> > platform.
> I remember display driver can only accept uncompressed MT21. Right?
> Basically V4L2_PIX_FMT_MT21 is compressed and is like an opaque
> format. It's not usable until it's decompressed and converted by image
> processor.
That's right in MT8173 platform.

best regards,
Tiffany
> > This private format is only available in our platform.
> > So I put it in "Reserved Format Identifiers" sections.
> >
> >
> > best regards,
> > Tiffany
> >
> >> Regards,
> >>
> >>       Hans
> >>
> >> > +     </row>
> >> >     </tbody>
> >> >        </tgroup>
> >> >      </table>
> >> >
> >
> >
> > --
> > 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




From henryc.chen at mediatek.com  Tue Jul 12 20:34:28 2016
From: henryc.chen at mediatek.com (Henry Chen)
Date: Wed, 13 Jul 2016 11:34:28 +0800
Subject: [RESEND PATCH] soc: mediatek: PMIC wrap: Extend the waiting time to
 10ms.
Message-ID: <1468380868-16683-1-git-send-email-henryc.chen@mediatek.com>

Read data fails sometimes because of a timeout that PMIC cannot transfer data
to PMIC wrap on time, extend the waiting time to 10ms to reduce the failed
rate.

Signed-off-by: Henry Chen <henryc.chen at mediatek.com>
---
Resend to fixed the typo on commit message
---
 drivers/soc/mediatek/mtk-pmic-wrap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
index a003ba2..a5f1093 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -583,7 +583,7 @@ static int pwrap_wait_for_state(struct pmic_wrapper *wrp,
 {
 	unsigned long timeout;
 
-	timeout = jiffies + usecs_to_jiffies(255);
+	timeout = jiffies + usecs_to_jiffies(10000);
 
 	do {
 		if (time_after(jiffies, timeout))
-- 
1.8.1.1.dirty



From chunfeng.yun at mediatek.com  Tue Jul 12 22:40:11 2016
From: chunfeng.yun at mediatek.com (chunfeng yun)
Date: Wed, 13 Jul 2016 13:40:11 +0800
Subject: Add MediaTek USB3 DRD Driver
In-Reply-To: <1465960040-768-1-git-send-email-chunfeng.yun@mediatek.com>
References: <1465960040-768-1-git-send-email-chunfeng.yun@mediatek.com>
Message-ID: <1468388411.29220.4.camel@mhfsdcap03>

Hi Felipe:

Could you please give me some suggestions if you have already reviewed
some codes.

Thanks a lot.


On Wed, 2016-06-15 at 11:07 +0800, Chunfeng Yun wrote:
> From 48552e96e4e33f8830cb6a59154fe148425532fd Mon Sep 17 00:00:00 2001
> From: Chunfeng Yun <chunfeng.yun at mediatek.com>
> Date: Wed, 15 Jun 2016 10:58:10 +0800
> Subject: [PATCH v4,0/5] Add MediaTek USB3 DRD Driver
> 
> These patches introduce the MediaTek USB3 dual-role controller
> driver.
> 
> The driver can be configured as Dual-Role Device (DRD),
> Peripheral Only and Host Only (xHCI) modes. It works well
> with Mass Storage, RNDIS and g_zero on FS/HS and SS. And it is
> tested on MT8173 platform which only contains USB2.0 device IP,
> and on MT6290 platform which contains USB3.0 device IP.
> 
> Change in v4:
> 1. fix build errors on non-mediatek platforms
> 2. provide manual dual-role switch via debugfs instead of sysfs
> 

> --
> 1.7.9.5
> 
> 




From tiffany.lin at mediatek.com  Wed Jul 13 01:05:23 2016
From: tiffany.lin at mediatek.com (Tiffany Lin)
Date: Wed, 13 Jul 2016 16:05:23 +0800
Subject: [PATCH] [media] mtk-vcodec: fix default OUTPUT buffer size
Message-ID: <1468397123-9808-1-git-send-email-tiffany.lin@mediatek.com>

When calculate OUTPUT buffer size in vidioc_try_fmt, it will
add more size hw need in each plane.
But in mtk_vcodec_enc_set_default_params, it do not add
same size in each plane.
This makes v4l2-compliance test fail.
This patch fix the issue.

Signed-off-by: Tiffany Lin <tiffany.lin at mediatek.com>
---
 drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c |   13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
index 907a6d1..3ed3f2d 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
@@ -328,10 +328,11 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct mtk_video_fmt *fmt)
 			pix_fmt_mp->height += 32;
 
 		mtk_v4l2_debug(0,
-			"before resize width=%d, height=%d, after resize width=%d, height=%d, sizeimage=%d",
+			"before resize width=%d, height=%d, after resize width=%d, height=%d, sizeimage=%d %d",
 			tmp_w, tmp_h, pix_fmt_mp->width,
 			pix_fmt_mp->height,
-			pix_fmt_mp->width * pix_fmt_mp->height);
+			pix_fmt_mp->plane_fmt[0].sizeimage,
+			pix_fmt_mp->plane_fmt[1].sizeimage);
 
 		pix_fmt_mp->num_planes = fmt->num_planes;
 		pix_fmt_mp->plane_fmt[0].sizeimage =
@@ -1166,9 +1167,13 @@ void mtk_vcodec_enc_set_default_params(struct mtk_vcodec_ctx *ctx)
 		(q_data->coded_height + 32) <= MTK_VENC_MAX_H)
 		q_data->coded_height += 32;
 
-	q_data->sizeimage[0] = q_data->coded_width * q_data->coded_height;
+	q_data->sizeimage[0] =
+		q_data->coded_width * q_data->coded_height+
+		((ALIGN(q_data->coded_width, 16) * 2) * 16);
 	q_data->bytesperline[0] = q_data->coded_width;
-	q_data->sizeimage[1] = q_data->sizeimage[0] / 2;
+	q_data->sizeimage[1] =
+		(q_data->coded_width * q_data->coded_height) / 2 +
+		(ALIGN(q_data->coded_width, 16) * 16);
 	q_data->bytesperline[1] = q_data->coded_width;
 
 	q_data = &ctx->q_data[MTK_Q_DATA_DST];
-- 
1.7.9.5



From k.kozlowski at samsung.com  Wed Jul 13 01:39:27 2016
From: k.kozlowski at samsung.com (Krzysztof Kozlowski)
Date: Wed, 13 Jul 2016 10:39:27 +0200
Subject: [PATCH v6 00/46] dma-mapping: Use unsigned long for dma_attrs
Message-ID: <1468399167-28083-1-git-send-email-k.kozlowski@samsung.com>

Hi,

The fifth version of this patchset was merged by Andrew Morton
few days ago.  It was rebased on v4.7-rc5 so it missed some ongoing
changes.

This is just rebase on next-20160713.


For easier testing the patchset is available here:
repo:   https://github.com/krzk/linux
branch: for-next/dma-attrs-const-v6


Changes since v5
================
1. New patches:
   1/46:  [media] mtk-vcodec: Remove unused dma_attrs
   44/46: remoteproc: qcom: Use unsigned long for dma_attrs
2. 19/46: rebased on next, some more changes inside
3. Added accumulated acks: Marek Szyprowski, Richard Kuo,
   Konrad Rzeszutek Wilk, Daniel Vetter and Joerg Roedel.


Changes since v4
================
1. Collect some acks. Still need more.
2. Minor fixes pointed by Robin Murphy.
3. Applied changes from Bart Van Assche's comment.
4. More tests and builds (using https://www.kernel.org/pub/tools/crosstool/).


Changes since v3
================
1. Collect some acks.
2. Drop wrong patch 1/45 ("powerpc: dma-mapping: Don't hard-code
   the value of DMA_ATTR_WEAK_ORDERING").
3. Minor fix pointed out by Michael Ellerman.


Changes since v2
================
1. Follow Christoph Hellwig's comments (don't use BIT add
   documentation, remove dma_get_attr).


Rationale
=========
The dma-mapping core and the implementations do not change the
DMA attributes passed by pointer.  Thus the pointer can point to const
data.  However the attributes do not have to be a bitfield. Instead
unsigned long will do fine:

1. This is just simpler.  Both in terms of reading the code and setting
   attributes.  Instead of initializing local attributes on the stack
   and passing pointer to it to dma_set_attr(), just set the bits.

2. It brings safeness and checking for const correctness because the
   attributes are passed by value.


Best regards,
Krzysztof


Krzysztof Kozlowski (46):
  [media] mtk-vcodec: Remove unused dma_attrs
  dma-mapping: Use unsigned long for dma_attrs
  alpha: dma-mapping: Use unsigned long for dma_attrs
  arc: dma-mapping: Use unsigned long for dma_attrs
  ARM: dma-mapping: Use unsigned long for dma_attrs
  arm64: dma-mapping: Use unsigned long for dma_attrs
  avr32: dma-mapping: Use unsigned long for dma_attrs
  blackfin: dma-mapping: Use unsigned long for dma_attrs
  c6x: dma-mapping: Use unsigned long for dma_attrs
  cris: dma-mapping: Use unsigned long for dma_attrs
  frv: dma-mapping: Use unsigned long for dma_attrs
  drm/exynos: dma-mapping: Use unsigned long for dma_attrs
  drm/mediatek: dma-mapping: Use unsigned long for dma_attrs
  drm/msm: dma-mapping: Use unsigned long for dma_attrs
  drm/nouveau: dma-mapping: Use unsigned long for dma_attrs
  drm/rockship: dma-mapping: Use unsigned long for dma_attrs
  infiniband: dma-mapping: Use unsigned long for dma_attrs
  iommu: dma-mapping: Use unsigned long for dma_attrs
  [media] dma-mapping: Use unsigned long for dma_attrs
  xen: dma-mapping: Use unsigned long for dma_attrs
  swiotlb: dma-mapping: Use unsigned long for dma_attrs
  powerpc: dma-mapping: Use unsigned long for dma_attrs
  video: dma-mapping: Use unsigned long for dma_attrs
  x86: dma-mapping: Use unsigned long for dma_attrs
  iommu: intel: dma-mapping: Use unsigned long for dma_attrs
  h8300: dma-mapping: Use unsigned long for dma_attrs
  hexagon: dma-mapping: Use unsigned long for dma_attrs
  ia64: dma-mapping: Use unsigned long for dma_attrs
  m68k: dma-mapping: Use unsigned long for dma_attrs
  metag: dma-mapping: Use unsigned long for dma_attrs
  microblaze: dma-mapping: Use unsigned long for dma_attrs
  mips: dma-mapping: Use unsigned long for dma_attrs
  mn10300: dma-mapping: Use unsigned long for dma_attrs
  nios2: dma-mapping: Use unsigned long for dma_attrs
  openrisc: dma-mapping: Use unsigned long for dma_attrs
  parisc: dma-mapping: Use unsigned long for dma_attrs
  misc: mic: dma-mapping: Use unsigned long for dma_attrs
  s390: dma-mapping: Use unsigned long for dma_attrs
  sh: dma-mapping: Use unsigned long for dma_attrs
  sparc: dma-mapping: Use unsigned long for dma_attrs
  tile: dma-mapping: Use unsigned long for dma_attrs
  unicore32: dma-mapping: Use unsigned long for dma_attrs
  xtensa: dma-mapping: Use unsigned long for dma_attrs
  remoteproc: qcom: Use unsigned long for dma_attrs
  dma-mapping: Remove dma_get_attr
  dma-mapping: Document the DMA attributes next to the declaration

 Documentation/DMA-API.txt                          |  33 +++---
 Documentation/DMA-attributes.txt                   |   2 +-
 arch/alpha/include/asm/dma-mapping.h               |   2 -
 arch/alpha/kernel/pci-noop.c                       |   2 +-
 arch/alpha/kernel/pci_iommu.c                      |  12 +-
 arch/arc/mm/dma.c                                  |  12 +-
 arch/arm/common/dmabounce.c                        |   4 +-
 arch/arm/include/asm/dma-mapping.h                 |  13 +--
 arch/arm/include/asm/xen/page-coherent.h           |  16 +--
 arch/arm/mm/dma-mapping.c                          | 117 +++++++++----------
 arch/arm/xen/mm.c                                  |   8 +-
 arch/arm64/mm/dma-mapping.c                        |  66 +++++------
 arch/avr32/mm/dma-coherent.c                       |  12 +-
 arch/blackfin/kernel/dma-mapping.c                 |   8 +-
 arch/c6x/include/asm/dma-mapping.h                 |   4 +-
 arch/c6x/kernel/dma.c                              |   9 +-
 arch/c6x/mm/dma-coherent.c                         |   4 +-
 arch/cris/arch-v32/drivers/pci/dma.c               |   9 +-
 arch/frv/mb93090-mb00/pci-dma-nommu.c              |   8 +-
 arch/frv/mb93090-mb00/pci-dma.c                    |   9 +-
 arch/h8300/kernel/dma.c                            |   8 +-
 arch/hexagon/include/asm/dma-mapping.h             |   1 -
 arch/hexagon/kernel/dma.c                          |   8 +-
 arch/ia64/hp/common/sba_iommu.c                    |  22 ++--
 arch/ia64/include/asm/machvec.h                    |   1 -
 arch/ia64/kernel/pci-swiotlb.c                     |   4 +-
 arch/ia64/sn/pci/pci_dma.c                         |  22 ++--
 arch/m68k/kernel/dma.c                             |  12 +-
 arch/metag/kernel/dma.c                            |  16 +--
 arch/microblaze/include/asm/dma-mapping.h          |   1 -
 arch/microblaze/kernel/dma.c                       |  12 +-
 arch/mips/cavium-octeon/dma-octeon.c               |   8 +-
 arch/mips/loongson64/common/dma-swiotlb.c          |  10 +-
 arch/mips/mm/dma-default.c                         |  20 ++--
 arch/mips/netlogic/common/nlm-dma.c                |   4 +-
 arch/mn10300/mm/dma-alloc.c                        |   8 +-
 arch/nios2/mm/dma-mapping.c                        |  12 +-
 arch/openrisc/kernel/dma.c                         |  21 ++--
 arch/parisc/kernel/pci-dma.c                       |  18 +--
 arch/powerpc/include/asm/dma-mapping.h             |   7 +-
 arch/powerpc/include/asm/iommu.h                   |  10 +-
 arch/powerpc/kernel/dma-iommu.c                    |  12 +-
 arch/powerpc/kernel/dma.c                          |  18 +--
 arch/powerpc/kernel/ibmebus.c                      |  12 +-
 arch/powerpc/kernel/iommu.c                        |  12 +-
 arch/powerpc/kernel/vio.c                          |  12 +-
 arch/powerpc/platforms/cell/iommu.c                |  28 ++---
 arch/powerpc/platforms/pasemi/iommu.c              |   2 +-
 arch/powerpc/platforms/powernv/npu-dma.c           |   8 +-
 arch/powerpc/platforms/powernv/pci-ioda.c          |   4 +-
 arch/powerpc/platforms/powernv/pci.c               |   2 +-
 arch/powerpc/platforms/powernv/pci.h               |   2 +-
 arch/powerpc/platforms/ps3/system-bus.c            |  18 +--
 arch/powerpc/platforms/pseries/iommu.c             |   6 +-
 arch/powerpc/sysdev/dart_iommu.c                   |   2 +-
 arch/s390/include/asm/dma-mapping.h                |   1 -
 arch/s390/pci/pci_dma.c                            |  23 ++--
 arch/sh/include/asm/dma-mapping.h                  |   4 +-
 arch/sh/kernel/dma-nommu.c                         |   4 +-
 arch/sh/mm/consistent.c                            |   4 +-
 arch/sparc/kernel/iommu.c                          |  12 +-
 arch/sparc/kernel/ioport.c                         |  24 ++--
 arch/sparc/kernel/pci_sun4v.c                      |  12 +-
 arch/tile/kernel/pci-dma.c                         |  28 ++---
 arch/unicore32/mm/dma-swiotlb.c                    |   4 +-
 arch/x86/include/asm/dma-mapping.h                 |   5 +-
 arch/x86/include/asm/swiotlb.h                     |   4 +-
 arch/x86/include/asm/xen/page-coherent.h           |   9 +-
 arch/x86/kernel/amd_gart_64.c                      |  20 ++--
 arch/x86/kernel/pci-calgary_64.c                   |  14 +--
 arch/x86/kernel/pci-dma.c                          |   4 +-
 arch/x86/kernel/pci-nommu.c                        |   4 +-
 arch/x86/kernel/pci-swiotlb.c                      |   4 +-
 arch/x86/pci/sta2x11-fixup.c                       |   2 +-
 arch/x86/pci/vmd.c                                 |  16 +--
 arch/xtensa/kernel/pci-dma.c                       |  12 +-
 drivers/gpu/drm/exynos/exynos_drm_fbdev.c          |   2 +-
 drivers/gpu/drm/exynos/exynos_drm_g2d.c            |  12 +-
 drivers/gpu/drm/exynos/exynos_drm_gem.c            |  20 ++--
 drivers/gpu/drm/exynos/exynos_drm_gem.h            |   2 +-
 drivers/gpu/drm/mediatek/mtk_drm_gem.c             |  13 +--
 drivers/gpu/drm/mediatek/mtk_drm_gem.h             |   2 +-
 drivers/gpu/drm/msm/msm_drv.c                      |  13 +--
 .../gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c    |  13 +--
 drivers/gpu/drm/rockchip/rockchip_drm_gem.c        |  17 ++-
 drivers/gpu/drm/rockchip/rockchip_drm_gem.h        |   2 +-
 drivers/infiniband/core/umem.c                     |   7 +-
 drivers/iommu/amd_iommu.c                          |  12 +-
 drivers/iommu/dma-iommu.c                          |   8 +-
 drivers/iommu/intel-iommu.c                        |  12 +-
 .../media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c |   4 -
 drivers/media/platform/sti/bdisp/bdisp-hw.c        |  26 ++---
 drivers/media/v4l2-core/videobuf2-dma-contig.c     |  28 ++---
 drivers/media/v4l2-core/videobuf2-dma-sg.c         |  21 +---
 drivers/media/v4l2-core/videobuf2-vmalloc.c        |   2 +-
 drivers/misc/mic/host/mic_boot.c                   |  20 ++--
 drivers/parisc/ccio-dma.c                          |  16 +--
 drivers/parisc/sba_iommu.c                         |  16 +--
 drivers/remoteproc/qcom_q6v5_pil.c                 |   7 +-
 drivers/video/fbdev/omap2/omapfb/omapfb-main.c     |  12 +-
 drivers/video/fbdev/omap2/omapfb/omapfb.h          |   3 +-
 drivers/xen/swiotlb-xen.c                          |  14 +--
 include/linux/dma-attrs.h                          |  71 ------------
 include/linux/dma-iommu.h                          |   6 +-
 include/linux/dma-mapping.h                        | 128 ++++++++++++++-------
 include/linux/swiotlb.h                            |  10 +-
 include/media/videobuf2-core.h                     |   6 +-
 include/media/videobuf2-dma-contig.h               |   2 -
 include/rdma/ib_verbs.h                            |   8 +-
 include/xen/swiotlb-xen.h                          |  12 +-
 lib/dma-noop.c                                     |   9 +-
 lib/swiotlb.c                                      |  13 ++-
 112 files changed, 694 insertions(+), 798 deletions(-)
 delete mode 100644 include/linux/dma-attrs.h

-- 
1.9.1



From k.kozlowski at samsung.com  Wed Jul 13 01:40:52 2016
From: k.kozlowski at samsung.com (Krzysztof Kozlowski)
Date: Wed, 13 Jul 2016 10:40:52 +0200
Subject: [PATCH v6 01/46] [media] mtk-vcodec: Remove unused dma_attrs
In-Reply-To: <1468399167-28083-1-git-send-email-k.kozlowski@samsung.com>
References: <1468399167-28083-1-git-send-email-k.kozlowski@samsung.com>
Message-ID: <1468399300-5399-1-git-send-email-k.kozlowski@samsung.com>

The local variable dma_attrs is set but never read.

Signed-off-by: Krzysztof Kozlowski <k.kozlowski at samsung.com>

---

Changes since v5:
New patch.
---
 drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
index 60b0bde232f4..ae1eb8fde7f8 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
@@ -246,7 +246,6 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
 	struct video_device *vfd_enc;
 	struct resource *res;
 	int i, j, ret;
-	DEFINE_DMA_ATTRS(attrs);
 
 	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
 	if (!dev)
@@ -380,9 +379,6 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
 		goto err_enc_reg;
 	}
 
-	/* Avoid the iommu eat big hunks */
-	dma_set_attr(DMA_ATTR_ALLOC_SINGLE_PAGES, &attrs);
-
 	mtk_v4l2_debug(0, "encoder registered as /dev/video%d",
 			vfd_enc->num);
 
-- 
1.9.1



From k.kozlowski at samsung.com  Wed Jul 13 01:41:04 2016
From: k.kozlowski at samsung.com (Krzysztof Kozlowski)
Date: Wed, 13 Jul 2016 10:41:04 +0200
Subject: [PATCH v6 13/46] drm/mediatek: dma-mapping: Use unsigned long for
 dma_attrs
In-Reply-To: <1468399300-5399-12-git-send-email-k.kozlowski@samsung.com>
References: <1468399167-28083-1-git-send-email-k.kozlowski@samsung.com>
 <1468399300-5399-1-git-send-email-k.kozlowski@samsung.com>
 <1468399300-5399-2-git-send-email-k.kozlowski@samsung.com>
 <1468399300-5399-3-git-send-email-k.kozlowski@samsung.com>
 <1468399300-5399-4-git-send-email-k.kozlowski@samsung.com>
 <1468399300-5399-5-git-send-email-k.kozlowski@samsung.com>
 <1468399300-5399-6-git-send-email-k.kozlowski@samsung.com>
 <1468399300-5399-7-git-send-email-k.kozlowski@samsung.com>
 <1468399300-5399-8-git-send-email-k.kozlowski@samsung.com>
 <1468399300-5399-9-git-send-email-k.kozlowski@samsung.com>
 <1468399300-5399-10-git-send-email-k.kozlowski@samsung.com>
 <1468399300-5399-11-git-send-email-k.kozlowski@samsung.com>
 <1468399300-5399-12-git-send-email-k.kozlowski@samsung.com>
Message-ID: <1468399300-5399-13-git-send-email-k.kozlowski@samsung.com>

Split out subsystem specific changes for easier reviews. This will be
squashed with main commit.

Signed-off-by: Krzysztof Kozlowski <k.kozlowski at samsung.com>
[for drm]
Acked-by: Daniel Vetter <daniel.vetter at ffwll.ch>
---
 drivers/gpu/drm/mediatek/mtk_drm_gem.c | 13 ++++++-------
 drivers/gpu/drm/mediatek/mtk_drm_gem.h |  2 +-
 2 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_gem.c b/drivers/gpu/drm/mediatek/mtk_drm_gem.c
index fa2ec0cd00e8..7abc550ebc00 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_gem.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_gem.c
@@ -54,15 +54,14 @@ struct mtk_drm_gem_obj *mtk_drm_gem_create(struct drm_device *dev,
 
 	obj = &mtk_gem->base;
 
-	init_dma_attrs(&mtk_gem->dma_attrs);
-	dma_set_attr(DMA_ATTR_WRITE_COMBINE, &mtk_gem->dma_attrs);
+	mtk_gem->dma_attrs = DMA_ATTR_WRITE_COMBINE;
 
 	if (!alloc_kmap)
-		dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &mtk_gem->dma_attrs);
+		mtk_gem->dma_attrs |= DMA_ATTR_NO_KERNEL_MAPPING;
 
 	mtk_gem->cookie = dma_alloc_attrs(priv->dma_dev, obj->size,
 					  &mtk_gem->dma_addr, GFP_KERNEL,
-					  &mtk_gem->dma_attrs);
+					  mtk_gem->dma_attrs);
 	if (!mtk_gem->cookie) {
 		DRM_ERROR("failed to allocate %zx byte dma buffer", obj->size);
 		ret = -ENOMEM;
@@ -93,7 +92,7 @@ void mtk_drm_gem_free_object(struct drm_gem_object *obj)
 		drm_prime_gem_destroy(obj, mtk_gem->sg);
 	else
 		dma_free_attrs(priv->dma_dev, obj->size, mtk_gem->cookie,
-			       mtk_gem->dma_addr, &mtk_gem->dma_attrs);
+			       mtk_gem->dma_addr, mtk_gem->dma_attrs);
 
 	/* release file pointer to gem object. */
 	drm_gem_object_release(obj);
@@ -173,7 +172,7 @@ static int mtk_drm_gem_object_mmap(struct drm_gem_object *obj,
 	vma->vm_pgoff = 0;
 
 	ret = dma_mmap_attrs(priv->dma_dev, vma, mtk_gem->cookie,
-			     mtk_gem->dma_addr, obj->size, &mtk_gem->dma_attrs);
+			     mtk_gem->dma_addr, obj->size, mtk_gem->dma_attrs);
 	if (ret)
 		drm_gem_vm_close(vma);
 
@@ -224,7 +223,7 @@ struct sg_table *mtk_gem_prime_get_sg_table(struct drm_gem_object *obj)
 
 	ret = dma_get_sgtable_attrs(priv->dma_dev, sgt, mtk_gem->cookie,
 				    mtk_gem->dma_addr, obj->size,
-				    &mtk_gem->dma_attrs);
+				    mtk_gem->dma_attrs);
 	if (ret) {
 		DRM_ERROR("failed to allocate sgt, %d\n", ret);
 		kfree(sgt);
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_gem.h b/drivers/gpu/drm/mediatek/mtk_drm_gem.h
index 3a2a5624a1cb..2752718fa5b2 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_gem.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_gem.h
@@ -35,7 +35,7 @@ struct mtk_drm_gem_obj {
 	void			*cookie;
 	void			*kvaddr;
 	dma_addr_t		dma_addr;
-	struct dma_attrs	dma_attrs;
+	unsigned long		dma_attrs;
 	struct sg_table		*sg;
 };
 
-- 
1.9.1



From arnd at arndb.de  Wed Jul 13 01:47:40 2016
From: arnd at arndb.de (Arnd Bergmann)
Date: Wed, 13 Jul 2016 10:47:40 +0200
Subject: [PATCH v2] [media] mtk-vcodec: fix more type mismatches
Message-ID: <20160713084916.2765651-1-arnd@arndb.de>

The newly added mtk-vcodec driver produces a number of warnings in an ARM
allmodconfig build, mainly since it assumes that dma_addr_t is 32-bit wide:

mtk-vcodec/venc/venc_vp8_if.c: In function 'vp8_enc_alloc_work_buf':
mtk-vcodec/venc/venc_vp8_if.c:212:191: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
mtk-vcodec/venc/venc_h264_if.c: In function 'h264_enc_alloc_work_buf':
mtk-vcodec/venc/venc_h264_if.c:297:190: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]

This rearranges the format strings and type casts to what they should have been
in order to avoid the warnings. e0f80d8d62f5 ("[media] mtk-vcodec: fix two compiler
warnings") fixed some of the problems that were introduced at the same time, but
missed two others.

Signed-off-by: Arnd Bergmann <arnd at arndb.de>
---
 drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c | 4 ++--
 drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c  | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
index f4e18bb44cb9..9a600525b3c1 100644
--- a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
+++ b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
@@ -295,9 +295,9 @@ static int h264_enc_alloc_work_buf(struct venc_h264_inst *inst)
 		wb[i].iova = inst->work_bufs[i].dma_addr;
 
 		mtk_vcodec_debug(inst,
-				 "work_buf[%d] va=0x%p iova=0x%p size=%zu",
+				 "work_buf[%d] va=0x%p iova=%pad size=%zu",
 				 i, inst->work_bufs[i].va,
-				 (void *)inst->work_bufs[i].dma_addr,
+				 &inst->work_bufs[i].dma_addr,
 				 inst->work_bufs[i].size);
 	}
 
diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
index 5b4ef0f1740c..60bbcd2a0510 100644
--- a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
+++ b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
@@ -210,9 +210,9 @@ static int vp8_enc_alloc_work_buf(struct venc_vp8_inst *inst)
 		wb[i].iova = inst->work_bufs[i].dma_addr;
 
 		mtk_vcodec_debug(inst,
-				 "work_bufs[%d] va=0x%p,iova=0x%p,size=%zu",
+				 "work_bufs[%d] va=0x%p,iova=%pad,size=%zu",
 				 i, inst->work_bufs[i].va,
-				 (void *)inst->work_bufs[i].dma_addr,
+				 &inst->work_bufs[i].dma_addr,
 				 inst->work_bufs[i].size);
 	}
 
-- 
2.9.0



From tiffany.lin at mediatek.com  Wed Jul 13 02:56:26 2016
From: tiffany.lin at mediatek.com (tiffany lin)
Date: Wed, 13 Jul 2016 17:56:26 +0800
Subject: [PATCH] [media] mtk-vcodec: fix type mismatches
In-Reply-To: <20160711213959.2481081-1-arnd@arndb.de>
References: <20160711213959.2481081-1-arnd@arndb.de>
Message-ID: <1468403786.32454.16.camel@mtksdaap41>

Hi Arnd,

On Mon, 2016-07-11 at 23:37 +0200, Arnd Bergmann wrote:
> The newly added mtk-vcodec driver produces a number of warnings in an ARM
> allmodconfig build, mainly since it assumes that dma_addr_t is 32-bit wide:
> 
> mtk-vcodec/venc/venc_vp8_if.c: In function 'vp8_enc_alloc_work_buf':
> mtk-vcodec/venc/venc_vp8_if.c:212:191: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
> mtk-vcodec/venc/venc_h264_if.c: In function 'h264_enc_alloc_work_buf':
> mtk-vcodec/venc/venc_h264_if.c:297:190: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
> mtk-vcodec/mtk_vcodec_enc.c: In function 'mtk_venc_worker':
> mtk-vcodec/mtk_vcodec_enc.c:1030:46: error: format '%lx' expects argument of type 'long unsigned int', but argument 7 has type 'size_t {aka unsigned int}' [-Werror=format=]
>   mtk_v4l2_debug(2,
> mtk-vcodec/mtk_vcodec_enc.c:1030:46: error: format '%lx' expects argument of type 'long unsigned int', but argument 10 has type 'size_t {aka unsigned int}' [-Werror=format=]
> mtk-vcodec/venc_vpu_if.c: In function 'vpu_enc_ipi_handler':
> mtk-vcodec/venc_vpu_if.c:40:30: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
>   struct venc_vpu_inst *vpu = (struct venc_vpu_inst *)msg->venc_inst;
> 
> This rearranges the format strings and type casts to what they should have been
> in order to avoid the warnings.
> 
> Signed-off-by: Arnd Bergmann <arnd at arndb.de>
> ---
>  drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c    | 8 ++++----
>  drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c | 4 ++--
>  drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c  | 4 ++--
>  drivers/media/platform/mtk-vcodec/venc_vpu_if.c       | 4 ++--
>  4 files changed, 10 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
> index 6dcae0a0a1f2..0b25a8700877 100644
> --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
> +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
> @@ -1028,15 +1028,15 @@ static void mtk_venc_worker(struct work_struct *work)
>  	bs_buf.size = (size_t)dst_buf->planes[0].length;
>  
>  	mtk_v4l2_debug(2,
> -			"Framebuf VA=%p PA=%llx Size=0x%lx;VA=%p PA=0x%llx Size=0x%lx;VA=%p PA=0x%llx Size=%zu",
> +			"Framebuf VA=%p PA=%pad Size=0x%zx;VA=%p PA=%pad Size=0x%zx;VA=%p PA=%pad Size=0x%zx",
>  			frm_buf.fb_addr[0].va,
> -			(u64)frm_buf.fb_addr[0].dma_addr,
> +			&frm_buf.fb_addr[0].dma_addr,
>  			frm_buf.fb_addr[0].size,
>  			frm_buf.fb_addr[1].va,
> -			(u64)frm_buf.fb_addr[1].dma_addr,
> +			&frm_buf.fb_addr[1].dma_addr,
>  			frm_buf.fb_addr[1].size,
>  			frm_buf.fb_addr[2].va,
> -			(u64)frm_buf.fb_addr[2].dma_addr,
> +			&frm_buf.fb_addr[2].dma_addr,
>  			frm_buf.fb_addr[2].size);
This change will make debug message dump address of dma_addr field but
not the value of the dma_addr we want.
How about change it from
PA=%llx -> PA=%u
(u64)frm_buf.fb_addr[0].dma_addr -> (u32)frm_buf.fb_addr[0].dma_addr,

>  
>  	ret = venc_if_encode(ctx, VENC_START_OPT_ENCODE_FRAME,
> diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
> index f4e18bb44cb9..9a600525b3c1 100644
> --- a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
> +++ b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
> @@ -295,9 +295,9 @@ static int h264_enc_alloc_work_buf(struct venc_h264_inst *inst)
>  		wb[i].iova = inst->work_bufs[i].dma_addr;
>  
>  		mtk_vcodec_debug(inst,
> -				 "work_buf[%d] va=0x%p iova=0x%p size=%zu",
> +				 "work_buf[%d] va=0x%p iova=%pad size=%zu",
>  				 i, inst->work_bufs[i].va,
> -				 (void *)inst->work_bufs[i].dma_addr,
> +				 &inst->work_bufs[i].dma_addr,
>  				 inst->work_bufs[i].size);
>  	}
>  
Same as above.

best regards,
Tiffany

> diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
> index 431ae706a427..5b35aa1900d7 100644
> --- a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
> +++ b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
> @@ -210,9 +210,9 @@ static int vp8_enc_alloc_work_buf(struct venc_vp8_inst *inst)
>  		wb[i].iova = inst->work_bufs[i].dma_addr;
>  
>  		mtk_vcodec_debug(inst,
> -				 "work_bufs[%d] va=0x%p,iova=0x%p,size=%zu",
> +				 "work_bufs[%d] va=0x%p,iova=%pad,size=%zu",
>  				 i, inst->work_bufs[i].va,
> -				 (void *)inst->work_bufs[i].dma_addr,
> +				 &inst->work_bufs[i].dma_addr,
>  				 inst->work_bufs[i].size);
>  	}
>  
> diff --git a/drivers/media/platform/mtk-vcodec/venc_vpu_if.c b/drivers/media/platform/mtk-vcodec/venc_vpu_if.c
> index b92c6d2a892d..8907b02729fa 100644
> --- a/drivers/media/platform/mtk-vcodec/venc_vpu_if.c
> +++ b/drivers/media/platform/mtk-vcodec/venc_vpu_if.c
> @@ -37,7 +37,7 @@ static void handle_enc_encode_msg(struct venc_vpu_inst *vpu, void *data)
>  static void vpu_enc_ipi_handler(void *data, unsigned int len, void *priv)
>  {
>  	struct venc_vpu_ipi_msg_common *msg = data;
> -	struct venc_vpu_inst *vpu = (struct venc_vpu_inst *)msg->venc_inst;
> +	struct venc_vpu_inst *vpu = (struct venc_vpu_inst *)(uintptr_t)msg->venc_inst;
>  
>  	mtk_vcodec_debug(vpu, "msg_id %x inst %p status %d",
>  			 msg->msg_id, vpu, msg->status);
> @@ -112,7 +112,7 @@ int vpu_enc_init(struct venc_vpu_inst *vpu)
>  
>  	memset(&out, 0, sizeof(out));
>  	out.msg_id = AP_IPIMSG_ENC_INIT;
> -	out.venc_inst = (unsigned long)vpu;
> +	out.venc_inst = (uintptr_t)vpu;
>  	if (vpu_enc_send_msg(vpu, &out, sizeof(out))) {
>  		mtk_vcodec_err(vpu, "AP_IPIMSG_ENC_INIT fail");
>  		return -EINVAL;




From pochun.lin at mediatek.com  Wed Jul 13 03:52:43 2016
From: pochun.lin at mediatek.com (pochun lin)
Date: Wed, 13 Jul 2016 18:52:43 +0800
Subject: [PATCH v2] [media] mtk-vcodec: fix more type mismatches
In-Reply-To: <20160713084916.2765651-1-arnd@arndb.de>
References: <20160713084916.2765651-1-arnd@arndb.de>
Message-ID: <1468407163.3555.1.camel@mtksdaap41>

Hi Arnd,

On Wed, 2016-07-13 at 10:47 +0200, Arnd Bergmann wrote:
> The newly added mtk-vcodec driver produces a number of warnings in an ARM
> allmodconfig build, mainly since it assumes that dma_addr_t is 32-bit wide:
> 
> mtk-vcodec/venc/venc_vp8_if.c: In function 'vp8_enc_alloc_work_buf':
> mtk-vcodec/venc/venc_vp8_if.c:212:191: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
> mtk-vcodec/venc/venc_h264_if.c: In function 'h264_enc_alloc_work_buf':
> mtk-vcodec/venc/venc_h264_if.c:297:190: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
> 
> This rearranges the format strings and type casts to what they should have been
> in order to avoid the warnings. e0f80d8d62f5 ("[media] mtk-vcodec: fix two compiler
> warnings") fixed some of the problems that were introduced at the same time, but
> missed two others.
> 
> Signed-off-by: Arnd Bergmann <arnd at arndb.de>
> ---
>  drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c | 4 ++--
>  drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c  | 4 ++--
>  2 files changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
> index f4e18bb44cb9..9a600525b3c1 100644
> --- a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
> +++ b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
> @@ -295,9 +295,9 @@ static int h264_enc_alloc_work_buf(struct venc_h264_inst *inst)
>  		wb[i].iova = inst->work_bufs[i].dma_addr;
>  
>  		mtk_vcodec_debug(inst,
> -				 "work_buf[%d] va=0x%p iova=0x%p size=%zu",
> +				 "work_buf[%d] va=0x%p iova=%pad size=%zu",
>  				 i, inst->work_bufs[i].va,
> -				 (void *)inst->work_bufs[i].dma_addr,
> +				 &inst->work_bufs[i].dma_addr,
>  				 inst->work_bufs[i].size);
>  	}
>  

This modified will dump dma_addr's address, not dma_addr value.
In actually, we need to dump dma_addr value.
Thanks.

> diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
> index 5b4ef0f1740c..60bbcd2a0510 100644
> --- a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
> +++ b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
> @@ -210,9 +210,9 @@ static int vp8_enc_alloc_work_buf(struct venc_vp8_inst *inst)
>  		wb[i].iova = inst->work_bufs[i].dma_addr;
>  
>  		mtk_vcodec_debug(inst,
> -				 "work_bufs[%d] va=0x%p,iova=0x%p,size=%zu",
> +				 "work_bufs[%d] va=0x%p,iova=%pad,size=%zu",
>  				 i, inst->work_bufs[i].va,
> -				 (void *)inst->work_bufs[i].dma_addr,
> +				 &inst->work_bufs[i].dma_addr,
>  				 inst->work_bufs[i].size);
>  	}
>  

The same as above.

Best Regards
PoChun




From weiyj_lk at 163.com  Wed Jul 13 05:44:41 2016
From: weiyj_lk at 163.com (weiyj_lk at 163.com)
Date: Wed, 13 Jul 2016 12:44:41 +0000
Subject: [PATCH -next] drm/mediatek/mtk_mipi_tx: remove redundant dev_err call
 in mtk_mipi_tx_probe()
Message-ID: <1468413881-2588-1-git-send-email-weiyj_lk@163.com>

From: Wei Yongjun <yongjun_wei at trendmicro.com.cn>

There is a error message within devm_ioremap_resource
already, so remove the dev_err call to avoid redundant
error message.

Signed-off-by: Wei Yongjun <yongjun_wei at trendmicro.com.cn>
---
 drivers/gpu/drm/mediatek/mtk_mipi_tx.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
index 1c366f8..b835bba 100644
--- a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
+++ b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
@@ -393,11 +393,8 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev)
 
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	mipi_tx->regs = devm_ioremap_resource(dev, mem);
-	if (IS_ERR(mipi_tx->regs)) {
-		ret = PTR_ERR(mipi_tx->regs);
-		dev_err(dev, "Failed to get memory resource: %d\n", ret);
-		return ret;
-	}
+	if (IS_ERR(mipi_tx->regs))
+		return PTR_ERR(mipi_tx->regs);
 
 	ref_clk = devm_clk_get(dev, NULL);
 	if (IS_ERR(ref_clk)) {






From arnd at arndb.de  Wed Jul 13 06:08:09 2016
From: arnd at arndb.de (Arnd Bergmann)
Date: Wed, 13 Jul 2016 15:08:09 +0200
Subject: [PATCH] [media] mtk-vcodec: fix type mismatches
In-Reply-To: <1468403786.32454.16.camel@mtksdaap41>
References: <20160711213959.2481081-1-arnd@arndb.de>
 <1468403786.32454.16.camel@mtksdaap41>
Message-ID: <4915511.9pXBipIRF8@wuerfel>

On Wednesday, July 13, 2016 5:56:26 PM CEST tiffany lin wrote:
> > diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
> > index 6dcae0a0a1f2..0b25a8700877 100644
> > --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
> > +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
> > @@ -1028,15 +1028,15 @@ static void mtk_venc_worker(struct work_struct *work)
> >       bs_buf.size = (size_t)dst_buf->planes[0].length;
> >  
> >       mtk_v4l2_debug(2,
> > -                     "Framebuf VA=%p PA=%llx Size=0x%lx;VA=%p PA=0x%llx Size=0x%lx;VA=%p PA=0x%llx Size=%zu",
> > +                     "Framebuf VA=%p PA=%pad Size=0x%zx;VA=%p PA=%pad Size=0x%zx;VA=%p PA=%pad Size=0x%zx",
> >                       frm_buf.fb_addr[0].va,
> > -                     (u64)frm_buf.fb_addr[0].dma_addr,
> > +                     &frm_buf.fb_addr[0].dma_addr,
> >                       frm_buf.fb_addr[0].size,
> >                       frm_buf.fb_addr[1].va,
> > -                     (u64)frm_buf.fb_addr[1].dma_addr,
> > +                     &frm_buf.fb_addr[1].dma_addr,
> >                       frm_buf.fb_addr[1].size,
> >                       frm_buf.fb_addr[2].va,
> > -                     (u64)frm_buf.fb_addr[2].dma_addr,
> > +                     &frm_buf.fb_addr[2].dma_addr,
> >                       frm_buf.fb_addr[2].size);
> This change will make debug message dump address of dma_addr field but
> not the value of the dma_addr we want.
> How about change it from
> PA=%llx -> PA=%u
> (u64)frm_buf.fb_addr[0].dma_addr -> (u32)frm_buf.fb_addr[0].dma_addr,
> 

The %llx works fine with the cast to u64, the change above is mainly for the "%lx"
on a size_t causing a warning.

The change to %pad is done in order to use a consistent output for the
dma_addr_t, which had a leading "0x" in two cases but not in the first
one.

printk interprets %pad as a pointer to a dma_addr_t and prints the
address, not the pointer to it, see Documentation/printk-formats.txt,
which lets you avoid the type cast as well as the 0x.

	Arnd


From arnd at arndb.de  Wed Jul 13 06:17:17 2016
From: arnd at arndb.de (Arnd Bergmann)
Date: Wed, 13 Jul 2016 15:17:17 +0200
Subject: [PATCH v2] [media] mtk-vcodec: fix more type mismatches
In-Reply-To: <1468407163.3555.1.camel@mtksdaap41>
References: <20160713084916.2765651-1-arnd@arndb.de>
 <1468407163.3555.1.camel@mtksdaap41>
Message-ID: <9022784.B8ChAA686D@wuerfel>

On Wednesday, July 13, 2016 6:52:43 PM CEST pochun lin wrote:
> > diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
> > index f4e18bb44cb9..9a600525b3c1 100644
> > --- a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
> > +++ b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
> > @@ -295,9 +295,9 @@ static int h264_enc_alloc_work_buf(struct venc_h264_inst *inst)
> >               wb[i].iova = inst->work_bufs[i].dma_addr;
> >  
> >               mtk_vcodec_debug(inst,
> > -                              "work_buf[%d] va=0x%p iova=0x%p size=%zu",
> > +                              "work_buf[%d] va=0x%p iova=%pad size=%zu",
> >                                i, inst->work_bufs[i].va,
> > -                              (void *)inst->work_bufs[i].dma_addr,
> > +                              &inst->work_bufs[i].dma_addr,
> >                                inst->work_bufs[i].size);
> >       }
> >  
> 
> This modified will dump dma_addr's address, not dma_addr value.
> In actually, we need to dump dma_addr value.

According to Documentation/printk-formats.txt, it gets passed by
reference:

| DMA addresses types dma_addr_t:
|
|        %pad    0x01234567 or 0x0123456789abcdef
|
|        For printing a dma_addr_t type which can vary based on build options,
|        regardless of the width of the CPU data path. Passed by reference.

The whole point of the %pad/%pr/%pM/... format strings is to print
something that cannot be passed by value because the type is not
a fixed-size integer.

	Arnd


From pochun.lin at mediatek.com  Wed Jul 13 06:22:35 2016
From: pochun.lin at mediatek.com (pochun lin)
Date: Wed, 13 Jul 2016 21:22:35 +0800
Subject: [PATCH v2] [media] mtk-vcodec: fix more type mismatches
In-Reply-To: <9022784.B8ChAA686D@wuerfel>
References: <20160713084916.2765651-1-arnd@arndb.de>
 <1468407163.3555.1.camel@mtksdaap41> <9022784.B8ChAA686D@wuerfel>
Message-ID: <1468416155.20788.2.camel@mtksdaap41>

Hi Arnd,

On Wed, 2016-07-13 at 15:17 +0200, Arnd Bergmann wrote:
> On Wednesday, July 13, 2016 6:52:43 PM CEST pochun lin wrote:
> > > diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
> > > index f4e18bb44cb9..9a600525b3c1 100644
> > > --- a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
> > > +++ b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
> > > @@ -295,9 +295,9 @@ static int h264_enc_alloc_work_buf(struct venc_h264_inst *inst)
> > >               wb[i].iova = inst->work_bufs[i].dma_addr;
> > >  
> > >               mtk_vcodec_debug(inst,
> > > -                              "work_buf[%d] va=0x%p iova=0x%p size=%zu",
> > > +                              "work_buf[%d] va=0x%p iova=%pad size=%zu",
> > >                                i, inst->work_bufs[i].va,
> > > -                              (void *)inst->work_bufs[i].dma_addr,
> > > +                              &inst->work_bufs[i].dma_addr,
> > >                                inst->work_bufs[i].size);
> > >       }
> > >  
> > 
> > This modified will dump dma_addr's address, not dma_addr value.
> > In actually, we need to dump dma_addr value.
> 
> According to Documentation/printk-formats.txt, it gets passed by
> reference:
> 
> | DMA addresses types dma_addr_t:
> |
> |        %pad    0x01234567 or 0x0123456789abcdef
> |
> |        For printing a dma_addr_t type which can vary based on build options,
> |        regardless of the width of the CPU data path. Passed by reference.
> 
> The whole point of the %pad/%pr/%pM/... format strings is to print
> something that cannot be passed by value because the type is not
> a fixed-size integer.
> 
> 	Arnd

Got it. And sorry I was wrong.
Thanks your explain clearly.

Best Regards
PoChun



From tiffany.lin at mediatek.com  Wed Jul 13 06:55:21 2016
From: tiffany.lin at mediatek.com (tiffany lin)
Date: Wed, 13 Jul 2016 21:55:21 +0800
Subject: [PATCH] [media] mtk-vcodec: fix type mismatches
In-Reply-To: <4915511.9pXBipIRF8@wuerfel>
References: <20160711213959.2481081-1-arnd@arndb.de>
 <1468403786.32454.16.camel@mtksdaap41> <4915511.9pXBipIRF8@wuerfel>
Message-ID: <1468418121.32454.19.camel@mtksdaap41>

Hi Arnd,

On Wed, 2016-07-13 at 15:08 +0200, Arnd Bergmann wrote:
> On Wednesday, July 13, 2016 5:56:26 PM CEST tiffany lin wrote:
> > > diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
> > > index 6dcae0a0a1f2..0b25a8700877 100644
> > > --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
> > > +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
> > > @@ -1028,15 +1028,15 @@ static void mtk_venc_worker(struct work_struct *work)
> > >       bs_buf.size = (size_t)dst_buf->planes[0].length;
> > >  
> > >       mtk_v4l2_debug(2,
> > > -                     "Framebuf VA=%p PA=%llx Size=0x%lx;VA=%p PA=0x%llx Size=0x%lx;VA=%p PA=0x%llx Size=%zu",
> > > +                     "Framebuf VA=%p PA=%pad Size=0x%zx;VA=%p PA=%pad Size=0x%zx;VA=%p PA=%pad Size=0x%zx",
> > >                       frm_buf.fb_addr[0].va,
> > > -                     (u64)frm_buf.fb_addr[0].dma_addr,
> > > +                     &frm_buf.fb_addr[0].dma_addr,
> > >                       frm_buf.fb_addr[0].size,
> > >                       frm_buf.fb_addr[1].va,
> > > -                     (u64)frm_buf.fb_addr[1].dma_addr,
> > > +                     &frm_buf.fb_addr[1].dma_addr,
> > >                       frm_buf.fb_addr[1].size,
> > >                       frm_buf.fb_addr[2].va,
> > > -                     (u64)frm_buf.fb_addr[2].dma_addr,
> > > +                     &frm_buf.fb_addr[2].dma_addr,
> > >                       frm_buf.fb_addr[2].size);
> > This change will make debug message dump address of dma_addr field but
> > not the value of the dma_addr we want.
> > How about change it from
> > PA=%llx -> PA=%u
> > (u64)frm_buf.fb_addr[0].dma_addr -> (u32)frm_buf.fb_addr[0].dma_addr,
> > 
> 
> The %llx works fine with the cast to u64, the change above is mainly for the "%lx"
> on a size_t causing a warning.
> 
> The change to %pad is done in order to use a consistent output for the
> dma_addr_t, which had a leading "0x" in two cases but not in the first
> one.
> 
> printk interprets %pad as a pointer to a dma_addr_t and prints the
> address, not the pointer to it, see Documentation/printk-formats.txt,
> which lets you avoid the type cast as well as the 0x.
> 
I understood now, I will check Documentation/printk-formats.txt.
Thanks for your explanation.


best regards,
Tiffany

> 	Arnd




From nicolas at ndufresne.ca  Wed Jul 13 06:55:57 2016
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 13 Jul 2016 09:55:57 -0400
Subject: [PATCH v3 3/9] DocBook/v4l: Add compressed video formats used
 on MT8173 codec driver
In-Reply-To: <1468375209.2462.20.camel@mtksdaap41>
References: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-2-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-3-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-4-git-send-email-tiffany.lin@mediatek.com>
 <5a793171-24a7-4e9e-8bfd-f668c789f8e0@xs4all.nl>
 <1468205771.3725.8.camel@mtksdaap41>
 <CAOMLVLiZU3D587dSyp2b2v4DV+MS9vh85bA4BoG7ddK6556rbA@mail.gmail.com>
 <1468350511.8843.16.camel@gmail.com> <1468350842.8843.18.camel@gmail.com>
 <1468375209.2462.20.camel@mtksdaap41>
Message-ID: <1468418157.2867.12.camel@ndufresne.ca>

Le mercredi 13 juillet 2016 ? 10:00 +0800, tiffany lin a ?crit?:
> Hi Nicolas,
> 
> On Tue, 2016-07-12 at 15:14 -0400, Nicolas Dufresne wrote:
> > Le mardi 12 juillet 2016 ? 15:08 -0400, Nicolas Dufresne a ?crit :
> > > Le mardi 12 juillet 2016 ? 16:16 +0800, Wu-Cheng Li (???) a ?crit
> :
> > > > Decoder hardware produces MT21 (compressed). Image processor
> can
> > > > convert it to a format that can be input of display driver.
> > > > Tiffany.
> > > > When do you plan to upstream image processor (mtk-mdp)?
> > > > >?
> > > > > It can be as input format for encoder, MDP and display
> drivers in
> > > > our
> > > > > platform.
> > > > I remember display driver can only accept uncompressed MT21.
> Right?
> > > > Basically V4L2_PIX_FMT_MT21 is compressed and is like an opaque
> > > > format. It's not usable until it's decompressed and converted
> by
> > > > image
> > > > processor.
> > >?
> > > Previously it was described as MediaTek block mode, and now as a
> > > MediaTek compressed format. It makes me think you have no idea
> what
> > > this pixel format really is. Is that right ?
> > >?
> > > The main reason why I keep asking, is that we often find
> similarities
> > > between what vendor like to call their proprietary formats. Doing
> the
> > > proper research helps not creating a mess like in Android where
> you
> > > have a lot of formats that all point to the same format. I
> believe
> > > there was the same concern when Samsung wanted to introduce their
> Z-
> > > flip-Z NV12 tile format. In the end they simply provided
> sufficient
> > > documentation so we could document it and implement software
> > > converters
> > > for test and validation purpose.
> >?
> > Here's the kind of information we want in the documentation.
> >?
> > https://chromium.googlesource.com/chromium/src/media/+/master/base/
> vide
> > o_types.h#40
> >?
> >?? // MediaTek proprietary format. MT21 is similar to NV21 except
> the memory
> >?? // layout and pixel layout (swizzles). 12bpp with Y plane
> followed by a 2x2
> >?? // interleaved VU plane. Each image contains two buffers -- Y
> plane and VU
> >?? // plane. Two planes can be non-contiguous in memory. The
> starting addresses
> >?? // of Y plane and VU plane are 4KB alignment.
> >?? // Suppose image dimension is (width, height). For both Y plane
> and VU plane:
> >?? // Row pitch = ((width+15)/16) * 16.
> >?? // Plane size = Row pitch * (((height+31)/32)*32)
> >?
> > Now obviously this is incomplete, as the swizzling need to be
> documented of course.
> >?
> Because it's finally a compressed format from our codec hw, we cannot
> describe its swizzling.

Can you clarify why it cannot be described ? I don't buy any argument
that it's impossible to convert without hardware. Intel did document
their compressed formats.

Debugging an integration with such format that we have literally
decided to no make public is a pain. A lot of decoder got abandoned or
never used because of that.

It would be nice to explain the architecture you are suggesting to make
this decoder useful. How will userspace application be able to use your
decoder. Will the image processor usable outside the display path ?
People might want to do transcoding, or other relatively common task
that does not imply a display.

regards,
Nicolas

p.s.
A small note to Wu-Cheng, the definition of the DRM format in your
Chromium branch is not correct. DRM uses format modifier, such that the
format is the family, in your case it's most likely NV21, and the
modifier is the compression or tiling algorithm in place (or both as
needed).


From tiffany.lin at mediatek.com  Wed Jul 13 23:27:54 2016
From: tiffany.lin at mediatek.com (tiffany lin)
Date: Thu, 14 Jul 2016 14:27:54 +0800
Subject: [PATCH] vcodec: mediatek: Add g/s_selection support for V4L2
 Encoder
In-Reply-To: <4ca82842-968d-a5e2-587d-752c71713607@xs4all.nl>
References: <1464594768-1993-1-git-send-email-tiffany.lin@mediatek.com>
 <4ca82842-968d-a5e2-587d-752c71713607@xs4all.nl>
Message-ID: <1468477674.32454.36.camel@mtksdaap41>

Hi Hans,


On Mon, 2016-07-11 at 06:32 +0200, Hans Verkuil wrote:
> Hi Tiffany,
> 
> My apologies for the delay, but here is my review at last:
> 
> On 05/30/2016 09:52 AM, Tiffany Lin wrote:
> > This patch add g/s_selection support for MT8173
> > 
> > Signed-off-by: Tiffany Lin <tiffany.lin at mediatek.com>
> > ---
> >  drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c |   74 ++++++++++++++++++++
> >  1 file changed, 74 insertions(+)
> > 
> > diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
> > index 6e72d73..23ef9a1 100644
> > --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
> > +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
> > @@ -630,6 +630,77 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
> >  	return vidioc_try_fmt(f, fmt);
> >  }
> >  
> > +static int vidioc_venc_g_selection(struct file *file, void *priv,
> > +				     struct v4l2_selection *s)
> > +{
> > +	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
> > +	struct mtk_q_data *q_data;
> > +
> > +	/* crop means compose for output devices */
> > +	switch (s->target) {
> > +	case V4L2_SEL_TGT_CROP_DEFAULT:
> > +	case V4L2_SEL_TGT_CROP_BOUNDS:
> > +	case V4L2_SEL_TGT_CROP:
> > +	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
> > +	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
> > +	case V4L2_SEL_TGT_COMPOSE:
> > +		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
> > +			mtk_v4l2_err("Invalid s->type = %d", s->type);
> > +			return -EINVAL;
> > +		}
> > +		break;
> > +	default:
> > +		mtk_v4l2_err("Invalid s->target = %d", s->target);
> > +		return -EINVAL;
> > +	}
> > +
> > +	q_data = mtk_venc_get_q_data(ctx, s->type);
> > +	if (!q_data)
> > +		return -EINVAL;
> > +
> > +	s->r.top = 0;
> > +	s->r.left = 0;
> > +	s->r.width = q_data->visible_width;
> > +	s->r.height = q_data->visible_height;
> > +
> > +	return 0;
> > +}
> > +
> > +static int vidioc_venc_s_selection(struct file *file, void *priv,
> > +				     struct v4l2_selection *s)
> > +{
> > +	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
> > +	struct mtk_q_data *q_data;
> > +
> > +	switch (s->target) {
> > +	case V4L2_SEL_TGT_CROP_DEFAULT:
> > +	case V4L2_SEL_TGT_CROP_BOUNDS:
> > +	case V4L2_SEL_TGT_CROP:
> > +	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
> > +	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
> > +	case V4L2_SEL_TGT_COMPOSE:
> > +		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
> > +			mtk_v4l2_err("Invalid s->type = %d", s->type);
> > +			return -EINVAL;
> > +		}
> > +		break;
> > +	default:
> > +		mtk_v4l2_err("Invalid s->target = %d", s->target);
> > +		return -EINVAL;
> > +	}
> > +
> > +	q_data = mtk_venc_get_q_data(ctx, s->type);
> > +	if (!q_data)
> > +		return -EINVAL;
> > +
> > +	s->r.top = 0;
> > +	s->r.left = 0;
> > +	q_data->visible_width = s->r.width;
> > +	q_data->visible_height = s->r.height;
> 
> This makes no sense.
> 
> See this page:
> 
> https://hverkuil.home.xs4all.nl/spec/media.html#selection-api
> 
> For the video output direction (memory -> HW encoder) the data source is
> the memory, the data sink is the HW encoder. For the video capture direction
> (HW encoder -> memory) the data source is the HW encoder and the data sink
> is the memory.
> 
> Usually for m2m devices the video output direction may support cropping and
> the video capture direction may support composing.
> 
> It's not clear what you intend here, especially since you set left and right
> to 0. That's not what the selection operation is supposed to do.
> 
I am confused about about g/s_selection.
If application want to configure encode area and crop meta-data, it
should set crop info to OUTPUT queue, is that right?
if user space still use g/s_crop ioctl, in 
v4l_g_crop and v4l_s_crop, it set target to V4L2_SEL_TGT_COMPOSE_ACTIVE
when buf type is V4L2_TYPE_IS_OUTPUT.

It looks like when work with g/s_crop ioctl, command set to OUTPUT
buffer will use target V4L2_SEL_TGT_COMPOSE_ACTIVE.
When work with g/s_selection ictol, command set to OUTPUT buffer will
use V4L2_SEL_TGT_CROP_ACTIVE.
Is this correct behavior?


static int v4l_g_crop(const struct v4l2_ioctl_ops *ops,
				struct file *file, void *fh, void *arg)
{
	struct v4l2_crop *p = arg;
	struct v4l2_selection s = {
		.type = p->type,
	};
	int ret;

	if (ops->vidioc_g_crop)
		return ops->vidioc_g_crop(file, fh, p);
	/* simulate capture crop using selection api */

	/* crop means compose for output devices */
	if (V4L2_TYPE_IS_OUTPUT(p->type))
		s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE;
	else
		s.target = V4L2_SEL_TGT_CROP_ACTIVE;

	ret = ops->vidioc_g_selection(file, fh, &s);

	/* copying results to old structure on success */
	if (!ret)
		p->c = s.r;
	return ret;
}

static int v4l_s_crop(const struct v4l2_ioctl_ops *ops,
				struct file *file, void *fh, void *arg)
{
	struct v4l2_crop *p = arg;
	struct v4l2_selection s = {
		.type = p->type,
		.r = p->c,
	};

	if (ops->vidioc_s_crop)
		return ops->vidioc_s_crop(file, fh, p);
	/* simulate capture crop using selection api */

	/* crop means compose for output devices */
	if (V4L2_TYPE_IS_OUTPUT(p->type))
		s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE;
	else
		s.target = V4L2_SEL_TGT_CROP_ACTIVE;

	return ops->vidioc_s_selection(file, fh, &s);
}


best regards,
Tiffany




> Regards,
> 
> 	Hans
> 
> > +
> > +	return 0;
> > +}
> > +
> >  static int vidioc_venc_qbuf(struct file *file, void *priv,
> >  			    struct v4l2_buffer *buf)
> >  {
> > @@ -688,6 +759,9 @@ const struct v4l2_ioctl_ops mtk_venc_ioctl_ops = {
> >  
> >  	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,
> >  	.vidioc_prepare_buf		= v4l2_m2m_ioctl_prepare_buf,
> > +
> > +	.vidioc_g_selection		= vidioc_venc_g_selection,
> > +	.vidioc_s_selection		= vidioc_venc_s_selection,
> >  };
> >  
> >  static int vb2ops_venc_queue_setup(struct vb2_queue *vq,
> > 




From tiffany.lin at mediatek.com  Thu Jul 14 00:30:10 2016
From: tiffany.lin at mediatek.com (tiffany lin)
Date: Thu, 14 Jul 2016 15:30:10 +0800
Subject: [PATCH v3 3/9] DocBook/v4l: Add compressed video formats used
 on MT8173 codec driver
In-Reply-To: <1468418157.2867.12.camel@ndufresne.ca>
References: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-2-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-3-git-send-email-tiffany.lin@mediatek.com>
 <1464611363-14936-4-git-send-email-tiffany.lin@mediatek.com>
 <5a793171-24a7-4e9e-8bfd-f668c789f8e0@xs4all.nl>
 <1468205771.3725.8.camel@mtksdaap41>
 <CAOMLVLiZU3D587dSyp2b2v4DV+MS9vh85bA4BoG7ddK6556rbA@mail.gmail.com>
 <1468350511.8843.16.camel@gmail.com> <1468350842.8843.18.camel@gmail.com>
 <1468375209.2462.20.camel@mtksdaap41>
 <1468418157.2867.12.camel@ndufresne.ca>
Message-ID: <1468481410.27199.17.camel@mtksdaap41>

Hi Nicolas,

On Wed, 2016-07-13 at 09:55 -0400, Nicolas Dufresne wrote:
> Le mercredi 13 juillet 2016 ? 10:00 +0800, tiffany lin a ?crit :
> > Hi Nicolas,
> > 
> > On Tue, 2016-07-12 at 15:14 -0400, Nicolas Dufresne wrote:
> > > Le mardi 12 juillet 2016 ? 15:08 -0400, Nicolas Dufresne a ?crit :
> > > > Le mardi 12 juillet 2016 ? 16:16 +0800, Wu-Cheng Li (???) a ?crit
> > :
> > > > > Decoder hardware produces MT21 (compressed). Image processor
> > can
> > > > > convert it to a format that can be input of display driver.
> > > > > Tiffany.
> > > > > When do you plan to upstream image processor (mtk-mdp)?
> > > > > > 
> > > > > > It can be as input format for encoder, MDP and display
> > drivers in
> > > > > our
> > > > > > platform.
> > > > > I remember display driver can only accept uncompressed MT21.
> > Right?
> > > > > Basically V4L2_PIX_FMT_MT21 is compressed and is like an opaque
> > > > > format. It's not usable until it's decompressed and converted
> > by
> > > > > image
> > > > > processor.
> > > > 
> > > > Previously it was described as MediaTek block mode, and now as a
> > > > MediaTek compressed format. It makes me think you have no idea
> > what
> > > > this pixel format really is. Is that right ?
> > > > 
> > > > The main reason why I keep asking, is that we often find
> > similarities
> > > > between what vendor like to call their proprietary formats. Doing
> > the
> > > > proper research helps not creating a mess like in Android where
> > you
> > > > have a lot of formats that all point to the same format. I
> > believe
> > > > there was the same concern when Samsung wanted to introduce their
> > Z-
> > > > flip-Z NV12 tile format. In the end they simply provided
> > sufficient
> > > > documentation so we could document it and implement software
> > > > converters
> > > > for test and validation purpose.
> > > 
> > > Here's the kind of information we want in the documentation.
> > > 
> > > https://chromium.googlesource.com/chromium/src/media/+/master/base/
> > vide
> > > o_types.h#40
> > > 
> > >   // MediaTek proprietary format. MT21 is similar to NV21 except
> > the memory
> > >   // layout and pixel layout (swizzles). 12bpp with Y plane
> > followed by a 2x2
> > >   // interleaved VU plane. Each image contains two buffers -- Y
> > plane and VU
> > >   // plane. Two planes can be non-contiguous in memory. The
> > starting addresses
> > >   // of Y plane and VU plane are 4KB alignment.
> > >   // Suppose image dimension is (width, height). For both Y plane
> > and VU plane:
> > >   // Row pitch = ((width+15)/16) * 16.
> > >   // Plane size = Row pitch * (((height+31)/32)*32)
> > > 
> > > Now obviously this is incomplete, as the swizzling need to be
> > documented of course.
> > > 
> > Because it's finally a compressed format from our codec hw, we cannot
> > describe its swizzling.
> 
> Can you clarify why it cannot be described ? I don't buy any argument
> that it's impossible to convert without hardware. Intel did document
> their compressed formats.
> 
What's the Intel compressed formats? Could you provide link so we could
reference how they provide this information.

> Debugging an integration with such format that we have literally
> decided to no make public is a pain. A lot of decoder got abandoned or
> never used because of that.
> 
> It would be nice to explain the architecture you are suggesting to make
> this decoder useful. How will userspace application be able to use your
> decoder. Will the image processor usable outside the display path ?
> People might want to do transcoding, or other relatively common task
> that does not imply a display.
> 

In MT8173 platform, it has MDP driver, it could convert
V4L2_PIX_FMT_MT21 to V4L2_PIX_FMT_NV12M or V4L2_PIX_FMT_YUV420M.

MDP is stand alone driver, it is usable outside the display path.

NV12M/YUV420M/MT21 -> MDP -> NV12M/YUV420M

NV12M/NV21M/YUV420M/YVU420M -> mt8173 Encoder -> H264/VP8

H264/VP8/VP9 -> mtk8173 Decoder -> MT21

When encode with MT21 source, the pipeline will be:
MT21 -> MDP driver-> NV12M/NV21M/YUV420M/YVU420M -> Encoder -> H264/VP8

When playback, the pipeline will be:
H264/VP8/VP9 -> Decoder driver -> MT21 -> MDP Driver -> DRM


best regards,
Tiffany


> regards,
> Nicolas
> 
> p.s.
> A small note to Wu-Cheng, the definition of the DRM format in your
> Chromium branch is not correct. DRM uses format modifier, such that the
> format is the family, in your case it's most likely NV21, and the
> modifier is the compression or tiling algorithm in place (or both as
> needed).




From tiffany.lin at mediatek.com  Thu Jul 14 00:34:14 2016
From: tiffany.lin at mediatek.com (tiffany lin)
Date: Thu, 14 Jul 2016 15:34:14 +0800
Subject: [PATCH] [media] mtk-vcodec: fix type mismatches
In-Reply-To: <20160711213959.2481081-1-arnd@arndb.de>
References: <20160711213959.2481081-1-arnd@arndb.de>
Message-ID: <1468481654.27199.19.camel@mtksdaap41>

On Mon, 2016-07-11 at 23:37 +0200, Arnd Bergmann wrote:
> The newly added mtk-vcodec driver produces a number of warnings in an ARM
> allmodconfig build, mainly since it assumes that dma_addr_t is 32-bit wide:
> 
> mtk-vcodec/venc/venc_vp8_if.c: In function 'vp8_enc_alloc_work_buf':
> mtk-vcodec/venc/venc_vp8_if.c:212:191: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
> mtk-vcodec/venc/venc_h264_if.c: In function 'h264_enc_alloc_work_buf':
> mtk-vcodec/venc/venc_h264_if.c:297:190: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
> mtk-vcodec/mtk_vcodec_enc.c: In function 'mtk_venc_worker':
> mtk-vcodec/mtk_vcodec_enc.c:1030:46: error: format '%lx' expects argument of type 'long unsigned int', but argument 7 has type 'size_t {aka unsigned int}' [-Werror=format=]
>   mtk_v4l2_debug(2,
> mtk-vcodec/mtk_vcodec_enc.c:1030:46: error: format '%lx' expects argument of type 'long unsigned int', but argument 10 has type 'size_t {aka unsigned int}' [-Werror=format=]
> mtk-vcodec/venc_vpu_if.c: In function 'vpu_enc_ipi_handler':
> mtk-vcodec/venc_vpu_if.c:40:30: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
>   struct venc_vpu_inst *vpu = (struct venc_vpu_inst *)msg->venc_inst;
> 
> This rearranges the format strings and type casts to what they should have been
> in order to avoid the warnings.
> 
> Signed-off-by: Arnd Bergmann <arnd at arndb.de>
> ---
>  drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c    | 8 ++++----
>  drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c | 4 ++--
>  drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c  | 4 ++--
>  drivers/media/platform/mtk-vcodec/venc_vpu_if.c       | 4 ++--
>  4 files changed, 10 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
> index 6dcae0a0a1f2..0b25a8700877 100644
> --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
> +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
> @@ -1028,15 +1028,15 @@ static void mtk_venc_worker(struct work_struct *work)
>  	bs_buf.size = (size_t)dst_buf->planes[0].length;
>  
>  	mtk_v4l2_debug(2,
> -			"Framebuf VA=%p PA=%llx Size=0x%lx;VA=%p PA=0x%llx Size=0x%lx;VA=%p PA=0x%llx Size=%zu",
> +			"Framebuf VA=%p PA=%pad Size=0x%zx;VA=%p PA=%pad Size=0x%zx;VA=%p PA=%pad Size=0x%zx",
>  			frm_buf.fb_addr[0].va,
> -			(u64)frm_buf.fb_addr[0].dma_addr,
> +			&frm_buf.fb_addr[0].dma_addr,
>  			frm_buf.fb_addr[0].size,
>  			frm_buf.fb_addr[1].va,
> -			(u64)frm_buf.fb_addr[1].dma_addr,
> +			&frm_buf.fb_addr[1].dma_addr,
>  			frm_buf.fb_addr[1].size,
>  			frm_buf.fb_addr[2].va,
> -			(u64)frm_buf.fb_addr[2].dma_addr,
> +			&frm_buf.fb_addr[2].dma_addr,
>  			frm_buf.fb_addr[2].size);

Acked-by:Tiffany Lin <tiffany.lin at mediatek.com>


>  
>  	ret = venc_if_encode(ctx, VENC_START_OPT_ENCODE_FRAME,
> diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
> index f4e18bb44cb9..9a600525b3c1 100644
> --- a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
> +++ b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
> @@ -295,9 +295,9 @@ static int h264_enc_alloc_work_buf(struct venc_h264_inst *inst)
>  		wb[i].iova = inst->work_bufs[i].dma_addr;
>  
>  		mtk_vcodec_debug(inst,
> -				 "work_buf[%d] va=0x%p iova=0x%p size=%zu",
> +				 "work_buf[%d] va=0x%p iova=%pad size=%zu",
>  				 i, inst->work_bufs[i].va,
> -				 (void *)inst->work_bufs[i].dma_addr,
> +				 &inst->work_bufs[i].dma_addr,
>  				 inst->work_bufs[i].size);
>  	}
>  
> diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
> index 431ae706a427..5b35aa1900d7 100644
> --- a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
> +++ b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
> @@ -210,9 +210,9 @@ static int vp8_enc_alloc_work_buf(struct venc_vp8_inst *inst)
>  		wb[i].iova = inst->work_bufs[i].dma_addr;
>  
>  		mtk_vcodec_debug(inst,
> -				 "work_bufs[%d] va=0x%p,iova=0x%p,size=%zu",
> +				 "work_bufs[%d] va=0x%p,iova=%pad,size=%zu",
>  				 i, inst->work_bufs[i].va,
> -				 (void *)inst->work_bufs[i].dma_addr,
> +				 &inst->work_bufs[i].dma_addr,
>  				 inst->work_bufs[i].size);
>  	}
>  
> diff --git a/drivers/media/platform/mtk-vcodec/venc_vpu_if.c b/drivers/media/platform/mtk-vcodec/venc_vpu_if.c
> index b92c6d2a892d..8907b02729fa 100644
> --- a/drivers/media/platform/mtk-vcodec/venc_vpu_if.c
> +++ b/drivers/media/platform/mtk-vcodec/venc_vpu_if.c
> @@ -37,7 +37,7 @@ static void handle_enc_encode_msg(struct venc_vpu_inst *vpu, void *data)
>  static void vpu_enc_ipi_handler(void *data, unsigned int len, void *priv)
>  {
>  	struct venc_vpu_ipi_msg_common *msg = data;
> -	struct venc_vpu_inst *vpu = (struct venc_vpu_inst *)msg->venc_inst;
> +	struct venc_vpu_inst *vpu = (struct venc_vpu_inst *)(uintptr_t)msg->venc_inst;
>  
>  	mtk_vcodec_debug(vpu, "msg_id %x inst %p status %d",
>  			 msg->msg_id, vpu, msg->status);
> @@ -112,7 +112,7 @@ int vpu_enc_init(struct venc_vpu_inst *vpu)
>  
>  	memset(&out, 0, sizeof(out));
>  	out.msg_id = AP_IPIMSG_ENC_INIT;
> -	out.venc_inst = (unsigned long)vpu;
> +	out.venc_inst = (uintptr_t)vpu;
>  	if (vpu_enc_send_msg(vpu, &out, sizeof(out))) {
>  		mtk_vcodec_err(vpu, "AP_IPIMSG_ENC_INIT fail");
>  		return -EINVAL;




From hs.liao at mediatek.com  Thu Jul 14 04:28:49 2016
From: hs.liao at mediatek.com (HS Liao)
Date: Thu, 14 Jul 2016 19:28:49 +0800
Subject: [PATCH v10 0/4] Mediatek MT8173 CMDQ support
Message-ID: <1468495733-12178-1-git-send-email-hs.liao@mediatek.com>

Hi,

This is Mediatek MT8173 Command Queue(CMDQ) driver. The CMDQ is used
to help write registers with critical time limitation, such as
updating display configuration during the vblank. It controls Global
Command Engine (GCE) hardware to achieve this requirement.

These patches have a build dependency on top of v4.7-rc1.

Changes since v9:
 - rename merge_wfe to atomic_exec
   atomic_exec should merge wfe (wait for event) commands and prevent
   to suspend gce when gce starts to execute commands after wfe.
 - merge cmdq_rec into cmdq_task since command buffer allocation for
   cmdq_task had been modified to the same as cmdq_rec in CMDQ v9
 - refine mailbox part in device tree binding document

Best regards,
HS Liao

HS Liao (4):
  dt-bindings: soc: Add documentation for the MediaTek GCE unit
  CMDQ: Mediatek CMDQ driver
  arm64: dts: mt8173: Add GCE node
  CMDQ: save more energy in idle

 .../devicetree/bindings/soc/mediatek/gce.txt       |  47 +
 arch/arm64/boot/dts/mediatek/mt8173.dtsi           |  10 +
 drivers/soc/mediatek/Kconfig                       |  11 +
 drivers/soc/mediatek/Makefile                      |   1 +
 drivers/soc/mediatek/mtk-cmdq.c                    | 987 +++++++++++++++++++++
 include/soc/mediatek/cmdq.h                        | 179 ++++
 6 files changed, 1235 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/soc/mediatek/gce.txt
 create mode 100644 drivers/soc/mediatek/mtk-cmdq.c
 create mode 100644 include/soc/mediatek/cmdq.h

-- 
1.9.1



From hs.liao at mediatek.com  Thu Jul 14 04:28:50 2016
From: hs.liao at mediatek.com (HS Liao)
Date: Thu, 14 Jul 2016 19:28:50 +0800
Subject: [PATCH v10 1/4] dt-bindings: soc: Add documentation for the MediaTek
 GCE unit
In-Reply-To: <1468495733-12178-1-git-send-email-hs.liao@mediatek.com>
References: <1468495733-12178-1-git-send-email-hs.liao@mediatek.com>
Message-ID: <1468495733-12178-2-git-send-email-hs.liao@mediatek.com>

This adds documentation for the MediaTek Global Command Engine (GCE) unit
found in MT8173 SoCs.

Signed-off-by: HS Liao <hs.liao at mediatek.com>
Acked-by: Rob Herring <robh at kernel.org>
---
 .../devicetree/bindings/soc/mediatek/gce.txt       | 47 ++++++++++++++++++++++
 1 file changed, 47 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/soc/mediatek/gce.txt

diff --git a/Documentation/devicetree/bindings/soc/mediatek/gce.txt b/Documentation/devicetree/bindings/soc/mediatek/gce.txt
new file mode 100644
index 0000000..2b3e655
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/mediatek/gce.txt
@@ -0,0 +1,47 @@
+MediaTek GCE
+===============
+
+The Global Command Engine (GCE) is used to help read/write registers with
+critical time limitation, such as updating display configuration during the
+vblank. The GCE can be used to implement the Command Queue (CMDQ) driver.
+
+CMDQ driver uses mailbox framework for communication. Please refer to
+../../mailbox/mailbox.txt for generic information about mailbox device-tree
+bindings.
+
+Required properties:
+- compatible: Must be "mediatek,mt8173-gce"
+- reg: Address range of the GCE unit
+- interrupts: The interrupt signal from the GCE block
+- clock: Clocks according to the common clock binding
+- clock-names: Must be "gce" to stand for GCE clock
+- #mbox-cells: Should be 2
+
+Required properties for a client device:
+- mediatek,gce: If a client asks GCE to access its registers, it should have
+  this property and point to the respective GCE block.
+- mboxes: If a client will communicate with GCE via mailbox, it should have
+  this property and list of phandle, mailbox channel specifiers, and atomic
+  execution flag.
+
+Example:
+
+	gce: gce at 10212000 {
+		compatible = "mediatek,mt8173-gce";
+		reg = <0 0x10212000 0 0x1000>;
+		interrupts = <GIC_SPI 135 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&infracfg CLK_INFRA_GCE>;
+		clock-names = "gce";
+
+		#mbox-cells = <2>;
+	};
+
+Example for a client device:
+
+	mmsys: clock-controller at 14000000 {
+		compatible = "mediatek,mt8173-mmsys";
+		mediatek,gce = <&gce>;
+		mboxes = <&gce 0 1 /* main display with atomic execution */
+			  &gce 1 1>; /* sub display with atomic execution */
+		...
+	};
-- 
1.9.1



From hs.liao at mediatek.com  Thu Jul 14 04:28:51 2016
From: hs.liao at mediatek.com (HS Liao)
Date: Thu, 14 Jul 2016 19:28:51 +0800
Subject: [PATCH v10 2/4] CMDQ: Mediatek CMDQ driver
In-Reply-To: <1468495733-12178-1-git-send-email-hs.liao@mediatek.com>
References: <1468495733-12178-1-git-send-email-hs.liao@mediatek.com>
Message-ID: <1468495733-12178-3-git-send-email-hs.liao@mediatek.com>

This patch is first version of Mediatek Command Queue(CMDQ) driver. The
CMDQ is used to help write registers with critical time limitation,
such as updating display configuration during the vblank. It controls
Global Command Engine (GCE) hardware to achieve this requirement.
Currently, CMDQ only supports display related hardwares, but we expect
it can be extended to other hardwares for future requirements.

Signed-off-by: HS Liao <hs.liao at mediatek.com>
Signed-off-by: CK Hu <ck.hu at mediatek.com>
---
 drivers/soc/mediatek/Kconfig    |  11 +
 drivers/soc/mediatek/Makefile   |   1 +
 drivers/soc/mediatek/mtk-cmdq.c | 948 ++++++++++++++++++++++++++++++++++++++++
 include/soc/mediatek/cmdq.h     | 179 ++++++++
 4 files changed, 1139 insertions(+)
 create mode 100644 drivers/soc/mediatek/mtk-cmdq.c
 create mode 100644 include/soc/mediatek/cmdq.h

diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
index 0a4ea80..50869e4 100644
--- a/drivers/soc/mediatek/Kconfig
+++ b/drivers/soc/mediatek/Kconfig
@@ -1,6 +1,17 @@
 #
 # MediaTek SoC drivers
 #
+config MTK_CMDQ
+	bool "MediaTek CMDQ Support"
+	depends on ARM64 && ( ARCH_MEDIATEK || COMPILE_TEST )
+	select MAILBOX
+	select MTK_INFRACFG
+	help
+	  Say yes here to add support for the MediaTek Command Queue (CMDQ)
+	  driver. The CMDQ is used to help read/write registers with critical
+	  time limitation, such as updating display configuration during the
+	  vblank.
+
 config MTK_INFRACFG
 	bool "MediaTek INFRACFG Support"
 	depends on ARCH_MEDIATEK || COMPILE_TEST
diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
index 12998b0..f7397ef 100644
--- a/drivers/soc/mediatek/Makefile
+++ b/drivers/soc/mediatek/Makefile
@@ -1,3 +1,4 @@
+obj-$(CONFIG_MTK_CMDQ) += mtk-cmdq.o
 obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o
 obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
 obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
diff --git a/drivers/soc/mediatek/mtk-cmdq.c b/drivers/soc/mediatek/mtk-cmdq.c
new file mode 100644
index 0000000..d032603
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-cmdq.c
@@ -0,0 +1,948 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * 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.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/completion.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/mailbox_client.h>
+#include <linux/mailbox_controller.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/suspend.h>
+#include <linux/timer.h>
+#include <soc/mediatek/cmdq.h>
+
+#define CMDQ_THR_MAX_COUNT		3 /* main, sub, general(misc) */
+#define CMDQ_INST_SIZE			8 /* instruction is 64-bit */
+#define CMDQ_TIMEOUT_MS			1000
+#define CMDQ_IRQ_MASK			0xffff
+#define CMDQ_NUM_CMD(t)			(t->cmd_buf_size / CMDQ_INST_SIZE)
+
+#define CMDQ_CURR_IRQ_STATUS		0x10
+#define CMDQ_THR_SLOT_CYCLES		0x30
+
+#define CMDQ_THR_BASE			0x100
+#define CMDQ_THR_SIZE			0x80
+#define CMDQ_THR_WARM_RESET		0x00
+#define CMDQ_THR_ENABLE_TASK		0x04
+#define CMDQ_THR_SUSPEND_TASK		0x08
+#define CMDQ_THR_CURR_STATUS		0x0c
+#define CMDQ_THR_IRQ_STATUS		0x10
+#define CMDQ_THR_IRQ_ENABLE		0x14
+#define CMDQ_THR_CURR_ADDR		0x20
+#define CMDQ_THR_END_ADDR		0x24
+
+#define CMDQ_THR_ENABLED		0x1
+#define CMDQ_THR_DISABLED		0x0
+#define CMDQ_THR_SUSPEND		0x1
+#define CMDQ_THR_RESUME			0x0
+#define CMDQ_THR_STATUS_SUSPENDED	BIT(1)
+#define CMDQ_THR_DO_WARM_RESET		BIT(0)
+#define CMDQ_THR_ACTIVE_SLOT_CYCLES	0x3200
+#define CMDQ_THR_IRQ_DONE		0x1
+#define CMDQ_THR_IRQ_ERROR		0x12
+#define CMDQ_THR_IRQ_EN			(CMDQ_THR_IRQ_ERROR | CMDQ_THR_IRQ_DONE)
+
+#define CMDQ_OP_CODE_SHIFT		24
+#define CMDQ_SUBSYS_SHIFT		16
+
+#define CMDQ_ARG_A_WRITE_MASK		0xffff
+#define CMDQ_OP_CODE_MASK		(0xff << CMDQ_OP_CODE_SHIFT)
+
+#define CMDQ_WRITE_ENABLE_MASK		BIT(0)
+#define CMDQ_JUMP_BY_OFFSET		0x10000000
+#define CMDQ_JUMP_BY_PA			0x10000001
+#define CMDQ_JUMP_PASS			CMDQ_INST_SIZE
+#define CMDQ_WFE_UPDATE			BIT(31)
+#define CMDQ_WFE_WAIT			BIT(15)
+#define CMDQ_WFE_WAIT_VALUE		0x1
+#define CMDQ_EOC_IRQ_EN			BIT(0)
+
+/*
+ * CMDQ_CODE_MASK:
+ *   set write mask
+ *   format: op mask
+ * CMDQ_CODE_WRITE:
+ *   write value into target register
+ *   format: op subsys address value
+ * CMDQ_CODE_JUMP:
+ *   jump by offset
+ *   format: op offset
+ * CMDQ_CODE_WFE:
+ *   wait for event and clear
+ *   it is just clear if no wait
+ *   format: [wait]  op event update:1 to_wait:1 wait:1
+ *           [clear] op event update:1 to_wait:0 wait:0
+ * CMDQ_CODE_EOC:
+ *   end of command
+ *   format: op irq_flag
+ */
+enum cmdq_code {
+	CMDQ_CODE_MASK = 0x02,
+	CMDQ_CODE_WRITE = 0x04,
+	CMDQ_CODE_JUMP = 0x10,
+	CMDQ_CODE_WFE = 0x20,
+	CMDQ_CODE_EOC = 0x40,
+};
+
+struct cmdq_task_cb {
+	cmdq_async_flush_cb	cb;
+	void			*data;
+};
+
+struct cmdq_thread {
+	struct mbox_chan	*chan;
+	void __iomem		*base;
+	struct list_head	task_busy_list;
+	struct timer_list	timeout;
+	bool			atomic_exec;
+};
+
+struct cmdq_task {
+	struct cmdq		*cmdq;
+	struct list_head	list_entry;
+	void			*va_base;
+	dma_addr_t		pa_base;
+	size_t			cmd_buf_size; /* command occupied size */
+	size_t			buf_size; /* real buffer size */
+	bool			finalized;
+	struct cmdq_thread	*thread;
+	struct cmdq_task_cb	cb;
+};
+
+struct cmdq {
+	struct mbox_controller	mbox;
+	void __iomem		*base;
+	u32			irq;
+	struct cmdq_thread	thread[CMDQ_THR_MAX_COUNT];
+	struct mutex		task_mutex;
+	struct clk		*clock;
+	bool			suspended;
+};
+
+struct cmdq_subsys {
+	u32	base;
+	int	id;
+};
+
+static const struct cmdq_subsys gce_subsys[] = {
+	{0x1400, 1},
+	{0x1401, 2},
+	{0x1402, 3},
+};
+
+static int cmdq_subsys_base_to_id(u32 base)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(gce_subsys); i++)
+		if (gce_subsys[i].base == base)
+			return gce_subsys[i].id;
+	return -EFAULT;
+}
+
+static int cmdq_thread_suspend(struct cmdq *cmdq, struct cmdq_thread *thread)
+{
+	u32 status;
+
+	writel(CMDQ_THR_SUSPEND, thread->base + CMDQ_THR_SUSPEND_TASK);
+
+	/* If already disabled, treat as suspended successful. */
+	if (!(readl(thread->base + CMDQ_THR_ENABLE_TASK) & CMDQ_THR_ENABLED))
+		return 0;
+
+	if (readl_poll_timeout_atomic(thread->base + CMDQ_THR_CURR_STATUS,
+			status, status & CMDQ_THR_STATUS_SUSPENDED, 0, 10)) {
+		dev_err(cmdq->mbox.dev, "suspend GCE thread 0x%x failed\n",
+			(u32)(thread->base - cmdq->base));
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static void cmdq_thread_resume(struct cmdq_thread *thread)
+{
+	writel(CMDQ_THR_RESUME, thread->base + CMDQ_THR_SUSPEND_TASK);
+}
+
+static int cmdq_thread_reset(struct cmdq *cmdq, struct cmdq_thread *thread)
+{
+	u32 warm_reset;
+
+	writel(CMDQ_THR_DO_WARM_RESET, thread->base + CMDQ_THR_WARM_RESET);
+	if (readl_poll_timeout_atomic(thread->base + CMDQ_THR_WARM_RESET,
+			warm_reset, !(warm_reset & CMDQ_THR_DO_WARM_RESET),
+			0, 10)) {
+		dev_err(cmdq->mbox.dev, "reset GCE thread 0x%x failed\n",
+			(u32)(thread->base - cmdq->base));
+		return -EFAULT;
+	}
+	writel(CMDQ_THR_ACTIVE_SLOT_CYCLES, cmdq->base + CMDQ_THR_SLOT_CYCLES);
+	return 0;
+}
+
+static void cmdq_thread_disable(struct cmdq *cmdq, struct cmdq_thread *thread)
+{
+	cmdq_thread_reset(cmdq, thread);
+	writel(CMDQ_THR_DISABLED, thread->base + CMDQ_THR_ENABLE_TASK);
+}
+
+/* notify GCE to re-fetch commands by setting GCE thread PC */
+static void cmdq_thread_invalidate_fetched_data(struct cmdq_thread *thread)
+{
+	writel(readl(thread->base + CMDQ_THR_CURR_ADDR),
+	       thread->base + CMDQ_THR_CURR_ADDR);
+}
+
+static void cmdq_task_insert_into_thread(struct cmdq_task *task)
+{
+	struct device *dev = task->cmdq->mbox.dev;
+	struct cmdq_thread *thread = task->thread;
+	struct cmdq_task *prev_task = list_last_entry(
+			&thread->task_busy_list, typeof(*task), list_entry);
+	u64 *prev_task_base = prev_task->va_base;
+
+	/* let previous task jump to this task */
+	dma_sync_single_for_cpu(dev, prev_task->pa_base,
+				prev_task->cmd_buf_size, DMA_TO_DEVICE);
+	prev_task_base[CMDQ_NUM_CMD(prev_task) - 1] =
+		(u64)CMDQ_JUMP_BY_PA << 32 | task->pa_base;
+	dma_sync_single_for_device(dev, prev_task->pa_base,
+				   prev_task->cmd_buf_size, DMA_TO_DEVICE);
+
+	cmdq_thread_invalidate_fetched_data(thread);
+}
+
+static bool cmdq_command_is_wfe(u64 cmd)
+{
+	u64 wfe_option = CMDQ_WFE_UPDATE | CMDQ_WFE_WAIT | CMDQ_WFE_WAIT_VALUE;
+	u64 wfe_op = (u64)(CMDQ_CODE_WFE << CMDQ_OP_CODE_SHIFT) << 32;
+	u64 wfe_mask = (u64)CMDQ_OP_CODE_MASK << 32 | 0xffffffff;
+
+	return ((cmd & wfe_mask) == (wfe_op | wfe_option));
+}
+
+/* we assume tasks in the same display GCE thread are waiting the same event. */
+static void cmdq_task_remove_wfe(struct cmdq_task *task)
+{
+	struct device *dev = task->cmdq->mbox.dev;
+	u64 *base = task->va_base;
+	int i;
+
+	dma_sync_single_for_cpu(dev, task->pa_base, task->cmd_buf_size,
+				DMA_TO_DEVICE);
+	for (i = 0; i < CMDQ_NUM_CMD(task); i++)
+		if (cmdq_command_is_wfe(base[i]))
+			base[i] = (u64)CMDQ_JUMP_BY_OFFSET << 32 |
+				  CMDQ_JUMP_PASS;
+	dma_sync_single_for_device(dev, task->pa_base, task->cmd_buf_size,
+				   DMA_TO_DEVICE);
+}
+
+static bool cmdq_thread_is_in_wfe(struct cmdq_thread *thread,
+				  unsigned long curr_pa)
+{
+	struct device *dev = thread->chan->mbox->dev;
+	struct cmdq_task *task;
+	u32 task_end_pa;
+	u64 *va;
+	bool ret;
+
+	task = list_first_entry(&thread->task_busy_list, struct cmdq_task,
+				list_entry);
+	task_end_pa = task->pa_base + task->cmd_buf_size;
+	if (!(curr_pa >= task->pa_base &&
+	      curr_pa < task_end_pa - CMDQ_INST_SIZE))
+		return false;
+
+	va = task->va_base + (curr_pa - task->pa_base);
+	dma_sync_single_for_cpu(dev, task->pa_base, task->cmd_buf_size,
+				DMA_TO_DEVICE);
+	ret = cmdq_command_is_wfe(*va);
+	dma_sync_single_for_device(dev, task->pa_base, task->cmd_buf_size,
+				   DMA_TO_DEVICE);
+	return ret;
+}
+
+static void cmdq_thread_wait_end(struct cmdq_thread *thread,
+				 unsigned long end_pa)
+{
+	struct device *dev = thread->chan->mbox->dev;
+	unsigned long curr_pa;
+
+	if (readl_poll_timeout_atomic(thread->base + CMDQ_THR_CURR_ADDR,
+			curr_pa, curr_pa == end_pa, 1, 20))
+		dev_err(dev, "GCE thread cannot run to end.\n");
+}
+
+static void cmdq_task_exec(struct cmdq_task *task, struct cmdq_thread *thread)
+{
+	struct cmdq *cmdq = task->cmdq;
+	unsigned long curr_pa, end_pa;
+
+	task->thread = thread;
+	if (list_empty(&thread->task_busy_list)) {
+		WARN_ON(clk_enable(cmdq->clock) < 0);
+		WARN_ON(cmdq_thread_reset(cmdq, thread) < 0);
+
+		writel(task->pa_base, thread->base + CMDQ_THR_CURR_ADDR);
+		writel(task->pa_base + task->cmd_buf_size,
+		       thread->base + CMDQ_THR_END_ADDR);
+		writel(CMDQ_THR_IRQ_EN, thread->base + CMDQ_THR_IRQ_ENABLE);
+		writel(CMDQ_THR_ENABLED, thread->base + CMDQ_THR_ENABLE_TASK);
+
+		mod_timer(&thread->timeout,
+			  jiffies + msecs_to_jiffies(CMDQ_TIMEOUT_MS));
+	} else {
+		WARN_ON(cmdq_thread_suspend(cmdq, thread) < 0);
+		curr_pa = readl(thread->base + CMDQ_THR_CURR_ADDR);
+		end_pa = readl(thread->base + CMDQ_THR_END_ADDR);
+
+		/*
+		 * Atomic exection should remove the following wfe, i.e. only
+		 * wait event at first task, and prevent to pause when running.
+		 */
+		if (thread->atomic_exec) {
+			/* GCE is executing if command is not WFE */
+			if (!cmdq_thread_is_in_wfe(thread, curr_pa)) {
+				cmdq_thread_resume(thread);
+				cmdq_thread_wait_end(thread, end_pa);
+				WARN_ON(cmdq_thread_suspend(cmdq, thread) < 0);
+				/* set to this task directly */
+				writel(task->pa_base,
+				       thread->base + CMDQ_THR_CURR_ADDR);
+			} else {
+				cmdq_task_insert_into_thread(task);
+				cmdq_task_remove_wfe(task);
+				smp_mb(); /* modify jump before enable thread */
+			}
+		} else {
+			/* check boundary */
+			if (curr_pa == end_pa - CMDQ_INST_SIZE ||
+			    curr_pa == end_pa) {
+				/* set to this task directly */
+				writel(task->pa_base,
+				       thread->base + CMDQ_THR_CURR_ADDR);
+			} else {
+				cmdq_task_insert_into_thread(task);
+				smp_mb(); /* modify jump before enable thread */
+			}
+		}
+		writel(task->pa_base + task->cmd_buf_size,
+		       thread->base + CMDQ_THR_END_ADDR);
+		cmdq_thread_resume(thread);
+	}
+	list_move_tail(&task->list_entry, &thread->task_busy_list);
+}
+
+static void cmdq_task_exec_done(struct cmdq_task *task, bool err)
+{
+	struct device *dev = task->cmdq->mbox.dev;
+	struct cmdq_cb_data cmdq_cb_data;
+
+	if (task->cb.cb) {
+		cmdq_cb_data.err = err;
+		cmdq_cb_data.data = task->cb.data;
+		task->cb.cb(cmdq_cb_data);
+	}
+	list_del(&task->list_entry);
+	dma_unmap_single(dev, task->pa_base, task->cmd_buf_size, DMA_TO_DEVICE);
+	kfree(task->va_base);
+}
+
+static void cmdq_task_handle_error(struct cmdq_task *task)
+{
+	struct cmdq_thread *thread = task->thread;
+	struct cmdq_task *next_task;
+
+	dev_err(task->cmdq->mbox.dev, "task 0x%p error\n", task);
+	WARN_ON(cmdq_thread_suspend(task->cmdq, thread) < 0);
+	next_task = list_first_entry_or_null(&thread->task_busy_list,
+			struct cmdq_task, list_entry);
+	if (next_task)
+		writel(next_task->pa_base, thread->base + CMDQ_THR_CURR_ADDR);
+	cmdq_thread_resume(thread);
+}
+
+static void cmdq_thread_irq_handler(struct cmdq *cmdq,
+				    struct cmdq_thread *thread)
+{
+	struct cmdq_task *task, *tmp, *curr_task = NULL;
+	u32 curr_pa, irq_flag, task_end_pa;
+	bool err;
+
+	irq_flag = readl(thread->base + CMDQ_THR_IRQ_STATUS);
+	writel(~irq_flag, thread->base + CMDQ_THR_IRQ_STATUS);
+
+	/*
+	 * When ISR call this function, another CPU core could run
+	 * "release task" right before we acquire the spin lock, and thus
+	 * reset / disable this GCE thread, so we need to check the enable
+	 * bit of this GCE thread.
+	 */
+	if (!(readl(thread->base + CMDQ_THR_ENABLE_TASK) & CMDQ_THR_ENABLED))
+		return;
+
+	if (irq_flag & CMDQ_THR_IRQ_ERROR)
+		err = true;
+	else if (irq_flag & CMDQ_THR_IRQ_DONE)
+		err = false;
+	else
+		return;
+
+	curr_pa = readl(thread->base + CMDQ_THR_CURR_ADDR);
+
+	list_for_each_entry_safe(task, tmp, &thread->task_busy_list,
+				 list_entry) {
+		task_end_pa = task->pa_base + task->cmd_buf_size;
+		if (curr_pa >= task->pa_base && curr_pa < task_end_pa)
+			curr_task = task;
+
+		if (!curr_task || curr_pa == task_end_pa - CMDQ_INST_SIZE) {
+			cmdq_task_exec_done(task, false);
+			kfree(task);
+		} else if (err) {
+			cmdq_task_exec_done(task, true);
+			cmdq_task_handle_error(curr_task);
+			kfree(task);
+		}
+
+		if (curr_task)
+			break;
+	}
+
+	if (list_empty(&thread->task_busy_list)) {
+		cmdq_thread_disable(cmdq, thread);
+		clk_disable(cmdq->clock);
+	} else {
+		mod_timer(&thread->timeout,
+			  jiffies + msecs_to_jiffies(CMDQ_TIMEOUT_MS));
+	}
+}
+
+static irqreturn_t cmdq_irq_handler(int irq, void *dev)
+{
+	struct cmdq *cmdq = dev;
+	unsigned long irq_status, flags = 0L;
+	int bit;
+
+	irq_status = readl(cmdq->base + CMDQ_CURR_IRQ_STATUS) & CMDQ_IRQ_MASK;
+	if (!(irq_status ^ CMDQ_IRQ_MASK))
+		return IRQ_NONE;
+
+	for_each_clear_bit(bit, &irq_status, fls(CMDQ_IRQ_MASK)) {
+		struct cmdq_thread *thread = &cmdq->thread[bit];
+
+		spin_lock_irqsave(&thread->chan->lock, flags);
+		cmdq_thread_irq_handler(cmdq, thread);
+		spin_unlock_irqrestore(&thread->chan->lock, flags);
+	}
+	return IRQ_HANDLED;
+}
+
+static void cmdq_thread_handle_timeout(unsigned long data)
+{
+	struct cmdq_thread *thread = (struct cmdq_thread *)data;
+	struct cmdq *cmdq = container_of(thread->chan->mbox, struct cmdq, mbox);
+	struct cmdq_task *task, *tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&thread->chan->lock, flags);
+	WARN_ON(cmdq_thread_suspend(cmdq, thread) < 0);
+
+	/*
+	 * Although IRQ is disabled, GCE continues to execute.
+	 * It may have pending IRQ before GCE thread is suspended,
+	 * so check this condition again.
+	 */
+	cmdq_thread_irq_handler(cmdq, thread);
+
+	if (list_empty(&thread->task_busy_list)) {
+		cmdq_thread_resume(thread);
+		spin_unlock_irqrestore(&thread->chan->lock, flags);
+		return;
+	}
+
+	dev_err(cmdq->mbox.dev, "timeout\n");
+	list_for_each_entry_safe(task, tmp, &thread->task_busy_list,
+				 list_entry) {
+		cmdq_task_exec_done(task, true);
+		kfree(task);
+	}
+
+	cmdq_thread_resume(thread);
+	cmdq_thread_disable(cmdq, thread);
+	clk_disable(cmdq->clock);
+	spin_unlock_irqrestore(&thread->chan->lock, flags);
+}
+
+static int cmdq_task_realloc_cmd_buffer(struct cmdq_task *task, size_t size)
+{
+	void *new_buf;
+
+	new_buf = krealloc(task->va_base, size, GFP_KERNEL | __GFP_ZERO);
+	if (!new_buf)
+		return -ENOMEM;
+	task->va_base = new_buf;
+	task->buf_size = size;
+	return 0;
+}
+
+struct cmdq_base *cmdq_register_device(struct device *dev)
+{
+	struct cmdq_base *cmdq_base;
+	struct resource res;
+	int subsys;
+	u32 base;
+
+	if (of_address_to_resource(dev->of_node, 0, &res))
+		return NULL;
+	base = (u32)res.start;
+
+	subsys = cmdq_subsys_base_to_id(base >> 16);
+	if (subsys < 0)
+		return NULL;
+
+	cmdq_base = devm_kmalloc(dev, sizeof(*cmdq_base), GFP_KERNEL);
+	if (!cmdq_base)
+		return NULL;
+	cmdq_base->subsys = subsys;
+	cmdq_base->base = base;
+
+	return cmdq_base;
+}
+EXPORT_SYMBOL(cmdq_register_device);
+
+struct cmdq_client *cmdq_mbox_create(struct device *dev, int index)
+{
+	struct cmdq_client *client;
+
+	client = kzalloc(sizeof(*client), GFP_KERNEL);
+	client->client.dev = dev;
+	client->client.tx_block = false;
+	client->chan = mbox_request_channel(&client->client, index);
+	return client;
+}
+EXPORT_SYMBOL(cmdq_mbox_create);
+
+int cmdq_task_create(struct device *dev, struct cmdq_task **task_ptr)
+{
+	struct cmdq_task *task;
+	int err;
+
+	task = kzalloc(sizeof(*task), GFP_KERNEL);
+	if (!task)
+		return -ENOMEM;
+	task->cmdq = dev_get_drvdata(dev);
+	err = cmdq_task_realloc_cmd_buffer(task, PAGE_SIZE);
+	if (err < 0) {
+		kfree(task);
+		return err;
+	}
+	*task_ptr = task;
+	return 0;
+}
+EXPORT_SYMBOL(cmdq_task_create);
+
+static int cmdq_task_append_command(struct cmdq_task *task, enum cmdq_code code,
+				    u32 arg_a, u32 arg_b)
+{
+	u64 *cmd_ptr;
+	int err;
+
+	if (WARN_ON(task->finalized))
+		return -EBUSY;
+	if (unlikely(task->cmd_buf_size + CMDQ_INST_SIZE > task->buf_size)) {
+		err = cmdq_task_realloc_cmd_buffer(task, task->buf_size * 2);
+		if (err < 0)
+			return err;
+	}
+	cmd_ptr = task->va_base + task->cmd_buf_size;
+	(*cmd_ptr) = (u64)((code << CMDQ_OP_CODE_SHIFT) | arg_a) << 32 | arg_b;
+	task->cmd_buf_size += CMDQ_INST_SIZE;
+	return 0;
+}
+
+int cmdq_task_write(struct cmdq_task *task, u32 value, struct cmdq_base *base,
+		    u32 offset)
+{
+	u32 arg_a = ((base->base + offset) & CMDQ_ARG_A_WRITE_MASK) |
+		    (base->subsys << CMDQ_SUBSYS_SHIFT);
+	return cmdq_task_append_command(task, CMDQ_CODE_WRITE, arg_a, value);
+}
+EXPORT_SYMBOL(cmdq_task_write);
+
+int cmdq_task_write_mask(struct cmdq_task *task, u32 value,
+			 struct cmdq_base *base, u32 offset, u32 mask)
+{
+	u32 offset_mask = offset;
+	int err;
+
+	if (mask != 0xffffffff) {
+		err = cmdq_task_append_command(task, CMDQ_CODE_MASK, 0, ~mask);
+		if (err < 0)
+			return err;
+		offset_mask |= CMDQ_WRITE_ENABLE_MASK;
+	}
+	return cmdq_task_write(task, value, base, offset_mask);
+}
+EXPORT_SYMBOL(cmdq_task_write_mask);
+
+static const u32 cmdq_event_value[CMDQ_MAX_EVENT] = {
+	/* Display start of frame(SOF) events */
+	[CMDQ_EVENT_DISP_OVL0_SOF] = 11,
+	[CMDQ_EVENT_DISP_OVL1_SOF] = 12,
+	[CMDQ_EVENT_DISP_RDMA0_SOF] = 13,
+	[CMDQ_EVENT_DISP_RDMA1_SOF] = 14,
+	[CMDQ_EVENT_DISP_RDMA2_SOF] = 15,
+	[CMDQ_EVENT_DISP_WDMA0_SOF] = 16,
+	[CMDQ_EVENT_DISP_WDMA1_SOF] = 17,
+	/* Display end of frame(EOF) events */
+	[CMDQ_EVENT_DISP_OVL0_EOF] = 39,
+	[CMDQ_EVENT_DISP_OVL1_EOF] = 40,
+	[CMDQ_EVENT_DISP_RDMA0_EOF] = 41,
+	[CMDQ_EVENT_DISP_RDMA1_EOF] = 42,
+	[CMDQ_EVENT_DISP_RDMA2_EOF] = 43,
+	[CMDQ_EVENT_DISP_WDMA0_EOF] = 44,
+	[CMDQ_EVENT_DISP_WDMA1_EOF] = 45,
+	/* Mutex end of frame(EOF) events */
+	[CMDQ_EVENT_MUTEX0_STREAM_EOF] = 53,
+	[CMDQ_EVENT_MUTEX1_STREAM_EOF] = 54,
+	[CMDQ_EVENT_MUTEX2_STREAM_EOF] = 55,
+	[CMDQ_EVENT_MUTEX3_STREAM_EOF] = 56,
+	[CMDQ_EVENT_MUTEX4_STREAM_EOF] = 57,
+	/* Display underrun events */
+	[CMDQ_EVENT_DISP_RDMA0_UNDERRUN] = 63,
+	[CMDQ_EVENT_DISP_RDMA1_UNDERRUN] = 64,
+	[CMDQ_EVENT_DISP_RDMA2_UNDERRUN] = 65,
+};
+
+int cmdq_task_wfe(struct cmdq_task *task, enum cmdq_event event)
+{
+	u32 arg_b;
+
+	if (event >= CMDQ_MAX_EVENT || event < 0)
+		return -EINVAL;
+
+	/*
+	 * WFE arg_b
+	 * bit 0-11: wait value
+	 * bit 15: 1 - wait, 0 - no wait
+	 * bit 16-27: update value
+	 * bit 31: 1 - update, 0 - no update
+	 */
+	arg_b = CMDQ_WFE_UPDATE | CMDQ_WFE_WAIT | CMDQ_WFE_WAIT_VALUE;
+	return cmdq_task_append_command(task, CMDQ_CODE_WFE,
+			cmdq_event_value[event], arg_b);
+}
+EXPORT_SYMBOL(cmdq_task_wfe);
+
+int cmdq_task_clear_event(struct cmdq_task *task, enum cmdq_event event)
+{
+	if (event >= CMDQ_MAX_EVENT || event < 0)
+		return -EINVAL;
+
+	return cmdq_task_append_command(task, CMDQ_CODE_WFE,
+			cmdq_event_value[event], CMDQ_WFE_UPDATE);
+}
+EXPORT_SYMBOL(cmdq_task_clear_event);
+
+static int cmdq_task_finalize(struct cmdq_task *task)
+{
+	int err;
+
+	if (task->finalized)
+		return 0;
+
+	/* insert EOC and generate IRQ for each command iteration */
+	err = cmdq_task_append_command(task, CMDQ_CODE_EOC, 0, CMDQ_EOC_IRQ_EN);
+	if (err < 0)
+		return err;
+
+	/* JUMP to end */
+	err = cmdq_task_append_command(task, CMDQ_CODE_JUMP, 0, CMDQ_JUMP_PASS);
+	if (err < 0)
+		return err;
+
+	task->finalized = true;
+	return 0;
+}
+
+int cmdq_task_flush_async(struct cmdq_client *client, struct cmdq_task *task,
+			  cmdq_async_flush_cb cb, void *data)
+{
+	struct cmdq *cmdq = task->cmdq;
+	int err;
+
+	mutex_lock(&cmdq->task_mutex);
+	if (cmdq->suspended) {
+		dev_err(cmdq->mbox.dev, "%s is called after suspended\n",
+			__func__);
+		mutex_unlock(&cmdq->task_mutex);
+		return -EPERM;
+	}
+
+	err = cmdq_task_finalize(task);
+	if (err < 0) {
+		mutex_unlock(&cmdq->task_mutex);
+		return err;
+	}
+
+	INIT_LIST_HEAD(&task->list_entry);
+	task->cb.cb = cb;
+	task->cb.data = data;
+	task->pa_base = dma_map_single(cmdq->mbox.dev, task->va_base,
+				       task->cmd_buf_size, DMA_TO_DEVICE);
+
+	mbox_send_message(client->chan, task);
+	/* We can send next task immediately, so just call txdone. */
+	mbox_client_txdone(client->chan, 0);
+	mutex_unlock(&cmdq->task_mutex);
+	return 0;
+}
+EXPORT_SYMBOL(cmdq_task_flush_async);
+
+struct cmdq_flush_completion {
+	struct completion cmplt;
+	bool err;
+};
+
+static void cmdq_task_flush_cb(struct cmdq_cb_data data)
+{
+	struct cmdq_flush_completion *cmplt = data.data;
+
+	cmplt->err = data.err;
+	complete(&cmplt->cmplt);
+}
+
+int cmdq_task_flush(struct cmdq_client *client, struct cmdq_task *task)
+{
+	struct cmdq_flush_completion cmplt;
+	int err;
+
+	init_completion(&cmplt.cmplt);
+	err = cmdq_task_flush_async(client, task, cmdq_task_flush_cb, &cmplt);
+	if (err < 0)
+		return err;
+	wait_for_completion(&cmplt.cmplt);
+	return cmplt.err ? -EFAULT : 0;
+}
+EXPORT_SYMBOL(cmdq_task_flush);
+
+void cmdq_mbox_free(struct cmdq_client *client)
+{
+	mbox_free_channel(client->chan);
+	kfree(client);
+}
+EXPORT_SYMBOL(cmdq_mbox_free);
+
+static int cmdq_suspend(struct device *dev)
+{
+	struct cmdq *cmdq = dev_get_drvdata(dev);
+	struct cmdq_thread *thread;
+	int i;
+	bool task_running = false;
+
+	mutex_lock(&cmdq->task_mutex);
+	cmdq->suspended = true;
+	mutex_unlock(&cmdq->task_mutex);
+
+	for (i = 0; i < ARRAY_SIZE(cmdq->thread); i++) {
+		thread = &cmdq->thread[i];
+		if (!list_empty(&thread->task_busy_list)) {
+			mod_timer(&thread->timeout, jiffies + 1);
+			task_running = true;
+		}
+	}
+
+	if (task_running) {
+		dev_warn(dev, "exist running task(s) in suspend\n");
+		msleep(20);
+	}
+
+	clk_unprepare(cmdq->clock);
+	return 0;
+}
+
+static int cmdq_resume(struct device *dev)
+{
+	struct cmdq *cmdq = dev_get_drvdata(dev);
+
+	WARN_ON(clk_prepare(cmdq->clock) < 0);
+	cmdq->suspended = false;
+	return 0;
+}
+
+static int cmdq_remove(struct platform_device *pdev)
+{
+	struct cmdq *cmdq = platform_get_drvdata(pdev);
+
+	mbox_controller_unregister(&cmdq->mbox);
+	clk_unprepare(cmdq->clock);
+	return 0;
+}
+
+static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data)
+{
+	cmdq_task_exec(data, chan->con_priv);
+	return 0;
+}
+
+static int cmdq_mbox_startup(struct mbox_chan *chan)
+{
+	return 0;
+}
+
+static void cmdq_mbox_shutdown(struct mbox_chan *chan)
+{
+}
+
+static bool cmdq_mbox_last_tx_done(struct mbox_chan *chan)
+{
+	return true;
+}
+
+static const struct mbox_chan_ops cmdq_mbox_chan_ops = {
+	.send_data = cmdq_mbox_send_data,
+	.startup = cmdq_mbox_startup,
+	.shutdown = cmdq_mbox_shutdown,
+	.last_tx_done = cmdq_mbox_last_tx_done,
+};
+
+static struct mbox_chan *cmdq_xlate(struct mbox_controller *mbox,
+		const struct of_phandle_args *sp)
+{
+	int ind = sp->args[0];
+	struct cmdq_thread *thread;
+
+	if (ind >= mbox->num_chans)
+		return ERR_PTR(-EINVAL);
+
+	thread = mbox->chans[ind].con_priv;
+	thread->atomic_exec = (sp->args[1] != 0);
+	thread->chan = &mbox->chans[ind];
+
+	return &mbox->chans[ind];
+}
+
+static int cmdq_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	struct resource *res;
+	struct cmdq *cmdq;
+	int err, i;
+
+	cmdq = devm_kzalloc(dev, sizeof(*cmdq), GFP_KERNEL);
+	if (!cmdq)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	cmdq->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(cmdq->base)) {
+		dev_err(dev, "failed to ioremap gce\n");
+		return PTR_ERR(cmdq->base);
+	}
+
+	cmdq->irq = irq_of_parse_and_map(node, 0);
+	if (!cmdq->irq) {
+		dev_err(dev, "failed to get irq\n");
+		return -EINVAL;
+	}
+	err = devm_request_irq(dev, cmdq->irq, cmdq_irq_handler, IRQF_SHARED,
+			       "mtk_cmdq", cmdq);
+	if (err < 0) {
+		dev_err(dev, "failed to register ISR (%d)\n", err);
+		return err;
+	}
+
+	dev_dbg(dev, "cmdq device: addr:0x%p, va:0x%p, irq:%d\n",
+		dev, cmdq->base, cmdq->irq);
+
+	cmdq->clock = devm_clk_get(dev, "gce");
+	if (IS_ERR(cmdq->clock)) {
+		dev_err(dev, "failed to get gce clk\n");
+		return PTR_ERR(cmdq->clock);
+	}
+
+	cmdq->mbox.dev = dev;
+	cmdq->mbox.chans = devm_kcalloc(dev, CMDQ_THR_MAX_COUNT,
+					sizeof(*cmdq->mbox.chans), GFP_KERNEL);
+	if (!cmdq->mbox.chans)
+		return -ENOMEM;
+
+	cmdq->mbox.num_chans = CMDQ_THR_MAX_COUNT;
+	cmdq->mbox.ops = &cmdq_mbox_chan_ops;
+	cmdq->mbox.of_xlate = cmdq_xlate;
+
+	/* make use of TXDONE_BY_ACK */
+	cmdq->mbox.txdone_irq = false;
+	cmdq->mbox.txdone_poll = false;
+
+	for (i = 0; i < ARRAY_SIZE(cmdq->thread); i++) {
+		cmdq->thread[i].base = cmdq->base + CMDQ_THR_BASE +
+				CMDQ_THR_SIZE * i;
+		INIT_LIST_HEAD(&cmdq->thread[i].task_busy_list);
+		init_timer(&cmdq->thread[i].timeout);
+		cmdq->thread[i].timeout.function = cmdq_thread_handle_timeout;
+		cmdq->thread[i].timeout.data = (unsigned long)&cmdq->thread[i];
+		cmdq->mbox.chans[i].con_priv = &cmdq->thread[i];
+	}
+
+	err = mbox_controller_register(&cmdq->mbox);
+	if (err < 0) {
+		dev_err(dev, "failed to register mailbox: %d\n", err);
+		return err;
+	}
+
+	mutex_init(&cmdq->task_mutex);
+	platform_set_drvdata(pdev, cmdq);
+	WARN_ON(clk_prepare(cmdq->clock) < 0);
+	return 0;
+}
+
+static const struct dev_pm_ops cmdq_pm_ops = {
+	.suspend = cmdq_suspend,
+	.resume = cmdq_resume,
+};
+
+static const struct of_device_id cmdq_of_ids[] = {
+	{.compatible = "mediatek,mt8173-gce",},
+	{}
+};
+
+static struct platform_driver cmdq_drv = {
+	.probe = cmdq_probe,
+	.remove = cmdq_remove,
+	.driver = {
+		.name = "mtk_cmdq",
+		.owner = THIS_MODULE,
+		.pm = &cmdq_pm_ops,
+		.of_match_table = cmdq_of_ids,
+	}
+};
+
+builtin_platform_driver(cmdq_drv);
diff --git a/include/soc/mediatek/cmdq.h b/include/soc/mediatek/cmdq.h
new file mode 100644
index 0000000..1ee2eb0
--- /dev/null
+++ b/include/soc/mediatek/cmdq.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * 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.
+ */
+
+#ifndef __MTK_CMDQ_H__
+#define __MTK_CMDQ_H__
+
+#include <linux/mailbox_client.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+/* display events in command queue(CMDQ) */
+enum cmdq_event {
+	/* Display start of frame(SOF) events */
+	CMDQ_EVENT_DISP_OVL0_SOF,
+	CMDQ_EVENT_DISP_OVL1_SOF,
+	CMDQ_EVENT_DISP_RDMA0_SOF,
+	CMDQ_EVENT_DISP_RDMA1_SOF,
+	CMDQ_EVENT_DISP_RDMA2_SOF,
+	CMDQ_EVENT_DISP_WDMA0_SOF,
+	CMDQ_EVENT_DISP_WDMA1_SOF,
+	/* Display end of frame(EOF) events */
+	CMDQ_EVENT_DISP_OVL0_EOF,
+	CMDQ_EVENT_DISP_OVL1_EOF,
+	CMDQ_EVENT_DISP_RDMA0_EOF,
+	CMDQ_EVENT_DISP_RDMA1_EOF,
+	CMDQ_EVENT_DISP_RDMA2_EOF,
+	CMDQ_EVENT_DISP_WDMA0_EOF,
+	CMDQ_EVENT_DISP_WDMA1_EOF,
+	/* Mutex end of frame(EOF) events */
+	CMDQ_EVENT_MUTEX0_STREAM_EOF,
+	CMDQ_EVENT_MUTEX1_STREAM_EOF,
+	CMDQ_EVENT_MUTEX2_STREAM_EOF,
+	CMDQ_EVENT_MUTEX3_STREAM_EOF,
+	CMDQ_EVENT_MUTEX4_STREAM_EOF,
+	/* Display underrun events */
+	CMDQ_EVENT_DISP_RDMA0_UNDERRUN,
+	CMDQ_EVENT_DISP_RDMA1_UNDERRUN,
+	CMDQ_EVENT_DISP_RDMA2_UNDERRUN,
+	/* Keep this at the end */
+	CMDQ_MAX_EVENT,
+};
+
+struct cmdq_cb_data {
+	bool	err;
+	void	*data;
+};
+
+typedef void (*cmdq_async_flush_cb)(struct cmdq_cb_data data);
+
+struct cmdq_task;
+
+struct cmdq_base {
+	int	subsys;
+	u32	base;
+};
+
+struct cmdq_client {
+	struct mbox_client client;
+	struct mbox_chan *chan;
+};
+
+/**
+ * cmdq_register_device() - register device which needs CMDQ
+ * @dev:	device for CMDQ to access its registers
+ *
+ * Return: cmdq_base pointer or NULL for failed
+ */
+struct cmdq_base *cmdq_register_device(struct device *dev);
+
+/**
+ * cmdq_mbox_create() - create CMDQ mailbox client and channel
+ * @dev:	device of CMDQ mailbox client
+ * @index:	index of CMDQ mailbox channel
+ *
+ * Return: CMDQ mailbox client pointer
+ */
+struct cmdq_client *cmdq_mbox_create(struct device *dev, int index);
+
+/**
+ * cmdq_task_create() - create CMDQ task
+ * @dev:	CMDQ device
+ * @task_ptr:	CMDQ task pointer to retrieve cmdq_task
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_task_create(struct device *dev, struct cmdq_task **task_ptr);
+
+/**
+ * cmdq_task_write() - append write command to the CMDQ task
+ * @task:	the CMDQ task
+ * @value:	the specified target register value
+ * @base:	the CMDQ base
+ * @offset:	register offset from module base
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_task_write(struct cmdq_task *task, u32 value,
+		    struct cmdq_base *base, u32 offset);
+
+/**
+ * cmdq_task_write_mask() - append write command with mask to the CMDQ task
+ * @task:	the CMDQ task
+ * @value:	the specified target register value
+ * @base:	the CMDQ base
+ * @offset:	register offset from module base
+ * @mask:	the specified target register mask
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_task_write_mask(struct cmdq_task *task, u32 value,
+			 struct cmdq_base *base, u32 offset, u32 mask);
+
+/**
+ * cmdq_task_wfe() - append wait for event command to the CMDQ task
+ * @task:	the CMDQ task
+ * @event:	the desired event type to "wait and CLEAR"
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_task_wfe(struct cmdq_task *task, enum cmdq_event event);
+
+/**
+ * cmdq_task_clear_event() - append clear event command to the CMDQ task
+ * @task:	the CMDQ task
+ * @event:	the desired event to be cleared
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_task_clear_event(struct cmdq_task *task, enum cmdq_event event);
+
+/**
+ * cmdq_task_flush() - trigger CMDQ to execute the recorded commands
+ * @client:	the CMDQ mailbox client
+ * @task:	the CMDQ task
+ *
+ * Return: 0 for success; else the error code is returned
+ *
+ * Trigger CMDQ to execute the recorded commands. Note that this is a
+ * synchronous flush function. When the function returned, the recorded
+ * commands have been done. CMDQ task will be destroy automatically
+ * after CMDQ finish all the recorded commands.
+ */
+int cmdq_task_flush(struct cmdq_client *client, struct cmdq_task *task);
+
+/**
+ * cmdq_task_flush_async() - trigger CMDQ to asynchronously execute the recorded
+ *			     commands and call back at the end of ISR
+ * @client:	the CMDQ mailbox client
+ * @task:	the CMDQ task
+ * @cb:		called at the end of CMDQ ISR
+ * @data:	this data will pass back to cb
+ *
+ * Return: 0 for success; else the error code is returned
+ *
+ * Trigger CMDQ to asynchronously execute the recorded commands and call back
+ * at the end of ISR. Note that this is an ASYNC function. When the function
+ * returned, it may or may not be finished. CMDQ task will be destroy
+ * automatically after CMDQ finish all the recorded commands.
+ */
+int cmdq_task_flush_async(struct cmdq_client *client, struct cmdq_task *task,
+			  cmdq_async_flush_cb cb, void *data);
+
+/**
+ * cmdq_mbox_free() - destroy CMDQ mailbox client and channel
+ * @client:	the CMDQ mailbox client
+ */
+void cmdq_mbox_free(struct cmdq_client *client);
+
+#endif	/* __MTK_CMDQ_H__ */
-- 
1.9.1



From hs.liao at mediatek.com  Thu Jul 14 04:28:52 2016
From: hs.liao at mediatek.com (HS Liao)
Date: Thu, 14 Jul 2016 19:28:52 +0800
Subject: [PATCH v10 3/4] arm64: dts: mt8173: Add GCE node
In-Reply-To: <1468495733-12178-1-git-send-email-hs.liao@mediatek.com>
References: <1468495733-12178-1-git-send-email-hs.liao@mediatek.com>
Message-ID: <1468495733-12178-4-git-send-email-hs.liao@mediatek.com>

This patch adds the device node of the GCE hardware for CMDQ module.

Signed-off-by: HS Liao <hs.liao at mediatek.com>
---
 arch/arm64/boot/dts/mediatek/mt8173.dtsi | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
index 05f89c4..a68207c 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -343,6 +343,16 @@
 			#clock-cells = <1>;
 		};
 
+		gce: gce at 10212000 {
+			compatible = "mediatek,mt8173-gce";
+			reg = <0 0x10212000 0 0x1000>;
+			interrupts = <GIC_SPI 135 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&infracfg CLK_INFRA_GCE>;
+			clock-names = "gce";
+
+			#mbox-cells = <2>;
+		};
+
 		gic: interrupt-controller at 10220000 {
 			compatible = "arm,gic-400";
 			#interrupt-cells = <3>;
-- 
1.9.1



From hs.liao at mediatek.com  Thu Jul 14 04:28:53 2016
From: hs.liao at mediatek.com (HS Liao)
Date: Thu, 14 Jul 2016 19:28:53 +0800
Subject: [PATCH v10 4/4] CMDQ: save more energy in idle
In-Reply-To: <1468495733-12178-1-git-send-email-hs.liao@mediatek.com>
References: <1468495733-12178-1-git-send-email-hs.liao@mediatek.com>
Message-ID: <1468495733-12178-5-git-send-email-hs.liao@mediatek.com>

Use clk_disable_unprepare instead of clk_disable to save more energy
when CMDQ is idle.

Signed-off-by: HS Liao <hs.liao at mediatek.com>
---
 drivers/soc/mediatek/mtk-cmdq.c | 55 +++++++++++++++++++++++++++++++++++------
 1 file changed, 47 insertions(+), 8 deletions(-)

diff --git a/drivers/soc/mediatek/mtk-cmdq.c b/drivers/soc/mediatek/mtk-cmdq.c
index d032603..35b791eb2 100644
--- a/drivers/soc/mediatek/mtk-cmdq.c
+++ b/drivers/soc/mediatek/mtk-cmdq.c
@@ -32,6 +32,7 @@
 #include <linux/spinlock.h>
 #include <linux/suspend.h>
 #include <linux/timer.h>
+#include <linux/workqueue.h>
 #include <soc/mediatek/cmdq.h>
 
 #define CMDQ_THR_MAX_COUNT		3 /* main, sub, general(misc) */
@@ -132,10 +133,16 @@ struct cmdq_task {
 	struct cmdq_task_cb	cb;
 };
 
+struct cmdq_clk_release {
+	struct cmdq		*cmdq;
+	struct work_struct	release_work;
+};
+
 struct cmdq {
 	struct mbox_controller	mbox;
 	void __iomem		*base;
 	u32			irq;
+	struct workqueue_struct	*clk_release_wq;
 	struct cmdq_thread	thread[CMDQ_THR_MAX_COUNT];
 	struct mutex		task_mutex;
 	struct clk		*clock;
@@ -301,11 +308,19 @@ static void cmdq_thread_wait_end(struct cmdq_thread *thread,
 static void cmdq_task_exec(struct cmdq_task *task, struct cmdq_thread *thread)
 {
 	struct cmdq *cmdq = task->cmdq;
-	unsigned long curr_pa, end_pa;
+	unsigned long curr_pa, end_pa, flags;
 
 	task->thread = thread;
 	if (list_empty(&thread->task_busy_list)) {
-		WARN_ON(clk_enable(cmdq->clock) < 0);
+		/*
+		 * Unlock for clk prepare (sleeping function).
+		 * We are safe to do that since we have task_mutex and
+		 * only flush will add task.
+		 */
+		spin_unlock_irqrestore(&thread->chan->lock, flags);
+		WARN_ON(clk_prepare_enable(cmdq->clock) < 0);
+		spin_lock_irqsave(&thread->chan->lock, flags);
+
 		WARN_ON(cmdq_thread_reset(cmdq, thread) < 0);
 
 		writel(task->pa_base, thread->base + CMDQ_THR_CURR_ADDR);
@@ -387,6 +402,26 @@ static void cmdq_task_handle_error(struct cmdq_task *task)
 	cmdq_thread_resume(thread);
 }
 
+static void cmdq_clk_release_work(struct work_struct *work_item)
+{
+	struct cmdq_clk_release *clk_release = container_of(work_item,
+			struct cmdq_clk_release, release_work);
+	struct cmdq *cmdq = clk_release->cmdq;
+
+	clk_disable_unprepare(cmdq->clock);
+	kfree(clk_release);
+}
+
+static void cmdq_clk_release_schedule(struct cmdq *cmdq)
+{
+	struct cmdq_clk_release *clk_release;
+
+	clk_release = kmalloc(sizeof(*clk_release), GFP_ATOMIC);
+	clk_release->cmdq = cmdq;
+	INIT_WORK(&clk_release->release_work, cmdq_clk_release_work);
+	queue_work(cmdq->clk_release_wq, &clk_release->release_work);
+}
+
 static void cmdq_thread_irq_handler(struct cmdq *cmdq,
 				    struct cmdq_thread *thread)
 {
@@ -436,7 +471,7 @@ static void cmdq_thread_irq_handler(struct cmdq *cmdq,
 
 	if (list_empty(&thread->task_busy_list)) {
 		cmdq_thread_disable(cmdq, thread);
-		clk_disable(cmdq->clock);
+		cmdq_clk_release_schedule(cmdq);
 	} else {
 		mod_timer(&thread->timeout,
 			  jiffies + msecs_to_jiffies(CMDQ_TIMEOUT_MS));
@@ -495,7 +530,7 @@ static void cmdq_thread_handle_timeout(unsigned long data)
 
 	cmdq_thread_resume(thread);
 	cmdq_thread_disable(cmdq, thread);
-	clk_disable(cmdq->clock);
+	cmdq_clk_release_schedule(cmdq);
 	spin_unlock_irqrestore(&thread->chan->lock, flags);
 }
 
@@ -783,7 +818,7 @@ static int cmdq_suspend(struct device *dev)
 		msleep(20);
 	}
 
-	clk_unprepare(cmdq->clock);
+	flush_workqueue(cmdq->clk_release_wq);
 	return 0;
 }
 
@@ -791,7 +826,6 @@ static int cmdq_resume(struct device *dev)
 {
 	struct cmdq *cmdq = dev_get_drvdata(dev);
 
-	WARN_ON(clk_prepare(cmdq->clock) < 0);
 	cmdq->suspended = false;
 	return 0;
 }
@@ -800,8 +834,8 @@ static int cmdq_remove(struct platform_device *pdev)
 {
 	struct cmdq *cmdq = platform_get_drvdata(pdev);
 
+	destroy_workqueue(cmdq->clk_release_wq);
 	mbox_controller_unregister(&cmdq->mbox);
-	clk_unprepare(cmdq->clock);
 	return 0;
 }
 
@@ -919,8 +953,13 @@ static int cmdq_probe(struct platform_device *pdev)
 	}
 
 	mutex_init(&cmdq->task_mutex);
+
+	cmdq->clk_release_wq = alloc_ordered_workqueue(
+			"%s", WQ_MEM_RECLAIM | WQ_HIGHPRI,
+			"cmdq_clk_release");
+
 	platform_set_drvdata(pdev, cmdq);
-	WARN_ON(clk_prepare(cmdq->clock) < 0);
+
 	return 0;
 }
 
-- 
1.9.1



From minghsiu.tsai at mediatek.com  Thu Jul 14 05:17:57 2016
From: minghsiu.tsai at mediatek.com (Minghsiu Tsai)
Date: Thu, 14 Jul 2016 20:17:57 +0800
Subject: [PATCH 0/4] Add MT8173 MDP Driver 
Message-ID: <1468498681-19955-1-git-send-email-minghsiu.tsai@mediatek.com>

==============
 Introduction
==============

The purpose of this series is to add the driver for Media Data Path HW embedded in the Mediatek's MT8173 SoC.
MDP is used for scaling and color space conversion.

It could convert V4L2_PIX_FMT_MT21 to V4L2_PIX_FMT_NV12M or V4L2_PIX_FMT_YUV420M.

NV12M/YUV420M/MT21 -> MDP -> NV12M/YUV420M

This patch series rely on MTK VPU driver in patch series "Add MT8173 Video Encoder Driver and VPU Driver"[1] and "Add MT8173 Video Decoder Driver"[2].
MDP driver rely on VPU driver to load, communicate with VPU.

Internally the driver uses videobuf2 framework and MTK IOMMU and MTK SMI both have been merged in v4.6-rc1.

[1]https://patchwork.kernel.org/patch/9002171/
[2]https://patchwork.kernel.org/patch/9141245/

==================
 Device interface
==================

In principle the driver bases on v4l2 memory-to-memory framework:
it provides a single video node and each opened file handle gets its own private context with separate buffer queues. Each context consist of 2 buffer queues: OUTPUT (for source buffers) and CAPTURE (for destination buffers).
OUTPUT and CAPTURE buffer could be MMAP or DMABUF memory type.

v4l2-compliance test output:
localhost ~ # v4l2-compliance -d /dev/image-proc0
v4l2-compliance SHA   : 3d225130559e8578dce347052bee3813ddf08f28

Driver Info:
        Driver name   : mtk-mdp
        Card type     : 14001000.rdma
        Bus info      : platform:mt8173
        Driver version: 3.18.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

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 (Not Supported)

        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: 42, Succeeded: 42, Failed: 0, Warnings: 0


Minghsiu Tsai (4):
  VPU: mediatek: Add mdp support
  dt-bindings: Add a binding for Mediatek MDP
  media: Add Mediatek MDP Driver
  arm64: dts: mediatek: Add MDP for MT8173

 .../devicetree/bindings/media/mediatek-mdp.txt     |   92 ++
 arch/arm64/boot/dts/mediatek/mt8173.dtsi           |   80 ++
 drivers/media/platform/Kconfig                     |   16 +
 drivers/media/platform/Makefile                    |    2 +
 drivers/media/platform/mtk-mdp/Makefile            |    9 +
 drivers/media/platform/mtk-mdp/mtk_mdp_comp.c      |  159 +++
 drivers/media/platform/mtk-mdp/mtk_mdp_comp.h      |   72 ++
 drivers/media/platform/mtk-mdp/mtk_mdp_core.c      |  294 +++++
 drivers/media/platform/mtk-mdp/mtk_mdp_core.h      |  233 ++++
 drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h       |  126 ++
 drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c       | 1304 ++++++++++++++++++++
 drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h       |   22 +
 drivers/media/platform/mtk-mdp/mtk_mdp_regs.c      |  153 +++
 drivers/media/platform/mtk-mdp/mtk_mdp_regs.h      |   31 +
 drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c       |  140 +++
 drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h       |   41 +
 drivers/media/platform/mtk-vpu/mtk_vpu.h           |    5 +
 17 files changed, 2779 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/mediatek-mdp.txt
 create mode 100644 drivers/media/platform/mtk-mdp/Makefile
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_comp.c
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_comp.h
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_core.c
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_core.h
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_regs.c
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_regs.h
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h

--
1.7.9.5



From minghsiu.tsai at mediatek.com  Thu Jul 14 05:18:01 2016
From: minghsiu.tsai at mediatek.com (Minghsiu Tsai)
Date: Thu, 14 Jul 2016 20:18:01 +0800
Subject: [PATCH 4/4] arm64: dts: mediatek: Add MDP for MT8173
In-Reply-To: <1468498681-19955-1-git-send-email-minghsiu.tsai@mediatek.com>
References: <1468498681-19955-1-git-send-email-minghsiu.tsai@mediatek.com>
Message-ID: <1468498681-19955-5-git-send-email-minghsiu.tsai@mediatek.com>

Add MDP node for MT8173

Signed-off-by: Minghsiu Tsai <minghsiu.tsai at mediatek.com>
---
 arch/arm64/boot/dts/mediatek/mt8173.dtsi |   80 ++++++++++++++++++++++++++++++
 1 file changed, 80 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
index 77b8c4e..8e1b85d 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -26,6 +26,16 @@
 	#address-cells = <2>;
 	#size-cells = <2>;
 
+	aliases {
+		mdp_rdma0 = &mdp_rdma0;
+		mdp_rdma1 = &mdp_rdma1;
+		mdp_rsz0 = &mdp_rsz0;
+		mdp_rsz1 = &mdp_rsz1;
+		mdp_rsz2 = &mdp_rsz2;
+		mdp_wdma0 = &mdp_wdma0;
+		mdp_wrot0 = &mdp_wrot0;
+		mdp_wrot1 = &mdp_wrot1;
+	};
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -678,6 +688,76 @@
 			#clock-cells = <1>;
 		};
 
+		mdp_rdma0: rdma at 14001000 {
+			compatible = "mediatek,mt8173-mdp-rdma",
+				     "mediatek,mt8173-mdp";
+			reg = <0 0x14001000 0 0x1000>;
+			clocks = <&mmsys CLK_MM_MDP_RDMA0>,
+				 <&mmsys CLK_MM_MUTEX_32K>;
+			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+			iommus = <&iommu M4U_PORT_MDP_RDMA0>;
+			mediatek,larb = <&larb0>;
+			mediatek,vpu = <&vpu>;
+		};
+
+		mdp_rdma1: rdma at 14002000 {
+			compatible = "mediatek,mt8173-mdp-rdma";
+			reg = <0 0x14002000 0 0x1000>;
+			clocks = <&mmsys CLK_MM_MDP_RDMA1>,
+				 <&mmsys CLK_MM_MUTEX_32K>;
+			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+			iommus = <&iommu M4U_PORT_MDP_RDMA1>;
+			mediatek,larb = <&larb4>;
+		};
+
+		mdp_rsz0: rsz at 14003000 {
+			compatible = "mediatek,mt8173-mdp-rsz";
+			reg = <0 0x14003000 0 0x1000>;
+			clocks = <&mmsys CLK_MM_MDP_RSZ0>;
+			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+		};
+
+		mdp_rsz1: rsz at 14004000 {
+			compatible = "mediatek,mt8173-mdp-rsz";
+			reg = <0 0x14004000 0 0x1000>;
+			clocks = <&mmsys CLK_MM_MDP_RSZ1>;
+			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+		};
+
+		mdp_rsz2: rsz at 14005000 {
+			compatible = "mediatek,mt8173-mdp-rsz";
+			reg = <0 0x14005000 0 0x1000>;
+			clocks = <&mmsys CLK_MM_MDP_RSZ2>;
+			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+		};
+
+		mdp_wdma0: wdma at 14006000 {
+			compatible = "mediatek,mt8173-mdp-wdma";
+			reg = <0 0x14006000 0 0x1000>;
+			clocks = <&mmsys CLK_MM_MDP_WDMA>;
+			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+			iommus = <&iommu M4U_PORT_MDP_WDMA>;
+			mediatek,larb = <&larb0>;
+		};
+
+		mdp_wrot0: wrot at 14007000 {
+			compatible = "mediatek,mt8173-mdp-wrot";
+			reg = <0 0x14007000 0 0x1000>;
+			clocks = <&mmsys CLK_MM_MDP_WROT0>;
+			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+			iommus = <&iommu M4U_PORT_MDP_WROT0>;
+			mediatek,larb = <&larb0>;
+		};
+
+		mdp_wrot1: wrot at 14008000 {
+			compatible = "mediatek,mt8173-mdp-wrot";
+			reg = <0 0x14008000 0 0x1000>;
+			clocks = <&mmsys CLK_MM_MDP_WROT1>;
+			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+			iommus = <&iommu M4U_PORT_MDP_WROT1>;
+			mediatek,larb = <&larb4>;
+		};
+
 		pwm0: pwm at 1401e000 {
 			compatible = "mediatek,mt8173-disp-pwm",
 				     "mediatek,mt6595-disp-pwm";
-- 
1.7.9.5



From minghsiu.tsai at mediatek.com  Thu Jul 14 05:17:59 2016
From: minghsiu.tsai at mediatek.com (Minghsiu Tsai)
Date: Thu, 14 Jul 2016 20:17:59 +0800
Subject: [PATCH 2/4] dt-bindings: Add a binding for Mediatek MDP
In-Reply-To: <1468498681-19955-1-git-send-email-minghsiu.tsai@mediatek.com>
References: <1468498681-19955-1-git-send-email-minghsiu.tsai@mediatek.com>
Message-ID: <1468498681-19955-3-git-send-email-minghsiu.tsai@mediatek.com>

Add a DT binding documentation of MDP for the MT8173 SoC
from Mediatek

Signed-off-by: Minghsiu Tsai <minghsiu.tsai at mediatek.com>
---
 .../devicetree/bindings/media/mediatek-mdp.txt     |   92 ++++++++++++++++++++
 1 file changed, 92 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/mediatek-mdp.txt

diff --git a/Documentation/devicetree/bindings/media/mediatek-mdp.txt b/Documentation/devicetree/bindings/media/mediatek-mdp.txt
new file mode 100644
index 0000000..ef570c3
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/mediatek-mdp.txt
@@ -0,0 +1,92 @@
+* Mediatek Media Data Path
+
+Media Data Path is used for scaling and color space conversion.
+
+Required properties:
+  - compatible : should contain them as below:
+        "mediatek,mt8173-mdp"
+        "mediatek,mt8173-mdp-rdma"
+        "mediatek,mt8173-mdp-rsz"
+        "mediatek,mt8173-mdp-wdma"
+        "mediatek,mt8173-mdp-wrot"
+  - clocks : device clocks
+  - power-domains : a phandle to the power domain.
+  - mediatek,larb : should contain the larbes of current platform
+  - iommus : Mediatek IOMMU H/W has designed the fixed associations with
+        the multimedia H/W. and there is only one multimedia iommu domain.
+        "iommus = <&iommu portid>" the "portid" is from
+        dt-bindings\iommu\mt8173-iommu-port.h, it means that this portid will
+        enable iommu. The portid default is disable iommu if "<&iommu portid>"
+        don't be added.
+  - mediatek,vpu : the node of video processor unit
+
+Example:
+	mdp_rdma0: rdma at 14001000 {
+		compatible = "mediatek,mt8173-mdp-rdma",
+			     "mediatek,mt8173-mdp";
+		reg = <0 0x14001000 0 0x1000>;
+		clocks = <&mmsys CLK_MM_MDP_RDMA0>,
+			 <&mmsys CLK_MM_MUTEX_32K>;
+		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+		iommus = <&iommu M4U_PORT_MDP_RDMA0>;
+		mediatek,larb = <&larb0>;
+		mediatek,vpu = <&vpu>;
+	};
+
+	mdp_rdma1: rdma at 14002000 {
+		compatible = "mediatek,mt8173-mdp-rdma";
+		reg = <0 0x14002000 0 0x1000>;
+		clocks = <&mmsys CLK_MM_MDP_RDMA1>,
+			 <&mmsys CLK_MM_MUTEX_32K>;
+		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+		iommus = <&iommu M4U_PORT_MDP_RDMA1>;
+		mediatek,larb = <&larb4>;
+	};
+
+	mdp_rsz0: rsz at 14003000 {
+		compatible = "mediatek,mt8173-mdp-rsz";
+		reg = <0 0x14003000 0 0x1000>;
+		clocks = <&mmsys CLK_MM_MDP_RSZ0>;
+		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+	};
+
+	mdp_rsz1: rsz at 14004000 {
+		compatible = "mediatek,mt8173-mdp-rsz";
+		reg = <0 0x14004000 0 0x1000>;
+		clocks = <&mmsys CLK_MM_MDP_RSZ1>;
+		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+	};
+
+	mdp_rsz2: rsz at 14005000 {
+		compatible = "mediatek,mt8173-mdp-rsz";
+		reg = <0 0x14005000 0 0x1000>;
+		clocks = <&mmsys CLK_MM_MDP_RSZ2>;
+		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+	};
+
+	mdp_wdma0: wdma at 14006000 {
+		compatible = "mediatek,mt8173-mdp-wdma";
+		reg = <0 0x14006000 0 0x1000>;
+		clocks = <&mmsys CLK_MM_MDP_WDMA>;
+		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+		iommus = <&iommu M4U_PORT_MDP_WDMA>;
+		mediatek,larb = <&larb0>;
+	};
+
+	mdp_wrot0: wrot at 14007000 {
+		compatible = "mediatek,mt8173-mdp-wrot";
+		reg = <0 0x14007000 0 0x1000>;
+		clocks = <&mmsys CLK_MM_MDP_WROT0>;
+		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+		iommus = <&iommu M4U_PORT_MDP_WROT0>;
+		mediatek,larb = <&larb0>;
+	};
+
+	mdp_wrot1: wrot at 14008000 {
+		compatible = "mediatek,mt8173-mdp-wrot";
+		reg = <0 0x14008000 0 0x1000>;
+		clocks = <&mmsys CLK_MM_MDP_WROT1>;
+		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+		iommus = <&iommu M4U_PORT_MDP_WROT1>;
+		mediatek,larb = <&larb4>;
+	};
-- 
1.7.9.5



From minghsiu.tsai at mediatek.com  Thu Jul 14 05:17:58 2016
From: minghsiu.tsai at mediatek.com (Minghsiu Tsai)
Date: Thu, 14 Jul 2016 20:17:58 +0800
Subject: [PATCH 1/4] VPU: mediatek: Add mdp support
In-Reply-To: <1468498681-19955-1-git-send-email-minghsiu.tsai@mediatek.com>
References: <1468498681-19955-1-git-send-email-minghsiu.tsai@mediatek.com>
Message-ID: <1468498681-19955-2-git-send-email-minghsiu.tsai@mediatek.com>

VPU driver add mdp support

Signed-off-by: Minghsiu Tsai <minghsiu.tsai at mediatek.com>
---
 drivers/media/platform/mtk-vpu/mtk_vpu.h |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.h b/drivers/media/platform/mtk-vpu/mtk_vpu.h
index f457479..291ae46 100644
--- a/drivers/media/platform/mtk-vpu/mtk_vpu.h
+++ b/drivers/media/platform/mtk-vpu/mtk_vpu.h
@@ -53,6 +53,8 @@ typedef void (*ipi_handler_t) (void *data,
 			 handle H264 video encoder job, and vice versa.
  * @IPI_VENC_VP8:	 The interrupt fro vpu is to notify kernel to
 			 handle VP8 video encoder job,, and vice versa.
+ * @IPI_MDP:		 The interrupt from vpu is to notify kernel to
+			 handle MDP (Media Data Path) job, and vice versa.
  * @IPI_MAX:		 The maximum IPI number
  */
 
@@ -63,6 +65,7 @@ enum ipi_id {
 	IPI_VDEC_VP9,
 	IPI_VENC_H264,
 	IPI_VENC_VP8,
+	IPI_MDP,
 	IPI_MAX,
 };
 
@@ -71,11 +74,13 @@ enum ipi_id {
  *
  * @VPU_RST_ENC: encoder reset id
  * @VPU_RST_DEC: decoder reset id
+ * @VPU_RST_MDP: MDP (Media Data Path) reset id
  * @VPU_RST_MAX: maximum reset id
  */
 enum rst_id {
 	VPU_RST_ENC,
 	VPU_RST_DEC,
+	VPU_RST_MDP,
 	VPU_RST_MAX,
 };
 
-- 
1.7.9.5



From minghsiu.tsai at mediatek.com  Thu Jul 14 05:18:00 2016
From: minghsiu.tsai at mediatek.com (Minghsiu Tsai)
Date: Thu, 14 Jul 2016 20:18:00 +0800
Subject: [PATCH 3/4] media: Add Mediatek MDP Driver
In-Reply-To: <1468498681-19955-1-git-send-email-minghsiu.tsai@mediatek.com>
References: <1468498681-19955-1-git-send-email-minghsiu.tsai@mediatek.com>
Message-ID: <1468498681-19955-4-git-send-email-minghsiu.tsai@mediatek.com>

Add MDP driver for MT8173

Signed-off-by: Minghsiu Tsai <minghsiu.tsai at mediatek.com>
---
 drivers/media/platform/Kconfig                |   16 +
 drivers/media/platform/Makefile               |    2 +
 drivers/media/platform/mtk-mdp/Makefile       |    9 +
 drivers/media/platform/mtk-mdp/mtk_mdp_comp.c |  159 +++
 drivers/media/platform/mtk-mdp/mtk_mdp_comp.h |   72 ++
 drivers/media/platform/mtk-mdp/mtk_mdp_core.c |  294 ++++++
 drivers/media/platform/mtk-mdp/mtk_mdp_core.h |  233 +++++
 drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h  |  126 +++
 drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c  | 1304 +++++++++++++++++++++++++
 drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h  |   22 +
 drivers/media/platform/mtk-mdp/mtk_mdp_regs.c |  153 +++
 drivers/media/platform/mtk-mdp/mtk_mdp_regs.h |   31 +
 drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c  |  140 +++
 drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h  |   41 +
 14 files changed, 2602 insertions(+)
 create mode 100644 drivers/media/platform/mtk-mdp/Makefile
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_comp.c
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_comp.h
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_core.c
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_core.h
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_regs.c
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_regs.h
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h

diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 2c2670c..782b618 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -166,6 +166,22 @@ config VIDEO_MEDIATEK_VPU
 	    To compile this driver as a module, choose M here: the
 	    module will be called mtk-vpu.
 
+config VIDEO_MEDIATEK_MDP
+	tristate "Mediatek MDP driver"
+	depends on MTK_IOMMU || COMPILE_TEST
+	depends on VIDEO_DEV && VIDEO_V4L2
+	depends on ARCH_MEDIATEK || COMPILE_TEST
+	select VIDEOBUF2_DMA_CONTIG
+	select V4L2_MEM2MEM_DEV
+	select VIDEO_MEDIATEK_VPU
+	default n
+	---help---
+	    It is a v4l2 driver and present in Mediatek MT8173 SoCs.
+	    The driver supports for scaling and color space conversion.
+
+	    To compile this driver as a module, choose M here: the
+	    module will be called mtk-mdp.
+
 config VIDEO_MEDIATEK_VCODEC
 	tristate "Mediatek Video Codec driver"
 	depends on MTK_IOMMU || COMPILE_TEST
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index c6b3b92..9c54f1a 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -62,3 +62,5 @@ ccflags-y += -I$(srctree)/drivers/media/i2c
 obj-$(CONFIG_VIDEO_MEDIATEK_VPU)	+= mtk-vpu/
 
 obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC)	+= mtk-vcodec/
+
+obj-$(CONFIG_VIDEO_MEDIATEK_MDP)	+= mtk-mdp/
diff --git a/drivers/media/platform/mtk-mdp/Makefile b/drivers/media/platform/mtk-mdp/Makefile
new file mode 100644
index 0000000..f802569
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp/Makefile
@@ -0,0 +1,9 @@
+mtk-mdp-y += mtk_mdp_core.o
+mtk-mdp-y += mtk_mdp_comp.o
+mtk-mdp-y += mtk_mdp_m2m.o
+mtk-mdp-y += mtk_mdp_regs.o
+mtk-mdp-y += mtk_mdp_vpu.o
+
+obj-$(CONFIG_VIDEO_MEDIATEK_MDP) += mtk-mdp.o
+
+ccflags-y += -I$(srctree)/drivers/media/platform/mtk-vpu
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_comp.c b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.c
new file mode 100644
index 0000000..aa8f9fd
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <soc/mediatek/smi.h>
+
+#include "mtk_mdp_comp.h"
+
+
+static const char * const mtk_mdp_comp_stem[MTK_MDP_COMP_TYPE_MAX] = {
+	"mdp_rdma",
+	"mdp_rsz",
+	"mdp_wdma",
+	"mdp_wrot",
+};
+
+struct mtk_mdp_comp_match {
+	enum mtk_mdp_comp_type type;
+	int alias_id;
+};
+
+static const struct mtk_mdp_comp_match mtk_mdp_matches[MTK_MDP_COMP_ID_MAX] = {
+	{ MTK_MDP_RDMA,	0 },
+	{ MTK_MDP_RDMA,	1 },
+	{ MTK_MDP_RSZ,	0 },
+	{ MTK_MDP_RSZ,	1 },
+	{ MTK_MDP_RSZ,	2 },
+	{ MTK_MDP_WDMA,	0 },
+	{ MTK_MDP_WROT,	0 },
+	{ MTK_MDP_WROT,	1 },
+};
+
+int mtk_mdp_comp_get_id(struct device *dev, struct device_node *node,
+			enum mtk_mdp_comp_type comp_type)
+{
+	int id = of_alias_get_id(node, mtk_mdp_comp_stem[comp_type]);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mtk_mdp_matches); i++) {
+		if (comp_type == mtk_mdp_matches[i].type &&
+		    id == mtk_mdp_matches[i].alias_id)
+			return i;
+	}
+
+	dev_err(dev, "Failed to get id. type: %d, id: %d\n", comp_type, id);
+
+	return -EINVAL;
+}
+
+void mtk_mdp_comp_clock_on(struct device *dev, struct mtk_mdp_comp *comp)
+{
+	int i, err;
+
+	if (comp->larb_dev) {
+		err = mtk_smi_larb_get(comp->larb_dev);
+		if (err)
+			dev_err(dev,
+				"failed to get larb, err %d. type:%d id:%d\n",
+				err, comp->type, comp->id);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(comp->clk); i++) {
+		if (!comp->clk[i])
+			continue;
+		err = clk_prepare_enable(comp->clk[i]);
+		if (err)
+			dev_err(dev,
+			"failed to enable clock, err %d. type:%d id:%d i:%d\n",
+				err, comp->type, comp->id, i);
+	}
+}
+
+void mtk_mdp_comp_clock_off(struct device *dev, struct mtk_mdp_comp *comp)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(comp->clk); i++) {
+		if (!comp->clk[i])
+			continue;
+		clk_disable_unprepare(comp->clk[i]);
+	}
+
+	if (comp->larb_dev)
+		mtk_smi_larb_put(comp->larb_dev);
+}
+
+int mtk_mdp_comp_init(struct device *dev, struct device_node *node,
+		      struct mtk_mdp_comp *comp, enum mtk_mdp_comp_id comp_id)
+{
+	struct device_node *larb_node;
+	struct platform_device *larb_pdev;
+	int i;
+
+	if (comp_id < 0 || comp_id >= MTK_MDP_COMP_ID_MAX) {
+		dev_err(dev, "Invalid comp_id %d\n", comp_id);
+		return -EINVAL;
+	}
+
+	comp->dev_node = of_node_get(node);
+	comp->id = comp_id;
+	comp->type = mtk_mdp_matches[comp_id].type;
+	comp->regs = of_iomap(node, 0);
+
+	for (i = 0; i < ARRAY_SIZE(comp->clk); i++) {
+		comp->clk[i] = of_clk_get(node, i);
+
+		/* Only RDMA needs two clocks */
+		if (comp->type != MTK_MDP_RDMA)
+			break;
+	}
+
+	/* Only DMA capable components need the LARB property */
+	comp->larb_dev = NULL;
+	if (comp->type != MTK_MDP_RDMA &&
+	    comp->type != MTK_MDP_WDMA &&
+	    comp->type != MTK_MDP_WROT)
+		return 0;
+
+	larb_node = of_parse_phandle(node, "mediatek,larb", 0);
+	if (!larb_node) {
+		dev_err(dev,
+			"Missing mediadek,larb phandle in %s node\n",
+			node->full_name);
+		return -EINVAL;
+	}
+
+	larb_pdev = of_find_device_by_node(larb_node);
+	if (!larb_pdev) {
+		dev_warn(dev, "Waiting for larb device %s\n",
+			 larb_node->full_name);
+		of_node_put(larb_node);
+		return -EPROBE_DEFER;
+	}
+	of_node_put(larb_node);
+
+	comp->larb_dev = &larb_pdev->dev;
+
+	return 0;
+}
+
+void mtk_mdp_comp_deinit(struct device *dev, struct mtk_mdp_comp *comp)
+{
+	of_node_put(comp->dev_node);
+}
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_comp.h b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.h
new file mode 100644
index 0000000..63b3983
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __MTK_MDP_COMP_H__
+#define __MTK_MDP_COMP_H__
+
+/**
+ * enum mtk_mdp_comp_type - the MDP component
+ * @MTK_MDP_RDMA:	Read DMA
+ * @MTK_MDP_RSZ:	Riszer
+ * @MTK_MDP_WDMA:	Write DMA
+ * @MTK_MDP_WROT:	Write DMA with rotation
+ */
+enum mtk_mdp_comp_type {
+	MTK_MDP_RDMA,
+	MTK_MDP_RSZ,
+	MTK_MDP_WDMA,
+	MTK_MDP_WROT,
+	MTK_MDP_COMP_TYPE_MAX,
+};
+
+enum mtk_mdp_comp_id {
+	MTK_MDP_COMP_RDMA0,
+	MTK_MDP_COMP_RDMA1,
+	MTK_MDP_COMP_RSZ0,
+	MTK_MDP_COMP_RSZ1,
+	MTK_MDP_COMP_RSZ2,
+	MTK_MDP_COMP_WDMA,
+	MTK_MDP_COMP_WROT0,
+	MTK_MDP_COMP_WROT1,
+	MTK_MDP_COMP_ID_MAX,
+};
+
+/**
+ * struct mtk_mdp_comp - the MDP's function component data
+ * @dev_node:	component device node
+ * @clk:	clocks required for component
+ * @regs:	Mapped address of component registers.
+ * @larb_dev:	SMI device required for component
+ * @type:	component type
+ * @id:		component ID
+ */
+struct mtk_mdp_comp {
+	struct device_node	*dev_node;
+	struct clk		*clk[2];
+	void __iomem		*regs;
+	struct device		*larb_dev;
+	enum mtk_mdp_comp_type	type;
+	enum mtk_mdp_comp_id	id;
+};
+
+int mtk_mdp_comp_init(struct device *dev, struct device_node *node,
+		      struct mtk_mdp_comp *comp, enum mtk_mdp_comp_id comp_id);
+void mtk_mdp_comp_deinit(struct device *dev, struct mtk_mdp_comp *comp);
+int mtk_mdp_comp_get_id(struct device *dev, struct device_node *node,
+			enum mtk_mdp_comp_type comp_type);
+void mtk_mdp_comp_clock_on(struct device *dev, struct mtk_mdp_comp *comp);
+void mtk_mdp_comp_clock_off(struct device *dev, struct mtk_mdp_comp *comp);
+
+
+#endif /* __MTK_MDP_COMP_H__ */
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c
new file mode 100644
index 0000000..8a81dd9
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2015-2016 MediaTek Inc.
+ * Author: Houlong Wei <houlong.wei at mediatek.com>
+ *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/workqueue.h>
+#include <soc/mediatek/smi.h>
+
+#include "mtk_mdp_core.h"
+#include "mtk_mdp_m2m.h"
+#include "mtk_vpu.h"
+
+/* MDP debug log level (0-3). 3 shows all the logs. */
+int mtk_mdp_dbg_level;
+EXPORT_SYMBOL(mtk_mdp_dbg_level);
+
+module_param(mtk_mdp_dbg_level, int, S_IRUGO | S_IWUSR);
+
+static const struct of_device_id mtk_mdp_comp_dt_ids[] = {
+	{
+		.compatible = "mediatek,mt8173-mdp-rdma",
+		.data = (void *)MTK_MDP_RDMA
+	}, {
+		.compatible = "mediatek,mt8173-mdp-rsz",
+		.data = (void *)MTK_MDP_RSZ
+	}, {
+		.compatible = "mediatek,mt8173-mdp-wdma",
+		.data = (void *)MTK_MDP_WDMA
+	}, {
+		.compatible = "mediatek,mt8173-mdp-wrot",
+		.data = (void *)MTK_MDP_WROT
+	}
+};
+
+static const struct of_device_id mtk_mdp_of_ids[] = {
+	{ .compatible = "mediatek,mt8173-mdp", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, mtk_mdp_of_ids);
+
+static void mtk_mdp_clock_on(struct mtk_mdp_dev *mdp)
+{
+	struct device *dev = &mdp->pdev->dev;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mdp->comp); i++)
+		mtk_mdp_comp_clock_on(dev, mdp->comp[i]);
+}
+
+static void mtk_mdp_clock_off(struct mtk_mdp_dev *mdp)
+{
+	struct device *dev = &mdp->pdev->dev;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mdp->comp); i++)
+		mtk_mdp_comp_clock_off(dev, mdp->comp[i]);
+}
+
+static void mtk_mdp_wdt_worker(struct work_struct *work)
+{
+	struct mtk_mdp_dev *mdp =
+			container_of(work, struct mtk_mdp_dev, wdt_work);
+	struct mtk_mdp_ctx *ctx;
+
+	mtk_mdp_err("Watchdog timeout");
+
+	list_for_each_entry(ctx, &mdp->ctx_list, list) {
+		mtk_mdp_dbg(0, "[%d] Change as state error", ctx->id);
+		mtk_mdp_ctx_state_lock_set(ctx, MTK_MDP_CTX_ERROR);
+	}
+}
+
+static void mtk_mdp_reset_handler(void *priv)
+{
+	struct mtk_mdp_dev *mdp = priv;
+
+	queue_work(mdp->wdt_wq, &mdp->wdt_work);
+}
+
+static int mtk_mdp_probe(struct platform_device *pdev)
+{
+	struct mtk_mdp_dev *mdp;
+	struct device *dev = &pdev->dev;
+	struct device_node *node;
+	int i, ret = 0;
+
+	mdp = devm_kzalloc(dev, sizeof(*mdp), GFP_KERNEL);
+	if (!mdp)
+		return -ENOMEM;
+
+	mdp->id = pdev->id;
+	mdp->pdev = pdev;
+	INIT_LIST_HEAD(&mdp->ctx_list);
+
+	mutex_init(&mdp->lock);
+	mutex_init(&mdp->vpulock);
+
+	/* Iterate over sibling MDP function blocks */
+	for_each_child_of_node(dev->of_node->parent, node) {
+		const struct of_device_id *of_id;
+		enum mtk_mdp_comp_type comp_type;
+		int comp_id;
+		struct mtk_mdp_comp *comp;
+
+		of_id = of_match_node(mtk_mdp_comp_dt_ids, node);
+		if (!of_id)
+			continue;
+
+		if (!of_device_is_available(node)) {
+			dev_err(dev, "Skipping disabled component %s\n",
+				node->full_name);
+			continue;
+		}
+
+		comp_type = (enum mtk_mdp_comp_type)of_id->data;
+		comp_id = mtk_mdp_comp_get_id(dev, node, comp_type);
+		if (comp_id < 0) {
+			dev_warn(dev, "Skipping unknown component %s\n",
+				 node->full_name);
+			continue;
+		}
+
+		comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL);
+		if (!comp) {
+			ret = -ENOMEM;
+			goto err_comp;
+		}
+		mdp->comp[comp_id] = comp;
+
+		ret = mtk_mdp_comp_init(dev, node, comp, comp_id);
+		if (ret)
+			goto err_comp;
+	}
+
+	mdp->job_wq = create_singlethread_workqueue(MTK_MDP_MODULE_NAME);
+	if (!mdp->job_wq) {
+		dev_err(&pdev->dev, "unable to alloc job workqueue\n");
+		ret = -ENOMEM;
+		goto err_alloc_job_wq;
+	}
+
+	mdp->wdt_wq = create_singlethread_workqueue("mdp_wdt_wq");
+	if (!mdp->wdt_wq) {
+		dev_err(&pdev->dev, "unable to alloc wdt workqueue\n");
+		ret = -ENOMEM;
+		goto err_alloc_wdt_wq;
+	}
+	INIT_WORK(&mdp->wdt_work, mtk_mdp_wdt_worker);
+
+	ret = v4l2_device_register(dev, &mdp->v4l2_dev);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register v4l2 device\n");
+		ret = -EINVAL;
+		goto err_dev_register;
+	}
+
+	ret = mtk_mdp_register_m2m_device(mdp);
+	if (ret) {
+		v4l2_err(&mdp->v4l2_dev, "Failed to init mem2mem device\n");
+		goto err_m2m_register;
+	}
+
+	mdp->vpu_dev = vpu_get_plat_device(pdev);
+	vpu_wdt_reg_handler(mdp->vpu_dev, mtk_mdp_reset_handler, mdp,
+			    VPU_RST_MDP);
+
+	platform_set_drvdata(pdev, mdp);
+
+	vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32));
+
+	pm_runtime_enable(dev);
+	dev_dbg(dev, "mdp-%d registered successfully\n", mdp->id);
+
+	return 0;
+
+err_m2m_register:
+	v4l2_device_unregister(&mdp->v4l2_dev);
+
+err_dev_register:
+	destroy_workqueue(mdp->wdt_wq);
+
+err_alloc_wdt_wq:
+	destroy_workqueue(mdp->job_wq);
+
+err_alloc_job_wq:
+
+err_comp:
+	for (i = 0; i < ARRAY_SIZE(mdp->comp); i++)
+		mtk_mdp_comp_deinit(dev, mdp->comp[i]);
+
+	dev_dbg(dev, "err %d\n", ret);
+	return ret;
+}
+
+static int mtk_mdp_remove(struct platform_device *pdev)
+{
+	struct mtk_mdp_dev *mdp = platform_get_drvdata(pdev);
+	int i;
+
+	pm_runtime_disable(&pdev->dev);
+	vb2_dma_contig_clear_max_seg_size(&pdev->dev);
+	mtk_mdp_unregister_m2m_device(mdp);
+	v4l2_device_unregister(&mdp->v4l2_dev);
+
+	flush_workqueue(mdp->job_wq);
+	destroy_workqueue(mdp->job_wq);
+
+	for (i = 0; i < ARRAY_SIZE(mdp->comp); i++)
+		mtk_mdp_comp_deinit(&pdev->dev, mdp->comp[i]);
+
+	dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
+	return 0;
+}
+
+#if defined(CONFIG_PM_RUNTIME) || defined(CONFIG_PM_SLEEP)
+static int mtk_mdp_pm_suspend(struct device *dev)
+{
+	struct mtk_mdp_dev *mdp = dev_get_drvdata(dev);
+
+	mtk_mdp_clock_off(mdp);
+
+	return 0;
+}
+
+static int mtk_mdp_pm_resume(struct device *dev)
+{
+	struct mtk_mdp_dev *mdp = dev_get_drvdata(dev);
+
+	mtk_mdp_clock_on(mdp);
+
+	return 0;
+}
+#endif /* CONFIG_PM_RUNTIME || CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM_SLEEP
+static int mtk_mdp_suspend(struct device *dev)
+{
+	if (pm_runtime_suspended(dev))
+		return 0;
+
+	return mtk_mdp_pm_suspend(dev);
+}
+
+static int mtk_mdp_resume(struct device *dev)
+{
+	if (pm_runtime_suspended(dev))
+		return 0;
+
+	return mtk_mdp_pm_resume(dev);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops mtk_mdp_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(mtk_mdp_suspend, mtk_mdp_resume)
+	SET_RUNTIME_PM_OPS(mtk_mdp_pm_suspend, mtk_mdp_pm_resume, NULL)
+};
+
+static struct platform_driver mtk_mdp_driver = {
+	.probe		= mtk_mdp_probe,
+	.remove		= mtk_mdp_remove,
+	.driver = {
+		.name	= MTK_MDP_MODULE_NAME,
+		.owner	= THIS_MODULE,
+		.pm	= &mtk_mdp_pm_ops,
+		.of_match_table = mtk_mdp_of_ids,
+	}
+};
+
+module_platform_driver(mtk_mdp_driver);
+
+MODULE_AUTHOR("Houlong Wei <houlong.wei at mediatek.com>");
+MODULE_DESCRIPTION("Mediatek image processor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.h b/drivers/media/platform/mtk-mdp/mtk_mdp_core.h
new file mode 100644
index 0000000..9046968
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.h
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2015-2016 MediaTek Inc.
+ * Author: Houlong Wei <houlong.wei at mediatek.com>
+ *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __MTK_MDP_CORE_H__
+#define __MTK_MDP_CORE_H__
+
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "mtk_mdp_vpu.h"
+#include "mtk_mdp_comp.h"
+
+
+#define MTK_MDP_MODULE_NAME		"mtk-mdp"
+
+#define MTK_MDP_SHUTDOWN_TIMEOUT	((100*HZ)/1000) /* 100ms */
+#define MTK_MDP_MAX_CTRL_NUM		10
+
+#define MTK_MDP_FMT_FLAG_OUTPUT		BIT(0)
+#define MTK_MDP_FMT_FLAG_CAPTURE	BIT(1)
+
+#define MTK_MDP_SRC_FMT			BIT(1)
+#define MTK_MDP_DST_FMT			BIT(2)
+#define MTK_MDP_CTX_ERROR		BIT(5)
+
+/**
+ * struct mtk_mdp_fmt - the driver's internal color format data
+ * @name: format description
+ * @pixelformat: the fourcc code for this format, 0 if not applicable
+ * @num_planes: number of physically non-contiguous data planes
+ * @depth: per plane driver's private 'number of bits per pixel'
+ * @flags: flags indicating which operation mode format applies to
+	   MTK_MDP_FMT_FLAG_OUTPUT is used in OUTPUT stream
+	   MTK_MDP_FMT_FLAG_CAPTURE is used in CAPTURE stream
+ */
+struct mtk_mdp_fmt {
+	char	*name;
+	u32	pixelformat;
+	u16	num_planes;
+	u8	depth[VIDEO_MAX_PLANES];
+	u32	flags;
+};
+
+/**
+ * struct mtk_mdp_addr - the image processor physical address set
+ * @addr:	address of planes
+ */
+struct mtk_mdp_addr {
+	dma_addr_t addr[MTK_MDP_MAX_NUM_PLANE];
+};
+
+/* struct mtk_mdp_ctrls - the image processor control set
+ * @rotate: rotation degree
+ * @hflip: horizontal flip
+ * @vflip: vertical flip
+ * @global_alpha: the alpha value of current frame
+ */
+struct mtk_mdp_ctrls {
+	struct v4l2_ctrl *rotate;
+	struct v4l2_ctrl *hflip;
+	struct v4l2_ctrl *vflip;
+	struct v4l2_ctrl *global_alpha;
+};
+
+/**
+ * struct mtk_mdp_frame - source/target frame properties
+ * @width:	SRC : SRCIMG_WIDTH, DST : OUTPUTDMA_WHOLE_IMG_WIDTH
+ * @height:	SRC : SRCIMG_HEIGHT, DST : OUTPUTDMA_WHOLE_IMG_HEIGHT
+ * @crop:	cropped(source)/scaled(destination) size
+ * @payload:	image size in bytes (w x h x bpp)
+ * @pitch:	bytes per line of image in memory
+ * @addr:	image frame buffer physical addresses
+ * @fmt:	color format pointer
+ * @alpha:	frame's alpha value
+ */
+struct mtk_mdp_frame {
+	u32				width;
+	u32				height;
+	struct v4l2_rect		crop;
+	unsigned long			payload[VIDEO_MAX_PLANES];
+	unsigned int			pitch[VIDEO_MAX_PLANES];
+	struct mtk_mdp_addr		addr;
+	const struct mtk_mdp_fmt	*fmt;
+	u8				alpha;
+};
+
+/**
+ * struct mtk_mdp_variant - image processor variant information
+ * @pix_max:		maximum limit of image size
+ * @pix_min:		minimun limit of image size
+ * @pix_align:		alignement of image
+ * @h_scale_up_max:	maximum scale-up in horizontal
+ * @v_scale_up_max:	maximum scale-up in vertical
+ * @h_scale_down_max:	maximum scale-down in horizontal
+ * @v_scale_down_max:	maximum scale-down in vertical
+ */
+struct mtk_mdp_variant {
+	struct mtk_mdp_pix_limit	*pix_max;
+	struct mtk_mdp_pix_limit	*pix_min;
+	struct mtk_mdp_pix_align	*pix_align;
+	u16				h_scale_up_max;
+	u16				v_scale_up_max;
+	u16				h_scale_down_max;
+	u16				v_scale_down_max;
+};
+
+/**
+ * struct mtk_mdp_dev - abstraction for image processor entity
+ * @lock:	the mutex protecting this data structure
+ * @vpulock:	the mutex protecting the communication with VPU
+ * @pdev:	pointer to the image processor platform device
+ * @variant:	the IP variant information
+ * @id:		image processor device index (0..MTK_MDP_MAX_DEVS)
+ * @comp:	MDP function components
+ * @m2m_dev:	v4l2 memory-to-memory device data
+ * @ctx_list:	list of struct mtk_mdp_ctx
+ * @vdev:	video device for image processor driver
+ * @v4l2_dev:	V4L2 device to register video devices for.
+ * @job_wq:	processor work queue
+ * @vpu_dev:	VPU platform device
+ * @ctx_num:	counter of active MTK MDP context
+ * @id_counter:	An integer id given to the next opened context
+ * @wdt_wq:	work queue for VPU watchdog
+ * @wdt_work:	worker for VPU watchdog
+ */
+struct mtk_mdp_dev {
+	struct mutex			lock;
+	struct mutex			vpulock;
+	struct platform_device		*pdev;
+	struct mtk_mdp_variant		*variant;
+	u16				id;
+	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 v4l2_device		v4l2_dev;
+	struct workqueue_struct		*job_wq;
+	struct platform_device		*vpu_dev;
+	int				ctx_num;
+	unsigned long			id_counter;
+	struct workqueue_struct		*wdt_wq;
+	struct work_struct		wdt_work;
+};
+
+/**
+ * mtk_mdp_ctx - the device context data
+ * @list:		link to ctx_list of mtk_mdp_dev
+ * @s_frame:		source frame properties
+ * @d_frame:		destination frame properties
+ * @id:			index of the context that this structure describes
+ * @flags:		additional flags for image conversion
+ * @state:		flags to keep track of user configuration
+			Protected by slock
+ * @rotation:		rotates the image by specified angle
+ * @hflip:		mirror the picture horizontally
+ * @vflip:		mirror the picture vertically
+ * @mdp_dev:		the image processor device this context applies to
+ * @m2m_ctx:		memory-to-memory device context
+ * @fh:			v4l2 file handle
+ * @ctrl_handler:	v4l2 controls handler
+ * @ctrls		image processor control set
+ * @ctrls_rdy:		true if the control handler is initialized
+ * @vpu:		VPU instance
+ * @slock:		the mutex protecting mtp_mdp_ctx.state
+ * @work:		worker for image processing
+ */
+struct mtk_mdp_ctx {
+	struct list_head		list;
+	struct mtk_mdp_frame		s_frame;
+	struct mtk_mdp_frame		d_frame;
+	u32				flags;
+	u32				state;
+	int				id;
+	int				rotation;
+	u32				hflip:1;
+	u32				vflip:1;
+	struct mtk_mdp_dev		*mdp_dev;
+	struct v4l2_m2m_ctx		*m2m_ctx;
+	struct v4l2_fh			fh;
+	struct v4l2_ctrl_handler	ctrl_handler;
+	struct mtk_mdp_ctrls		ctrls;
+	bool				ctrls_rdy;
+
+	struct mtk_mdp_vpu		vpu;
+	struct mutex			slock;
+	struct work_struct		work;
+};
+
+extern int mtk_mdp_dbg_level;
+
+#if defined(DEBUG)
+
+#define mtk_mdp_dbg(level, fmt, args...)				 \
+	do {								 \
+		if (mtk_mdp_dbg_level >= level)				 \
+			pr_info("[MTK_MDP] level=%d %s(),%d: " fmt "\n", \
+				level, __func__, __LINE__, ##args);	 \
+	} while (0)
+
+#define mtk_mdp_err(fmt, args...)					\
+	pr_err("[MTK_MDP][ERROR] %s:%d: " fmt "\n", __func__, __LINE__, \
+	       ##args)
+
+
+#define mtk_mdp_dbg_enter()  mtk_mdp_dbg(3, "+")
+#define mtk_mdp_dbg_leave()  mtk_mdp_dbg(3, "-")
+
+#else
+
+#define mtk_mdp_dbg(level, fmt, args...)
+#define mtk_mdp_err(fmt, args...)
+#define mtk_mdp_dbg_enter()
+#define mtk_mdp_dbg_leave()
+
+#endif
+
+#endif /* __MTK_MDP_CORE_H__ */
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h b/drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h
new file mode 100644
index 0000000..78e2cc0
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2015-2016 MediaTek Inc.
+ * Author: Houlong Wei <houlong.wei at mediatek.com>
+ *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __MTK_MDP_IPI_H__
+#define __MTK_MDP_IPI_H__
+
+#define MTK_MDP_MAX_NUM_PLANE		3
+
+enum mdp_ipi_msgid {
+	AP_MDP_INIT		= 0xd000,
+	AP_MDP_DEINIT		= 0xd001,
+	AP_MDP_PROCESS		= 0xd002,
+
+	VPU_MDP_INIT_ACK	= 0xe000,
+	VPU_MDP_DEINIT_ACK	= 0xe001,
+	VPU_MDP_PROCESS_ACK	= 0xe002
+};
+
+#pragma pack(push, 4)
+
+/**
+ * struct mdp_ipi_init - for AP_MDP_INIT
+ * @msg_id   : AP_MDP_INIT
+ * @ipi_id   : IPI_MDP
+ * @ap_inst  : AP mtk_mdp_vpu address
+ */
+struct mdp_ipi_init {
+	uint32_t msg_id;
+	uint32_t ipi_id;
+	uint64_t ap_inst;
+};
+
+/**
+ * struct mdp_ipi_comm - for AP_MDP_PROCESS, AP_MDP_DEINIT
+ * @msg_id        : AP_MDP_PROCESS, AP_MDP_DEINIT
+ * @ipi_id        : IPI_MDP
+ * @ap_inst       : AP mtk_mdp_vpu address
+ * @vpu_inst_addr : VPU MDP instance address
+ */
+struct mdp_ipi_comm {
+	uint32_t msg_id;
+	uint32_t ipi_id;
+	uint64_t ap_inst;
+	uint32_t vpu_inst_addr;
+};
+
+/**
+ * struct mdp_ipi_comm_ack - for VPU_MDP_DEINIT_ACK, VPU_MDP_PROCESS_ACK
+ * @msg_id        : VPU_MDP_DEINIT_ACK, VPU_MDP_PROCESS_ACK
+ * @ipi_id        : IPI_MDP
+ * @ap_inst       : AP mtk_mdp_vpu address
+ * @vpu_inst_addr : VPU MDP instance address
+ * @status        : VPU exeuction result
+ */
+struct mdp_ipi_comm_ack {
+	uint32_t msg_id;
+	uint32_t ipi_id;
+	uint64_t ap_inst;
+	uint32_t vpu_inst_addr;
+	int32_t status;
+};
+
+/**
+ * struct mdp_config - configured for source/destination image
+ * @x        : left
+ * @y        : top
+ * @w        : width
+ * @h        : height
+ * @w_stride : bytes in horizontal
+ * @h_stride : bytes in vertical
+ * @crop_x   : cropped left
+ * @crop_y   : cropped top
+ * @crop_w   : cropped width
+ * @crop_h   : cropped height
+ * @format   : color format
+ */
+struct mdp_config {
+	int32_t x;
+	int32_t y;
+	int32_t w;
+	int32_t h;
+	int32_t w_stride;
+	int32_t h_stride;
+	int32_t crop_x;
+	int32_t crop_y;
+	int32_t crop_w;
+	int32_t crop_h;
+	int32_t format;
+};
+
+struct mdp_buffer {
+	uint64_t addr_mva[MTK_MDP_MAX_NUM_PLANE];
+	int32_t plane_size[MTK_MDP_MAX_NUM_PLANE];
+	int32_t plane_num;
+};
+
+struct mdp_config_misc {
+	int32_t orientation; /* 0, 90, 180, 270 */
+	int32_t hflip; /* 1 will enable the flip */
+	int32_t vflip; /* 1 will enable the flip */
+	int32_t alpha; /* global alpha */
+};
+
+struct mdp_process_vsi {
+	struct mdp_config src_config;
+	struct mdp_buffer src_buffer;
+	struct mdp_config dst_config;
+	struct mdp_buffer dst_buffer;
+	struct mdp_config_misc misc;
+};
+
+#pragma pack(pop)
+
+#endif /* __MTK_MDP_IPI_H__ */
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
new file mode 100644
index 0000000..e3ea97d
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
@@ -0,0 +1,1304 @@
+/*
+ * Copyright (c) 2015-2016 MediaTek Inc.
+ * Author: Houlong Wei <houlong.wei at mediatek.com>
+ *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/pm_runtime.h>
+#include <linux/workqueue.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+
+#include "mtk_mdp_core.h"
+#include "mtk_mdp_m2m.h"
+#include "mtk_mdp_regs.h"
+#include "mtk_vpu.h"
+
+
+/**
+ *  struct mtk_mdp_pix_limit - image pixel size limits
+ *  @org_w: source pixel width
+ *  @org_h: source pixel height
+ *  @target_rot_dis_w: pixel dst scaled width with the rotator is off
+ *  @target_rot_dis_h: pixel dst scaled height with the rotator is off
+ *  @target_rot_en_w: pixel dst scaled width with the rotator is on
+ *  @target_rot_en_h: pixel dst scaled height with the rotator is on
+ */
+struct mtk_mdp_pix_limit {
+	u16 org_w;
+	u16 org_h;
+	u16 target_rot_dis_w;
+	u16 target_rot_dis_h;
+	u16 target_rot_en_w;
+	u16 target_rot_en_h;
+};
+
+/**
+ *  struct mtk_mdp_pix_align - alignement of image
+ *  @org_w: source alignment of width
+ *  @org_h: source alignment of height
+ *  @target_w: dst alignment of width
+ *  @target_h: dst alignment of height
+ */
+struct mtk_mdp_pix_align {
+	u16 org_w;
+	u16 org_h;
+	u16 target_w;
+	u16 target_h;
+};
+
+static const struct mtk_mdp_fmt mtk_mdp_formats[] = {
+	{
+		.name		= "YUV420 MT21. 2p, Y/CbCr",
+		.pixelformat	= V4L2_PIX_FMT_MT21,
+		.depth		= { 8, 4 },
+		.num_planes	= 2,
+		.flags		= MTK_MDP_FMT_FLAG_OUTPUT,
+	}, {
+		.name		= "YUV420 non-contig. 2p, Y/CbCr",
+		.pixelformat	= V4L2_PIX_FMT_NV12M,
+		.depth		= { 8, 4 },
+		.num_planes	= 2,
+		.flags		= MTK_MDP_FMT_FLAG_OUTPUT |
+				  MTK_MDP_FMT_FLAG_CAPTURE,
+	}, {
+		.name		= "YUV420 non-contig. 3p, Y/Cb/Cr",
+		.pixelformat	= V4L2_PIX_FMT_YUV420M,
+		.depth		= { 8, 2, 2 },
+		.num_planes	= 3,
+		.flags		= MTK_MDP_FMT_FLAG_OUTPUT |
+				  MTK_MDP_FMT_FLAG_CAPTURE,
+	}
+};
+
+static struct mtk_mdp_pix_limit mtk_mdp_size_max = {
+	.target_rot_dis_w	= 4096,
+	.target_rot_dis_h	= 4096,
+	.target_rot_en_w	= 4096,
+	.target_rot_en_h	= 4096,
+};
+
+static struct mtk_mdp_pix_limit mtk_mdp_size_min = {
+	.org_w			= 16,
+	.org_h			= 16,
+	.target_rot_dis_w	= 16,
+	.target_rot_dis_h	= 16,
+	.target_rot_en_w	= 16,
+	.target_rot_en_h	= 16,
+};
+
+static struct mtk_mdp_pix_align mtk_mdp_size_align = {
+	.org_w			= 16,
+	.org_h			= 16,
+	.target_w		= 2,
+	.target_h		= 2,
+};
+
+static struct mtk_mdp_variant mtk_mdp_default_variant = {
+	.pix_max		= &mtk_mdp_size_max,
+	.pix_min		= &mtk_mdp_size_min,
+	.pix_align		= &mtk_mdp_size_align,
+	.h_scale_up_max		= 32,
+	.v_scale_up_max		= 32,
+	.h_scale_down_max	= 32,
+	.v_scale_down_max	= 128,
+};
+
+static const struct mtk_mdp_fmt *mtk_mdp_find_fmt(u32 pixelformat, u32 type)
+{
+	u32 i, flag;
+
+	flag = V4L2_TYPE_IS_OUTPUT(type) ? MTK_MDP_FMT_FLAG_OUTPUT :
+					   MTK_MDP_FMT_FLAG_CAPTURE;
+
+	for (i = 0; i < ARRAY_SIZE(mtk_mdp_formats); ++i) {
+		if (!(mtk_mdp_formats[i].flags & flag))
+			continue;
+		if (mtk_mdp_formats[i].pixelformat == pixelformat)
+			return &mtk_mdp_formats[i];
+	}
+	return NULL;
+}
+
+static const struct mtk_mdp_fmt *mtk_mdp_find_fmt_by_index(u32 index, u32 type)
+{
+	u32 i, flag, num = 0;
+
+	flag = V4L2_TYPE_IS_OUTPUT(type) ? MTK_MDP_FMT_FLAG_OUTPUT :
+					   MTK_MDP_FMT_FLAG_CAPTURE;
+
+	for (i = 0; i < ARRAY_SIZE(mtk_mdp_formats); ++i) {
+		if (!(mtk_mdp_formats[i].flags & flag))
+			continue;
+		if (index == num)
+			return &mtk_mdp_formats[i];
+		num++;
+	}
+	return NULL;
+}
+
+static void mtk_mdp_bound_align_image(u32 *w, unsigned int wmin,
+				      unsigned int wmax, unsigned int align_w,
+				      u32 *h, unsigned int hmin,
+				      unsigned int hmax, unsigned int align_h)
+{
+	int org_w, org_h, step_w, step_h;
+	int walign, halign;
+
+	org_w = *w;
+	org_h = *h;
+	walign = ffs(align_w) - 1;
+	halign = ffs(align_h) - 1;
+	v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
+
+	step_w = 1 << walign;
+	step_h = 1 << halign;
+	if (*w < org_w && (*w + step_w) <= wmax)
+		*w += step_w;
+	if (*h < org_h && (*h + step_h) <= hmax)
+		*h += step_h;
+}
+
+static const struct mtk_mdp_fmt *mtk_mdp_try_fmt_mplane(struct mtk_mdp_ctx *ctx,
+							struct v4l2_format *f)
+{
+	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
+	struct mtk_mdp_variant *variant = mdp->variant;
+	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+	const struct mtk_mdp_fmt *fmt;
+	u32 max_w, max_h, align_w, align_h;
+	u32 min_w, min_h, org_w, org_h;
+	int i;
+
+	fmt = mtk_mdp_find_fmt(pix_mp->pixelformat, f->type);
+	if (!fmt)
+		fmt = mtk_mdp_find_fmt_by_index(0, f->type);
+	if (!fmt) {
+		dev_dbg(&ctx->mdp_dev->pdev->dev,
+			"pixelformat format 0x%X invalid\n",
+			pix_mp->pixelformat);
+		return NULL;
+	}
+
+	pix_mp->field = V4L2_FIELD_NONE;
+	pix_mp->pixelformat = fmt->pixelformat;
+	memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
+
+	max_w = variant->pix_max->target_rot_dis_w;
+	max_h = variant->pix_max->target_rot_dis_h;
+
+	align_w = variant->pix_align->org_w;
+	align_h = variant->pix_align->org_h;
+
+	if (V4L2_TYPE_IS_OUTPUT(f->type)) {
+		min_w = variant->pix_min->org_w;
+		min_h = variant->pix_min->org_h;
+	} else {
+		min_w = variant->pix_min->target_rot_dis_w;
+		min_h = variant->pix_min->target_rot_dis_h;
+	}
+
+	mtk_mdp_dbg(2, "[%d] type:%d, wxh:%ux%u, align:%ux%u, max:%ux%u",
+		    ctx->id, f->type, pix_mp->width, pix_mp->height,
+		    align_w, align_h, max_w, max_h);
+	/*
+	 * To check if image size is modified to adjust parameter against
+	 * hardware abilities
+	 */
+	org_w = pix_mp->width;
+	org_h = pix_mp->height;
+
+	mtk_mdp_bound_align_image(&pix_mp->width, min_w, max_w, align_w,
+				  &pix_mp->height, min_h, max_h, align_h);
+
+	if (org_w != pix_mp->width || org_h != pix_mp->height)
+		mtk_mdp_dbg(1, "[%d] size change:%ux%u to %ux%u", ctx->id,
+			    org_w, org_h, pix_mp->width, pix_mp->height);
+	pix_mp->num_planes = fmt->num_planes;
+
+	for (i = 0; i < pix_mp->num_planes; ++i) {
+		int bpl = (pix_mp->width * fmt->depth[i]) >> 3;
+		int sizeimage = bpl * pix_mp->height;
+
+		pix_mp->plane_fmt[i].bytesperline = bpl;
+		if (pix_mp->plane_fmt[i].sizeimage < sizeimage)
+			pix_mp->plane_fmt[i].sizeimage = sizeimage;
+		memset(pix_mp->plane_fmt[i].reserved, 0,
+		       sizeof(pix_mp->plane_fmt[i].reserved));
+		mtk_mdp_dbg(2, "[%d] p%d, bpl:%d, sizeimage:%u (%u)", ctx->id,
+			    i, bpl, pix_mp->plane_fmt[i].sizeimage, sizeimage);
+	}
+
+	return fmt;
+}
+
+static struct mtk_mdp_frame *mtk_mdp_ctx_get_frame(struct mtk_mdp_ctx *ctx,
+					    enum v4l2_buf_type type)
+{
+	if (V4L2_TYPE_IS_OUTPUT(type))
+		return &ctx->s_frame;
+	return &ctx->d_frame;
+}
+
+static void mtk_mdp_check_crop_change(u32 new_w, u32 new_h, u32 *w, u32 *h)
+{
+	if (new_w != *w || new_h != *h) {
+		mtk_mdp_dbg(1, "size change:%dx%d to %dx%d",
+			    *w, *h, new_w, new_h);
+
+		*w = new_w;
+		*h = new_h;
+	}
+}
+
+static int mtk_mdp_try_crop(struct mtk_mdp_ctx *ctx, struct v4l2_crop *cr)
+{
+	struct mtk_mdp_frame *frame;
+	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
+	struct mtk_mdp_variant *variant = mdp->variant;
+	u32 align_w, align_h, new_w, new_h;
+	u32 min_w, min_h, max_w, max_h;
+
+	if (cr->c.top < 0 || cr->c.left < 0) {
+		dev_err(&ctx->mdp_dev->pdev->dev,
+			"doesn't support negative values for top & left\n");
+		return -EINVAL;
+	}
+
+	mtk_mdp_dbg(2, "[%d] type:%d, set wxh:%dx%d", ctx->id, cr->type,
+		    cr->c.width, cr->c.height);
+
+	frame = mtk_mdp_ctx_get_frame(ctx, cr->type);
+	max_w = frame->width;
+	max_h = frame->height;
+	new_w = cr->c.width;
+	new_h = cr->c.height;
+
+	if (V4L2_TYPE_IS_OUTPUT(cr->type)) {
+		align_w = 1;
+		align_h = 1;
+		min_w = 64;
+		min_h = 32;
+	} else {
+		align_w = variant->pix_align->target_w;
+		align_h = variant->pix_align->target_h;
+		if (ctx->ctrls.rotate->val == 90 ||
+		    ctx->ctrls.rotate->val == 270) {
+			max_w = frame->height;
+			max_h = frame->width;
+			min_w = variant->pix_min->target_rot_en_w;
+			min_h = variant->pix_min->target_rot_en_h;
+			new_w = cr->c.height;
+			new_h = cr->c.width;
+		} else {
+			min_w = variant->pix_min->target_rot_dis_w;
+			min_h = variant->pix_min->target_rot_dis_h;
+		}
+	}
+
+	mtk_mdp_dbg(2, "[%d] align:%dx%d, min:%dx%d, new:%dx%d", ctx->id,
+		    align_w, align_h, min_w, min_h, new_w, new_h);
+
+	mtk_mdp_bound_align_image(&new_w, min_w, max_w, align_w,
+				  &new_h, min_h, max_h, align_h);
+
+	if (!V4L2_TYPE_IS_OUTPUT(cr->type) &&
+		(ctx->ctrls.rotate->val == 90 ||
+		ctx->ctrls.rotate->val == 270))
+		mtk_mdp_check_crop_change(new_h, new_w,
+					  &cr->c.width, &cr->c.height);
+	else
+		mtk_mdp_check_crop_change(new_w, new_h,
+					  &cr->c.width, &cr->c.height);
+
+	/* adjust left/top if cropping rectangle is out of bounds */
+	/* Need to add code to algin left value with 2's multiple */
+	if (cr->c.left + new_w > max_w)
+		cr->c.left = max_w - new_w;
+	if (cr->c.top + new_h > max_h)
+		cr->c.top = max_h - new_h;
+
+	if (cr->c.left & 1)
+		cr->c.left -= 1;
+
+	mtk_mdp_dbg(2, "[%d] crop l,t,w,h:%d,%d,%d,%d, max:%dx%d", ctx->id,
+		    cr->c.left, cr->c.top, cr->c.width,
+		    cr->c.height, max_w, max_h);
+	return 0;
+}
+
+static inline struct mtk_mdp_ctx *fh_to_ctx(struct v4l2_fh *fh)
+{
+	return container_of(fh, struct mtk_mdp_ctx, fh);
+}
+
+static inline struct mtk_mdp_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl)
+{
+	return container_of(ctrl->handler, struct mtk_mdp_ctx, ctrl_handler);
+}
+
+void mtk_mdp_ctx_state_lock_set(struct mtk_mdp_ctx *ctx, u32 state)
+{
+	mutex_lock(&ctx->slock);
+	ctx->state |= state;
+	mutex_unlock(&ctx->slock);
+}
+
+static void mtk_mdp_ctx_state_lock_clear(struct mtk_mdp_ctx *ctx, u32 state)
+{
+	mutex_lock(&ctx->slock);
+	ctx->state &= ~state;
+	mutex_unlock(&ctx->slock);
+}
+
+static bool mtk_mdp_ctx_state_is_set(struct mtk_mdp_ctx *ctx, u32 mask)
+{
+	bool ret;
+
+	mutex_lock(&ctx->slock);
+	ret = (ctx->state & mask) == mask;
+	mutex_unlock(&ctx->slock);
+	return ret;
+}
+
+static void mtk_mdp_ctx_lock(struct vb2_queue *vq)
+{
+	struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vq);
+
+	mutex_lock(&ctx->mdp_dev->lock);
+}
+
+static void mtk_mdp_ctx_unlock(struct vb2_queue *vq)
+{
+	struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vq);
+
+	mutex_unlock(&ctx->mdp_dev->lock);
+}
+
+static void mtk_mdp_set_frame_size(struct mtk_mdp_frame *frame, int width,
+				   int height)
+{
+	frame->width = width;
+	frame->height = height;
+	frame->crop.width = width;
+	frame->crop.height = height;
+	frame->crop.left = 0;
+	frame->crop.top = 0;
+}
+
+static int mtk_mdp_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct mtk_mdp_ctx *ctx = q->drv_priv;
+	int ret;
+
+	ret = pm_runtime_get_sync(&ctx->mdp_dev->pdev->dev);
+	if (ret < 0)
+		mtk_mdp_dbg(1, "[%d] pm_runtime_get_sync failed:%d",
+			    ctx->id, ret);
+
+	return 0;
+}
+
+static void *mtk_mdp_m2m_buf_remove(struct mtk_mdp_ctx *ctx,
+				    enum v4l2_buf_type type)
+{
+	if (V4L2_TYPE_IS_OUTPUT(type))
+		return v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+	else
+		return v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+}
+
+static void mtk_mdp_m2m_stop_streaming(struct vb2_queue *q)
+{
+	struct mtk_mdp_ctx *ctx = q->drv_priv;
+	struct vb2_buffer *vb;
+
+	vb = mtk_mdp_m2m_buf_remove(ctx, q->type);
+	while (vb != NULL) {
+		v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_ERROR);
+		vb = mtk_mdp_m2m_buf_remove(ctx, q->type);
+	}
+
+	pm_runtime_put(&ctx->mdp_dev->pdev->dev);
+}
+
+static void mtk_mdp_m2m_job_abort(void *priv)
+{
+}
+
+/* The color format (num_planes) must be already configured. */
+static void mtk_mdp_prepare_addr(struct mtk_mdp_ctx *ctx,
+				 struct vb2_buffer *vb,
+				 struct mtk_mdp_frame *frame,
+				 struct mtk_mdp_addr *addr)
+{
+	u32 pix_size, planes, i;
+
+	pix_size = frame->width * frame->height;
+	planes = min_t(u32, frame->fmt->num_planes, ARRAY_SIZE(addr->addr));
+	for (i = 0; i < planes; i++)
+		addr->addr[i] = vb2_dma_contig_plane_dma_addr(vb, i);
+
+	mtk_mdp_dbg(3, "[%d] planes:%d, size:%d, addr:%p,%p,%p",
+		    ctx->id, planes, pix_size, (void *)addr->addr[0],
+		    (void *)addr->addr[1], (void *)addr->addr[2]);
+}
+
+static void mtk_mdp_m2m_get_bufs(struct mtk_mdp_ctx *ctx)
+{
+	struct mtk_mdp_frame *s_frame, *d_frame;
+	struct vb2_buffer *src_vb, *dst_vb;
+	struct vb2_v4l2_buffer *src_vbuf, *dst_vbuf;
+
+	s_frame = &ctx->s_frame;
+	d_frame = &ctx->d_frame;
+
+	src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+	mtk_mdp_prepare_addr(ctx, src_vb, s_frame, &s_frame->addr);
+
+	dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+	mtk_mdp_prepare_addr(ctx, dst_vb, d_frame, &d_frame->addr);
+
+	src_vbuf = to_vb2_v4l2_buffer(src_vb);
+	dst_vbuf = to_vb2_v4l2_buffer(dst_vb);
+	dst_vbuf->vb2_buf.timestamp = src_vbuf->vb2_buf.timestamp;
+}
+
+static void mtk_mdp_process_done(void *priv, int vb_state)
+{
+	struct mtk_mdp_dev *mdp = priv;
+	struct mtk_mdp_ctx *ctx;
+	struct vb2_buffer *src_vb, *dst_vb;
+	struct vb2_v4l2_buffer *src_vbuf = NULL, *dst_vbuf = NULL;
+
+	ctx = v4l2_m2m_get_curr_priv(mdp->m2m_dev);
+	if (!ctx)
+		return;
+
+	src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+	src_vbuf = to_vb2_v4l2_buffer(src_vb);
+	dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+	dst_vbuf = to_vb2_v4l2_buffer(dst_vb);
+
+	dst_vbuf->vb2_buf.timestamp = src_vbuf->vb2_buf.timestamp;
+	dst_vbuf->timecode = src_vbuf->timecode;
+	dst_vbuf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+	dst_vbuf->flags |= src_vbuf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+
+	v4l2_m2m_buf_done(src_vbuf, vb_state);
+	v4l2_m2m_buf_done(dst_vbuf, vb_state);
+	v4l2_m2m_job_finish(ctx->mdp_dev->m2m_dev, ctx->m2m_ctx);
+}
+
+static void mtk_mdp_m2m_worker(struct work_struct *work)
+{
+	struct mtk_mdp_ctx *ctx =
+				container_of(work, struct mtk_mdp_ctx, work);
+	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
+	enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
+	int ret;
+
+	if (mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_CTX_ERROR)) {
+		dev_err(&mdp->pdev->dev, "ctx is in error state");
+		goto worker_end;
+	}
+
+	mtk_mdp_m2m_get_bufs(ctx);
+
+	mtk_mdp_hw_set_input_addr(ctx, &ctx->s_frame.addr);
+	mtk_mdp_hw_set_output_addr(ctx, &ctx->d_frame.addr);
+
+	mtk_mdp_hw_set_in_size(ctx);
+	mtk_mdp_hw_set_in_image_format(ctx);
+
+	mtk_mdp_hw_set_out_size(ctx);
+	mtk_mdp_hw_set_out_image_format(ctx);
+
+	mtk_mdp_hw_set_rotation(ctx);
+	mtk_mdp_hw_set_global_alpha(ctx);
+
+	ret = mtk_mdp_vpu_process(&ctx->vpu);
+	if (ret) {
+		dev_err(&mdp->pdev->dev, "processing failed: %d", ret);
+		goto worker_end;
+	}
+
+	buf_state = VB2_BUF_STATE_DONE;
+
+worker_end:
+	mtk_mdp_process_done(mdp, buf_state);
+}
+
+static void mtk_mdp_m2m_device_run(void *priv)
+{
+	struct mtk_mdp_ctx *ctx = priv;
+
+	queue_work(ctx->mdp_dev->job_wq, &ctx->work);
+}
+
+static int mtk_mdp_m2m_queue_setup(struct vb2_queue *vq,
+			unsigned int *num_buffers, unsigned int *num_planes,
+			unsigned int sizes[], struct device *alloc_devs[])
+{
+	struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vq);
+	struct mtk_mdp_frame *frame;
+	int i;
+
+	frame = mtk_mdp_ctx_get_frame(ctx, vq->type);
+	*num_planes = frame->fmt->num_planes;
+	for (i = 0; i < frame->fmt->num_planes; i++)
+		sizes[i] = frame->payload[i];
+	mtk_mdp_dbg(2, "[%d] type:%d, planes:%d, buffers:%d, size:%u,%u",
+		    ctx->id, vq->type, *num_planes, *num_buffers,
+		    sizes[0], sizes[1]);
+	return 0;
+}
+
+static int mtk_mdp_m2m_buf_prepare(struct vb2_buffer *vb)
+{
+	struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct mtk_mdp_frame *frame;
+	int i;
+
+	frame = mtk_mdp_ctx_get_frame(ctx, vb->vb2_queue->type);
+
+	if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
+		for (i = 0; i < frame->fmt->num_planes; i++)
+			vb2_set_plane_payload(vb, i, frame->payload[i]);
+	}
+
+	return 0;
+}
+
+static void mtk_mdp_m2m_buf_queue(struct vb2_buffer *vb)
+{
+	struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+	v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb));
+}
+
+static struct vb2_ops mtk_mdp_m2m_qops = {
+	.queue_setup	 = mtk_mdp_m2m_queue_setup,
+	.buf_prepare	 = mtk_mdp_m2m_buf_prepare,
+	.buf_queue	 = mtk_mdp_m2m_buf_queue,
+	.wait_prepare	 = mtk_mdp_ctx_unlock,
+	.wait_finish	 = mtk_mdp_ctx_lock,
+	.stop_streaming	 = mtk_mdp_m2m_stop_streaming,
+	.start_streaming = mtk_mdp_m2m_start_streaming,
+};
+
+static int mtk_mdp_m2m_querycap(struct file *file, void *fh,
+				struct v4l2_capability *cap)
+{
+	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
+	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
+
+	strlcpy(cap->driver, MTK_MDP_MODULE_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, mdp->pdev->name, sizeof(cap->card));
+	strlcpy(cap->bus_info, "platform:mt8173", sizeof(cap->bus_info));
+	cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+	return 0;
+}
+
+static int mtk_mdp_enum_fmt_mplane(struct v4l2_fmtdesc *f, u32 type)
+{
+	const struct mtk_mdp_fmt *fmt;
+
+	fmt = mtk_mdp_find_fmt_by_index(f->index, type);
+	if (!fmt)
+		return -EINVAL;
+
+	strlcpy(f->description, fmt->name, sizeof(f->description));
+	f->pixelformat = fmt->pixelformat;
+
+	return 0;
+}
+
+static int mtk_mdp_m2m_enum_fmt_mplane_vid_cap(struct file *file, void *priv,
+				       struct v4l2_fmtdesc *f)
+{
+	return mtk_mdp_enum_fmt_mplane(f, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+}
+
+static int mtk_mdp_m2m_enum_fmt_mplane_vid_out(struct file *file, void *priv,
+				       struct v4l2_fmtdesc *f)
+{
+	return mtk_mdp_enum_fmt_mplane(f, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+}
+
+static int mtk_mdp_g_fmt_mplane(struct mtk_mdp_ctx *ctx, struct v4l2_format *f)
+{
+	struct mtk_mdp_frame *frame;
+	struct v4l2_pix_format_mplane *pix_mp;
+	int i;
+
+	mtk_mdp_dbg(2, "[%d] type:%d", ctx->id, f->type);
+
+	frame = mtk_mdp_ctx_get_frame(ctx, f->type);
+	pix_mp = &f->fmt.pix_mp;
+
+	pix_mp->width = frame->width;
+	pix_mp->height = frame->height;
+	pix_mp->field = V4L2_FIELD_NONE;
+	pix_mp->pixelformat = frame->fmt->pixelformat;
+	pix_mp->num_planes = frame->fmt->num_planes;
+	mtk_mdp_dbg(2, "[%d] wxh:%dx%d", ctx->id,
+		    pix_mp->width, pix_mp->height);
+
+	for (i = 0; i < pix_mp->num_planes; ++i) {
+		pix_mp->plane_fmt[i].bytesperline = (frame->width *
+			frame->fmt->depth[i]) / 8;
+		pix_mp->plane_fmt[i].sizeimage =
+			 pix_mp->plane_fmt[i].bytesperline * frame->height;
+
+		mtk_mdp_dbg(2, "[%d] p%d, bpl:%d, sizeimage:%d", ctx->id, i,
+			    pix_mp->plane_fmt[i].bytesperline,
+			    pix_mp->plane_fmt[i].sizeimage);
+	}
+
+	return 0;
+}
+
+static int mtk_mdp_m2m_g_fmt_mplane(struct file *file, void *fh,
+				    struct v4l2_format *f)
+{
+	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
+
+	return mtk_mdp_g_fmt_mplane(ctx, f);
+}
+
+static int mtk_mdp_m2m_try_fmt_mplane(struct file *file, void *fh,
+				      struct v4l2_format *f)
+{
+	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
+
+	if (!mtk_mdp_try_fmt_mplane(ctx, f))
+		return -EINVAL;
+	return 0;
+}
+
+static int mtk_mdp_m2m_s_fmt_mplane(struct file *file, void *fh,
+				    struct v4l2_format *f)
+{
+	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
+	struct vb2_queue *vq;
+	struct mtk_mdp_frame *frame;
+	struct v4l2_pix_format_mplane *pix;
+	const struct mtk_mdp_fmt *fmt;
+	int i;
+
+	mtk_mdp_dbg(2, "[%d] type:%d", ctx->id, f->type);
+
+	frame = mtk_mdp_ctx_get_frame(ctx, f->type);
+	fmt = mtk_mdp_try_fmt_mplane(ctx, f);
+	if (!fmt) {
+		mtk_mdp_err("[%d] try_fmt failed, type:%d", ctx->id, f->type);
+		return -EINVAL;
+	}
+	frame->fmt = fmt;
+
+	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+	if (vb2_is_streaming(vq)) {
+		dev_info(&ctx->mdp_dev->pdev->dev, "queue %d busy", f->type);
+		return -EBUSY;
+	}
+
+	pix = &f->fmt.pix_mp;
+	for (i = 0; i < frame->fmt->num_planes; i++) {
+		frame->payload[i] = pix->plane_fmt[i].sizeimage;
+		frame->pitch[i] = pix->plane_fmt[i].bytesperline;
+	}
+
+	mtk_mdp_set_frame_size(frame, pix->width, pix->height);
+
+	if (V4L2_TYPE_IS_OUTPUT(f->type))
+		mtk_mdp_ctx_state_lock_set(ctx, MTK_MDP_SRC_FMT);
+	else
+		mtk_mdp_ctx_state_lock_set(ctx, MTK_MDP_DST_FMT);
+
+	mtk_mdp_dbg(2, "[%d] type:%d, frame:%dx%d", ctx->id, f->type,
+		    frame->width, frame->height);
+
+	return 0;
+}
+
+static int mtk_mdp_m2m_reqbufs(struct file *file, void *fh,
+			       struct v4l2_requestbuffers *reqbufs)
+{
+	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
+
+	if (reqbufs->count == 0) {
+		if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+			mtk_mdp_ctx_state_lock_clear(ctx, MTK_MDP_SRC_FMT);
+		else
+			mtk_mdp_ctx_state_lock_clear(ctx, MTK_MDP_DST_FMT);
+	}
+
+	return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int mtk_mdp_m2m_querybuf(struct file *file, void *fh,
+				struct v4l2_buffer *buf)
+{
+	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
+
+	return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int mtk_mdp_m2m_qbuf(struct file *file, void *fh,
+			    struct v4l2_buffer *buf)
+{
+	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
+
+	return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int mtk_mdp_m2m_dqbuf(struct file *file, void *fh,
+			     struct v4l2_buffer *buf)
+{
+	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
+
+	return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int mtk_mdp_m2m_streamon(struct file *file, void *fh,
+				enum v4l2_buf_type type)
+{
+	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
+
+	/* The source and target color format need to be set */
+	if (V4L2_TYPE_IS_OUTPUT(type)) {
+		if (!mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_SRC_FMT))
+			return -EINVAL;
+	} else if (!mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_DST_FMT)) {
+		return -EINVAL;
+	}
+
+	return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int mtk_mdp_m2m_streamoff(struct file *file, void *fh,
+			    enum v4l2_buf_type type)
+{
+	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
+
+	return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+/*
+ * Return true if rectangle a is enclosed in rectangle b, or false otherwise.
+ */
+static bool mtk_mdp_m2m_is_rectangle_enclosed(struct v4l2_rect *a,
+					     struct v4l2_rect *b)
+{
+	if (a->left < b->left || a->top < b->top)
+		return false;
+
+	if (a->left + a->width > b->left + b->width)
+		return false;
+
+	if (a->top + a->height > b->top + b->height)
+		return false;
+
+	return true;
+}
+
+static int mtk_mdp_m2m_g_selection(struct file *file, void *fh,
+				   struct v4l2_selection *s)
+{
+	struct mtk_mdp_frame *frame;
+	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
+
+	if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+	    (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+		return -EINVAL;
+
+	frame = mtk_mdp_ctx_get_frame(ctx, s->type);
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+		s->r.left = 0;
+		s->r.top = 0;
+		s->r.width = frame->width;
+		s->r.height = frame->height;
+		return 0;
+
+	case V4L2_SEL_TGT_COMPOSE:
+	case V4L2_SEL_TGT_CROP:
+		s->r.left = frame->crop.left;
+		s->r.top = frame->crop.top;
+		s->r.width = frame->crop.width;
+		s->r.height = frame->crop.height;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int mtk_mdp_check_scaler_ratio(struct mtk_mdp_variant *var, int src_w,
+				      int src_h, int dst_w, int dst_h, int rot)
+{
+	int tmp_w, tmp_h;
+
+	if (rot == 90 || rot == 270) {
+		tmp_w = dst_h;
+		tmp_h = dst_w;
+	} else {
+		tmp_w = dst_w;
+		tmp_h = dst_h;
+	}
+
+	if ((src_w / tmp_w) > var->h_scale_down_max ||
+	    (src_h / tmp_h) > var->v_scale_down_max ||
+	    (tmp_w / src_w) > var->h_scale_up_max ||
+	    (tmp_h / src_h) > var->v_scale_up_max)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int mtk_mdp_m2m_s_selection(struct file *file, void *fh,
+				   struct v4l2_selection *s)
+{
+	struct mtk_mdp_frame *frame;
+	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
+	struct v4l2_crop cr;
+	struct mtk_mdp_variant *variant = ctx->mdp_dev->variant;
+	int ret;
+
+	cr.type = s->type;
+	cr.c = s->r;
+
+	if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+	    (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+		return -EINVAL;
+
+	ret = mtk_mdp_try_crop(ctx, &cr);
+	if (ret)
+		return ret;
+
+	if (s->flags & V4L2_SEL_FLAG_LE &&
+	    !mtk_mdp_m2m_is_rectangle_enclosed(&cr.c, &s->r))
+		return -ERANGE;
+
+	if (s->flags & V4L2_SEL_FLAG_GE &&
+	    !mtk_mdp_m2m_is_rectangle_enclosed(&s->r, &cr.c))
+		return -ERANGE;
+
+	s->r = cr.c;
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE:
+		frame = &ctx->s_frame;
+		break;
+
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+	case V4L2_SEL_TGT_CROP:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+		frame = &ctx->d_frame;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Check to see if scaling ratio is within supported range */
+	if (mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_DST_FMT | MTK_MDP_SRC_FMT)) {
+		if (V4L2_TYPE_IS_OUTPUT(s->type)) {
+			ret = mtk_mdp_check_scaler_ratio(variant, cr.c.width,
+				cr.c.height, ctx->d_frame.crop.width,
+				ctx->d_frame.crop.height,
+				ctx->ctrls.rotate->val);
+		} else {
+			ret = mtk_mdp_check_scaler_ratio(variant,
+				ctx->s_frame.crop.width,
+				ctx->s_frame.crop.height, cr.c.width,
+				cr.c.height, ctx->ctrls.rotate->val);
+		}
+
+		if (ret) {
+			dev_info(&ctx->mdp_dev->pdev->dev,
+				"Out of scaler range");
+			return -EINVAL;
+		}
+	}
+
+	frame->crop = cr.c;
+
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops mtk_mdp_m2m_ioctl_ops = {
+	.vidioc_querycap		= mtk_mdp_m2m_querycap,
+	.vidioc_enum_fmt_vid_cap_mplane	= mtk_mdp_m2m_enum_fmt_mplane_vid_cap,
+	.vidioc_enum_fmt_vid_out_mplane	= mtk_mdp_m2m_enum_fmt_mplane_vid_out,
+	.vidioc_g_fmt_vid_cap_mplane	= mtk_mdp_m2m_g_fmt_mplane,
+	.vidioc_g_fmt_vid_out_mplane	= mtk_mdp_m2m_g_fmt_mplane,
+	.vidioc_try_fmt_vid_cap_mplane	= mtk_mdp_m2m_try_fmt_mplane,
+	.vidioc_try_fmt_vid_out_mplane	= mtk_mdp_m2m_try_fmt_mplane,
+	.vidioc_s_fmt_vid_cap_mplane	= mtk_mdp_m2m_s_fmt_mplane,
+	.vidioc_s_fmt_vid_out_mplane	= mtk_mdp_m2m_s_fmt_mplane,
+	.vidioc_reqbufs			= mtk_mdp_m2m_reqbufs,
+	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,
+	.vidioc_expbuf			= v4l2_m2m_ioctl_expbuf,
+	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
+	.vidioc_querybuf		= mtk_mdp_m2m_querybuf,
+	.vidioc_qbuf			= mtk_mdp_m2m_qbuf,
+	.vidioc_dqbuf			= mtk_mdp_m2m_dqbuf,
+	.vidioc_streamon		= mtk_mdp_m2m_streamon,
+	.vidioc_streamoff		= mtk_mdp_m2m_streamoff,
+	.vidioc_g_selection		= mtk_mdp_m2m_g_selection,
+	.vidioc_s_selection		= mtk_mdp_m2m_s_selection
+};
+
+static int mtk_mdp_m2m_queue_init(void *priv, struct vb2_queue *src_vq,
+				  struct vb2_queue *dst_vq)
+{
+	struct mtk_mdp_ctx *ctx = priv;
+	int ret;
+
+	memset(src_vq, 0, sizeof(*src_vq));
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+	src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+	src_vq->drv_priv = ctx;
+	src_vq->ops = &mtk_mdp_m2m_qops;
+	src_vq->mem_ops = &vb2_dma_contig_memops;
+	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+
+	ret = vb2_queue_init(src_vq);
+	if (ret)
+		return ret;
+
+	memset(dst_vq, 0, sizeof(*dst_vq));
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+	dst_vq->drv_priv = ctx;
+	dst_vq->ops = &mtk_mdp_m2m_qops;
+	dst_vq->mem_ops = &vb2_dma_contig_memops;
+	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+
+	return vb2_queue_init(dst_vq);
+}
+
+static int mtk_mdp_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct mtk_mdp_ctx *ctx = ctrl_to_ctx(ctrl);
+	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
+	struct mtk_mdp_variant *variant = mdp->variant;
+	u32 state = MTK_MDP_DST_FMT | MTK_MDP_SRC_FMT;
+	int ret = 0;
+
+	if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
+		return 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_HFLIP:
+		ctx->hflip = ctrl->val;
+		break;
+	case V4L2_CID_VFLIP:
+		ctx->vflip = ctrl->val;
+		break;
+	case V4L2_CID_ROTATE:
+		if (mtk_mdp_ctx_state_is_set(ctx, state)) {
+			ret = mtk_mdp_check_scaler_ratio(variant,
+					ctx->s_frame.crop.width,
+					ctx->s_frame.crop.height,
+					ctx->d_frame.crop.width,
+					ctx->d_frame.crop.height,
+					ctx->ctrls.rotate->val);
+
+			if (ret)
+				return -EINVAL;
+		}
+
+		ctx->rotation = ctrl->val;
+		break;
+	case V4L2_CID_ALPHA_COMPONENT:
+		ctx->d_frame.alpha = ctrl->val;
+		break;
+	}
+
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops mtk_mdp_ctrl_ops = {
+	.s_ctrl = mtk_mdp_s_ctrl,
+};
+
+static int mtk_mdp_ctrls_create(struct mtk_mdp_ctx *ctx)
+{
+	v4l2_ctrl_handler_init(&ctx->ctrl_handler, MTK_MDP_MAX_CTRL_NUM);
+
+	ctx->ctrls.rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+			&mtk_mdp_ctrl_ops, V4L2_CID_ROTATE, 0, 270, 90, 0);
+	ctx->ctrls.hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+					     &mtk_mdp_ctrl_ops,
+					     V4L2_CID_HFLIP,
+					     0, 1, 1, 0);
+	ctx->ctrls.vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+					     &mtk_mdp_ctrl_ops,
+					     V4L2_CID_VFLIP,
+					     0, 1, 1, 0);
+	ctx->ctrls.global_alpha = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+						    &mtk_mdp_ctrl_ops,
+						    V4L2_CID_ALPHA_COMPONENT,
+						    0, 255, 1, 0);
+	ctx->ctrls_rdy = ctx->ctrl_handler.error == 0;
+
+	if (ctx->ctrl_handler.error) {
+		int err = ctx->ctrl_handler.error;
+
+		v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+		dev_err(&ctx->mdp_dev->pdev->dev,
+			"Failed to create control handlers\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static void mtk_mdp_set_default_params(struct mtk_mdp_ctx *ctx)
+{
+	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
+	struct mtk_mdp_frame *frame;
+
+	frame = mtk_mdp_ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+	frame->fmt = mtk_mdp_find_fmt_by_index(0,
+					V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+	frame->width = mdp->variant->pix_min->org_w;
+	frame->height = mdp->variant->pix_min->org_h;
+	frame->payload[0] = frame->width * frame->height;
+	frame->payload[1] = frame->payload[0] / 2;
+
+	frame = mtk_mdp_ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+	frame->fmt = mtk_mdp_find_fmt_by_index(0,
+					V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+	frame->width = mdp->variant->pix_min->target_rot_dis_w;
+	frame->height = mdp->variant->pix_min->target_rot_dis_h;
+	frame->payload[0] = frame->width * frame->height;
+	frame->payload[1] = frame->payload[0] / 2;
+
+}
+
+static int mtk_mdp_m2m_open(struct file *file)
+{
+	struct mtk_mdp_dev *mdp = video_drvdata(file);
+	struct video_device *vfd = video_devdata(file);
+	struct mtk_mdp_ctx *ctx = NULL;
+	int ret;
+
+	if (mutex_lock_interruptible(&mdp->lock))
+		return -ERESTARTSYS;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx) {
+		ret = -ENOMEM;
+		goto err_ctx_alloc;
+	}
+
+	mutex_init(&ctx->slock);
+	ctx->id = mdp->id_counter++;
+	v4l2_fh_init(&ctx->fh, vfd);
+	file->private_data = &ctx->fh;
+	ret = mtk_mdp_ctrls_create(ctx);
+	if (ret)
+		goto error_ctrls;
+
+	/* Use separate control handler per file handle */
+	ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+	v4l2_fh_add(&ctx->fh);
+	INIT_LIST_HEAD(&ctx->list);
+
+	ctx->mdp_dev = mdp;
+	mtk_mdp_set_default_params(ctx);
+
+	INIT_WORK(&ctx->work, mtk_mdp_m2m_worker);
+	ctx->m2m_ctx = v4l2_m2m_ctx_init(mdp->m2m_dev, ctx,
+					 mtk_mdp_m2m_queue_init);
+	if (IS_ERR(ctx->m2m_ctx)) {
+		dev_err(&mdp->pdev->dev, "Failed to initialize m2m context");
+		ret = PTR_ERR(ctx->m2m_ctx);
+		goto error_m2m_ctx;
+	}
+	ctx->fh.m2m_ctx = ctx->m2m_ctx;
+	if (mdp->ctx_num++ == 0) {
+		ret = vpu_load_firmware(mdp->vpu_dev);
+		if (ret < 0) {
+			dev_err(&mdp->pdev->dev,
+				"vpu_load_firmware failed %d\n", ret);
+			goto err_load_vpu;
+		}
+
+		ret = mtk_mdp_vpu_register(mdp->pdev);
+		if (ret < 0) {
+			dev_err(&mdp->pdev->dev,
+				"mdp_vpu register failed %d\n", ret);
+			goto err_load_vpu;
+		}
+	}
+
+	ret = mtk_mdp_vpu_init(&ctx->vpu);
+	if (ret < 0) {
+		dev_err(&mdp->pdev->dev, "Initialize vpu failed %d\n", ret);
+		ret = -EINVAL;
+		goto err_load_vpu;
+	}
+	list_add(&ctx->list, &mdp->ctx_list);
+	mutex_unlock(&mdp->lock);
+
+	mtk_mdp_dbg(0, "%s [%d]", dev_name(&mdp->pdev->dev), ctx->id);
+
+	return 0;
+
+err_load_vpu:
+	mdp->ctx_num--;
+	v4l2_m2m_ctx_release(ctx->m2m_ctx);
+error_m2m_ctx:
+	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+error_ctrls:
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+err_ctx_alloc:
+	kfree(ctx);
+	mutex_unlock(&mdp->lock);
+
+	return ret;
+}
+
+static int mtk_mdp_m2m_release(struct file *file)
+{
+	struct mtk_mdp_ctx *ctx = fh_to_ctx(file->private_data);
+	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
+
+	flush_workqueue(mdp->job_wq);
+	mutex_lock(&mdp->lock);
+	v4l2_m2m_ctx_release(ctx->m2m_ctx);
+	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	mtk_mdp_vpu_deinit(&ctx->vpu);
+	mdp->ctx_num--;
+	list_del_init(&ctx->list);
+
+	mtk_mdp_dbg(0, "%s [%d]", dev_name(&mdp->pdev->dev), ctx->id);
+
+	mutex_unlock(&mdp->lock);
+	kfree(ctx);
+
+	return 0;
+}
+
+static unsigned int mtk_mdp_m2m_poll(struct file *file,
+				     struct poll_table_struct *wait)
+{
+	struct mtk_mdp_ctx *ctx = fh_to_ctx(file->private_data);
+	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
+	int ret;
+
+	if (mutex_lock_interruptible(&mdp->lock))
+		return -ERESTARTSYS;
+
+	ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+	mutex_unlock(&mdp->lock);
+
+	return ret;
+}
+
+static int mtk_mdp_m2m_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct mtk_mdp_ctx *ctx = fh_to_ctx(file->private_data);
+	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
+	int ret;
+
+	if (mutex_lock_interruptible(&mdp->lock))
+		return -ERESTARTSYS;
+
+	ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+	mutex_unlock(&mdp->lock);
+
+	return ret;
+}
+
+static const struct v4l2_file_operations mtk_mdp_m2m_fops = {
+	.owner		= THIS_MODULE,
+	.open		= mtk_mdp_m2m_open,
+	.release	= mtk_mdp_m2m_release,
+	.poll		= mtk_mdp_m2m_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= mtk_mdp_m2m_mmap,
+};
+
+static struct v4l2_m2m_ops mtk_mdp_m2m_ops = {
+	.device_run	= mtk_mdp_m2m_device_run,
+	.job_abort	= mtk_mdp_m2m_job_abort,
+};
+
+int mtk_mdp_register_m2m_device(struct mtk_mdp_dev *mdp)
+{
+	struct device *dev = &mdp->pdev->dev;
+	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",
+		 MTK_MDP_MODULE_NAME);
+	video_set_drvdata(&mdp->vdev, mdp);
+
+	mdp->m2m_dev = v4l2_m2m_init(&mtk_mdp_m2m_ops);
+	if (IS_ERR(mdp->m2m_dev)) {
+		dev_err(dev, "failed to initialize v4l2-m2m device\n");
+		ret = PTR_ERR(mdp->m2m_dev);
+		goto err_m2m_init;
+	}
+
+	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);
+	return 0;
+
+err_vdev_register:
+	v4l2_m2m_release(mdp->m2m_dev);
+err_m2m_init:
+	video_device_release(&mdp->vdev);
+
+	return ret;
+}
+
+void mtk_mdp_unregister_m2m_device(struct mtk_mdp_dev *mdp)
+{
+	video_device_release(&mdp->vdev);
+	v4l2_m2m_release(mdp->m2m_dev);
+}
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h
new file mode 100644
index 0000000..45afd36
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __MTK_MDP_M2M_H__
+#define __MTK_MDP_M2M_H__
+
+void mtk_mdp_ctx_state_lock_set(struct mtk_mdp_ctx *ctx, u32 state);
+int mtk_mdp_register_m2m_device(struct mtk_mdp_dev *mdp);
+void mtk_mdp_unregister_m2m_device(struct mtk_mdp_dev *mdp);
+
+#endif /* __MTK_MDP_M2M_H__ */
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_regs.c b/drivers/media/platform/mtk-mdp/mtk_mdp_regs.c
new file mode 100644
index 0000000..063e7b1
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_regs.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2015-2016 MediaTek Inc.
+ * Author: Houlong Wei <houlong.wei at mediatek.com>
+ *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/platform_device.h>
+
+#include "mtk_mdp_core.h"
+#include "mtk_mdp_regs.h"
+
+
+#define MDP_COLORFMT_PACK(VIDEO, PLANE, COPLANE, HF, VF, BITS, GROUP, SWAP, ID)\
+	(((VIDEO) << 27) | ((PLANE) << 24) | ((COPLANE) << 22) |\
+	((HF) << 20) | ((VF) << 18) | ((BITS) << 8) | ((GROUP) << 6) |\
+	((SWAP) << 5) | ((ID) << 0))
+
+enum MDP_COLOR_ENUM {
+	MDP_COLOR_UNKNOWN = 0,
+	MDP_COLOR_NV12 = MDP_COLORFMT_PACK(0, 2, 1, 1, 1, 8, 1, 0, 12),
+	MDP_COLOR_I420 = MDP_COLORFMT_PACK(0, 3, 0, 1, 1, 8, 1, 0, 8),
+	/* Mediatek proprietary format */
+	MDP_COLOR_420_MT21 = MDP_COLORFMT_PACK(5, 2, 1, 1, 1, 256, 1, 0, 12),
+};
+
+static int32_t mtk_mdp_map_color_format(int v4l2_format)
+{
+	switch (v4l2_format) {
+	case V4L2_PIX_FMT_NV12M:
+	case V4L2_PIX_FMT_NV12:
+		return MDP_COLOR_NV12;
+	case V4L2_PIX_FMT_MT21:
+		return MDP_COLOR_420_MT21;
+	case V4L2_PIX_FMT_YUV420M:
+	case V4L2_PIX_FMT_YUV420:
+		return MDP_COLOR_I420;
+	}
+
+	mtk_mdp_err("Unknown format 0x%x", v4l2_format);
+
+	return MDP_COLOR_UNKNOWN;
+}
+
+void mtk_mdp_hw_set_input_addr(struct mtk_mdp_ctx *ctx,
+			       struct mtk_mdp_addr *addr)
+{
+	struct mdp_buffer *src_buf = &ctx->vpu.vsi->src_buffer;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(addr->addr); i++)
+		src_buf->addr_mva[i] = (uint64_t)addr->addr[i];
+}
+
+void mtk_mdp_hw_set_output_addr(struct mtk_mdp_ctx *ctx,
+				struct mtk_mdp_addr *addr)
+{
+	struct mdp_buffer *dst_buf = &ctx->vpu.vsi->dst_buffer;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(addr->addr); i++)
+		dst_buf->addr_mva[i] = (uint64_t)addr->addr[i];
+}
+
+void mtk_mdp_hw_set_in_size(struct mtk_mdp_ctx *ctx)
+{
+	struct mtk_mdp_frame *frame = &ctx->s_frame;
+	struct mdp_config *config = &ctx->vpu.vsi->src_config;
+
+	/* Set input pixel offset */
+	config->crop_x = frame->crop.left;
+	config->crop_y = frame->crop.top;
+
+	/* Set input cropped size */
+	config->crop_w = frame->crop.width;
+	config->crop_h = frame->crop.height;
+
+	/* Set input original size */
+	config->x = 0;
+	config->y = 0;
+	config->w = frame->width;
+	config->h = frame->height;
+}
+
+void mtk_mdp_hw_set_in_image_format(struct mtk_mdp_ctx *ctx)
+{
+	unsigned int i;
+	struct mtk_mdp_frame *frame = &ctx->s_frame;
+	struct mdp_config *config = &ctx->vpu.vsi->src_config;
+	struct mdp_buffer *src_buf = &ctx->vpu.vsi->src_buffer;
+
+	src_buf->plane_num = frame->fmt->num_planes;
+	config->format = mtk_mdp_map_color_format(frame->fmt->pixelformat);
+	config->w_stride = 0; /* MDP will calculate it by color format. */
+	config->h_stride = 0; /* MDP will calculate it by color format. */
+
+	for (i = 0; i < src_buf->plane_num; i++)
+		src_buf->plane_size[i] = frame->payload[i];
+}
+
+void mtk_mdp_hw_set_out_size(struct mtk_mdp_ctx *ctx)
+{
+	struct mtk_mdp_frame *frame = &ctx->d_frame;
+	struct mdp_config *config = &ctx->vpu.vsi->dst_config;
+
+	config->crop_x = frame->crop.left;
+	config->crop_y = frame->crop.top;
+	config->crop_w = frame->crop.width;
+	config->crop_h = frame->crop.height;
+	config->x = 0;
+	config->y = 0;
+	config->w = frame->width;
+	config->h = frame->height;
+}
+
+void mtk_mdp_hw_set_out_image_format(struct mtk_mdp_ctx *ctx)
+{
+	unsigned int i;
+	struct mtk_mdp_frame *frame = &ctx->d_frame;
+	struct mdp_config *config = &ctx->vpu.vsi->dst_config;
+	struct mdp_buffer *dst_buf = &ctx->vpu.vsi->dst_buffer;
+
+	dst_buf->plane_num = frame->fmt->num_planes;
+	config->format = mtk_mdp_map_color_format(frame->fmt->pixelformat);
+	config->w_stride = 0; /* MDP will calculate it by color format. */
+	config->h_stride = 0; /* MDP will calculate it by color format. */
+	for (i = 0; i < dst_buf->plane_num; i++)
+		dst_buf->plane_size[i] = frame->payload[i];
+}
+
+void mtk_mdp_hw_set_rotation(struct mtk_mdp_ctx *ctx)
+{
+	struct mdp_config_misc *misc = &ctx->vpu.vsi->misc;
+
+	misc->orientation = ctx->ctrls.rotate->val;
+	misc->hflip = ctx->ctrls.hflip->val;
+	misc->vflip = ctx->ctrls.vflip->val;
+}
+
+void mtk_mdp_hw_set_global_alpha(struct mtk_mdp_ctx *ctx)
+{
+	struct mdp_config_misc *misc = &ctx->vpu.vsi->misc;
+
+	misc->alpha = ctx->ctrls.global_alpha->val;
+}
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_regs.h b/drivers/media/platform/mtk-mdp/mtk_mdp_regs.h
new file mode 100644
index 0000000..42bd057
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_regs.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __MTK_MDP_REGS_H__
+#define __MTK_MDP_REGS_H__
+
+
+void mtk_mdp_hw_set_input_addr(struct mtk_mdp_ctx *ctx,
+			       struct mtk_mdp_addr *addr);
+void mtk_mdp_hw_set_output_addr(struct mtk_mdp_ctx *ctx,
+				struct mtk_mdp_addr *addr);
+void mtk_mdp_hw_set_in_size(struct mtk_mdp_ctx *ctx);
+void mtk_mdp_hw_set_in_image_format(struct mtk_mdp_ctx *ctx);
+void mtk_mdp_hw_set_out_size(struct mtk_mdp_ctx *ctx);
+void mtk_mdp_hw_set_out_image_format(struct mtk_mdp_ctx *ctx);
+void mtk_mdp_hw_set_rotation(struct mtk_mdp_ctx *ctx);
+void mtk_mdp_hw_set_global_alpha(struct mtk_mdp_ctx *ctx);
+
+
+#endif /* __MTK_MDP_REGS_H__ */
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c b/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c
new file mode 100644
index 0000000..850376a
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2015-2016 MediaTek Inc.
+ * Author: Houlong Wei <houlong.wei at mediatek.com>
+ *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include "mtk_mdp_core.h"
+#include "mtk_mdp_vpu.h"
+#include "mtk_vpu.h"
+
+
+static inline struct mtk_mdp_ctx *vpu_to_ctx(struct mtk_mdp_vpu *vpu)
+{
+	return container_of(vpu, struct mtk_mdp_ctx, vpu);
+}
+
+static void mtk_mdp_vpu_handle_init_ack(struct mdp_ipi_comm_ack *msg)
+{
+	struct mtk_mdp_vpu *vpu = (struct mtk_mdp_vpu *)msg->ap_inst;
+
+	/* mapping VPU address to kernel virtual address */
+	vpu->vsi = (struct mdp_process_vsi *)
+			vpu_mapping_dm_addr(vpu->pdev, msg->vpu_inst_addr);
+	vpu->inst_addr = msg->vpu_inst_addr;
+}
+
+static void mtk_mdp_vpu_ipi_handler(void *data, unsigned int len, void *priv)
+{
+	unsigned int msg_id = *(unsigned int *)data;
+	struct mdp_ipi_comm_ack *msg = (struct mdp_ipi_comm_ack *)data;
+	struct mtk_mdp_vpu *vpu = (struct mtk_mdp_vpu *)msg->ap_inst;
+	struct mtk_mdp_ctx *ctx;
+
+	vpu->failure = msg->status;
+	if (!vpu->failure) {
+		switch (msg_id) {
+		case VPU_MDP_INIT_ACK:
+			mtk_mdp_vpu_handle_init_ack(data);
+			break;
+		case VPU_MDP_DEINIT_ACK:
+		case VPU_MDP_PROCESS_ACK:
+			break;
+		default:
+			ctx = vpu_to_ctx(vpu);
+			dev_err(&ctx->mdp_dev->pdev->dev,
+				"handle unknown ipi msg:0x%x\n",
+				msg_id);
+			break;
+		}
+	} else {
+		ctx = vpu_to_ctx(vpu);
+		mtk_mdp_dbg(0, "[%d]:msg 0x%x, failure:%d", ctx->id,
+			    msg_id, vpu->failure);
+	}
+}
+
+int mtk_mdp_vpu_register(struct platform_device *pdev)
+{
+	struct mtk_mdp_dev *mdp = platform_get_drvdata(pdev);
+	int err;
+
+	err = vpu_ipi_register(mdp->vpu_dev, IPI_MDP,
+			       mtk_mdp_vpu_ipi_handler, "mdp_vpu", NULL);
+	if (err)
+		dev_err(&mdp->pdev->dev,
+			"vpu_ipi_registration fail status=%d\n", err);
+
+	return err;
+}
+
+static int mtk_mdp_vpu_send_msg(void *msg, int len, struct mtk_mdp_vpu *vpu,
+				int id)
+{
+	struct mtk_mdp_ctx *ctx = vpu_to_ctx(vpu);
+	int err;
+
+	mutex_lock(&ctx->mdp_dev->vpulock);
+	err = vpu_ipi_send(vpu->pdev, (enum ipi_id)id, msg, len);
+	if (err) {
+		mutex_unlock(&ctx->mdp_dev->vpulock);
+		dev_err(&ctx->mdp_dev->pdev->dev,
+			"vpu_ipi_send fail status %d\n", err);
+	}
+	mutex_unlock(&ctx->mdp_dev->vpulock);
+
+	return err;
+}
+
+static int mtk_mdp_vpu_send_ap_ipi(struct mtk_mdp_vpu *vpu, uint32_t msg_id)
+{
+	int err;
+	struct mdp_ipi_comm msg;
+
+	msg.msg_id = msg_id;
+	msg.ipi_id = IPI_MDP;
+	msg.vpu_inst_addr = vpu->inst_addr;
+	msg.ap_inst = (uint64_t)vpu;
+	err = mtk_mdp_vpu_send_msg((void *)&msg, sizeof(msg), vpu, IPI_MDP);
+	if (!err && vpu->failure)
+		err = -EINVAL;
+
+	return err;
+}
+
+int mtk_mdp_vpu_init(struct mtk_mdp_vpu *vpu)
+{
+	int err;
+	struct mdp_ipi_init msg;
+	struct mtk_mdp_ctx *ctx = vpu_to_ctx(vpu);
+
+	vpu->pdev = ctx->mdp_dev->vpu_dev;
+
+	msg.msg_id = AP_MDP_INIT;
+	msg.ipi_id = IPI_MDP;
+	msg.ap_inst = (uint64_t)vpu;
+	err = mtk_mdp_vpu_send_msg((void *)&msg, sizeof(msg), vpu, IPI_MDP);
+	if (!err && vpu->failure)
+		err = -EINVAL;
+
+	return err;
+}
+
+int mtk_mdp_vpu_deinit(struct mtk_mdp_vpu *vpu)
+{
+	return mtk_mdp_vpu_send_ap_ipi(vpu, AP_MDP_DEINIT);
+}
+
+int mtk_mdp_vpu_process(struct mtk_mdp_vpu *vpu)
+{
+	return mtk_mdp_vpu_send_ap_ipi(vpu, AP_MDP_PROCESS);
+}
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h b/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h
new file mode 100644
index 0000000..df4bdda
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015-2016 MediaTek Inc.
+ * Author: Houlong Wei <houlong.wei at mediatek.com>
+ *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __MTK_MDP_VPU_H__
+#define __MTK_MDP_VPU_H__
+
+#include "mtk_mdp_ipi.h"
+
+
+/**
+ * struct mtk_mdp_vpu - VPU instance for MDP
+ * @pdev	: pointer to the VPU platform device
+ * @inst_addr	: VPU MDP instance address
+ * @failure	: VPU execution result status
+ * @vsi		: VPU shared information
+ */
+struct mtk_mdp_vpu {
+	struct platform_device	*pdev;
+	uint32_t		inst_addr;
+	int32_t			failure;
+	struct mdp_process_vsi	*vsi;
+};
+
+int mtk_mdp_vpu_register(struct platform_device *pdev);
+int mtk_mdp_vpu_init(struct mtk_mdp_vpu *vpu);
+int mtk_mdp_vpu_deinit(struct mtk_mdp_vpu *vpu);
+int mtk_mdp_vpu_process(struct mtk_mdp_vpu *vpu);
+
+#endif /* __MTK_MDP_VPU_H__ */
-- 
1.7.9.5



From broonie at kernel.org  Thu Jul 14 09:32:07 2016
From: broonie at kernel.org (Mark Brown)
Date: Thu, 14 Jul 2016 17:32:07 +0100
Subject: Applied "ASoC: mediatek: mt2701: fix non static symbol warning" to
 the asoc tree
In-Reply-To: <1467985293-9041-1-git-send-email-weiyj_lk@163.com>
Message-ID: <E1bNjYV-0001SJ-C4@debutante>

The patch

   ASoC: mediatek: mt2701: fix non static symbol warning

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 25d01dc67894de03de463727633e72e1727b4f6d Mon Sep 17 00:00:00 2001
From: Wei Yongjun <yongjun_wei at trendmicro.com.cn>
Date: Fri, 8 Jul 2016 13:47:01 +0000
Subject: [PATCH] ASoC: mediatek: mt2701: fix non static symbol warning

Fixes the following sparse warning:

sound/soc/mediatek/mt2701/mt2701-afe-pcm.c:72:5: warning:
 symbol 'mt2701_dai_num_to_i2s' was not declared. Should it be static?

Signed-off-by: Wei Yongjun <yongjun_wei at trendmicro.com.cn>
Acked-by: Garlic Tseng <garlic.tseng at mediatek.com>
Signed-off-by: Mark Brown <broonie at kernel.org>
---
 sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
index 15522c08a967..34a6123480d3 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
@@ -69,7 +69,7 @@ static const struct mt2701_afe_rate mt2701_afe_i2s_rates[] = {
 	{ .rate = 352800, .regvalue = 24 },
 };
 
-int mt2701_dai_num_to_i2s(struct mtk_base_afe *afe, int num)
+static int mt2701_dai_num_to_i2s(struct mtk_base_afe *afe, int num)
 {
 	int val = num - MT2701_IO_I2S;
 
-- 
2.8.1



From broonie at kernel.org  Thu Jul 14 09:32:04 2016
From: broonie at kernel.org (Mark Brown)
Date: Thu, 14 Jul 2016 17:32:04 +0100
Subject: Applied "ASoC: mediatek: Add HDMI dai-links to the mt8173-rt5650
 machine driver" to the asoc tree
In-Reply-To: <1467710781-23590-1-git-send-email-p.zabel@pengutronix.de>
Message-ID: <E1bNjYS-0001R1-Fa@debutante>

The patch

   ASoC: mediatek: Add HDMI dai-links to the mt8173-rt5650 machine driver

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 97e1145a416e8bf0c00e7496e3522765437471ad Mon Sep 17 00:00:00 2001
From: PC Liao <pc.liao at mediatek.com>
Date: Tue, 5 Jul 2016 11:26:21 +0200
Subject: [PATCH] ASoC: mediatek: Add HDMI dai-links to the mt8173-rt5650
 machine driver

This patch adds HDMI audio output support to the MT8173 RT5650 machine
driver.

Signed-off-by: PC Liao <pc.liao at mediatek.com>
Signed-off-by: Philipp Zabel <p.zabel at pengutronix.de>
Signed-off-by: Mark Brown <broonie at kernel.org>
---
 .../devicetree/bindings/sound/mt8173-rt5650.txt    |  5 +++--
 sound/soc/mediatek/Kconfig                         |  1 +
 sound/soc/mediatek/mt8173/mt8173-rt5650.c          | 26 ++++++++++++++++++++++
 3 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/mt8173-rt5650.txt b/Documentation/devicetree/bindings/sound/mt8173-rt5650.txt
index f250fc7c7acc..29dce2ac8773 100644
--- a/Documentation/devicetree/bindings/sound/mt8173-rt5650.txt
+++ b/Documentation/devicetree/bindings/sound/mt8173-rt5650.txt
@@ -1,8 +1,9 @@
-MT8173 with RT5650 CODECS
+MT8173 with RT5650 CODECS and HDMI via I2S
 
 Required properties:
 - compatible : "mediatek,mt8173-rt5650"
 - mediatek,audio-codec: the phandles of rt5650 codecs
+                        and of the hdmi encoder node
 - mediatek,platform: the phandle of MT8173 ASoC platform
 
 Optional subnodes:
@@ -20,7 +21,7 @@ Example:
 
 	sound {
 		compatible = "mediatek,mt8173-rt5650";
-		mediatek,audio-codec = <&rt5650>;
+		mediatek,audio-codec = <&rt5650 &hdmi0>;
 		mediatek,platform = <&afe>;
 		mediatek,mclk = <0>;
 		codec-capture {
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 2fbe5434f03b..05cf809cf9e1 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -46,6 +46,7 @@ config SND_SOC_MT8173_RT5650
 	tristate "ASoC Audio driver for MT8173 with RT5650 codec"
 	depends on SND_SOC_MT8173 && I2C
 	select SND_SOC_RT5645
+	select SND_SOC_HDMI_CODEC
 	help
 	  This adds ASoC driver for Mediatek MT8173 boards
 	  with the RT5650 audio codec.
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
index d47897618cb5..ba65f4157a7e 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
@@ -169,7 +169,9 @@ static struct snd_soc_dai_link_component mt8173_rt5650_codecs[] = {
 enum {
 	DAI_LINK_PLAYBACK,
 	DAI_LINK_CAPTURE,
+	DAI_LINK_HDMI,
 	DAI_LINK_CODEC_I2S,
+	DAI_LINK_HDMI_I2S,
 };
 
 /* Digital audio interface glue - connects codec <---> CPU */
@@ -195,6 +197,16 @@ static struct snd_soc_dai_link mt8173_rt5650_dais[] = {
 		.dynamic = 1,
 		.dpcm_capture = 1,
 	},
+	[DAI_LINK_HDMI] = {
+		.name = "HDMI",
+		.stream_name = "HDMI PCM",
+		.cpu_dai_name = "HDMI",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+	},
 	/* Back End DAI links */
 	[DAI_LINK_CODEC_I2S] = {
 		.name = "Codec",
@@ -210,6 +222,13 @@ static struct snd_soc_dai_link mt8173_rt5650_dais[] = {
 		.dpcm_playback = 1,
 		.dpcm_capture = 1,
 	},
+	[DAI_LINK_HDMI_I2S] = {
+		.name = "HDMI BE",
+		.cpu_dai_name = "HDMIO",
+		.no_pcm = 1,
+		.codec_dai_name = "i2s-hifi",
+		.dpcm_playback = 1,
+	},
 };
 
 static struct snd_soc_card mt8173_rt5650_card = {
@@ -284,6 +303,13 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev)
 		}
 	}
 
+	mt8173_rt5650_dais[DAI_LINK_HDMI_I2S].codec_of_node =
+		of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 1);
+	if (!mt8173_rt5650_dais[DAI_LINK_HDMI_I2S].codec_of_node) {
+		dev_err(&pdev->dev,
+			"Property 'audio-codec' missing or invalid\n");
+		return -EINVAL;
+	}
 	card->dev = &pdev->dev;
 	platform_set_drvdata(pdev, card);
 
-- 
2.8.1



From paul.gortmaker at windriver.com  Thu Jul 14 16:38:25 2016
From: paul.gortmaker at windriver.com (Paul Gortmaker)
Date: Thu, 14 Jul 2016 19:38:25 -0400
Subject: [PATCH v10 2/4] CMDQ: Mediatek CMDQ driver
In-Reply-To: <1468495733-12178-3-git-send-email-hs.liao@mediatek.com>
References: <1468495733-12178-1-git-send-email-hs.liao@mediatek.com>
 <1468495733-12178-3-git-send-email-hs.liao@mediatek.com>
Message-ID: <CAP=VYLqPhZLYFmsWE45kRdfbjUTzMT+eGNVZnGjK8VD7+fQgBA@mail.gmail.com>

On Thu, Jul 14, 2016 at 7:28 AM, HS Liao <hs.liao at mediatek.com> wrote:
> This patch is first version of Mediatek Command Queue(CMDQ) driver. The
> CMDQ is used to help write registers with critical time limitation,
> such as updating display configuration during the vblank. It controls
> Global Command Engine (GCE) hardware to achieve this requirement.
> Currently, CMDQ only supports display related hardwares, but we expect
> it can be extended to other hardwares for future requirements.
>
> Signed-off-by: HS Liao <hs.liao at mediatek.com>
> Signed-off-by: CK Hu <ck.hu at mediatek.com>
> ---
>  drivers/soc/mediatek/Kconfig    |  11 +
>  drivers/soc/mediatek/Makefile   |   1 +
>  drivers/soc/mediatek/mtk-cmdq.c | 948 ++++++++++++++++++++++++++++++++++++++++
>  include/soc/mediatek/cmdq.h     | 179 ++++++++
>  4 files changed, 1139 insertions(+)
>  create mode 100644 drivers/soc/mediatek/mtk-cmdq.c
>  create mode 100644 include/soc/mediatek/cmdq.h
>
> diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
> index 0a4ea80..50869e4 100644
> --- a/drivers/soc/mediatek/Kconfig
> +++ b/drivers/soc/mediatek/Kconfig
> @@ -1,6 +1,17 @@
>  #
>  # MediaTek SoC drivers
>  #
> +config MTK_CMDQ
> +       bool "MediaTek CMDQ Support"
> +       depends on ARM64 && ( ARCH_MEDIATEK || COMPILE_TEST )
> +       select MAILBOX
> +       select MTK_INFRACFG
> +       help
> +         Say yes here to add support for the MediaTek Command Queue (CMDQ)
> +         driver. The CMDQ is used to help read/write registers with critical
> +         time limitation, such as updating display configuration during the
> +         vblank.
> +
>  config MTK_INFRACFG
>         bool "MediaTek INFRACFG Support"
>         depends on ARCH_MEDIATEK || COMPILE_TEST
> diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
> index 12998b0..f7397ef 100644
> --- a/drivers/soc/mediatek/Makefile
> +++ b/drivers/soc/mediatek/Makefile
> @@ -1,3 +1,4 @@
> +obj-$(CONFIG_MTK_CMDQ) += mtk-cmdq.o
>  obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o
>  obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
>  obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
> diff --git a/drivers/soc/mediatek/mtk-cmdq.c b/drivers/soc/mediatek/mtk-cmdq.c
> new file mode 100644
> index 0000000..d032603
> --- /dev/null
> +++ b/drivers/soc/mediatek/mtk-cmdq.c
> @@ -0,0 +1,948 @@
> +/*
> + * Copyright (c) 2015 MediaTek Inc.
> + *
> + * 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.
> + */
> +
> +#include <linux/bitops.h>
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/completion.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/errno.h>
> +#include <linux/interrupt.h>
> +#include <linux/iopoll.h>
> +#include <linux/kernel.h>
> +#include <linux/kthread.h>
> +#include <linux/mailbox_client.h>
> +#include <linux/mailbox_controller.h>
> +#include <linux/module.h>

Please don't use module.h and MODULE_* stuff in a driver that has
a bool Kconfig.  Either make it tristate if that has a sensible use case
or get rid of the modular stuff.

Thanks,
Paul.
--

> +#include <linux/mutex.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/suspend.h>
> +#include <linux/timer.h>
> +#include <soc/mediatek/cmdq.h>
> +
> +#define CMDQ_THR_MAX_COUNT             3 /* main, sub, general(misc) */
> +#define CMDQ_INST_SIZE                 8 /* instruction is 64-bit */
> +#define CMDQ_TIMEOUT_MS                        1000
> +#define CMDQ_IRQ_MASK                  0xffff
> +#define CMDQ_NUM_CMD(t)                        (t->cmd_buf_size / CMDQ_INST_SIZE)
> +
> +#define CMDQ_CURR_IRQ_STATUS           0x10
> +#define CMDQ_THR_SLOT_CYCLES           0x30
> +
> +#define CMDQ_THR_BASE                  0x100
> +#define CMDQ_THR_SIZE                  0x80


From hs.liao at mediatek.com  Thu Jul 14 18:39:55 2016
From: hs.liao at mediatek.com (Horng-Shyang Liao)
Date: Fri, 15 Jul 2016 09:39:55 +0800
Subject: [PATCH v10 2/4] CMDQ: Mediatek CMDQ driver
In-Reply-To: <CAP=VYLqPhZLYFmsWE45kRdfbjUTzMT+eGNVZnGjK8VD7+fQgBA@mail.gmail.com>
References: <1468495733-12178-1-git-send-email-hs.liao@mediatek.com>
 <1468495733-12178-3-git-send-email-hs.liao@mediatek.com>
 <CAP=VYLqPhZLYFmsWE45kRdfbjUTzMT+eGNVZnGjK8VD7+fQgBA@mail.gmail.com>
Message-ID: <1468546795.31101.2.camel@mtksdaap41>

Hi Paul,

On Thu, 2016-07-14 at 19:38 -0400, Paul Gortmaker wrote:
> On Thu, Jul 14, 2016 at 7:28 AM, HS Liao <hs.liao at mediatek.com> wrote:
> > This patch is first version of Mediatek Command Queue(CMDQ) driver. The
> > CMDQ is used to help write registers with critical time limitation,
> > such as updating display configuration during the vblank. It controls
> > Global Command Engine (GCE) hardware to achieve this requirement.
> > Currently, CMDQ only supports display related hardwares, but we expect
> > it can be extended to other hardwares for future requirements.
> >
> > Signed-off-by: HS Liao <hs.liao at mediatek.com>
> > Signed-off-by: CK Hu <ck.hu at mediatek.com>
> > ---
> >  drivers/soc/mediatek/Kconfig    |  11 +
> >  drivers/soc/mediatek/Makefile   |   1 +
> >  drivers/soc/mediatek/mtk-cmdq.c | 948 ++++++++++++++++++++++++++++++++++++++++
> >  include/soc/mediatek/cmdq.h     | 179 ++++++++
> >  4 files changed, 1139 insertions(+)
> >  create mode 100644 drivers/soc/mediatek/mtk-cmdq.c
> >  create mode 100644 include/soc/mediatek/cmdq.h
> >
> > diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
> > index 0a4ea80..50869e4 100644
> > --- a/drivers/soc/mediatek/Kconfig
> > +++ b/drivers/soc/mediatek/Kconfig
> > @@ -1,6 +1,17 @@
> >  #
> >  # MediaTek SoC drivers
> >  #
> > +config MTK_CMDQ
> > +       bool "MediaTek CMDQ Support"
> > +       depends on ARM64 && ( ARCH_MEDIATEK || COMPILE_TEST )
> > +       select MAILBOX
> > +       select MTK_INFRACFG
> > +       help
> > +         Say yes here to add support for the MediaTek Command Queue (CMDQ)
> > +         driver. The CMDQ is used to help read/write registers with critical
> > +         time limitation, such as updating display configuration during the
> > +         vblank.
> > +
> >  config MTK_INFRACFG
> >         bool "MediaTek INFRACFG Support"
> >         depends on ARCH_MEDIATEK || COMPILE_TEST
> > diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
> > index 12998b0..f7397ef 100644
> > --- a/drivers/soc/mediatek/Makefile
> > +++ b/drivers/soc/mediatek/Makefile
> > @@ -1,3 +1,4 @@
> > +obj-$(CONFIG_MTK_CMDQ) += mtk-cmdq.o
> >  obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o
> >  obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
> >  obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
> > diff --git a/drivers/soc/mediatek/mtk-cmdq.c b/drivers/soc/mediatek/mtk-cmdq.c
> > new file mode 100644
> > index 0000000..d032603
> > --- /dev/null
> > +++ b/drivers/soc/mediatek/mtk-cmdq.c
> > @@ -0,0 +1,948 @@
> > +/*
> > + * Copyright (c) 2015 MediaTek Inc.
> > + *
> > + * 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.
> > + */
> > +
> > +#include <linux/bitops.h>
> > +#include <linux/clk.h>
> > +#include <linux/clk-provider.h>
> > +#include <linux/completion.h>
> > +#include <linux/dma-mapping.h>
> > +#include <linux/errno.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/iopoll.h>
> > +#include <linux/kernel.h>
> > +#include <linux/kthread.h>
> > +#include <linux/mailbox_client.h>
> > +#include <linux/mailbox_controller.h>
> > +#include <linux/module.h>
> 
> Please don't use module.h and MODULE_* stuff in a driver that has
> a bool Kconfig.  Either make it tristate if that has a sensible use case
> or get rid of the modular stuff.

Will remove it.

> Thanks,
> Paul.
> --

Thanks,
HS



From ck.hu at mediatek.com  Thu Jul 14 22:52:04 2016
From: ck.hu at mediatek.com (CK Hu)
Date: Fri, 15 Jul 2016 13:52:04 +0800
Subject: [PATCH] drm: mediatek: add Maintainers entry for Mediatek DRM drivers
Message-ID: <1468561924-45582-1-git-send-email-ck.hu@mediatek.com>

Add CK Hu and Philipp Zabel as maintainers for Mediatek DRM drivers.

Signed-off-by: CK Hu <ck.hu at mediatek.com>
---
 MAINTAINERS |    8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 7304d2e..2a04cdc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3973,6 +3973,14 @@ S:	Orphan / Obsolete
 F:	drivers/gpu/drm/i810/
 F:	include/uapi/drm/i810_drm.h
 
+DRM DRIVERS FOR MEDIATEK
+M:	CK Hu <ck.hu at mediatek.com>
+M:	Philipp Zabel <p.zabel at pengutronix.de>
+L:	dri-devel at lists.freedesktop.org
+S:	Supported
+F:	drivers/gpu/drm/mediatek/
+F:	Documentation/devicetree/bindings/display/mediatek/
+
 DRM DRIVER FOR MSM ADRENO GPU
 M:	Rob Clark <robdclark at gmail.com>
 L:	linux-arm-msm at vger.kernel.org
-- 
1.7.9.5



From ck.hu at mediatek.com  Fri Jul 15 02:11:48 2016
From: ck.hu at mediatek.com (CK Hu)
Date: Fri, 15 Jul 2016 17:11:48 +0800
Subject: [PATCH v3 1/2] drm/mediatek: Add gamma correction
In-Reply-To: <1467877029-45236-2-git-send-email-bibby.hsieh@mediatek.com>
References: <1467877029-45236-1-git-send-email-bibby.hsieh@mediatek.com>
 <1467877029-45236-2-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1468573908.25670.10.camel@mtksdaap41>

Hi, Bibby:

Some comments inline.

On Thu, 2016-07-07 at 15:37 +0800, Bibby Hsieh wrote:
> Apply gamma function to correct brightness values.
> It applies arbitrary mapping curve to compensate the
> incorrect transfer function of the panel.
> 
> Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_drm_crtc.c     |    8 +++
>  drivers/gpu/drm/mediatek/mtk_drm_crtc.h     |    1 +
>  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |   89 ++++++++++++++++++++++++++-
>  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |   10 +++
>  4 files changed, 106 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> index 24aa3ba..ee219bb 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> @@ -409,6 +409,10 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
>  	}
>  	if (pending_planes)
>  		mtk_crtc->pending_planes = true;
> +	if (crtc->state->color_mgmt_changed)
> +		for (i = 0; i < mtk_crtc->ddp_comp_nr; i++)
> +			mtk_ddp_gamma_set(mtk_crtc->ddp_comp[i], crtc->state);
> +
>  }
>  
>  static const struct drm_crtc_funcs mtk_crtc_funcs = {
> @@ -418,6 +422,7 @@ static const struct drm_crtc_funcs mtk_crtc_funcs = {
>  	.reset			= mtk_drm_crtc_reset,
>  	.atomic_duplicate_state	= mtk_drm_crtc_duplicate_state,
>  	.atomic_destroy_state	= mtk_drm_crtc_destroy_state,
> +	.gamma_set		= drm_atomic_helper_legacy_gamma_set,
>  };
>  
>  static const struct drm_crtc_helper_funcs mtk_crtc_helper_funcs = {
> @@ -569,6 +574,9 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
>  	if (ret < 0)
>  		goto unprepare;
>  
> +	drm_mode_crtc_set_gamma_size(&mtk_crtc->base, MTK_LUT_SIZE);
> +	drm_helper_crtc_enable_color_mgmt(&mtk_crtc->base, MTK_LUT_SIZE,
> +					  MTK_LUT_SIZE);
>  	priv->crtc[pipe] = &mtk_crtc->base;
>  	priv->num_pipes++;
>  
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.h b/drivers/gpu/drm/mediatek/mtk_drm_crtc.h
> index 81e5566..d332564 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.h
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.h
> @@ -19,6 +19,7 @@
>  #include "mtk_drm_plane.h"
>  
>  #define OVL_LAYER_NR	4
> +#define MTK_LUT_SIZE	512
>  
>  int mtk_drm_crtc_enable_vblank(struct drm_device *drm, unsigned int pipe);
>  void mtk_drm_crtc_disable_vblank(struct drm_device *drm, unsigned int pipe);
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
> index 3970fcf..56c5894 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
> @@ -24,6 +24,7 @@
>  #include "mtk_drm_drv.h"
>  #include "mtk_drm_plane.h"
>  #include "mtk_drm_ddp_comp.h"
> +#include "mtk_drm_crtc.h"
>  
>  #define DISP_OD_EN				0x0000
>  #define DISP_OD_INTEN				0x0008
> @@ -38,6 +39,21 @@
>  #define DISP_COLOR_WIDTH			0x0c50
>  #define DISP_COLOR_HEIGHT			0x0c54
>  
> +#define DISP_AAL_EN				0x000
> +#define DISP_AAL_SIZE				0x030
> +
> +#define DISP_GAMMA_EN				0x000
> +#define DISP_GAMMA_CFG				0x020
> +#define DISP_GAMMA_SIZE				0x030
> +#define DISP_GAMMA_LUT				0x700

It's better that the digits of register address of OD, COLOR, AAL, and
GAMMA are the same. Maybe you can align all to 4 digits.

> +
> +#define LUT_10BIT_MASK				0x3ff
> +
> +#define AAL_EN			BIT(0)
> +
> +#define GAMMA_EN		BIT(0)
> +#define GAMMA_LUT_EN		BIT(1)
> +
>  #define	OD_RELAY_MODE		BIT(0)
>  
>  #define	UFO_BYPASS		BIT(2)
> @@ -76,6 +92,61 @@ static void mtk_ufoe_start(struct mtk_ddp_comp *comp)
>  	writel(UFO_BYPASS, comp->regs + DISP_REG_UFO_START);
>  }
>  
> +static void mtk_aal_config(struct mtk_ddp_comp *comp, unsigned int w,
> +			   unsigned int h, unsigned int vrefresh)
> +{
> +	writel(h << 16 | w, comp->regs + DISP_AAL_SIZE);
> +}
> +
> +static void mtk_aal_start(struct mtk_ddp_comp *comp)
> +{
> +	writel(AAL_EN, comp->regs  + DISP_AAL_EN);
> +}
> +
> +static void mtk_aal_stop(struct mtk_ddp_comp *comp)
> +{
> +	writel_relaxed(0x0, comp->regs  + DISP_AAL_EN);
> +}

I think AAL is somewhat different from GAMMA and this patch include 3
modifications:

1. AAL basic config
2. GAMMA basic config
3. Add gamma function of AAL and GAMMA

So you should split this patch into 3 patches.

> +
> +static void mtk_gamma_config(struct mtk_ddp_comp *comp, unsigned int w,
> +			     unsigned int h, unsigned int vrefresh)
> +{
> +	writel(h << 16 | w, comp->regs + DISP_GAMMA_SIZE);
> +}
> +
> +static void mtk_gamma_start(struct mtk_ddp_comp *comp)
> +{
> +	writel(GAMMA_EN, comp->regs  + DISP_GAMMA_EN);
> +}
> +
> +static void mtk_gamma_stop(struct mtk_ddp_comp *comp)
> +{
> +	writel_relaxed(0x0, comp->regs  + DISP_GAMMA_EN);
> +}
> +
> +static void mtk_gamma_set(struct mtk_ddp_comp *comp,
> +			  struct drm_crtc_state *state)
> +{
> +	unsigned int i, reg;
> +	struct drm_color_lut *lut;
> +	void __iomem *lut_base;
> +	u32 word;
> +
> +	if (state->gamma_lut) {
> +		reg = readl(comp->regs + DISP_GAMMA_CFG);
> +		reg = reg | GAMMA_LUT_EN;
> +		writel(reg, comp->regs + DISP_GAMMA_CFG);
> +		lut_base = comp->regs + DISP_GAMMA_LUT;
> +		lut = (struct drm_color_lut *)state->gamma_lut->data;
> +		for (i = 0; i < MTK_LUT_SIZE; i++) {
> +			word = (((lut[i].red >> 6) & LUT_10BIT_MASK) << 20) +
> +			      (((lut[i].green >> 6) & LUT_10BIT_MASK) << 10) +
> +			      ((lut[i].blue >> 6) & LUT_10BIT_MASK);
> +			writel(word, (lut_base + i * 4));
> +		}
> +	}
> +}
> +
>  static const struct mtk_ddp_comp_funcs ddp_color = {
>  	.config = mtk_color_config,
>  	.start = mtk_color_start,
> @@ -90,6 +161,20 @@ static const struct mtk_ddp_comp_funcs ddp_ufoe = {
>  	.start = mtk_ufoe_start,
>  };
>  
> +static const struct mtk_ddp_comp_funcs ddp_aal = {
> +	.gamma_set = mtk_gamma_set,
> +	.config = mtk_aal_config,
> +	.start = mtk_aal_start,
> +	.stop = mtk_aal_stop,
> +};
> +
> +static const struct mtk_ddp_comp_funcs ddp_gamma = {
> +	.gamma_set = mtk_gamma_set,
> +	.config = mtk_gamma_config,
> +	.start = mtk_gamma_start,
> +	.stop = mtk_gamma_stop,
> +};
> +
>  static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = {
>  	[MTK_DISP_OVL] = "ovl",
>  	[MTK_DISP_RDMA] = "rdma",
> @@ -112,13 +197,13 @@ struct mtk_ddp_comp_match {
>  };
>  
>  static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
> -	[DDP_COMPONENT_AAL]	= { MTK_DISP_AAL,	0, NULL },
> +	[DDP_COMPONENT_AAL]	= { MTK_DISP_AAL,	0, &ddp_aal },
>  	[DDP_COMPONENT_COLOR0]	= { MTK_DISP_COLOR,	0, &ddp_color },
>  	[DDP_COMPONENT_COLOR1]	= { MTK_DISP_COLOR,	1, &ddp_color },
>  	[DDP_COMPONENT_DPI0]	= { MTK_DPI,		0, NULL },
>  	[DDP_COMPONENT_DSI0]	= { MTK_DSI,		0, NULL },
>  	[DDP_COMPONENT_DSI1]	= { MTK_DSI,		1, NULL },
> -	[DDP_COMPONENT_GAMMA]	= { MTK_DISP_GAMMA,	0, NULL },
> +	[DDP_COMPONENT_GAMMA]	= { MTK_DISP_GAMMA,	0, &ddp_gamma },
>  	[DDP_COMPONENT_OD]	= { MTK_DISP_OD,	0, &ddp_od },
>  	[DDP_COMPONENT_OVL0]	= { MTK_DISP_OVL,	0, NULL },
>  	[DDP_COMPONENT_OVL1]	= { MTK_DISP_OVL,	1, NULL },
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
> index 6b13ba9..07e17fe 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
> @@ -20,6 +20,7 @@ struct device;
>  struct device_node;
>  struct drm_crtc;
>  struct drm_device;
> +struct drm_crtc_state;
>  struct mtk_plane_state;
>  
>  enum mtk_ddp_comp_type {
> @@ -73,6 +74,8 @@ struct mtk_ddp_comp_funcs {
>  	void (*layer_off)(struct mtk_ddp_comp *comp, unsigned int idx);
>  	void (*layer_config)(struct mtk_ddp_comp *comp, unsigned int idx,
>  			     struct mtk_plane_state *state);
> +	void (*gamma_set)(struct mtk_ddp_comp *comp,
> +			  struct drm_crtc_state *state);
>  };
>  
>  struct mtk_ddp_comp {
> @@ -139,6 +142,13 @@ static inline void mtk_ddp_comp_layer_config(struct mtk_ddp_comp *comp,
>  		comp->funcs->layer_config(comp, idx, state);
>  }
>  
> +static inline void mtk_ddp_gamma_set(struct mtk_ddp_comp *comp,
> +				     struct drm_crtc_state *state)
> +{
> +	if (comp->funcs && comp->funcs->gamma_set)
> +		comp->funcs->gamma_set(comp, state);
> +}
> +
>  int mtk_ddp_comp_get_id(struct device_node *node,
>  			enum mtk_ddp_comp_type comp_type);
>  int mtk_ddp_comp_init(struct device *dev, struct device_node *comp_node,




From p.zabel at pengutronix.de  Fri Jul 15 02:26:53 2016
From: p.zabel at pengutronix.de (Philipp Zabel)
Date: Fri, 15 Jul 2016 11:26:53 +0200
Subject: [PATCH] drm: mediatek: add Maintainers entry for Mediatek DRM
 drivers
In-Reply-To: <1468561924-45582-1-git-send-email-ck.hu@mediatek.com>
References: <1468561924-45582-1-git-send-email-ck.hu@mediatek.com>
Message-ID: <1468574813.7213.4.camel@pengutronix.de>

Am Freitag, den 15.07.2016, 13:52 +0800 schrieb CK Hu:
> Add CK Hu and Philipp Zabel as maintainers for Mediatek DRM drivers.
> 
> Signed-off-by: CK Hu <ck.hu at mediatek.com>

Acked-by: Philipp Zabel <p.zabel at pengutronix.de>

> ---
>  MAINTAINERS |    8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 7304d2e..2a04cdc 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -3973,6 +3973,14 @@ S:	Orphan / Obsolete
>  F:	drivers/gpu/drm/i810/
>  F:	include/uapi/drm/i810_drm.h
>  
> +DRM DRIVERS FOR MEDIATEK
> +M:	CK Hu <ck.hu at mediatek.com>
> +M:	Philipp Zabel <p.zabel at pengutronix.de>
> +L:	dri-devel at lists.freedesktop.org
> +S:	Supported
> +F:	drivers/gpu/drm/mediatek/
> +F:	Documentation/devicetree/bindings/display/mediatek/
> +
>  DRM DRIVER FOR MSM ADRENO GPU
>  M:	Rob Clark <robdclark at gmail.com>
>  L:	linux-arm-msm at vger.kernel.org

regards
Philipp



From yt.shen at mediatek.com  Fri Jul 15 03:07:46 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Fri, 15 Jul 2016 18:07:46 +0800
Subject: [PATCH v4 0/8] MT2701 DRM support
Message-ID: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>

This is MT2701 DRM support PATCH v4, based on 4.7-rc1.
We add DSI interrupt control, transfer function for MIPI DSI panel support.
Most codes are the same, except some register changed.

For example:
 - DISP_OVL address offset changed, color format definition changed.
 - DISP_RDMA fifo size changed.
 - DISP_COLOR offset changed.

We add a new component DDP_COMPONENT_BLS, and the settings are updated.
And we have shadow register support in MT2701.

Changes since v3:
- Add DSI support for MIPI DSI panels
- Update BLS binding to PWM nodes
- Remove ufoe device nodes
- Remove redundant parentheses
- Remove global variable initialization

Changes since v2:
- Rename mtk_ddp_mux_sel to mtk_ddp_sout_sel
- Update mt2701_mtk_ddp_ext components
- Changed to prefix naming
- Reorder the patch series
- Use of_device_get_match_data() to get driver private data
- Use iopoll macros to implement mtk_disp_mutex_acquire()
- Removed empty device tree nodes

Changes since v1:
- Removed BLS bindings and codes, which belong to pwm driver
- Moved mtk_disp_mutex_acquire() just before mtk_crtc_ddp_config()
- Split patch into smaller parts
- Added const keyword to constant structure
- Removed codes for special memory align

The PATCH depends on the following patch:
https://patchwork.kernel.org/patch/8832441/ ("dt-bindings: ARM: Mediatek: Document bindings for MT2701"),
https://patchwork.kernel.org/patch/9140487/ ("dt-bindings: pwm: Add MediaTek display PWM bindings"),
https://patchwork.kernel.org/patch/9137919/ ("dt-bindings: mediatek: add descriptions for mediatek mt2701 iommu and smi"),
https://patchwork.kernel.org/patch/9137923/ ("iommu/mediatek: move the common struct into header file"),
https://patchwork.kernel.org/patch/9137921/ ("memory/mediatek: add support for mt2701"),
https://patchwork.kernel.org/patch/9137927/ ("iommu/mediatek: add support for mtk iommu generation one HW"),
https://patchwork.kernel.org/patch/9137931/ ("ARM: dts: mt2701: add iommu/smi dtsi node for mt2701"),

Thanks,
yt.shen

YT Shen (5):
  drm/mediatek: rename macros, add chip prefix
  drm/mediatek: add *driver_data for different hardware settings
  drm/mediatek: add shadow register support
  drm/mediatek: add support for Mediatek SoC MT2701
  arm: dts: mt2701: Add display subsystem related nodes for MT2701

shaoming chen (3):
  drm/mediatek: add dsi interrupt control
  drm/mediatek: add dsi transfer function
  drm/mediatek: add mipi panel support

 arch/arm/boot/dts/mt2701.dtsi               |  100 +++++
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c     |   32 +-
 drivers/gpu/drm/mediatek/mtk_disp_rdma.c    |   17 +-
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c     |   75 ++--
 drivers/gpu/drm/mediatek/mtk_drm_ddp.c      |  134 ++++--
 drivers/gpu/drm/mediatek/mtk_drm_ddp.h      |    2 +
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |   34 +-
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |   14 +
 drivers/gpu/drm/mediatek/mtk_drm_drv.c      |   56 ++-
 drivers/gpu/drm/mediatek/mtk_drm_drv.h      |    9 +
 drivers/gpu/drm/mediatek/mtk_dsi.c          |  619 ++++++++++++++++++++++++---
 drivers/gpu/drm/mediatek/mtk_mipi_tx.c      |   82 ++--
 12 files changed, 1009 insertions(+), 165 deletions(-)

-- 
1.7.9.5



From yt.shen at mediatek.com  Fri Jul 15 03:07:47 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Fri, 15 Jul 2016 18:07:47 +0800
Subject: [PATCH v4 1/8] drm/mediatek: rename macros, add chip prefix
In-Reply-To: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
Message-ID: <1468577274-6178-2-git-send-email-yt.shen@mediatek.com>

Add MT8173 prefix for hardware related macros.

Signed-off-by: YT Shen <yt.shen at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_drm_ddp.c |   60 ++++++++++++++++----------------
 1 file changed, 30 insertions(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
index 17ba935..2fc4321 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
@@ -36,21 +36,21 @@
 #define DISP_REG_MUTEX_MOD(n)	(0x2c + 0x20 * (n))
 #define DISP_REG_MUTEX_SOF(n)	(0x30 + 0x20 * (n))
 
-#define MUTEX_MOD_DISP_OVL0		BIT(11)
-#define MUTEX_MOD_DISP_OVL1		BIT(12)
-#define MUTEX_MOD_DISP_RDMA0		BIT(13)
-#define MUTEX_MOD_DISP_RDMA1		BIT(14)
-#define MUTEX_MOD_DISP_RDMA2		BIT(15)
-#define MUTEX_MOD_DISP_WDMA0		BIT(16)
-#define MUTEX_MOD_DISP_WDMA1		BIT(17)
-#define MUTEX_MOD_DISP_COLOR0		BIT(18)
-#define MUTEX_MOD_DISP_COLOR1		BIT(19)
-#define MUTEX_MOD_DISP_AAL		BIT(20)
-#define MUTEX_MOD_DISP_GAMMA		BIT(21)
-#define MUTEX_MOD_DISP_UFOE		BIT(22)
-#define MUTEX_MOD_DISP_PWM0		BIT(23)
-#define MUTEX_MOD_DISP_PWM1		BIT(24)
-#define MUTEX_MOD_DISP_OD		BIT(25)
+#define MT8173_MUTEX_MOD_DISP_OVL0		BIT(11)
+#define MT8173_MUTEX_MOD_DISP_OVL1		BIT(12)
+#define MT8173_MUTEX_MOD_DISP_RDMA0		BIT(13)
+#define MT8173_MUTEX_MOD_DISP_RDMA1		BIT(14)
+#define MT8173_MUTEX_MOD_DISP_RDMA2		BIT(15)
+#define MT8173_MUTEX_MOD_DISP_WDMA0		BIT(16)
+#define MT8173_MUTEX_MOD_DISP_WDMA1		BIT(17)
+#define MT8173_MUTEX_MOD_DISP_COLOR0		BIT(18)
+#define MT8173_MUTEX_MOD_DISP_COLOR1		BIT(19)
+#define MT8173_MUTEX_MOD_DISP_AAL		BIT(20)
+#define MT8173_MUTEX_MOD_DISP_GAMMA		BIT(21)
+#define MT8173_MUTEX_MOD_DISP_UFOE		BIT(22)
+#define MT8173_MUTEX_MOD_DISP_PWM0		BIT(23)
+#define MT8173_MUTEX_MOD_DISP_PWM1		BIT(24)
+#define MT8173_MUTEX_MOD_DISP_OD		BIT(25)
 
 #define MUTEX_SOF_SINGLE_MODE		0
 #define MUTEX_SOF_DSI0			1
@@ -80,21 +80,21 @@ struct mtk_ddp {
 };
 
 static const unsigned int mutex_mod[DDP_COMPONENT_ID_MAX] = {
-	[DDP_COMPONENT_AAL] = MUTEX_MOD_DISP_AAL,
-	[DDP_COMPONENT_COLOR0] = MUTEX_MOD_DISP_COLOR0,
-	[DDP_COMPONENT_COLOR1] = MUTEX_MOD_DISP_COLOR1,
-	[DDP_COMPONENT_GAMMA] = MUTEX_MOD_DISP_GAMMA,
-	[DDP_COMPONENT_OD] = MUTEX_MOD_DISP_OD,
-	[DDP_COMPONENT_OVL0] = MUTEX_MOD_DISP_OVL0,
-	[DDP_COMPONENT_OVL1] = MUTEX_MOD_DISP_OVL1,
-	[DDP_COMPONENT_PWM0] = MUTEX_MOD_DISP_PWM0,
-	[DDP_COMPONENT_PWM1] = MUTEX_MOD_DISP_PWM1,
-	[DDP_COMPONENT_RDMA0] = MUTEX_MOD_DISP_RDMA0,
-	[DDP_COMPONENT_RDMA1] = MUTEX_MOD_DISP_RDMA1,
-	[DDP_COMPONENT_RDMA2] = MUTEX_MOD_DISP_RDMA2,
-	[DDP_COMPONENT_UFOE] = MUTEX_MOD_DISP_UFOE,
-	[DDP_COMPONENT_WDMA0] = MUTEX_MOD_DISP_WDMA0,
-	[DDP_COMPONENT_WDMA1] = MUTEX_MOD_DISP_WDMA1,
+	[DDP_COMPONENT_AAL] = MT8173_MUTEX_MOD_DISP_AAL,
+	[DDP_COMPONENT_COLOR0] = MT8173_MUTEX_MOD_DISP_COLOR0,
+	[DDP_COMPONENT_COLOR1] = MT8173_MUTEX_MOD_DISP_COLOR1,
+	[DDP_COMPONENT_GAMMA] = MT8173_MUTEX_MOD_DISP_GAMMA,
+	[DDP_COMPONENT_OD] = MT8173_MUTEX_MOD_DISP_OD,
+	[DDP_COMPONENT_OVL0] = MT8173_MUTEX_MOD_DISP_OVL0,
+	[DDP_COMPONENT_OVL1] = MT8173_MUTEX_MOD_DISP_OVL1,
+	[DDP_COMPONENT_PWM0] = MT8173_MUTEX_MOD_DISP_PWM0,
+	[DDP_COMPONENT_PWM1] = MT8173_MUTEX_MOD_DISP_PWM1,
+	[DDP_COMPONENT_RDMA0] = MT8173_MUTEX_MOD_DISP_RDMA0,
+	[DDP_COMPONENT_RDMA1] = MT8173_MUTEX_MOD_DISP_RDMA1,
+	[DDP_COMPONENT_RDMA2] = MT8173_MUTEX_MOD_DISP_RDMA2,
+	[DDP_COMPONENT_UFOE] = MT8173_MUTEX_MOD_DISP_UFOE,
+	[DDP_COMPONENT_WDMA0] = MT8173_MUTEX_MOD_DISP_WDMA0,
+	[DDP_COMPONENT_WDMA1] = MT8173_MUTEX_MOD_DISP_WDMA1,
 };
 
 static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur,
-- 
1.7.9.5



From yt.shen at mediatek.com  Fri Jul 15 03:07:48 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Fri, 15 Jul 2016 18:07:48 +0800
Subject: [PATCH v4 2/8] drm/mediatek: add *driver_data for different hardware
 settings
In-Reply-To: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
Message-ID: <1468577274-6178-3-git-send-email-yt.shen@mediatek.com>

There are some hardware settings changed, between MT8173 & MT2701:
DISP_OVL address offset changed, color format definition changed.
DISP_RDMA fifo size changed.
DISP_COLOR offset changed.
And add prefix for mtk_ddp_main & mtk_ddp_ext & mutex_mod.

Signed-off-by: YT Shen <yt.shen at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c     |   26 ++++++++++++++++----------
 drivers/gpu/drm/mediatek/mtk_disp_rdma.c    |   11 +++++++++--
 drivers/gpu/drm/mediatek/mtk_drm_ddp.c      |   11 +++++++----
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |   27 +++++++++++++++++++++------
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |   13 +++++++++++++
 drivers/gpu/drm/mediatek/mtk_drm_drv.c      |   25 ++++++++++++++++++-------
 drivers/gpu/drm/mediatek/mtk_drm_drv.h      |    8 ++++++++
 7 files changed, 92 insertions(+), 29 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index 8f62671f..eb5c05e 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -40,8 +40,6 @@
 #define	OVL_RDMA_MEM_GMC	0x40402020
 
 #define OVL_CON_BYTE_SWAP	BIT(24)
-#define OVL_CON_CLRFMT_RGB565	(0 << 12)
-#define OVL_CON_CLRFMT_RGB888	(1 << 12)
 #define OVL_CON_CLRFMT_RGBA8888	(2 << 12)
 #define OVL_CON_CLRFMT_ARGB8888	(3 << 12)
 #define	OVL_CON_AEN		BIT(8)
@@ -136,18 +134,18 @@ static void mtk_ovl_layer_off(struct mtk_ddp_comp *comp, unsigned int idx)
 	writel(0x0, comp->regs + DISP_REG_OVL_RDMA_CTRL(idx));
 }
 
-static unsigned int ovl_fmt_convert(unsigned int fmt)
+static unsigned int ovl_fmt_convert(struct mtk_ddp_comp *comp, unsigned int fmt)
 {
 	switch (fmt) {
 	default:
 	case DRM_FORMAT_RGB565:
-		return OVL_CON_CLRFMT_RGB565;
+		return comp->data->ovl.fmt_rgb565;
 	case DRM_FORMAT_BGR565:
-		return OVL_CON_CLRFMT_RGB565 | OVL_CON_BYTE_SWAP;
+		return comp->data->ovl.fmt_rgb565 | OVL_CON_BYTE_SWAP;
 	case DRM_FORMAT_RGB888:
-		return OVL_CON_CLRFMT_RGB888;
+		return comp->data->ovl.fmt_rgb888;
 	case DRM_FORMAT_BGR888:
-		return OVL_CON_CLRFMT_RGB888 | OVL_CON_BYTE_SWAP;
+		return comp->data->ovl.fmt_rgb888 | OVL_CON_BYTE_SWAP;
 	case DRM_FORMAT_RGBX8888:
 	case DRM_FORMAT_RGBA8888:
 		return OVL_CON_CLRFMT_ARGB8888;
@@ -177,7 +175,7 @@ static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx,
 	if (!pending->enable)
 		mtk_ovl_layer_off(comp, idx);
 
-	con = ovl_fmt_convert(fmt);
+	con = ovl_fmt_convert(comp, fmt);
 	if (idx != 0)
 		con |= OVL_CON_AEN | OVL_CON_ALPHA;
 
@@ -185,7 +183,8 @@ static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx,
 	writel_relaxed(pitch, comp->regs + DISP_REG_OVL_PITCH(idx));
 	writel_relaxed(src_size, comp->regs + DISP_REG_OVL_SRC_SIZE(idx));
 	writel_relaxed(offset, comp->regs + DISP_REG_OVL_OFFSET(idx));
-	writel_relaxed(addr, comp->regs + DISP_REG_OVL_ADDR(idx));
+	writel_relaxed(addr, comp->regs + comp->data->ovl.addr_offset
+					+ idx * 0x20);
 
 	if (pending->enable)
 		mtk_ovl_layer_on(comp, idx);
@@ -269,6 +268,8 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	priv->ddp_comp.data = of_device_get_match_data(dev);
+
 	platform_set_drvdata(pdev, priv);
 
 	ret = component_add(dev, &mtk_disp_ovl_component_ops);
@@ -285,8 +286,13 @@ static int mtk_disp_ovl_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct mtk_ddp_comp_driver_data mt8173_ovl_driver_data = {
+	.ovl = {0x0f40, 0, 1 << 12}
+};
+
 static const struct of_device_id mtk_disp_ovl_driver_dt_match[] = {
-	{ .compatible = "mediatek,mt8173-disp-ovl", },
+	{ .compatible = "mediatek,mt8173-disp-ovl",
+	  .data = &mt8173_ovl_driver_data},
 	{},
 };
 MODULE_DEVICE_TABLE(of, mtk_disp_ovl_driver_dt_match);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
index 5fb80cb..fb0db50 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
@@ -122,7 +122,7 @@ static void mtk_rdma_config(struct mtk_ddp_comp *comp, unsigned int width,
 	 */
 	threshold = width * height * vrefresh * 4 * 7 / 1000000;
 	reg = RDMA_FIFO_UNDERFLOW_EN |
-	      RDMA_FIFO_PSEUDO_SIZE(SZ_8K) |
+	      RDMA_FIFO_PSEUDO_SIZE(comp->data->rdma_fifo_pseudo_size) |
 	      RDMA_OUTPUT_VALID_FIFO_THRESHOLD(threshold);
 	writel(reg, comp->regs + DISP_REG_RDMA_FIFO_CON);
 }
@@ -207,6 +207,8 @@ static int mtk_disp_rdma_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	priv->ddp_comp.data = of_device_get_match_data(dev);
+
 	platform_set_drvdata(pdev, priv);
 
 	ret = component_add(dev, &mtk_disp_rdma_component_ops);
@@ -223,8 +225,13 @@ static int mtk_disp_rdma_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct mtk_ddp_comp_driver_data mt8173_rdma_driver_data = {
+	.rdma_fifo_pseudo_size = SZ_8K,
+};
+
 static const struct of_device_id mtk_disp_rdma_driver_dt_match[] = {
-	{ .compatible = "mediatek,mt8173-disp-rdma", },
+	{ .compatible = "mediatek,mt8173-disp-rdma",
+	  .data = &mt8173_rdma_driver_data},
 	{},
 };
 MODULE_DEVICE_TABLE(of, mtk_disp_rdma_driver_dt_match);
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
index 2fc4321..8030769 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
@@ -77,9 +77,10 @@ struct mtk_ddp {
 	struct clk			*clk;
 	void __iomem			*regs;
 	struct mtk_disp_mutex		mutex[10];
+	const unsigned int		*mutex_mod;
 };
 
-static const unsigned int mutex_mod[DDP_COMPONENT_ID_MAX] = {
+static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = {
 	[DDP_COMPONENT_AAL] = MT8173_MUTEX_MOD_DISP_AAL,
 	[DDP_COMPONENT_COLOR0] = MT8173_MUTEX_MOD_DISP_COLOR0,
 	[DDP_COMPONENT_COLOR1] = MT8173_MUTEX_MOD_DISP_COLOR1,
@@ -247,7 +248,7 @@ void mtk_disp_mutex_add_comp(struct mtk_disp_mutex *mutex,
 		break;
 	default:
 		reg = readl_relaxed(ddp->regs + DISP_REG_MUTEX_MOD(mutex->id));
-		reg |= mutex_mod[id];
+		reg |= ddp->mutex_mod[id];
 		writel_relaxed(reg, ddp->regs + DISP_REG_MUTEX_MOD(mutex->id));
 		return;
 	}
@@ -273,7 +274,7 @@ void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex,
 		break;
 	default:
 		reg = readl_relaxed(ddp->regs + DISP_REG_MUTEX_MOD(mutex->id));
-		reg &= ~mutex_mod[id];
+		reg &= ~(ddp->mutex_mod[id]);
 		writel_relaxed(reg, ddp->regs + DISP_REG_MUTEX_MOD(mutex->id));
 		break;
 	}
@@ -326,6 +327,8 @@ static int mtk_ddp_probe(struct platform_device *pdev)
 		return PTR_ERR(ddp->regs);
 	}
 
+	ddp->mutex_mod = of_device_get_match_data(dev);
+
 	platform_set_drvdata(pdev, ddp);
 
 	return 0;
@@ -337,7 +340,7 @@ static int mtk_ddp_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id ddp_driver_dt_match[] = {
-	{ .compatible = "mediatek,mt8173-disp-mutex" },
+	{ .compatible = "mediatek,mt8173-disp-mutex", .data = mt8173_mutex_mod},
 	{},
 };
 MODULE_DEVICE_TABLE(of, ddp_driver_dt_match);
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
index 3970fcf..4b4e449 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
@@ -34,9 +34,8 @@
 #define DISP_REG_UFO_START			0x0000
 
 #define DISP_COLOR_CFG_MAIN			0x0400
-#define DISP_COLOR_START			0x0c00
-#define DISP_COLOR_WIDTH			0x0c50
-#define DISP_COLOR_HEIGHT			0x0c54
+#define DISP_COLOR_WIDTH			0x50
+#define DISP_COLOR_HEIGHT			0x54
 
 #define	OD_RELAY_MODE		BIT(0)
 
@@ -48,15 +47,15 @@
 static void mtk_color_config(struct mtk_ddp_comp *comp, unsigned int w,
 			     unsigned int h, unsigned int vrefresh)
 {
-	writel(w, comp->regs + DISP_COLOR_WIDTH);
-	writel(h, comp->regs + DISP_COLOR_HEIGHT);
+	writel(w, comp->regs + comp->data->color_offset + DISP_COLOR_WIDTH);
+	writel(h, comp->regs + comp->data->color_offset + DISP_COLOR_HEIGHT);
 }
 
 static void mtk_color_start(struct mtk_ddp_comp *comp)
 {
 	writel(COLOR_BYPASS_ALL | COLOR_SEQ_SEL,
 	       comp->regs + DISP_COLOR_CFG_MAIN);
-	writel(0x1, comp->regs + DISP_COLOR_START);
+	writel(0x1, comp->regs + comp->data->color_offset);
 }
 
 static void mtk_od_config(struct mtk_ddp_comp *comp, unsigned int w,
@@ -131,6 +130,16 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
 	[DDP_COMPONENT_WDMA1]	= { MTK_DISP_WDMA,	1, NULL },
 };
 
+static const struct mtk_ddp_comp_driver_data mt8173_color_driver_data = {
+	.color_offset = 0x0c00,
+};
+
+static const struct of_device_id mtk_disp_color_driver_dt_match[] = {
+	{ .compatible = "mediatek,mt8173-disp-color",
+	  .data = &mt8173_color_driver_data},
+	{},
+};
+
 int mtk_ddp_comp_get_id(struct device_node *node,
 			enum mtk_ddp_comp_type comp_type)
 {
@@ -153,6 +162,7 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
 	enum mtk_ddp_comp_type type;
 	struct device_node *larb_node;
 	struct platform_device *larb_pdev;
+	const struct of_device_id *match;
 
 	if (comp_id < 0 || comp_id >= DDP_COMPONENT_ID_MAX)
 		return -EINVAL;
@@ -177,6 +187,11 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
 
 	type = mtk_ddp_matches[comp_id].type;
 
+	if (type == MTK_DISP_COLOR) {
+		match = of_match_node(mtk_disp_color_driver_dt_match, node);
+		comp->data = match->data;
+	}
+
 	/* Only DMA capable components need the LARB property */
 	comp->larb_dev = NULL;
 	if (type != MTK_DISP_OVL &&
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
index 6b13ba9..53065c7 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
@@ -75,6 +75,18 @@ struct mtk_ddp_comp_funcs {
 			     struct mtk_plane_state *state);
 };
 
+struct mtk_ddp_comp_driver_data {
+	union {
+		struct ovl {
+			unsigned int addr_offset;
+			unsigned int fmt_rgb565;
+			unsigned int fmt_rgb888;
+		} ovl;
+		unsigned int rdma_fifo_pseudo_size;
+		unsigned int color_offset;
+	};
+};
+
 struct mtk_ddp_comp {
 	struct clk *clk;
 	void __iomem *regs;
@@ -82,6 +94,7 @@ struct mtk_ddp_comp {
 	struct device *larb_dev;
 	enum mtk_ddp_comp_id id;
 	const struct mtk_ddp_comp_funcs *funcs;
+	const struct mtk_ddp_comp_driver_data *data;
 };
 
 static inline void mtk_ddp_comp_config(struct mtk_ddp_comp *comp,
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index b1223d5..80b4f54 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -109,7 +109,7 @@ static const struct drm_mode_config_funcs mtk_drm_mode_config_funcs = {
 	.atomic_commit = mtk_atomic_commit,
 };
 
-static const enum mtk_ddp_comp_id mtk_ddp_main[] = {
+static const enum mtk_ddp_comp_id mt8173_mtk_ddp_main[] = {
 	DDP_COMPONENT_OVL0,
 	DDP_COMPONENT_COLOR0,
 	DDP_COMPONENT_AAL,
@@ -120,7 +120,7 @@ static const enum mtk_ddp_comp_id mtk_ddp_main[] = {
 	DDP_COMPONENT_PWM0,
 };
 
-static const enum mtk_ddp_comp_id mtk_ddp_ext[] = {
+static const enum mtk_ddp_comp_id mt8173_mtk_ddp_ext[] = {
 	DDP_COMPONENT_OVL1,
 	DDP_COMPONENT_COLOR1,
 	DDP_COMPONENT_GAMMA,
@@ -128,6 +128,13 @@ static const enum mtk_ddp_comp_id mtk_ddp_ext[] = {
 	DDP_COMPONENT_DPI0,
 };
 
+static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = {
+	.main_path = mt8173_mtk_ddp_main,
+	.main_len = ARRAY_SIZE(mt8173_mtk_ddp_main),
+	.ext_path = mt8173_mtk_ddp_ext,
+	.ext_len = ARRAY_SIZE(mt8173_mtk_ddp_ext),
+};
+
 static int mtk_drm_kms_init(struct drm_device *drm)
 {
 	struct mtk_drm_private *private = drm->dev_private;
@@ -170,17 +177,19 @@ static int mtk_drm_kms_init(struct drm_device *drm)
 	 * and each statically assigned to a crtc:
 	 * OVL0 -> COLOR0 -> AAL -> OD -> RDMA0 -> UFOE -> DSI0 ...
 	 */
-	ret = mtk_drm_crtc_create(drm, mtk_ddp_main, ARRAY_SIZE(mtk_ddp_main));
+	ret = mtk_drm_crtc_create(drm, private->data->main_path,
+				  private->data->main_len);
 	if (ret < 0)
 		goto err_component_unbind;
 	/* ... and OVL1 -> COLOR1 -> GAMMA -> RDMA1 -> DPI0. */
-	ret = mtk_drm_crtc_create(drm, mtk_ddp_ext, ARRAY_SIZE(mtk_ddp_ext));
+	ret = mtk_drm_crtc_create(drm, private->data->ext_path,
+				  private->data->ext_len);
 	if (ret < 0)
 		goto err_component_unbind;
 
 	/* Use OVL device for all DMA memory allocations */
-	np = private->comp_node[mtk_ddp_main[0]] ?:
-	     private->comp_node[mtk_ddp_ext[0]];
+	np = private->comp_node[private->data->main_path[0]] ?:
+	     private->comp_node[private->data->ext_path[0]];
 	pdev = of_find_device_by_node(np);
 	if (!pdev) {
 		ret = -ENODEV;
@@ -353,6 +362,7 @@ static int mtk_drm_probe(struct platform_device *pdev)
 
 	mutex_init(&private->commit.lock);
 	INIT_WORK(&private->commit.work, mtk_atomic_work);
+	private->data = of_device_get_match_data(dev);
 
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	private->config_regs = devm_ioremap_resource(dev, mem);
@@ -504,7 +514,8 @@ static SIMPLE_DEV_PM_OPS(mtk_drm_pm_ops, mtk_drm_sys_suspend,
 			 mtk_drm_sys_resume);
 
 static const struct of_device_id mtk_drm_of_ids[] = {
-	{ .compatible = "mediatek,mt8173-mmsys", },
+	{ .compatible = "mediatek,mt8173-mmsys",
+	  .data = &mt8173_mmsys_driver_data},
 	{ }
 };
 
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
index aa93894..fa0b106 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
@@ -28,6 +28,13 @@ struct drm_fb_helper;
 struct drm_property;
 struct regmap;
 
+struct mtk_mmsys_driver_data {
+	const enum mtk_ddp_comp_id *main_path;
+	unsigned int main_len;
+	const enum mtk_ddp_comp_id *ext_path;
+	unsigned int ext_len;
+};
+
 struct mtk_drm_private {
 	struct drm_device *drm;
 	struct device *dma_dev;
@@ -40,6 +47,7 @@ struct mtk_drm_private {
 	void __iomem *config_regs;
 	struct device_node *comp_node[DDP_COMPONENT_ID_MAX];
 	struct mtk_ddp_comp *ddp_comp[DDP_COMPONENT_ID_MAX];
+	const struct mtk_mmsys_driver_data *data;
 
 	struct {
 		struct drm_atomic_state *state;
-- 
1.7.9.5



From yt.shen at mediatek.com  Fri Jul 15 03:07:49 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Fri, 15 Jul 2016 18:07:49 +0800
Subject: [PATCH v4 3/8] drm/mediatek: add shadow register support
In-Reply-To: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
Message-ID: <1468577274-6178-4-git-send-email-yt.shen@mediatek.com>

We need to acquire mutex before using the resources,
and need to release it after finished.
So we don't need to write registers in the blanking period.

Signed-off-by: YT Shen <yt.shen at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c |   75 +++++++++++++++++++------------
 drivers/gpu/drm/mediatek/mtk_drm_ddp.c  |   22 +++++++++
 drivers/gpu/drm/mediatek/mtk_drm_ddp.h  |    2 +
 drivers/gpu/drm/mediatek/mtk_drm_drv.h  |    1 +
 4 files changed, 71 insertions(+), 29 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index 24aa3ba..80d9641 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -315,6 +315,42 @@ static void mtk_crtc_ddp_hw_fini(struct mtk_drm_crtc *mtk_crtc)
 	pm_runtime_put(drm->dev);
 }
 
+static void mtk_crtc_ddp_config(struct drm_crtc *crtc)
+{
+	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
+	struct mtk_crtc_state *state = to_mtk_crtc_state(mtk_crtc->base.state);
+	struct mtk_ddp_comp *ovl = mtk_crtc->ddp_comp[0];
+	unsigned int i;
+
+	/*
+	 * TODO: instead of updating the registers here, we should prepare
+	 * working registers in atomic_commit and let the hardware command
+	 * queue update module registers on vblank.
+	 */
+	if (state->pending_config) {
+		mtk_ddp_comp_config(ovl, state->pending_width,
+				    state->pending_height,
+				    state->pending_vrefresh);
+
+		state->pending_config = false;
+	}
+
+	if (mtk_crtc->pending_planes) {
+		for (i = 0; i < OVL_LAYER_NR; i++) {
+			struct drm_plane *plane = &mtk_crtc->planes[i].base;
+			struct mtk_plane_state *plane_state;
+
+			plane_state = to_mtk_plane_state(plane->state);
+
+			if (plane_state->pending.config) {
+				mtk_ddp_comp_layer_config(ovl, i, plane_state);
+				plane_state->pending.config = false;
+			}
+		}
+		mtk_crtc->pending_planes = false;
+	}
+}
+
 static void mtk_drm_crtc_enable(struct drm_crtc *crtc)
 {
 	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
@@ -391,6 +427,7 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
 				      struct drm_crtc_state *old_crtc_state)
 {
 	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
+	struct mtk_drm_private *priv = crtc->dev->dev_private;
 	unsigned int pending_planes = 0;
 	int i;
 
@@ -409,6 +446,12 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
 	}
 	if (pending_planes)
 		mtk_crtc->pending_planes = true;
+
+	if (priv->data->shadow_register) {
+		mtk_disp_mutex_acquire(mtk_crtc->mutex);
+		mtk_crtc_ddp_config(crtc);
+		mtk_disp_mutex_release(mtk_crtc->mutex);
+	}
 }
 
 static const struct drm_crtc_funcs mtk_crtc_funcs = {
@@ -453,36 +496,10 @@ err_cleanup_crtc:
 void mtk_crtc_ddp_irq(struct drm_crtc *crtc, struct mtk_ddp_comp *ovl)
 {
 	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
-	struct mtk_crtc_state *state = to_mtk_crtc_state(mtk_crtc->base.state);
-	unsigned int i;
+	struct mtk_drm_private *priv = crtc->dev->dev_private;
 
-	/*
-	 * TODO: instead of updating the registers here, we should prepare
-	 * working registers in atomic_commit and let the hardware command
-	 * queue update module registers on vblank.
-	 */
-	if (state->pending_config) {
-		mtk_ddp_comp_config(ovl, state->pending_width,
-				    state->pending_height,
-				    state->pending_vrefresh);
-
-		state->pending_config = false;
-	}
-
-	if (mtk_crtc->pending_planes) {
-		for (i = 0; i < OVL_LAYER_NR; i++) {
-			struct drm_plane *plane = &mtk_crtc->planes[i].base;
-			struct mtk_plane_state *plane_state;
-
-			plane_state = to_mtk_plane_state(plane->state);
-
-			if (plane_state->pending.config) {
-				mtk_ddp_comp_layer_config(ovl, i, plane_state);
-				plane_state->pending.config = false;
-			}
-		}
-		mtk_crtc->pending_planes = false;
-	}
+	if (!priv->data->shadow_register)
+		mtk_crtc_ddp_config(crtc);
 
 	mtk_drm_finish_page_flip(mtk_crtc);
 }
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
index 8030769..fa53806 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
@@ -12,6 +12,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
@@ -32,6 +33,7 @@
 #define DISP_REG_CONFIG_MMSYS_CG_CON0		0x100
 
 #define DISP_REG_MUTEX_EN(n)	(0x20 + 0x20 * (n))
+#define DISP_REG_MUTEX(n)	(0x24 + 0x20 * (n))
 #define DISP_REG_MUTEX_RST(n)	(0x28 + 0x20 * (n))
 #define DISP_REG_MUTEX_MOD(n)	(0x2c + 0x20 * (n))
 #define DISP_REG_MUTEX_SOF(n)	(0x30 + 0x20 * (n))
@@ -300,6 +302,26 @@ void mtk_disp_mutex_disable(struct mtk_disp_mutex *mutex)
 	writel(0, ddp->regs + DISP_REG_MUTEX_EN(mutex->id));
 }
 
+void mtk_disp_mutex_acquire(struct mtk_disp_mutex *mutex)
+{
+	struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
+					   mutex[mutex->id]);
+	u32 tmp;
+
+	writel(1, ddp->regs + DISP_REG_MUTEX_EN(mutex->id));
+	writel(1, ddp->regs + DISP_REG_MUTEX(mutex->id));
+	readl_poll_timeout_atomic(ddp->regs + DISP_REG_MUTEX(mutex->id), tmp,
+				  tmp & 0x2, 1, 10000);
+}
+
+void mtk_disp_mutex_release(struct mtk_disp_mutex *mutex)
+{
+	struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
+					   mutex[mutex->id]);
+
+	writel(0, ddp->regs + DISP_REG_MUTEX(mutex->id));
+}
+
 static int mtk_ddp_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp.h
index 92c1175..f9a7991 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.h
@@ -37,5 +37,7 @@ void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex,
 				enum mtk_ddp_comp_id id);
 void mtk_disp_mutex_unprepare(struct mtk_disp_mutex *mutex);
 void mtk_disp_mutex_put(struct mtk_disp_mutex *mutex);
+void mtk_disp_mutex_acquire(struct mtk_disp_mutex *mutex);
+void mtk_disp_mutex_release(struct mtk_disp_mutex *mutex);
 
 #endif /* MTK_DRM_DDP_H */
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
index fa0b106..94f8b66 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
@@ -33,6 +33,7 @@ struct mtk_mmsys_driver_data {
 	unsigned int main_len;
 	const enum mtk_ddp_comp_id *ext_path;
 	unsigned int ext_len;
+	bool shadow_register;
 };
 
 struct mtk_drm_private {
-- 
1.7.9.5



From yt.shen at mediatek.com  Fri Jul 15 03:07:50 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Fri, 15 Jul 2016 18:07:50 +0800
Subject: [PATCH v4 4/8] drm/mediatek: add support for Mediatek SoC MT2701
In-Reply-To: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
Message-ID: <1468577274-6178-5-git-send-email-yt.shen@mediatek.com>

This patch add support for the Mediatek MT2701 DISP subsystem.
There is only one OVL engine in MT2701.

Signed-off-by: YT Shen <yt.shen at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c     |    6 ++++
 drivers/gpu/drm/mediatek/mtk_disp_rdma.c    |    6 ++++
 drivers/gpu/drm/mediatek/mtk_drm_ddp.c      |   41 +++++++++++++++++++++++++++
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |    7 +++++
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |    1 +
 drivers/gpu/drm/mediatek/mtk_drm_drv.c      |   31 ++++++++++++++++++++
 6 files changed, 92 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index eb5c05e..1da0a71 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -286,11 +286,17 @@ static int mtk_disp_ovl_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct mtk_ddp_comp_driver_data mt2701_ovl_driver_data = {
+	.ovl = {0x0040, 1 << 12, 0}
+};
+
 static const struct mtk_ddp_comp_driver_data mt8173_ovl_driver_data = {
 	.ovl = {0x0f40, 0, 1 << 12}
 };
 
 static const struct of_device_id mtk_disp_ovl_driver_dt_match[] = {
+	{ .compatible = "mediatek,mt2701-disp-ovl",
+	  .data = &mt2701_ovl_driver_data},
 	{ .compatible = "mediatek,mt8173-disp-ovl",
 	  .data = &mt8173_ovl_driver_data},
 	{},
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
index fb0db50..506a353 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
@@ -225,11 +225,17 @@ static int mtk_disp_rdma_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct mtk_ddp_comp_driver_data mt2701_rdma_driver_data = {
+	.rdma_fifo_pseudo_size = SZ_4K,
+};
+
 static const struct mtk_ddp_comp_driver_data mt8173_rdma_driver_data = {
 	.rdma_fifo_pseudo_size = SZ_8K,
 };
 
 static const struct of_device_id mtk_disp_rdma_driver_dt_match[] = {
+	{ .compatible = "mediatek,mt2701-disp-rdma",
+	  .data = &mt2701_rdma_driver_data},
 	{ .compatible = "mediatek,mt8173-disp-rdma",
 	  .data = &mt8173_rdma_driver_data},
 	{},
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
index fa53806..ee0326a 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
@@ -32,6 +32,10 @@
 #define DISP_REG_CONFIG_DISP_RDMA1_MOUT_EN	0x0c8
 #define DISP_REG_CONFIG_MMSYS_CG_CON0		0x100
 
+#define DISP_REG_CONFIG_DISP_OVL_MOUT_EN	0x030
+#define DISP_REG_CONFIG_OUT_SEL			0x04c
+#define DISP_REG_CONFIG_DSI_SEL			0x050
+
 #define DISP_REG_MUTEX_EN(n)	(0x20 + 0x20 * (n))
 #define DISP_REG_MUTEX(n)	(0x24 + 0x20 * (n))
 #define DISP_REG_MUTEX_RST(n)	(0x28 + 0x20 * (n))
@@ -54,6 +58,13 @@
 #define MT8173_MUTEX_MOD_DISP_PWM1		BIT(24)
 #define MT8173_MUTEX_MOD_DISP_OD		BIT(25)
 
+#define MT2701_MUTEX_MOD_DISP_OVL		BIT(3)
+#define MT2701_MUTEX_MOD_DISP_WDMA		BIT(6)
+#define MT2701_MUTEX_MOD_DISP_COLOR		BIT(7)
+#define MT2701_MUTEX_MOD_DISP_BLS		BIT(9)
+#define MT2701_MUTEX_MOD_DISP_RDMA0		BIT(10)
+#define MT2701_MUTEX_MOD_DISP_RDMA1		BIT(12)
+
 #define MUTEX_SOF_SINGLE_MODE		0
 #define MUTEX_SOF_DSI0			1
 #define MUTEX_SOF_DSI1			2
@@ -69,6 +80,10 @@
 #define DPI0_SEL_IN_RDMA1		0x1
 #define COLOR1_SEL_IN_OVL1		0x1
 
+#define OVL_MOUT_EN_RDMA		0x1
+#define BLS_TO_DSI_RDMA1_TO_DPI1	0x8
+#define DSI_SEL_IN_BLS			0x0
+
 struct mtk_disp_mutex {
 	int id;
 	bool claimed;
@@ -82,6 +97,15 @@ struct mtk_ddp {
 	const unsigned int		*mutex_mod;
 };
 
+static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+	[DDP_COMPONENT_BLS] = MT2701_MUTEX_MOD_DISP_BLS,
+	[DDP_COMPONENT_COLOR0] = MT2701_MUTEX_MOD_DISP_COLOR,
+	[DDP_COMPONENT_OVL0] = MT2701_MUTEX_MOD_DISP_OVL,
+	[DDP_COMPONENT_RDMA0] = MT2701_MUTEX_MOD_DISP_RDMA0,
+	[DDP_COMPONENT_RDMA1] = MT2701_MUTEX_MOD_DISP_RDMA1,
+	[DDP_COMPONENT_WDMA0] = MT2701_MUTEX_MOD_DISP_WDMA,
+};
+
 static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = {
 	[DDP_COMPONENT_AAL] = MT8173_MUTEX_MOD_DISP_AAL,
 	[DDP_COMPONENT_COLOR0] = MT8173_MUTEX_MOD_DISP_COLOR0,
@@ -109,6 +133,9 @@ static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur,
 	if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_COLOR0) {
 		*addr = DISP_REG_CONFIG_DISP_OVL0_MOUT_EN;
 		value = OVL0_MOUT_EN_COLOR0;
+	} else if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_RDMA0) {
+		*addr = DISP_REG_CONFIG_DISP_OVL_MOUT_EN;
+		value = OVL_MOUT_EN_RDMA;
 	} else if (cur == DDP_COMPONENT_OD && next == DDP_COMPONENT_RDMA0) {
 		*addr = DISP_REG_CONFIG_DISP_OD_MOUT_EN;
 		value = OD_MOUT_EN_RDMA0;
@@ -146,6 +173,9 @@ static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur,
 	} else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) {
 		*addr = DISP_REG_CONFIG_DISP_COLOR1_SEL_IN;
 		value = COLOR1_SEL_IN_OVL1;
+	} else if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0) {
+		*addr = DISP_REG_CONFIG_DSI_SEL;
+		value = DSI_SEL_IN_BLS;
 	} else {
 		value = 0;
 	}
@@ -153,6 +183,14 @@ static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur,
 	return value;
 }
 
+static void mtk_ddp_sout_sel(void __iomem *config_regs,
+			    enum mtk_ddp_comp_id cur, enum mtk_ddp_comp_id next)
+{
+	if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0)
+		writel_relaxed(BLS_TO_DSI_RDMA1_TO_DPI1,
+			       config_regs + DISP_REG_CONFIG_OUT_SEL);
+}
+
 void mtk_ddp_add_comp_to_path(void __iomem *config_regs,
 			      enum mtk_ddp_comp_id cur,
 			      enum mtk_ddp_comp_id next)
@@ -165,6 +203,8 @@ void mtk_ddp_add_comp_to_path(void __iomem *config_regs,
 		writel_relaxed(reg, config_regs + addr);
 	}
 
+	mtk_ddp_sout_sel(config_regs, cur, next);
+
 	value = mtk_ddp_sel_in(cur, next, &addr);
 	if (value) {
 		reg = readl_relaxed(config_regs + addr) | value;
@@ -362,6 +402,7 @@ static int mtk_ddp_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id ddp_driver_dt_match[] = {
+	{ .compatible = "mediatek,mt2701-disp-mutex", .data = mt2701_mutex_mod},
 	{ .compatible = "mediatek,mt8173-disp-mutex", .data = mt8173_mutex_mod},
 	{},
 };
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
index 4b4e449..465819b 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
@@ -112,6 +112,7 @@ struct mtk_ddp_comp_match {
 
 static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
 	[DDP_COMPONENT_AAL]	= { MTK_DISP_AAL,	0, NULL },
+	[DDP_COMPONENT_BLS]	= { MTK_DISP_PWM,	0, NULL },
 	[DDP_COMPONENT_COLOR0]	= { MTK_DISP_COLOR,	0, &ddp_color },
 	[DDP_COMPONENT_COLOR1]	= { MTK_DISP_COLOR,	1, &ddp_color },
 	[DDP_COMPONENT_DPI0]	= { MTK_DPI,		0, NULL },
@@ -130,11 +131,17 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
 	[DDP_COMPONENT_WDMA1]	= { MTK_DISP_WDMA,	1, NULL },
 };
 
+static const struct mtk_ddp_comp_driver_data mt2701_color_driver_data = {
+	.color_offset = 0x0f00,
+};
+
 static const struct mtk_ddp_comp_driver_data mt8173_color_driver_data = {
 	.color_offset = 0x0c00,
 };
 
 static const struct of_device_id mtk_disp_color_driver_dt_match[] = {
+	{ .compatible = "mediatek,mt2701-disp-color",
+	  .data = &mt2701_color_driver_data},
 	{ .compatible = "mediatek,mt8173-disp-color",
 	  .data = &mt8173_color_driver_data},
 	{},
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
index 53065c7..0850aa4 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
@@ -40,6 +40,7 @@ enum mtk_ddp_comp_type {
 
 enum mtk_ddp_comp_id {
 	DDP_COMPONENT_AAL,
+	DDP_COMPONENT_BLS,
 	DDP_COMPONENT_COLOR0,
 	DDP_COMPONENT_COLOR1,
 	DDP_COMPONENT_DPI0,
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index 80b4f54..13cf160 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -109,6 +109,19 @@ static const struct drm_mode_config_funcs mtk_drm_mode_config_funcs = {
 	.atomic_commit = mtk_atomic_commit,
 };
 
+static const enum mtk_ddp_comp_id mt2701_mtk_ddp_main[] = {
+	DDP_COMPONENT_OVL0,
+	DDP_COMPONENT_RDMA0,
+	DDP_COMPONENT_COLOR0,
+	DDP_COMPONENT_BLS,
+	DDP_COMPONENT_DSI0,
+};
+
+static const enum mtk_ddp_comp_id mt2701_mtk_ddp_ext[] = {
+	DDP_COMPONENT_RDMA1,
+	DDP_COMPONENT_DPI0,
+};
+
 static const enum mtk_ddp_comp_id mt8173_mtk_ddp_main[] = {
 	DDP_COMPONENT_OVL0,
 	DDP_COMPONENT_COLOR0,
@@ -128,6 +141,14 @@ static const enum mtk_ddp_comp_id mt8173_mtk_ddp_ext[] = {
 	DDP_COMPONENT_DPI0,
 };
 
+static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = {
+	.main_path = mt2701_mtk_ddp_main,
+	.main_len = ARRAY_SIZE(mt2701_mtk_ddp_main),
+	.ext_path = mt2701_mtk_ddp_ext,
+	.ext_len = ARRAY_SIZE(mt2701_mtk_ddp_ext),
+	.shadow_register = true,
+};
+
 static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = {
 	.main_path = mt8173_mtk_ddp_main,
 	.main_len = ARRAY_SIZE(mt8173_mtk_ddp_main),
@@ -331,16 +352,24 @@ static const struct component_master_ops mtk_drm_ops = {
 };
 
 static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
+	{ .compatible = "mediatek,mt2701-disp-ovl",   .data = (void *)MTK_DISP_OVL },
 	{ .compatible = "mediatek,mt8173-disp-ovl",   .data = (void *)MTK_DISP_OVL },
+	{ .compatible = "mediatek,mt2701-disp-rdma",  .data = (void *)MTK_DISP_RDMA },
 	{ .compatible = "mediatek,mt8173-disp-rdma",  .data = (void *)MTK_DISP_RDMA },
+	{ .compatible = "mediatek,mt2701-disp-wdma",  .data = (void *)MTK_DISP_WDMA },
 	{ .compatible = "mediatek,mt8173-disp-wdma",  .data = (void *)MTK_DISP_WDMA },
+	{ .compatible = "mediatek,mt2701-disp-color", .data = (void *)MTK_DISP_COLOR },
 	{ .compatible = "mediatek,mt8173-disp-color", .data = (void *)MTK_DISP_COLOR },
 	{ .compatible = "mediatek,mt8173-disp-aal",   .data = (void *)MTK_DISP_AAL},
 	{ .compatible = "mediatek,mt8173-disp-gamma", .data = (void *)MTK_DISP_GAMMA, },
 	{ .compatible = "mediatek,mt8173-disp-ufoe",  .data = (void *)MTK_DISP_UFOE },
+	{ .compatible = "mediatek,mt2701-dsi",	      .data = (void *)MTK_DSI },
 	{ .compatible = "mediatek,mt8173-dsi",        .data = (void *)MTK_DSI },
+	{ .compatible = "mediatek,mt2701-dpi",	      .data = (void *)MTK_DPI },
 	{ .compatible = "mediatek,mt8173-dpi",        .data = (void *)MTK_DPI },
+	{ .compatible = "mediatek,mt2701-disp-mutex", .data = (void *)MTK_DISP_MUTEX },
 	{ .compatible = "mediatek,mt8173-disp-mutex", .data = (void *)MTK_DISP_MUTEX },
+	{ .compatible = "mediatek,mt2701-disp-pwm",   .data = (void *)MTK_DISP_PWM },
 	{ .compatible = "mediatek,mt8173-disp-pwm",   .data = (void *)MTK_DISP_PWM },
 	{ .compatible = "mediatek,mt8173-disp-od",    .data = (void *)MTK_DISP_OD },
 	{ }
@@ -514,6 +543,8 @@ static SIMPLE_DEV_PM_OPS(mtk_drm_pm_ops, mtk_drm_sys_suspend,
 			 mtk_drm_sys_resume);
 
 static const struct of_device_id mtk_drm_of_ids[] = {
+	{ .compatible = "mediatek,mt2701-mmsys",
+	  .data = &mt2701_mmsys_driver_data},
 	{ .compatible = "mediatek,mt8173-mmsys",
 	  .data = &mt8173_mmsys_driver_data},
 	{ }
-- 
1.7.9.5



From yt.shen at mediatek.com  Fri Jul 15 03:07:51 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Fri, 15 Jul 2016 18:07:51 +0800
Subject: [PATCH v4 5/8] drm/mediatek: add dsi interrupt control
In-Reply-To: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
Message-ID: <1468577274-6178-6-git-send-email-yt.shen@mediatek.com>

From: shaoming chen <shaoming.chen at mediatek.com>

add dsi interrupt control

Signed-off-by: shaoming chen <shaoming.chen at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_dsi.c |  130 ++++++++++++++++++++++++++++++++++++
 1 file changed, 130 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index 2d808e5..de5ad7f 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -18,6 +18,7 @@
 #include <drm/drm_panel.h>
 #include <linux/clk.h>
 #include <linux/component.h>
+#include <linux/irq.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/of_graph.h>
@@ -32,6 +33,13 @@
 
 #define DSI_START		0x00
 
+#define DSI_INTEN		0x08
+
+#define DSI_INTSTA		0x0c
+#define LPRX_RD_RDY_INT_FLAG	BIT(0)
+#define CMD_DONE_INT_FLAG	BIT(1)
+#define DSI_BUSY		BIT(31)
+
 #define DSI_CON_CTRL		0x10
 #define DSI_RESET			BIT(0)
 #define DSI_EN				BIT(1)
@@ -74,6 +82,9 @@
 
 #define DSI_HSTX_CKL_WC		0x64
 
+#define DSI_RACK		0x84
+#define RACK			BIT(0)
+
 #define DSI_PHY_LCCON		0x104
 #define LC_HS_TX_EN			BIT(0)
 #define LC_ULPM_EN			BIT(1)
@@ -134,6 +145,18 @@ struct mtk_dsi {
 	struct videomode vm;
 	int refcount;
 	bool enabled;
+	int irq_num, irq_data;
+};
+
+enum {
+	DSI_INT_SLEEPOUT_DONE_FLAG	= BIT(6),
+	DSI_INT_VM_CMD_DONE_FLAG	= BIT(5),
+	DSI_INT_EXT_TE_RDY_FLAG		= BIT(4),
+	DSI_INT_VM_DONE_FLAG		= BIT(3),
+	DSI_INT_TE_RDY_FLAG		= BIT(2),
+	DSI_INT_CMD_DONE_FLAG		= BIT(1),
+	DSI_INT_LPRX_RD_RDY_FLAG	= BIT(0),
+	DSI_INT_ALL_BITS		= (0x7f)
 };
 
 static inline struct mtk_dsi *encoder_to_dsi(struct drm_encoder *e)
@@ -440,6 +463,94 @@ static void mtk_dsi_start(struct mtk_dsi *dsi)
 	writel(1, dsi->regs + DSI_START);
 }
 
+static void mtk_dsi_set_interrupt_enable(struct mtk_dsi *dsi)
+{
+	u32 inten = DSI_INT_ALL_BITS;
+
+	if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO)
+		inten &= ~(DSI_INT_TE_RDY_FLAG | DSI_INT_EXT_TE_RDY_FLAG);
+
+	writel(inten, dsi->regs + DSI_INTEN);
+}
+
+static void mtk_dsi_irq_wakeup(struct mtk_dsi *dsi, u32 irq_bit)
+{
+	dsi->irq_data |= irq_bit;
+}
+
+static irqreturn_t mtk_dsi_irq(int irq, void *dev_id)
+{
+	struct mtk_dsi *dsi = dev_id;
+
+	u32 status, tmp;
+
+	status = readl(dsi->regs + DSI_INTSTA);
+
+	if (status & DSI_INT_LPRX_RD_RDY_FLAG) {
+		/* write clear RD_RDY interrupt */
+		/* write clear RD_RDY interrupt must be before DSI_RACK */
+		/* because CMD_DONE will raise after DSI_RACK, */
+		/* so write clear RD_RDY after that will clear CMD_DONE too */
+		do {
+			/* send read ACK */
+			mtk_dsi_mask(dsi, DSI_RACK, RACK, RACK);
+			tmp = readl(dsi->regs + DSI_INTSTA);
+		} while (tmp & DSI_BUSY);
+
+		mtk_dsi_mask(dsi, DSI_INTSTA, DSI_INT_LPRX_RD_RDY_FLAG, 0);
+		mtk_dsi_irq_wakeup(dsi, DSI_INT_LPRX_RD_RDY_FLAG);
+	}
+
+	if (status & DSI_INT_CMD_DONE_FLAG) {
+		mtk_dsi_mask(dsi, DSI_INTSTA, DSI_INT_CMD_DONE_FLAG, 0);
+		mtk_dsi_irq_wakeup(dsi, DSI_INT_CMD_DONE_FLAG);
+	}
+
+	if (status & DSI_INT_TE_RDY_FLAG) {
+		mtk_dsi_mask(dsi, DSI_INTSTA, DSI_INT_TE_RDY_FLAG, 0);
+		mtk_dsi_irq_wakeup(dsi, DSI_INT_TE_RDY_FLAG);
+	}
+
+	if (status & DSI_INT_VM_DONE_FLAG) {
+		mtk_dsi_mask(dsi, DSI_INTSTA, DSI_INT_VM_DONE_FLAG, 0);
+		mtk_dsi_irq_wakeup(dsi, DSI_INT_VM_DONE_FLAG);
+	}
+
+	if (status & DSI_INT_EXT_TE_RDY_FLAG) {
+		mtk_dsi_mask(dsi, DSI_INTSTA, DSI_INT_EXT_TE_RDY_FLAG, 0);
+		mtk_dsi_irq_wakeup(dsi, DSI_INT_EXT_TE_RDY_FLAG);
+	}
+
+	if (status & DSI_INT_VM_CMD_DONE_FLAG) {
+		mtk_dsi_mask(dsi, DSI_INTSTA, DSI_INT_VM_CMD_DONE_FLAG, 0);
+		mtk_dsi_irq_wakeup(dsi, DSI_INT_VM_CMD_DONE_FLAG);
+	}
+
+	if (status & DSI_INT_SLEEPOUT_DONE_FLAG) {
+		mtk_dsi_mask(dsi, DSI_INTSTA, DSI_INT_SLEEPOUT_DONE_FLAG, 0);
+		mtk_dsi_irq_wakeup(dsi, DSI_INT_SLEEPOUT_DONE_FLAG);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static s32 mtk_dsi_wait_for_irq_timeout(struct mtk_dsi *dsi, u32 irq_bit,
+					u32 timeout_ms)
+{
+	while (timeout_ms--) {
+		if (dsi->irq_data & irq_bit) {
+			dsi->irq_data &= ~irq_bit;
+			return 0;
+		}
+
+		usleep_range(1000, 1100);
+	}
+
+	dsi->irq_data = 0;
+
+	return -1;
+}
+
 static void mtk_dsi_poweroff(struct mtk_dsi *dsi)
 {
 	if (WARN_ON(dsi->refcount == 0))
@@ -488,6 +599,7 @@ static void mtk_output_dsi_enable(struct mtk_dsi *dsi)
 
 	dsi_ps_control_vact(dsi);
 	dsi_config_vdo_timing(dsi);
+	mtk_dsi_set_interrupt_enable(dsi);
 
 	dsi_set_mode(dsi);
 	dsi_clk_hs_mode(dsi, 1);
@@ -883,6 +995,24 @@ static int mtk_dsi_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	dsi->irq_num = platform_get_irq(pdev, 0);
+	if (dsi->irq_num < 0) {
+		dev_err(&pdev->dev, "failed to request dsi irq resource\n");
+		ret = dsi->irq_num;
+		return -EPROBE_DEFER;
+	}
+
+	irq_set_status_flags(dsi->irq_num, IRQ_TYPE_LEVEL_LOW);
+	ret = devm_request_irq(&pdev->dev, dsi->irq_num, mtk_dsi_irq,
+			       IRQF_TRIGGER_LOW, dev_name(&pdev->dev), dsi);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to request mediatek dsi irq\n");
+		return -EPROBE_DEFER;
+	}
+
+	dsi->irq_data = 0;
+	dev_info(dev, "dsi irq num is 0x%x\n", dsi->irq_num);
+
 	platform_set_drvdata(pdev, dsi);
 
 	return component_add(&pdev->dev, &mtk_dsi_component_ops);
-- 
1.7.9.5



From yt.shen at mediatek.com  Fri Jul 15 03:07:52 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Fri, 15 Jul 2016 18:07:52 +0800
Subject: [PATCH v4 6/8] drm/mediatek: add dsi transfer function
In-Reply-To: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
Message-ID: <1468577274-6178-7-git-send-email-yt.shen@mediatek.com>

From: shaoming chen <shaoming.chen at mediatek.com>

add dsi read/write commands for transfer function

Signed-off-by: shaoming chen <shaoming.chen at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_dsi.c |  322 ++++++++++++++++++++++++++++++++++++
 1 file changed, 322 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index de5ad7f..1f99894 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -24,6 +24,7 @@
 #include <linux/of_graph.h>
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
+#include <video/mipi_display.h>
 #include <video/videomode.h>
 
 #include "mtk_drm_ddp_comp.h"
@@ -80,8 +81,16 @@
 #define DSI_HBP_WC		0x54
 #define DSI_HFP_WC		0x58
 
+#define DSI_CMDQ_SIZE		0x60
+#define CMDQ_SIZE		0x3f
+
 #define DSI_HSTX_CKL_WC		0x64
 
+#define DSI_RX_DATA0		0x74
+#define DSI_RX_DATA1		0x78
+#define DSI_RX_DATA2		0x7c
+#define DSI_RX_DATA3		0x80
+
 #define DSI_RACK		0x84
 #define RACK			BIT(0)
 
@@ -117,8 +126,25 @@
 #define CLK_HS_POST			(0xff << 8)
 #define CLK_HS_EXIT			(0xff << 16)
 
+#define DSI_CMDQ0		0x180
+
 #define NS_TO_CYCLE(n, c)    ((n) / (c) + (((n) % (c)) ? 1 : 0))
 
+#define MTK_DSI_HOST_IS_READ(type) \
+	((type == MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM) || \
+	(type == MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM) || \
+	(type == MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM) || \
+	(type == MIPI_DSI_DCS_READ))
+
+#define MTK_DSI_HOST_IS_WRITE(type) \
+	((type == MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM) || \
+	(type == MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM) || \
+	(type == MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM) || \
+	(type == MIPI_DSI_DCS_SHORT_WRITE) || \
+	(type == MIPI_DSI_DCS_SHORT_WRITE_PARAM) || \
+	(type == MIPI_DSI_GENERIC_LONG_WRITE) || \
+	(type == MIPI_DSI_DCS_LONG_WRITE))
+
 struct phy;
 
 struct mtk_dsi {
@@ -148,6 +174,38 @@ struct mtk_dsi {
 	int irq_num, irq_data;
 };
 
+struct dsi_cmd_t0 {
+	u8 config;
+	u8 type;
+	u8 data0;
+	u8 data1;
+};
+
+struct dsi_cmd_t2 {
+	u8 config;
+	u8 type;
+	u16 wc16;
+	u8 *pdata;
+};
+
+struct dsi_rx_data {
+	u8 byte0;
+	u8 byte1;
+	u8 byte2;
+	u8 byte3;
+};
+
+struct dsi_tx_cmdq {
+	u8 byte0;
+	u8 byte1;
+	u8 byte2;
+	u8 byte3;
+};
+
+struct dsi_tx_cmdq_regs {
+	struct dsi_tx_cmdq data[128];
+};
+
 enum {
 	DSI_INT_SLEEPOUT_DONE_FLAG	= BIT(6),
 	DSI_INT_VM_CMD_DONE_FLAG	= BIT(5),
@@ -858,9 +916,273 @@ static int mtk_dsi_host_detach(struct mipi_dsi_host *host,
 	return 0;
 }
 
+static void mtk_dsi_set_cmdq(void __iomem *reg, u32 mask, u32 data)
+{
+	u32 temp = readl(reg);
+
+	writel((temp & ~mask) | (data & mask), reg);
+}
+
+static void mtk_dsi_wait_for_idle(struct mtk_dsi *dsi)
+{
+	u32 timeout_ms = 500000; /* total 1s ~ 2s timeout */
+
+	while (timeout_ms--) {
+		if (!(readl(dsi->regs + DSI_INTSTA) & DSI_BUSY))
+			break;
+
+		usleep_range(2, 4);
+	}
+
+	if (timeout_ms == 0) {
+		dev_info(dsi->dev, "polling dsi wait not busy timeout!\n");
+
+		mtk_dsi_enable(dsi);
+		mtk_dsi_reset_engine(dsi);
+	}
+}
+
+static ssize_t mtk_dsi_host_read_cmd(struct mtk_dsi *dsi,
+				     const struct mipi_dsi_msg *msg)
+{
+	u8 max_try_count = 5;
+	u32 recv_data_cnt, tmp_val;
+	u32 recv_data0, recv_data1, recv_data2, recv_data3;
+	struct dsi_rx_data read_data0, read_data1, read_data2, read_data3;
+	struct dsi_cmd_t0 t0;
+	s32 ret;
+
+	u8 *buffer = msg->rx_buf;
+	u8 buffer_size = msg->rx_len;
+	u8 packet_type;
+
+	if (readl(dsi->regs + DSI_MODE_CTRL) & 0x03) {
+		dev_info(dsi->dev, "dsi engine is not command mode\n");
+		return -1;
+	}
+
+	if (!buffer) {
+		dev_info(dsi->dev, "dsi receive buffer size may be NULL\n");
+		return -1;
+	}
+
+	do {
+		if (max_try_count == 0) {
+			dev_info(dsi->dev, "dsi engine read counter has been maxinum\n");
+			return -1;
+		}
+
+		max_try_count--;
+		recv_data_cnt = 0;
+
+		mtk_dsi_wait_for_idle(dsi);
+
+		t0.config = 0x04;
+		t0.data0 = *((u8 *)(msg->tx_buf));
+
+		if (buffer_size < 0x3)
+			t0.type = MIPI_DSI_DCS_READ;
+		else
+			t0.type = MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM;
+
+		t0.data1 = 0;
+
+		tmp_val = (t0.data1 << 24) | (t0.data0 << 16) | (t0.type << 8) |
+			t0.config;
+
+		writel(tmp_val, dsi->regs + DSI_CMDQ0);
+		mtk_dsi_mask(dsi, DSI_CMDQ_SIZE, CMDQ_SIZE, 1);
+
+		mtk_dsi_mask(dsi, DSI_RACK, RACK, RACK);
+		mtk_dsi_mask(dsi, DSI_INTSTA, LPRX_RD_RDY_INT_FLAG,
+			     ~LPRX_RD_RDY_INT_FLAG);
+		mtk_dsi_mask(dsi, DSI_INTSTA, CMD_DONE_INT_FLAG,
+			     ~CMD_DONE_INT_FLAG);
+		mtk_dsi_mask(dsi, DSI_INTEN, DSI_INT_LPRX_RD_RDY_FLAG,
+			     DSI_INT_LPRX_RD_RDY_FLAG);
+		mtk_dsi_mask(dsi, DSI_INTEN, DSI_INT_CMD_DONE_FLAG,
+			     DSI_INT_CMD_DONE_FLAG);
+
+		mtk_dsi_start(dsi);
+
+		dev_info(dsi->dev, "Start polling DSI read ready!!!\n");
+
+		 /* 2s timeout*/
+		ret = mtk_dsi_wait_for_irq_timeout(dsi,
+						   DSI_INT_LPRX_RD_RDY_FLAG,
+						   2000);
+		if (ret) {
+			dev_info(dsi->dev, "Polling DSI read ready timeout!!!\n");
+
+			mtk_dsi_enable(dsi);
+			mtk_dsi_reset_engine(dsi);
+
+			return ret;
+		}
+
+		dev_info(dsi->dev, "End polling DSI read ready!!!\n");
+
+		mtk_dsi_mask(dsi, DSI_RACK, RACK, RACK);
+		mtk_dsi_mask(dsi, DSI_INTSTA, LPRX_RD_RDY_INT_FLAG,
+			     ~LPRX_RD_RDY_INT_FLAG);
+
+		recv_data0 = readl(dsi->regs + DSI_RX_DATA0);
+		recv_data1 = readl(dsi->regs + DSI_RX_DATA1);
+		recv_data2 = readl(dsi->regs + DSI_RX_DATA2);
+		recv_data3 = readl(dsi->regs + DSI_RX_DATA3);
+
+		read_data0 = *((struct dsi_rx_data *)(&recv_data0));
+		read_data1 = *((struct dsi_rx_data *)(&recv_data1));
+		read_data2 = *((struct dsi_rx_data *)(&recv_data2));
+		read_data3 = *((struct dsi_rx_data *)(&recv_data3));
+
+		ret = readl(dsi->regs + DSI_CMDQ_SIZE);
+		dev_info(dsi->dev, "DSI_CMDQ_SIZE : 0x%x\n", ret & CMDQ_SIZE);
+
+		ret = readl(dsi->regs + DSI_CMDQ0);
+		dev_info(dsi->dev, "DSI_CMDQ_DATA0 : 0x%x\n",
+			 ret & 0xff);
+		dev_info(dsi->dev, "DSI_CMDQ_DATA1 : 0x%x\n",
+			 (ret >> 8) & 0xff);
+		dev_info(dsi->dev, "DSI_CMDQ_DATA2 : 0x%x\n",
+			 (ret >> 16) & 0xff);
+		dev_info(dsi->dev, "DSI_CMDQ_DATA3 : 0x%x\n",
+			 (ret >> 24) & 0xff);
+
+		dev_info(dsi->dev, "DSI_RX_DATA0: 0x%x\n", recv_data0);
+		dev_info(dsi->dev, "DSI_RX_DATA1: 0x%x\n", recv_data1);
+		dev_info(dsi->dev, "DSI_RX_DATA2: 0x%x\n", recv_data2);
+		dev_info(dsi->dev, "DSI_RX_DATA3: 0x%x\n", recv_data3);
+
+		dev_info(dsi->dev, "read_data0: %x,%x,%x,%x\n",
+			 read_data0.byte0, read_data0.byte1, read_data0.byte2,
+			 read_data0.byte3);
+		dev_info(dsi->dev, "read_data1: %x,%x,%x,%x\n",
+			 read_data1.byte0, read_data1.byte1, read_data1.byte2,
+			 read_data1.byte3);
+		dev_info(dsi->dev, "read_data2: %x,%x,%x,%x\n",
+			 read_data2.byte0, read_data2.byte1, read_data2.byte2,
+			 read_data2.byte3);
+		dev_info(dsi->dev, "read_data3: %x,%x,%x,%x\n",
+			 read_data3.byte0, read_data3.byte1, read_data3.byte2,
+			 read_data3.byte3);
+
+		packet_type = read_data0.byte0;
+		dev_info(dsi->dev, "DSI read packet_type is 0x%x\n",
+			 packet_type);
+
+		if (packet_type == 0x1a || packet_type == 0x1c) {
+			void *read_tmp = (void *)&recv_data1;
+
+			recv_data_cnt = read_data0.byte1 +
+					read_data0.byte2 * 16;
+			if (recv_data_cnt > 10)
+				recv_data_cnt = 10;
+
+			if (recv_data_cnt > buffer_size)
+				recv_data_cnt = buffer_size;
+
+			memcpy(buffer, read_tmp, recv_data_cnt);
+		} else {
+			/* short  packet */
+			recv_data_cnt = 2;
+			if (recv_data_cnt > buffer_size)
+				recv_data_cnt = buffer_size;
+
+			memcpy(buffer, &read_data0.byte1, 2);
+		}
+	} while (packet_type != 0x1c && packet_type != 0x21 &&
+		packet_type != 0x22 && packet_type != 0x1a);
+
+	dev_info(dsi->dev, "dsi get %d byte data from the panel address(0x%x)\n",
+		 recv_data_cnt, *((u8 *)(msg->tx_buf)));
+
+	return recv_data_cnt;
+}
+
+static ssize_t mtk_dsi_host_write_cmd(struct mtk_dsi *dsi,
+				      const struct mipi_dsi_msg *msg)
+{
+	u32 i;
+	u32 goto_addr, mask_para, set_para, reg_val;
+	void __iomem *cmdq_reg;
+	struct dsi_cmd_t0 t0;
+	struct dsi_cmd_t2 t2;
+	const char *tx_buf = msg->tx_buf;
+	struct dsi_tx_cmdq_regs *dsi_cmd_reg;
+
+	dsi_cmd_reg = (struct dsi_tx_cmdq_regs *)(dsi->regs + DSI_CMDQ0);
+
+	mtk_dsi_wait_for_idle(dsi);
+
+	if (msg->tx_len > 2) {
+		t2.config = 2;
+		t2.type = msg->type;
+		t2.wc16 = msg->tx_len;
+
+		reg_val = (t2.wc16 << 16) | (t2.type << 8) | t2.config;
+
+		writel(reg_val, &dsi_cmd_reg->data[0]);
+
+		goto_addr = (u32)(&dsi_cmd_reg->data[1].byte0);
+		mask_para = (0xff << ((goto_addr & 0x3) * 8));
+		set_para = (tx_buf[0] << ((goto_addr & 0x3) * 8));
+		cmdq_reg = (void __iomem *)(goto_addr & (~0x3));
+		mtk_dsi_set_cmdq(cmdq_reg, mask_para, set_para);
+
+		for (i = 1; i < msg->tx_len; i++) {
+			goto_addr = (u32)(&dsi_cmd_reg->data[1].byte1) + i - 1;
+			mask_para = (0xff << ((goto_addr & 0x3) * 8));
+			set_para = (tx_buf[i] << ((goto_addr & 0x3) * 8));
+			cmdq_reg = (void __iomem *)(goto_addr & (~0x3));
+			mtk_dsi_set_cmdq(cmdq_reg, mask_para, set_para);
+		}
+
+		mtk_dsi_mask(dsi, DSI_CMDQ_SIZE, CMDQ_SIZE,
+			     2 + (msg->tx_len - 1) / 4);
+	} else {
+		t0.config = 0;
+		t0.data0 = tx_buf[0];
+		if (msg->tx_len == 2) {
+			t0.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM;
+			t0.data1 = tx_buf[1];
+		} else {
+			t0.type = MIPI_DSI_DCS_SHORT_WRITE;
+			t0.data1 = 0;
+		}
+
+		reg_val = (t0.data1 << 24) | (t0.data0 << 16) | (t0.type << 8) |
+			   t0.config;
+
+		writel(reg_val, &dsi_cmd_reg->data[0]);
+		mtk_dsi_mask(dsi, DSI_CMDQ_SIZE, CMDQ_SIZE, 1);
+	}
+
+	mtk_dsi_start(dsi);
+	mtk_dsi_wait_for_idle(dsi);
+
+	return 0;
+}
+
+static ssize_t mtk_dsi_host_transfer(struct mipi_dsi_host *host,
+				     const struct mipi_dsi_msg *msg)
+{
+	struct mtk_dsi *dsi = host_to_dsi(host);
+	u8 type = msg->type;
+	ssize_t ret = 0;
+
+	if (MTK_DSI_HOST_IS_READ(type))
+		ret = mtk_dsi_host_read_cmd(dsi, msg);
+	else if (MTK_DSI_HOST_IS_WRITE(type))
+		ret = mtk_dsi_host_write_cmd(dsi, msg);
+
+	return ret;
+}
+
 static const struct mipi_dsi_host_ops mtk_dsi_ops = {
 	.attach = mtk_dsi_host_attach,
 	.detach = mtk_dsi_host_detach,
+	.transfer = mtk_dsi_host_transfer,
 };
 
 static int mtk_dsi_bind(struct device *dev, struct device *master, void *data)
-- 
1.7.9.5



From yt.shen at mediatek.com  Fri Jul 15 03:07:53 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Fri, 15 Jul 2016 18:07:53 +0800
Subject: [PATCH v4 7/8] drm/mediatek: add mipi panel support
In-Reply-To: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
Message-ID: <1468577274-6178-8-git-send-email-yt.shen@mediatek.com>

From: shaoming chen <shaoming.chen at mediatek.com>

add dsi and mipi tx driver for mipi panel support

Signed-off-by: shaoming chen <shaoming.chen at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_dsi.c     |  169 ++++++++++++++++++++++----------
 drivers/gpu/drm/mediatek/mtk_mipi_tx.c |   82 +++++++++++-----
 2 files changed, 173 insertions(+), 78 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index 1f99894..4eae63c 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -29,9 +29,6 @@
 
 #include "mtk_drm_ddp_comp.h"
 
-#define DSI_VIDEO_FIFO_DEPTH	(1920 / 4)
-#define DSI_HOST_FIFO_DEPTH	64
-
 #define DSI_START		0x00
 
 #define DSI_INTEN		0x08
@@ -55,7 +52,7 @@
 #define MIX_MODE			BIT(17)
 
 #define DSI_TXRX_CTRL		0x18
-#define VC_NUM				(2 << 0)
+#define VC_NUM				BIT(1)
 #define LANE_NUM			(0xf << 2)
 #define DIS_EOT				BIT(6)
 #define NULL_EN				BIT(7)
@@ -94,6 +91,8 @@
 #define DSI_RACK		0x84
 #define RACK			BIT(0)
 
+#define DSI_MEM_CONTI		0x90
+
 #define DSI_PHY_LCCON		0x104
 #define LC_HS_TX_EN			BIT(0)
 #define LC_ULPM_EN			BIT(1)
@@ -126,6 +125,10 @@
 #define CLK_HS_POST			(0xff << 8)
 #define CLK_HS_EXIT			(0xff << 16)
 
+#define DSI_VM_CMD_CON		0x130
+#define VM_CMD_EN		BIT(0)
+#define TS_VFP_EN		BIT(5)
+
 #define DSI_CMDQ0		0x180
 
 #define NS_TO_CYCLE(n, c)    ((n) / (c) + (((n) % (c)) ? 1 : 0))
@@ -239,11 +242,11 @@ static void mtk_dsi_mask(struct mtk_dsi *dsi, u32 offset, u32 mask, u32 data)
 	writel((temp & ~mask) | (data & mask), dsi->regs + offset);
 }
 
-static void dsi_phy_timconfig(struct mtk_dsi *dsi)
+static void mtk_dsi_phy_timconfig(struct mtk_dsi *dsi)
 {
 	u32 timcon0, timcon1, timcon2, timcon3;
-	unsigned int ui, cycle_time;
-	unsigned int lpx;
+	u32 ui, cycle_time;
+	u32 lpx;
 
 	ui = 1000 / dsi->data_rate + 0x01;
 	cycle_time = 8000 / dsi->data_rate + 0x01;
@@ -273,7 +276,7 @@ static void mtk_dsi_disable(struct mtk_dsi *dsi)
 	mtk_dsi_mask(dsi, DSI_CON_CTRL, DSI_EN, 0);
 }
 
-static void mtk_dsi_reset(struct mtk_dsi *dsi)
+static void mtk_dsi_reset_engine(struct mtk_dsi *dsi)
 {
 	mtk_dsi_mask(dsi, DSI_CON_CTRL, DSI_RESET, DSI_RESET);
 	mtk_dsi_mask(dsi, DSI_CON_CTRL, DSI_RESET, 0);
@@ -293,7 +296,9 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi)
 	 * mipi_ratio is mipi clk coefficient for balance the pixel clk in mipi.
 	 * we set mipi_ratio is 1.05.
 	 */
-	dsi->data_rate = dsi->vm.pixelclock * 3 * 21 / (1 * 1000 * 10);
+	dsi->data_rate = dsi->vm.pixelclock * 12 * 21;
+	dsi->data_rate /= (dsi->lanes * 1000 * 10);
+	dev_info(dev, "set mipitx's data rate: %dMHz\n", dsi->data_rate);
 
 	ret = clk_set_rate(dsi->hs_clk, dsi->data_rate * 1000000);
 	if (ret < 0) {
@@ -315,10 +320,6 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi)
 		goto err_disable_engine_clk;
 	}
 
-	mtk_dsi_enable(dsi);
-	mtk_dsi_reset(dsi);
-	dsi_phy_timconfig(dsi);
-
 	return 0;
 
 err_disable_engine_clk:
@@ -330,33 +331,33 @@ err_refcount:
 	return ret;
 }
 
-static void dsi_clk_ulp_mode_enter(struct mtk_dsi *dsi)
+static void mtk_dsi_clk_ulp_mode_enter(struct mtk_dsi *dsi)
 {
 	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, 0);
-	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_ULPM_EN, 0);
+	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_ULPM_EN, LC_ULPM_EN);
 }
 
-static void dsi_clk_ulp_mode_leave(struct mtk_dsi *dsi)
+static void mtk_dsi_clk_ulp_mode_leave(struct mtk_dsi *dsi)
 {
 	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_ULPM_EN, 0);
 	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_WAKEUP_EN, LC_WAKEUP_EN);
 	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_WAKEUP_EN, 0);
 }
 
-static void dsi_lane0_ulp_mode_enter(struct mtk_dsi *dsi)
+static void mtk_dsi_lane0_ulp_mode_enter(struct mtk_dsi *dsi)
 {
 	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_HS_TX_EN, 0);
-	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_ULPM_EN, 0);
+	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_ULPM_EN, LD0_ULPM_EN);
 }
 
-static void dsi_lane0_ulp_mode_leave(struct mtk_dsi *dsi)
+static void mtk_dsi_lane0_ulp_mode_leave(struct mtk_dsi *dsi)
 {
 	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_ULPM_EN, 0);
 	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_WAKEUP_EN, LD0_WAKEUP_EN);
 	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_WAKEUP_EN, 0);
 }
 
-static bool dsi_clk_hs_state(struct mtk_dsi *dsi)
+static bool mtk_dsi_clk_hs_state(struct mtk_dsi *dsi)
 {
 	u32 tmp_reg1;
 
@@ -364,15 +365,15 @@ static bool dsi_clk_hs_state(struct mtk_dsi *dsi)
 	return ((tmp_reg1 & LC_HS_TX_EN) == 1) ? true : false;
 }
 
-static void dsi_clk_hs_mode(struct mtk_dsi *dsi, bool enter)
+static void mtk_dsi_clk_hs_mode(struct mtk_dsi *dsi, bool enter)
 {
-	if (enter && !dsi_clk_hs_state(dsi))
+	if (enter && !mtk_dsi_clk_hs_state(dsi))
 		mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, LC_HS_TX_EN);
-	else if (!enter && dsi_clk_hs_state(dsi))
+	else if (!enter && mtk_dsi_clk_hs_state(dsi))
 		mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, 0);
 }
 
-static void dsi_set_mode(struct mtk_dsi *dsi)
+static void mtk_dsi_set_mode(struct mtk_dsi *dsi)
 {
 	u32 vid_mode = CMD_MODE;
 
@@ -382,12 +383,22 @@ static void dsi_set_mode(struct mtk_dsi *dsi)
 		if ((dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) &&
 		    !(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE))
 			vid_mode = BURST_MODE;
+		else
+			vid_mode = SYNC_EVENT_MODE;
 	}
 
 	writel(vid_mode, dsi->regs + DSI_MODE_CTRL);
 }
 
-static void dsi_ps_control_vact(struct mtk_dsi *dsi)
+static void mtk_dsi_set_vm_cmd(struct mtk_dsi *dsi)
+{
+	writel(0x3c, dsi->regs + DSI_MEM_CONTI);
+
+	mtk_dsi_mask(dsi, DSI_VM_CMD_CON, VM_CMD_EN, VM_CMD_EN);
+	mtk_dsi_mask(dsi, DSI_VM_CMD_CON, TS_VFP_EN, TS_VFP_EN);
+}
+
+static void mtk_dsi_ps_control_vact(struct mtk_dsi *dsi)
 {
 	struct videomode *vm = &dsi->vm;
 	u32 dsi_buf_bpp, ps_wc;
@@ -421,7 +432,7 @@ static void dsi_ps_control_vact(struct mtk_dsi *dsi)
 	writel(ps_wc, dsi->regs + DSI_HSTX_CKL_WC);
 }
 
-static void dsi_rxtx_control(struct mtk_dsi *dsi)
+static void mtk_dsi_rxtx_control(struct mtk_dsi *dsi)
 {
 	u32 tmp_reg;
 
@@ -443,12 +454,15 @@ static void dsi_rxtx_control(struct mtk_dsi *dsi)
 		break;
 	}
 
+	tmp_reg |= (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) << 6;
+	tmp_reg |= (dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET) >> 3;
+
 	writel(tmp_reg, dsi->regs + DSI_TXRX_CTRL);
 }
 
-static void dsi_ps_control(struct mtk_dsi *dsi)
+static void mtk_dsi_ps_control(struct mtk_dsi *dsi)
 {
-	unsigned int dsi_tmp_buf_bpp;
+	u32 dsi_tmp_buf_bpp;
 	u32 tmp_reg;
 
 	switch (dsi->format) {
@@ -478,12 +492,12 @@ static void dsi_ps_control(struct mtk_dsi *dsi)
 	writel(tmp_reg, dsi->regs + DSI_PSCTRL);
 }
 
-static void dsi_config_vdo_timing(struct mtk_dsi *dsi)
+static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi)
 {
-	unsigned int horizontal_sync_active_byte;
-	unsigned int horizontal_backporch_byte;
-	unsigned int horizontal_frontporch_byte;
-	unsigned int dsi_tmp_buf_bpp;
+	u32 horizontal_sync_active_byte;
+	u32 horizontal_backporch_byte;
+	u32 horizontal_frontporch_byte;
+	u32 dsi_tmp_buf_bpp;
 
 	struct videomode *vm = &dsi->vm;
 
@@ -512,7 +526,7 @@ static void dsi_config_vdo_timing(struct mtk_dsi *dsi)
 	writel(horizontal_backporch_byte, dsi->regs + DSI_HBP_WC);
 	writel(horizontal_frontporch_byte, dsi->regs + DSI_HFP_WC);
 
-	dsi_ps_control(dsi);
+	mtk_dsi_ps_control(dsi);
 }
 
 static void mtk_dsi_start(struct mtk_dsi *dsi)
@@ -521,6 +535,19 @@ static void mtk_dsi_start(struct mtk_dsi *dsi)
 	writel(1, dsi->regs + DSI_START);
 }
 
+static void mtk_dsi_stop(struct mtk_dsi *dsi)
+{
+	writel(0, dsi->regs + DSI_START);
+}
+
+static void mtk_dsi_set_cmd_mode(struct mtk_dsi *dsi)
+{
+	u32 tmp_reg1;
+
+	tmp_reg1 = CMD_MODE;
+	writel(tmp_reg1, dsi->regs + DSI_MODE_CTRL);
+}
+
 static void mtk_dsi_set_interrupt_enable(struct mtk_dsi *dsi)
 {
 	u32 inten = DSI_INT_ALL_BITS;
@@ -609,6 +636,21 @@ static s32 mtk_dsi_wait_for_irq_timeout(struct mtk_dsi *dsi, u32 irq_bit,
 	return -1;
 }
 
+static void mtk_dsi_switch_to_cmd_mode(struct mtk_dsi *dsi)
+{
+	s32 ret = 0;
+
+	mtk_dsi_set_cmd_mode(dsi);
+
+	ret = mtk_dsi_wait_for_irq_timeout(dsi, DSI_INT_VM_DONE_FLAG, 500);
+	if (ret != 0) {
+		dev_info(dsi->dev, "dsi wait engine idle timeout\n");
+
+		mtk_dsi_enable(dsi);
+		mtk_dsi_reset_engine(dsi);
+	}
+}
+
 static void mtk_dsi_poweroff(struct mtk_dsi *dsi)
 {
 	if (WARN_ON(dsi->refcount == 0))
@@ -617,8 +659,19 @@ static void mtk_dsi_poweroff(struct mtk_dsi *dsi)
 	if (--dsi->refcount != 0)
 		return;
 
-	dsi_lane0_ulp_mode_enter(dsi);
-	dsi_clk_ulp_mode_enter(dsi);
+	mtk_dsi_switch_to_cmd_mode(dsi);
+
+	if (dsi->panel) {
+		if (drm_panel_unprepare(dsi->panel)) {
+			DRM_ERROR("failed to unprepare the panel\n");
+			return;
+		}
+	}
+
+	mtk_dsi_reset_engine(dsi);
+
+	mtk_dsi_lane0_ulp_mode_enter(dsi);
+	mtk_dsi_clk_ulp_mode_enter(dsi);
 
 	mtk_dsi_disable(dsi);
 
@@ -635,32 +688,40 @@ static void mtk_output_dsi_enable(struct mtk_dsi *dsi)
 	if (dsi->enabled)
 		return;
 
-	if (dsi->panel) {
-		if (drm_panel_prepare(dsi->panel)) {
-			DRM_ERROR("failed to setup the panel\n");
-			return;
-		}
-	}
-
 	ret = mtk_dsi_poweron(dsi);
 	if (ret < 0) {
 		DRM_ERROR("failed to power on dsi\n");
 		return;
 	}
 
-	dsi_rxtx_control(dsi);
+	usleep_range(20000, 21000);
 
-	dsi_clk_ulp_mode_leave(dsi);
-	dsi_lane0_ulp_mode_leave(dsi);
-	dsi_clk_hs_mode(dsi, 0);
-	dsi_set_mode(dsi);
-
-	dsi_ps_control_vact(dsi);
-	dsi_config_vdo_timing(dsi);
+	mtk_dsi_rxtx_control(dsi);
+	mtk_dsi_phy_timconfig(dsi);
+	mtk_dsi_ps_control_vact(dsi);
+	mtk_dsi_set_vm_cmd(dsi);
+	mtk_dsi_config_vdo_timing(dsi);
 	mtk_dsi_set_interrupt_enable(dsi);
 
-	dsi_set_mode(dsi);
-	dsi_clk_hs_mode(dsi, 1);
+	mtk_dsi_enable(dsi);
+	mtk_dsi_clk_ulp_mode_leave(dsi);
+	mtk_dsi_lane0_ulp_mode_leave(dsi);
+	mtk_dsi_clk_hs_mode(dsi, 0);
+
+	if (dsi->panel) {
+		if (drm_panel_prepare(dsi->panel)) {
+			DRM_ERROR("failed to prepare the panel\n");
+			return;
+		}
+
+		if (drm_panel_enable(dsi->panel)) {
+			DRM_ERROR("failed to enable the panel\n");
+			return;
+		}
+	}
+
+	mtk_dsi_set_mode(dsi);
+	mtk_dsi_clk_hs_mode(dsi, 1);
 
 	mtk_dsi_start(dsi);
 
@@ -679,6 +740,7 @@ static void mtk_output_dsi_disable(struct mtk_dsi *dsi)
 		}
 	}
 
+	mtk_dsi_stop(dsi);
 	mtk_dsi_poweroff(dsi);
 
 	dsi->enabled = false;
@@ -1351,6 +1413,7 @@ static int mtk_dsi_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id mtk_dsi_of_match[] = {
+	{ .compatible = "mediatek,mt2701-dsi" },
 	{ .compatible = "mediatek,mt8173-dsi" },
 	{ },
 };
diff --git a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
index cf8f38d..3bffc40 100644
--- a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
+++ b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
@@ -16,6 +16,7 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/phy/phy.h>
 
@@ -87,6 +88,9 @@
 
 #define MIPITX_DSI_PLL_CON2	0x58
 
+#define MIPITX_DSI_PLL_TOP	0x64
+#define RG_DSI_MPPLL_PRESERVE		(0xff << 8)
+
 #define MIPITX_DSI_PLL_PWR	0x68
 #define RG_DSI_MPPLL_SDM_PWR_ON		BIT(0)
 #define RG_DSI_MPPLL_SDM_ISO_EN		BIT(1)
@@ -123,10 +127,32 @@
 #define SW_LNT2_HSTX_PRE_OE		BIT(24)
 #define SW_LNT2_HSTX_OE			BIT(25)
 
+struct mtk_mipitx_data {
+	const u32 data;
+};
+
+static const struct mtk_mipitx_data mt2701_mipitx_data = {
+	.data = (3 << 8)
+};
+
+static const struct mtk_mipitx_data mt8173_mipitx_data = {
+	.data = (0 << 8)
+};
+
+static const struct of_device_id mtk_mipi_tx_match[] = {
+	{ .compatible = "mediatek,mt2701-mipi-tx",
+	  .data = &mt2701_mipitx_data },
+	{ .compatible = "mediatek,mt8173-mipi-tx",
+	  .data = &mt8173_mipitx_data },
+	{},
+};
+
 struct mtk_mipi_tx {
 	struct device *dev;
 	void __iomem *regs;
-	unsigned int data_rate;
+	u32 data_rate;
+	const struct mtk_mipitx_data *driver_data;
+
 	struct clk_hw pll_hw;
 	struct clk *pll;
 };
@@ -163,12 +189,14 @@ static void mtk_mipi_tx_update_bits(struct mtk_mipi_tx *mipi_tx, u32 offset,
 static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw)
 {
 	struct mtk_mipi_tx *mipi_tx = mtk_mipi_tx_from_clk_hw(hw);
-	unsigned int txdiv, txdiv0, txdiv1;
+	u8 txdiv, txdiv0, txdiv1;
 	u64 pcw;
 
 	dev_dbg(mipi_tx->dev, "prepare: %u Hz\n", mipi_tx->data_rate);
 
-	if (mipi_tx->data_rate >= 500000000) {
+	if (mipi_tx->data_rate > 1250000000) {
+		return -EINVAL;
+	} else if (mipi_tx->data_rate >= 500000000) {
 		txdiv = 1;
 		txdiv0 = 0;
 		txdiv1 = 0;
@@ -192,6 +220,10 @@ static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw)
 		return -EINVAL;
 	}
 
+	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_TOP_CON,
+				RG_DSI_LNT_IMP_CAL_CODE | RG_DSI_LNT_HS_BIAS_EN,
+				(8 << 4) | RG_DSI_LNT_HS_BIAS_EN);
+
 	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_BG_CON,
 				RG_DSI_VOUT_MSK |
 				RG_DSI_BG_CKEN | RG_DSI_BG_CORE_EN,
@@ -201,24 +233,18 @@ static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw)
 
 	usleep_range(30, 100);
 
-	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_TOP_CON,
-				RG_DSI_LNT_IMP_CAL_CODE | RG_DSI_LNT_HS_BIAS_EN,
-				(8 << 4) | RG_DSI_LNT_HS_BIAS_EN);
-
-	mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_CON,
-			     RG_DSI_CKG_LDOOUT_EN | RG_DSI_LDOCORE_EN);
+	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_CON,
+				RG_DSI_CKG_LDOOUT_EN | RG_DSI_LDOCORE_EN,
+				RG_DSI_CKG_LDOOUT_EN | RG_DSI_LDOCORE_EN);
 
 	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_PWR,
 				RG_DSI_MPPLL_SDM_PWR_ON |
 				RG_DSI_MPPLL_SDM_ISO_EN,
 				RG_DSI_MPPLL_SDM_PWR_ON);
 
-	mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON0,
-			       RG_DSI_MPPLL_PLL_EN);
-
 	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_CON0,
-				RG_DSI_MPPLL_TXDIV0 | RG_DSI_MPPLL_TXDIV1 |
-				RG_DSI_MPPLL_PREDIV,
+				RG_DSI_MPPLL_PREDIV | RG_DSI_MPPLL_TXDIV0 |
+				RG_DSI_MPPLL_TXDIV1 | RG_DSI_MPPLL_POSDIV,
 				(txdiv0 << 3) | (txdiv1 << 5));
 
 	/*
@@ -233,15 +259,21 @@ static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw)
 		      26000000);
 	writel(pcw, mipi_tx->regs + MIPITX_DSI_PLL_CON2);
 
-	mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_PLL_CON1,
-			     RG_DSI_MPPLL_SDM_FRA_EN);
+	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_CON1,
+				RG_DSI_MPPLL_SDM_FRA_EN,
+				RG_DSI_MPPLL_SDM_FRA_EN);
 
-	mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_PLL_CON0, RG_DSI_MPPLL_PLL_EN);
+	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_CON0,
+				RG_DSI_MPPLL_PLL_EN, RG_DSI_MPPLL_PLL_EN);
 
 	usleep_range(20, 100);
 
 	mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON1,
-			       RG_DSI_MPPLL_SDM_SSC_EN);
+					RG_DSI_MPPLL_SDM_SSC_EN);
+
+	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_TOP,
+				RG_DSI_MPPLL_PRESERVE,
+				mipi_tx->driver_data->data);
 
 	return 0;
 }
@@ -255,6 +287,10 @@ static void mtk_mipi_tx_pll_unprepare(struct clk_hw *hw)
 	mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON0,
 			       RG_DSI_MPPLL_PLL_EN);
 
+	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_TOP,
+				RG_DSI_MPPLL_PRESERVE,
+				mipi_tx->driver_data->data);
+
 	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_PWR,
 				RG_DSI_MPPLL_SDM_ISO_EN |
 				RG_DSI_MPPLL_SDM_PWR_ON,
@@ -310,7 +346,7 @@ static const struct clk_ops mtk_mipi_tx_pll_ops = {
 static int mtk_mipi_tx_power_on_signal(struct phy *phy)
 {
 	struct mtk_mipi_tx *mipi_tx = phy_get_drvdata(phy);
-	unsigned int reg;
+	u32 reg;
 
 	for (reg = MIPITX_DSI_CLOCK_LANE;
 	     reg <= MIPITX_DSI_DATA_LANE3; reg += 4)
@@ -341,7 +377,7 @@ static int mtk_mipi_tx_power_on(struct phy *phy)
 static void mtk_mipi_tx_power_off_signal(struct phy *phy)
 {
 	struct mtk_mipi_tx *mipi_tx = phy_get_drvdata(phy);
-	unsigned int reg;
+	u32 reg;
 
 	mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_TOP_CON,
 			     RG_DSI_PAD_TIE_LOW_EN);
@@ -391,6 +427,7 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev)
 	if (!mipi_tx)
 		return -ENOMEM;
 
+	mipi_tx->driver_data = of_device_get_match_data(dev);
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	mipi_tx->regs = devm_ioremap_resource(dev, mem);
 	if (IS_ERR(mipi_tx->regs)) {
@@ -448,11 +485,6 @@ static int mtk_mipi_tx_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static const struct of_device_id mtk_mipi_tx_match[] = {
-	{ .compatible = "mediatek,mt8173-mipi-tx", },
-	{},
-};
-
 struct platform_driver mtk_mipi_tx_driver = {
 	.probe = mtk_mipi_tx_probe,
 	.remove = mtk_mipi_tx_remove,
-- 
1.7.9.5



From yt.shen at mediatek.com  Fri Jul 15 03:07:54 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Fri, 15 Jul 2016 18:07:54 +0800
Subject: [PATCH v4 8/8] arm: dts: mt2701: Add display subsystem related nodes
 for MT2701
In-Reply-To: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
Message-ID: <1468577274-6178-9-git-send-email-yt.shen@mediatek.com>

This patch adds the device nodes for the DISP function blocks for MT2701

Signed-off-by: YT Shen <yt.shen at mediatek.com>
---
 arch/arm/boot/dts/mt2701.dtsi |  100 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 100 insertions(+)

diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
index 363de0d..7da9310 100644
--- a/arch/arm/boot/dts/mt2701.dtsi
+++ b/arch/arm/boot/dts/mt2701.dtsi
@@ -24,6 +24,11 @@
 	compatible = "mediatek,mt2701";
 	interrupt-parent = <&sysirq>;
 
+	aliases {
+		rdma0 = &rdma0;
+		rdma1 = &rdma1;
+	};
+
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -171,6 +176,16 @@
 		power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>;
 	};
 
+	mipi_tx0: mipi-dphy at 10010000 {
+		compatible = "mediatek,mt2701-mipi-tx";
+		reg = <0 0x10010000 0 0x90>;
+		clocks = <&clk26m>;
+		clock-output-names = "mipi_tx0_pll";
+		#clock-cells = <0>;
+		#phy-cells = <0>;
+		status = "disabled";
+	};
+
 	sysirq: interrupt-controller at 10200100 {
 		compatible = "mediatek,mt2701-sysirq",
 			     "mediatek,mt6577-sysirq";
@@ -255,6 +270,68 @@
 		status = "disabled";
 	};
 
+	ovl at 14007000 {
+		compatible = "mediatek,mt2701-disp-ovl";
+		reg = <0 0x14007000 0 0x1000>;
+		interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&mmsys CLK_MM_DISP_OVL>;
+		iommus = <&iommu MT2701_M4U_PORT_DISP_OVL_0>;
+		mediatek,larb = <&larb0>;
+	};
+
+	rdma0: rdma at 14008000 {
+		compatible = "mediatek,mt2701-disp-rdma";
+		reg = <0 0x14008000 0 0x1000>;
+		interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&mmsys CLK_MM_DISP_RDMA>;
+		iommus = <&iommu MT2701_M4U_PORT_DISP_RDMA>;
+		mediatek,larb = <&larb0>;
+	};
+
+	wdma at 14009000 {
+		compatible = "mediatek,mt2701-disp-wdma";
+		reg = <0 0x14009000 0 0x1000>;
+		interrupts = <GIC_SPI 154 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&mmsys CLK_MM_DISP_WDMA>;
+		iommus = <&iommu MT2701_M4U_PORT_DISP_WDMA>;
+		mediatek,larb = <&larb0>;
+	};
+
+	bls at 1400a000 {
+		compatible = "mediatek,mt2701-disp-pwm";
+		reg = <0 0x1400a000 0 0x1000>;
+		interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&mmsys CLK_MM_DISP_BLS>;
+	};
+
+	color at 1400b000 {
+		compatible = "mediatek,mt2701-disp-color";
+		reg = <0 0x1400b000 0 0x1000>;
+		interrupts = <GIC_SPI 156 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&mmsys CLK_MM_DISP_COLOR>;
+	};
+
+	dsi0: dsi at 1400c000 {
+		compatible = "mediatek,mt2701-dsi";
+		reg = <0 0x1400c000 0 0x1000>;
+		interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&mmsys CLK_MM_DSI_ENGINE>, <&mmsys CLK_MM_DSI_DIG>,
+			 <&mipi_tx0>;
+		clock-names = "engine", "digital", "hs";
+		mediatek,syscon-dsi = <&mmsys 0x138>;
+		mediatek,ssc-range = <5>;
+		phys = <&mipi_tx0>;
+		phy-names = "dphy";
+		status = "disabled";
+	};
+
+	mutex: mutex at 1400e000 {
+		compatible = "mediatek,mt2701-disp-mutex";
+		reg = <0 0x1400e000 0 0x1000>;
+		interrupts = <GIC_SPI 161 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&mmsys CLK_MM_MUTEX_32K>;
+	};
+
 	larb0: larb at 14010000 {
 		compatible = "mediatek,mt2701-smi-larb";
 		reg = <0 0x14010000 0 0x1000>;
@@ -265,6 +342,29 @@
 		power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>;
 	};
 
+	rdma1: rdma at 14012000 {
+		compatible = "mediatek,mt2701-disp-rdma";
+		reg = <0 0x14012000 0 0x1000>;
+		interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&mmsys CLK_MM_DISP_RDMA1>;
+		iommus = <&iommu MT2701_M4U_PORT_DISP_RDMA1>;
+		mediatek,larb = <&larb0>;
+	};
+
+	dpi0: dpi at 14014000 {
+		compatible = "mediatek,mt2701-dpi";
+		reg = <0 0x14014000 0 0x1000>;
+		interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&mmsys CLK_MM_DPI1_DIGL>,
+			 <&mmsys CLK_MM_DPI1_ENGINE>,
+			 <&topckgen CLK_TOP_DPI1_SEL>,
+			 <&topckgen CLK_TOP_TVDPLL>,
+			 <&topckgen CLK_TOP_TVDPLL_D2>,
+			 <&topckgen CLK_TOP_TVDPLL_D4>;
+		clock-names = "pixel", "engine", "sel","div1","div2","div4";
+		status = "disabled";
+	};
+
 	imgsys: syscon at 15000000 {
 		compatible = "mediatek,mt2701-imgsys", "syscon";
 		reg = <0 0x15000000 0 0x1000>;
-- 
1.7.9.5



From hverkuil at xs4all.nl  Fri Jul 15 10:50:15 2016
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Fri, 15 Jul 2016 19:50:15 +0200
Subject: [PATCH] vcodec: mediatek: Add g/s_selection support for V4L2
 Encoder
In-Reply-To: <1468477674.32454.36.camel@mtksdaap41>
References: <1464594768-1993-1-git-send-email-tiffany.lin@mediatek.com>
 <4ca82842-968d-a5e2-587d-752c71713607@xs4all.nl>
 <1468477674.32454.36.camel@mtksdaap41>
Message-ID: <bb96276a-8e6c-a535-6fd3-fe4327238f65@xs4all.nl>

On 07/14/2016 08:27 AM, tiffany lin wrote:
> Hi Hans,
> 
> 
> On Mon, 2016-07-11 at 06:32 +0200, Hans Verkuil wrote:
>> Hi Tiffany,
>>
>> My apologies for the delay, but here is my review at last:
>>
>> On 05/30/2016 09:52 AM, Tiffany Lin wrote:
>>> This patch add g/s_selection support for MT8173
>>>
>>> Signed-off-by: Tiffany Lin <tiffany.lin at mediatek.com>
>>> ---
>>>  drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c |   74 ++++++++++++++++++++
>>>  1 file changed, 74 insertions(+)
>>>
>>> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
>>> index 6e72d73..23ef9a1 100644
>>> --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
>>> +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
>>> @@ -630,6 +630,77 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
>>>  	return vidioc_try_fmt(f, fmt);
>>>  }
>>>  
>>> +static int vidioc_venc_g_selection(struct file *file, void *priv,
>>> +				     struct v4l2_selection *s)
>>> +{
>>> +	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
>>> +	struct mtk_q_data *q_data;
>>> +
>>> +	/* crop means compose for output devices */
>>> +	switch (s->target) {
>>> +	case V4L2_SEL_TGT_CROP_DEFAULT:
>>> +	case V4L2_SEL_TGT_CROP_BOUNDS:
>>> +	case V4L2_SEL_TGT_CROP:
>>> +	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
>>> +	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
>>> +	case V4L2_SEL_TGT_COMPOSE:
>>> +		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
>>> +			mtk_v4l2_err("Invalid s->type = %d", s->type);
>>> +			return -EINVAL;
>>> +		}
>>> +		break;
>>> +	default:
>>> +		mtk_v4l2_err("Invalid s->target = %d", s->target);
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	q_data = mtk_venc_get_q_data(ctx, s->type);
>>> +	if (!q_data)
>>> +		return -EINVAL;
>>> +
>>> +	s->r.top = 0;
>>> +	s->r.left = 0;
>>> +	s->r.width = q_data->visible_width;
>>> +	s->r.height = q_data->visible_height;
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int vidioc_venc_s_selection(struct file *file, void *priv,
>>> +				     struct v4l2_selection *s)
>>> +{
>>> +	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
>>> +	struct mtk_q_data *q_data;
>>> +
>>> +	switch (s->target) {
>>> +	case V4L2_SEL_TGT_CROP_DEFAULT:
>>> +	case V4L2_SEL_TGT_CROP_BOUNDS:
>>> +	case V4L2_SEL_TGT_CROP:
>>> +	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
>>> +	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
>>> +	case V4L2_SEL_TGT_COMPOSE:
>>> +		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
>>> +			mtk_v4l2_err("Invalid s->type = %d", s->type);
>>> +			return -EINVAL;
>>> +		}
>>> +		break;
>>> +	default:
>>> +		mtk_v4l2_err("Invalid s->target = %d", s->target);
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	q_data = mtk_venc_get_q_data(ctx, s->type);
>>> +	if (!q_data)
>>> +		return -EINVAL;
>>> +
>>> +	s->r.top = 0;
>>> +	s->r.left = 0;
>>> +	q_data->visible_width = s->r.width;
>>> +	q_data->visible_height = s->r.height;
>>
>> This makes no sense.
>>
>> See this page:
>>
>> https://hverkuil.home.xs4all.nl/spec/media.html#selection-api
>>
>> For the video output direction (memory -> HW encoder) the data source is
>> the memory, the data sink is the HW encoder. For the video capture direction
>> (HW encoder -> memory) the data source is the HW encoder and the data sink
>> is the memory.
>>
>> Usually for m2m devices the video output direction may support cropping and
>> the video capture direction may support composing.
>>
>> It's not clear what you intend here, especially since you set left and right
>> to 0. That's not what the selection operation is supposed to do.
>>
> I am confused about about g/s_selection.
> If application want to configure encode area and crop meta-data, it
> should set crop info to OUTPUT queue, is that right?
> if user space still use g/s_crop ioctl, in 
> v4l_g_crop and v4l_s_crop, it set target to V4L2_SEL_TGT_COMPOSE_ACTIVE
> when buf type is V4L2_TYPE_IS_OUTPUT.
> 
> It looks like when work with g/s_crop ioctl, command set to OUTPUT
> buffer will use target V4L2_SEL_TGT_COMPOSE_ACTIVE.

Correct. The semantics of g/s_crop for output devices is really weird
and g/s_crop is generally useless for mem2mem devices.

You should completely ignore the old g/s_crop and only look at g/s_selection.

> When work with g/s_selection ictol, command set to OUTPUT buffer will
> use V4L2_SEL_TGT_CROP_ACTIVE.
> Is this correct behavior?

Yes. What this means is that userspace has to use g/s_selection for
mem2mem devices since g/s_crop changes the wrong thing: compose instead
of crop for OUTPUT and crop instead of compose for CAPTURE.

The g/s_selection ioctls were added to solve this problem with g/s_crop.
It always confuses people and it was due to a lack of foresight when the
old crop API was designed: it was made for video capture where you
crop on the hardware side (in the video receiver), and for video output it
would compose the image in the video transmitter's total frame (usually
720x480/576). None of this applies in general to memory-to-memory devices.

Regards,

	Hans

> 
> 
> static int v4l_g_crop(const struct v4l2_ioctl_ops *ops,
> 				struct file *file, void *fh, void *arg)
> {
> 	struct v4l2_crop *p = arg;
> 	struct v4l2_selection s = {
> 		.type = p->type,
> 	};
> 	int ret;
> 
> 	if (ops->vidioc_g_crop)
> 		return ops->vidioc_g_crop(file, fh, p);
> 	/* simulate capture crop using selection api */
> 
> 	/* crop means compose for output devices */
> 	if (V4L2_TYPE_IS_OUTPUT(p->type))
> 		s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE;
> 	else
> 		s.target = V4L2_SEL_TGT_CROP_ACTIVE;
> 
> 	ret = ops->vidioc_g_selection(file, fh, &s);
> 
> 	/* copying results to old structure on success */
> 	if (!ret)
> 		p->c = s.r;
> 	return ret;
> }
> 
> static int v4l_s_crop(const struct v4l2_ioctl_ops *ops,
> 				struct file *file, void *fh, void *arg)
> {
> 	struct v4l2_crop *p = arg;
> 	struct v4l2_selection s = {
> 		.type = p->type,
> 		.r = p->c,
> 	};
> 
> 	if (ops->vidioc_s_crop)
> 		return ops->vidioc_s_crop(file, fh, p);
> 	/* simulate capture crop using selection api */
> 
> 	/* crop means compose for output devices */
> 	if (V4L2_TYPE_IS_OUTPUT(p->type))
> 		s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE;
> 	else
> 		s.target = V4L2_SEL_TGT_CROP_ACTIVE;
> 
> 	return ops->vidioc_s_selection(file, fh, &s);
> }
> 
> 
> best regards,
> Tiffany
> 
> 
> 
> 
>> Regards,
>>
>> 	Hans
>>
>>> +
>>> +	return 0;
>>> +}
>>> +
>>>  static int vidioc_venc_qbuf(struct file *file, void *priv,
>>>  			    struct v4l2_buffer *buf)
>>>  {
>>> @@ -688,6 +759,9 @@ const struct v4l2_ioctl_ops mtk_venc_ioctl_ops = {
>>>  
>>>  	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,
>>>  	.vidioc_prepare_buf		= v4l2_m2m_ioctl_prepare_buf,
>>> +
>>> +	.vidioc_g_selection		= vidioc_venc_g_selection,
>>> +	.vidioc_s_selection		= vidioc_venc_s_selection,
>>>  };
>>>  
>>>  static int vb2ops_venc_queue_setup(struct vb2_queue *vq,
>>>
> 
> 
> --
> 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
> 


From bjorn.andersson at linaro.org  Fri Jul 15 15:10:57 2016
From: bjorn.andersson at linaro.org (Bjorn Andersson)
Date: Fri, 15 Jul 2016 15:10:57 -0700
Subject: [PATCH 2/3] mmc: mmc: do not use CMD13 to get status after speed
 mode switch
In-Reply-To: <1463647662-27426-3-git-send-email-chaotian.jing@mediatek.com>
References: <1463647662-27426-1-git-send-email-chaotian.jing@mediatek.com>
 <1463647662-27426-3-git-send-email-chaotian.jing@mediatek.com>
Message-ID: <CAOCOHw67NAinC6dEX0KsDn02kuXyNwznm3-bhptSVvQH0V1dqQ@mail.gmail.com>

On Thu, May 19, 2016 at 1:47 AM, Chaotian Jing
<chaotian.jing at mediatek.com> wrote:
> Per JEDEC spec, it is not recommended to use CMD13 to get card status
> after speed mode switch. below are two reason about this:
> 1. CMD13 cannot be guaranteed due to the asynchronous operation.
> Therefore it is not recommended to use CMD13 to check busy completion
> of the timing change indication.
> 2. After switch to HS200, CMD13 will get response of 0x800, and even the
> busy signal gets de-asserted, the response of CMD13 is aslo 0x800.
>
> Signed-off-by: Chaotian Jing <chaotian.jing at mediatek.com>
> ---
>  drivers/mmc/core/mmc.c | 112 ++++++++++++++++++++-----------------------------
>  1 file changed, 45 insertions(+), 67 deletions(-)
>
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
[..]
> @@ -1274,20 +1254,18 @@ static int mmc_select_hs200(struct mmc_card *card)
>                 err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>                                    EXT_CSD_HS_TIMING, val,
>                                    card->ext_csd.generic_cmd6_time,
> -                                  true, send_status, true);
> +                                  true, false, true);
>                 if (err)
>                         goto err;
>                 old_timing = host->ios.timing;
>                 mmc_set_timing(host, MMC_TIMING_MMC_HS200);
> -               if (!send_status) {
> -                       err = mmc_switch_status(card);
> -                       /*
> -                        * mmc_select_timing() assumes timing has not changed if
> -                        * it is a switch error.
> -                        */
> -                       if (err == -EBADMSG)
> -                               mmc_set_timing(host, old_timing);
> -               }
> +               err = mmc_switch_status(card);
> +               /*
> +                * mmc_select_timing() assumes timing has not changed if
> +                * it is a switch error.
> +                */
> +               if (err == -EBADMSG)
> +                       mmc_set_timing(host, old_timing);

Sorry for not spotting this earlier, but with the move of the call of
mmc_switch_status() to after mmc_set_timing() we get following error
with sdhci-msm:

mmc0: mmc_select_hs200 failed, error -110
mmc0: error -110 whilst initialising MMC card
mmc0: Reset 0x1 never completed.
sdhci: =========== REGISTER DUMP (mmc0)===========
sdhci: Sys addr: 0x00000000 | Version: 0x00002e02
sdhci: Blk size: 0x00004000 | Blk cnt: 0x00000000
sdhci: Argument: 0x00000000 | Trn mode: 0x00000000
sdhci: Present: 0x01f80000 | Host ctl: 0x00000000
sdhci: Power: 0x00000000 | Blk gap: 0x00000000
sdhci: Wake-up: 0x00000000 | Clock: 0x00000003
sdhci: Timeout: 0x00000000 | Int stat: 0x00000000
sdhci: Int enab: 0x00000000 | Sig enab: 0x00000000
sdhci: AC12 err: 0x00000000 | Slot int: 0x00000000
sdhci: Caps: 0x322dc8b2 | Caps_1: 0x00008007
sdhci: Cmd: 0x00000000 | Max curr: 0x00000000
sdhci: Host ctl2: 0x00000000
sdhci: ADMA Err: 0x00000000 | ADMA Ptr: 0x0000000000000000
sdhci: ===========================================

But I if I understand the commit correctly this is the intention of
the patch (not the error, but the move).

Regards,
Bjorn

>         }
>  err:
>         if (err)
> --
> 1.8.1.1.dirty
>


From robh at kernel.org  Sat Jul 16 06:44:04 2016
From: robh at kernel.org (Rob Herring)
Date: Sat, 16 Jul 2016 08:44:04 -0500
Subject: [PATCH V2 1/3] dt-bindings: pwm: Add MediaTek display PWM bindings
In-Reply-To: <1468225089-28576-2-git-send-email-weiqing.kong@mediatek.com>
References: <1468225089-28576-1-git-send-email-weiqing.kong@mediatek.com>
 <1468225089-28576-2-git-send-email-weiqing.kong@mediatek.com>
Message-ID: <20160716134404.GA2143@rob-hp-laptop>

On Mon, Jul 11, 2016 at 04:18:07PM +0800, Weiqing Kong wrote:
> Add MT2701 compatible string.
> 
> Signed-off-by: Weiqing Kong <weiqing.kong at mediatek.com>
> ---
>  Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)

Acked-by: Rob Herring <robh at kernel.org>


From robh at kernel.org  Sat Jul 16 12:31:25 2016
From: robh at kernel.org (Rob Herring)
Date: Sat, 16 Jul 2016 14:31:25 -0500
Subject: [PATCH v4 1/3] dt-bindings: auxadc: Add binding document for
 Mediatek auxadc.
In-Reply-To: <1468291396.419.15.camel@mhfsdcap03>
References: <1468219197-9572-1-git-send-email-zhiyong.tao@mediatek.com>
 <1468219197-9572-2-git-send-email-zhiyong.tao@mediatek.com>
 <1468291396.419.15.camel@mhfsdcap03>
Message-ID: <20160716193125.GA14506@rob-hp-laptop>

On Tue, Jul 12, 2016 at 10:43:16AM +0800, zhiyong tao wrote:
> On Mon, 2016-07-11 at 14:39 +0800, Zhiyong Tao wrote:
> > The commit adds the device tree binding documentation for the mediatek
> > auxadc found on Mediatek MT2701.
> > Thermal gets auxadc sample data by iio device.
> > So the commit changes auxadc device tree binding documentation from
> > /soc/mediatek/auxadc.txt to /iio/adc/mt6577_auxadc.txt.
> > 
> > Signed-off-by: Zhiyong Tao <zhiyong.tao at mediatek.com>
> > ---
> 
> I forgot that I should use the command 'git format-patch -M' to submit
> this patch. The follow information is the patch after executing the
> above command. If the patch needs to be resent, please help to notify
> me. I will resend the patch quickly.
> The follow information:
> 
>  .../auxadc.txt => iio/adc/mt6577_auxadc.txt}       |   16
> +++++++++++-----
>  1 file changed, 11 insertions(+), 5 deletions(-)
>  rename Documentation/devicetree/bindings/{soc/mediatek/auxadc.txt =>
> iio/adc/mt6577_auxadc.txt} (50%)
> 
> diff --git a/Documentation/devicetree/bindings/soc/mediatek/auxadc.txt
> b/Documentation/devicetree/bindings/iio/adc/mt6577_auxadc.txt
> similarity index 50%
> rename from Documentation/devicetree/bindings/soc/mediatek/auxadc.txt
> rename to Documentation/devicetree/bindings/iio/adc/mt6577_auxadc.txt
> index bdb7829..bc23792 100644
> --- a/Documentation/devicetree/bindings/soc/mediatek/auxadc.txt
> +++ b/Documentation/devicetree/bindings/iio/adc/mt6577_auxadc.txt
> @@ -1,4 +1,4 @@
> -MediaTek AUXADC
> +* Mediatek AUXADC - Analog to Digital Converter on Mediatek mobile soc
> (mt65xx/mt81xx/mt27xx)
>  ===============
> 
>  The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found
> @@ -10,12 +10,18 @@
> Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
>  for the Thermal Controller which holds a phandle to the AUXADC.
> 
>  Required properties:
> -- compatible: Must be "mediatek,mt8173-auxadc"
> -- reg: Address range of the AUXADC unit
> +  - compatible: "mediatek,mt2701-auxadc" or "mediatek,mt8173-auxadc"

It's preferred to list one per line, but this is fine unless you resend.

Acked-by: Rob Herring <robh at kernel.org>


From robh at kernel.org  Sat Jul 16 16:01:13 2016
From: robh at kernel.org (Rob Herring)
Date: Sat, 16 Jul 2016 18:01:13 -0500
Subject: [PATCH 2/4] dt-bindings: Add a binding for Mediatek MDP
In-Reply-To: <1468498681-19955-3-git-send-email-minghsiu.tsai@mediatek.com>
References: <1468498681-19955-1-git-send-email-minghsiu.tsai@mediatek.com>
 <1468498681-19955-3-git-send-email-minghsiu.tsai@mediatek.com>
Message-ID: <20160716230113.GA31551@rob-hp-laptop>

On Thu, Jul 14, 2016 at 08:17:59PM +0800, Minghsiu Tsai wrote:
> Add a DT binding documentation of MDP for the MT8173 SoC
> from Mediatek
> 
> Signed-off-by: Minghsiu Tsai <minghsiu.tsai at mediatek.com>
> ---
>  .../devicetree/bindings/media/mediatek-mdp.txt     |   92 ++++++++++++++++++++
>  1 file changed, 92 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/media/mediatek-mdp.txt
> 
> diff --git a/Documentation/devicetree/bindings/media/mediatek-mdp.txt b/Documentation/devicetree/bindings/media/mediatek-mdp.txt
> new file mode 100644
> index 0000000..ef570c3
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/mediatek-mdp.txt
> @@ -0,0 +1,92 @@
> +* Mediatek Media Data Path
> +
> +Media Data Path is used for scaling and color space conversion.
> +
> +Required properties:
> +  - compatible : should contain them as below:
> +        "mediatek,mt8173-mdp"
> +        "mediatek,mt8173-mdp-rdma"
> +        "mediatek,mt8173-mdp-rsz"
> +        "mediatek,mt8173-mdp-wdma"
> +        "mediatek,mt8173-mdp-wrot"
> +  - clocks : device clocks
> +  - power-domains : a phandle to the power domain.
> +  - mediatek,larb : should contain the larbes of current platform
> +  - iommus : Mediatek IOMMU H/W has designed the fixed associations with
> +        the multimedia H/W. and there is only one multimedia iommu domain.
> +        "iommus = <&iommu portid>" the "portid" is from
> +        dt-bindings\iommu\mt8173-iommu-port.h, it means that this portid will
> +        enable iommu. The portid default is disable iommu if "<&iommu portid>"
> +        don't be added.
> +  - mediatek,vpu : the node of video processor unit

These properties don't apply to all the nodes. I think you need a 
section for each IP block.


From ck.hu at mediatek.com  Sun Jul 17 19:33:57 2016
From: ck.hu at mediatek.com (CK Hu)
Date: Mon, 18 Jul 2016 10:33:57 +0800
Subject: [PATCH v3 2/2] drm/mediatek: set mt8173 dithering function
In-Reply-To: <1467877029-45236-3-git-send-email-bibby.hsieh@mediatek.com>
References: <1467877029-45236-1-git-send-email-bibby.hsieh@mediatek.com>
 <1467877029-45236-3-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1468809237.30644.28.camel@mtksdaap41>

Hi, Bibby:

Some comments inline.

On Thu, 2016-07-07 at 15:37 +0800, Bibby Hsieh wrote:
> Some panels only accept bpc (bit per color) 6-bit.
> But, the default bpc in mt8173 display data path is 8-bit.
> If we didn't enable dithering function to convert bpc,
> display cannot show the smooth grayscale image.
> 
> In mt8173, the dithering function in OD (OverDrive) and
> GAMMA module, we have to config them with
> connector->display_mode.bpc when CRTC initial.
> 
> 1. Clear the default value at *_DITHER_5 and *_DITHER_7 register.
> 2. Calculate the LSB_ERR_SHIFT bits and ADD_LSHIFT bits two values.
> i.e. Input bpc of OD is 10 bits, we assume the bpc of panel is 6-bit,
> so, we need to set 4-bit to LSB_ERR_SHIFT and ADD_LSHIFT bits respectively.
> 3. Then, set the OD or GAMMA to dithering mode depends on path-1 or path-2.
> 
> Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_disp_ovl.c     |    3 +-
>  drivers/gpu/drm/mediatek/mtk_disp_rdma.c    |    3 +-
>  drivers/gpu/drm/mediatek/mtk_drm_crtc.c     |   21 ++++++--
>  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |   77 +++++++++++++++++++++++----
>  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |    6 +--
>  5 files changed, 92 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> index 8f62671f..019b7ca 100644
> --- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> @@ -103,7 +103,8 @@ static void mtk_ovl_stop(struct mtk_ddp_comp *comp)
>  }
>  
>  static void mtk_ovl_config(struct mtk_ddp_comp *comp, unsigned int w,
> -			   unsigned int h, unsigned int vrefresh)
> +			   unsigned int h, unsigned int vrefresh,
> +			   unsigned int bpc)
>  {
>  	if (w != 0 && h != 0)
>  		writel_relaxed(h << 16 | w, comp->regs + DISP_REG_OVL_ROI_SIZE);
> diff --git a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
> index 5fb80cb..0df05f9 100644
> --- a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
> +++ b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
> @@ -106,7 +106,8 @@ static void mtk_rdma_stop(struct mtk_ddp_comp *comp)
>  }
>  
>  static void mtk_rdma_config(struct mtk_ddp_comp *comp, unsigned int width,
> -			    unsigned int height, unsigned int vrefresh)
> +			    unsigned int height, unsigned int vrefresh,
> +			    unsigned int bpc)
>  {
>  	unsigned int threshold;
>  	unsigned int reg;
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> index ee219bb..18c9d0d 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> @@ -222,7 +222,9 @@ static void mtk_crtc_ddp_clk_disable(struct mtk_drm_crtc *mtk_crtc)
>  static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
>  {
>  	struct drm_crtc *crtc = &mtk_crtc->base;
> -	unsigned int width, height, vrefresh;
> +	struct drm_connector *connector;
> +	struct drm_encoder *encoder;
> +	unsigned int width, height, vrefresh, bpc = 0;
>  	int ret;
>  	int i;
>  
> @@ -234,6 +236,19 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
>  	height = crtc->state->adjusted_mode.vdisplay;
>  	vrefresh = crtc->state->adjusted_mode.vrefresh;
>  
> +	drm_for_each_encoder(encoder, crtc->dev) {
> +		if (encoder->crtc != crtc)
> +			continue;
> +
> +		drm_for_each_connector(connector, crtc->dev) {
> +			if (connector->encoder != encoder)
> +				continue;
> +			if (connector->display_info.bpc >= 3 &&

I think you should left this HW constrain in mtk_od_config() and
mtk_gamma_config(). Here just calculate the expected bpc.

> +			    (bpc == 0 || bpc > connector->display_info.bpc))

I think bpc should be initialized as HW default bpc and you can remove
this condiction 'bpc == 0' because we should set bpc to HW default bpc
while all connnector bpc is greater than HW default bpc.

> +				bpc = connector->display_info.bpc;
> +		}
> +	}
> +
>  	ret = pm_runtime_get_sync(crtc->dev->dev);
>  	if (ret < 0) {
>  		DRM_ERROR("Failed to enable power domain: %d\n", ret);
> @@ -266,7 +281,7 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
>  	for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
>  		struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[i];
>  
> -		mtk_ddp_comp_config(comp, width, height, vrefresh);
> +		mtk_ddp_comp_config(comp, width, height, vrefresh, bpc);
>  		mtk_ddp_comp_start(comp);
>  	}
>  
> @@ -469,7 +484,7 @@ void mtk_crtc_ddp_irq(struct drm_crtc *crtc, struct mtk_ddp_comp *ovl)
>  	if (state->pending_config) {
>  		mtk_ddp_comp_config(ovl, state->pending_width,
>  				    state->pending_height,
> -				    state->pending_vrefresh);
> +				    state->pending_vrefresh, 0);

Why set bpc as 0 here? Maybe you have a assumption that OVL don't care
the bpc parameter. If one day OVL care it and we do not review here, the
bugs happen.

>  
>  		state->pending_config = false;
>  	}
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
> index 56c5894..c10faac 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
> @@ -30,7 +30,26 @@
>  #define DISP_OD_INTEN				0x0008
>  #define DISP_OD_INTSTA				0x000c
>  #define DISP_OD_CFG				0x0020
> +#define OD_RELAYMODE				BIT(0)
> +#define OD_DITHERING				BIT(2)
>  #define DISP_OD_SIZE				0x0030
> +#define DISP_OD_DITHER_5			0x0114
> +#define DISP_OD_DITHER_7			0x011c
> +#define DISP_OD_DITHER_15			0x013c
> +#define DITHER_LSB_ERR_SHIFT_R(x)		(((x) & 0x7) << 28)
> +#define DITHER_OVFLW_BIT_R(x)			(((x) & 0x7) << 24)
> +#define DITHER_ADD_LSHIFT_R(x)			(((x) & 0x7) << 20)
> +#define DITHER_ADD_RSHIFT_R(x)			(((x) & 0x7) << 16)
> +#define DITHER_NEW_BIT_MODE			BIT(0)
> +#define DISP_OD_DITHER_16			0x140
> +#define DITHER_LSB_ERR_SHIFT_B(x)		(((x) & 0x7) << 28)
> +#define DITHER_OVFLW_BIT_B(x)			(((x) & 0x7) << 24)
> +#define DITHER_ADD_LSHIFT_B(x)			(((x) & 0x7) << 20)
> +#define DITHER_ADD_RSHIFT_B(x)			(((x) & 0x7) << 16)
> +#define DITHER_LSB_ERR_SHIFT_G(x)		(((x) & 0x7) << 12)
> +#define DITHER_OVFLW_BIT_G(x)			(((x) & 0x7) << 8)
> +#define DITHER_ADD_LSHIFT_G(x)			(((x) & 0x7) << 4)
> +#define DITHER_ADD_RSHIFT_G(x)			(((x) & 0x7) << 0)
>  
>  #define DISP_REG_UFO_START			0x0000
>  
> @@ -44,25 +63,28 @@
>  
>  #define DISP_GAMMA_EN				0x000
>  #define DISP_GAMMA_CFG				0x020
> +#define GAMMA_EN				BIT(0)
> +#define GAMMA_LUT_EN				BIT(1)
> +#define GAMMA_DITHERING				BIT(2)
>  #define DISP_GAMMA_SIZE				0x030
>  #define DISP_GAMMA_LUT				0x700
> +#define DISP_GAMMA_DITHER_5			0x0114
> +#define DISP_GAMMA_DITHER_7			0x011c
> +#define DISP_GAMMA_DITHER_15			0x013c
> +#define DISP_GAMMA_DITHER_16			0x0140
>  
>  #define LUT_10BIT_MASK				0x3ff
>  
>  #define AAL_EN			BIT(0)
>  
> -#define GAMMA_EN		BIT(0)
> -#define GAMMA_LUT_EN		BIT(1)
> -
> -#define	OD_RELAY_MODE		BIT(0)
> -
>  #define	UFO_BYPASS		BIT(2)
>  
>  #define	COLOR_BYPASS_ALL	BIT(7)
>  #define	COLOR_SEQ_SEL		BIT(13)
>  
>  static void mtk_color_config(struct mtk_ddp_comp *comp, unsigned int w,
> -			     unsigned int h, unsigned int vrefresh)
> +			     unsigned int h, unsigned int vrefresh,
> +			     unsigned int bpc)
>  {
>  	writel(w, comp->regs + DISP_COLOR_WIDTH);
>  	writel(h, comp->regs + DISP_COLOR_HEIGHT);
> @@ -76,14 +98,33 @@ static void mtk_color_start(struct mtk_ddp_comp *comp)
>  }
>  
>  static void mtk_od_config(struct mtk_ddp_comp *comp, unsigned int w,
> -			  unsigned int h, unsigned int vrefresh)
> +			  unsigned int h, unsigned int vrefresh,
> +			  unsigned int bpc)
>  {
>  	writel(w << 16 | h, comp->regs + DISP_OD_SIZE);
> +	if (bpc >= 3 && bpc < 10) {

Use symbol to replace magic number can improve the readability. For
example.

#define DITHER_MIN_BITS 3
#define DITHER_MAX_BITS 8

> +		writel(0, comp->regs + DISP_OD_DITHER_5);
> +		writel(0, comp->regs + DISP_OD_DITHER_7);
> +		writel(DITHER_LSB_ERR_SHIFT_R(10 - bpc) |
> +		       DITHER_ADD_LSHIFT_R(10 - bpc) |
> +		       DITHER_NEW_BIT_MODE,
> +		       comp->regs + DISP_OD_DITHER_15);
> +		writel(DITHER_LSB_ERR_SHIFT_B(10 - bpc) |
> +		       DITHER_ADD_LSHIFT_B(10 - bpc) |
> +		       DITHER_LSB_ERR_SHIFT_G(10 - bpc) |
> +		       DITHER_ADD_LSHIFT_G(10 - bpc),
> +		       comp->regs + DISP_OD_DITHER_16);
> +		writel(OD_DITHERING,
> +		       comp->regs + DISP_OD_CFG);
> +	} else {
> +		writel(OD_RELAYMODE,
> +		       comp->regs + DISP_OD_CFG);
> +	}
> +
>  }
>  
>  static void mtk_od_start(struct mtk_ddp_comp *comp)
>  {
> -	writel(OD_RELAY_MODE, comp->regs + DISP_OD_CFG);
>  	writel(1, comp->regs + DISP_OD_EN);
>  }
>  
> @@ -93,7 +134,8 @@ static void mtk_ufoe_start(struct mtk_ddp_comp *comp)
>  }
>  
>  static void mtk_aal_config(struct mtk_ddp_comp *comp, unsigned int w,
> -			   unsigned int h, unsigned int vrefresh)
> +			   unsigned int h, unsigned int vrefresh,
> +			   unsigned int bpc)
>  {
>  	writel(h << 16 | w, comp->regs + DISP_AAL_SIZE);
>  }
> @@ -109,9 +151,24 @@ static void mtk_aal_stop(struct mtk_ddp_comp *comp)
>  }
>  
>  static void mtk_gamma_config(struct mtk_ddp_comp *comp, unsigned int w,
> -			     unsigned int h, unsigned int vrefresh)
> +			     unsigned int h, unsigned int vrefresh,
> +			     unsigned int bpc)
>  {
>  	writel(h << 16 | w, comp->regs + DISP_GAMMA_SIZE);
> +	if (bpc >= 3 && bpc < 10) {
> +		writel(0, comp->regs + DISP_GAMMA_DITHER_5);
> +		writel(0, comp->regs + DISP_GAMMA_DITHER_7);
> +		writel(DITHER_LSB_ERR_SHIFT_R(10 - bpc) |
> +		       DITHER_ADD_LSHIFT_R(10 - bpc) |
> +		       DITHER_NEW_BIT_MODE,
> +		       comp->regs + DISP_GAMMA_DITHER_15);
> +		writel(DITHER_LSB_ERR_SHIFT_B(10 - bpc) |
> +		       DITHER_ADD_LSHIFT_B(10 - bpc) |
> +		       DITHER_LSB_ERR_SHIFT_G(10 - bpc) |
> +		       DITHER_ADD_LSHIFT_G(10 - bpc),
> +		       comp->regs + DISP_GAMMA_DITHER_16);
> +		writel(GAMMA_DITHERING, comp->regs + DISP_GAMMA_CFG);
> +	}

This part is the same as mtk_od_config(), so it's better to have a
function 'mtk_dither_config()' and both mtk_od_config() and
mtk_gamma_config() call this function.

>  }
>  
>  static void mtk_gamma_start(struct mtk_ddp_comp *comp)
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
> index 07e17fe..c7c2e92 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
> @@ -65,7 +65,7 @@ struct mtk_ddp_comp;
>  
>  struct mtk_ddp_comp_funcs {
>  	void (*config)(struct mtk_ddp_comp *comp, unsigned int w,
> -		       unsigned int h, unsigned int vrefresh);
> +		       unsigned int h, unsigned int vrefresh, unsigned int bpc);
>  	void (*start)(struct mtk_ddp_comp *comp);
>  	void (*stop)(struct mtk_ddp_comp *comp);
>  	void (*enable_vblank)(struct mtk_ddp_comp *comp, struct drm_crtc *crtc);
> @@ -89,10 +89,10 @@ struct mtk_ddp_comp {
>  
>  static inline void mtk_ddp_comp_config(struct mtk_ddp_comp *comp,
>  				       unsigned int w, unsigned int h,
> -				       unsigned int vrefresh)
> +				       unsigned int vrefresh, unsigned int bpc)
>  {
>  	if (comp->funcs && comp->funcs->config)
> -		comp->funcs->config(comp, w, h, vrefresh);
> +		comp->funcs->config(comp, w, h, vrefresh, bpc);
>  }
>  
>  static inline void mtk_ddp_comp_start(struct mtk_ddp_comp *comp)




From ck.hu at mediatek.com  Sun Jul 17 23:32:55 2016
From: ck.hu at mediatek.com (CK Hu)
Date: Mon, 18 Jul 2016 14:32:55 +0800
Subject: [PATCH v4 3/8] drm/mediatek: add shadow register support
In-Reply-To: <1468577274-6178-4-git-send-email-yt.shen@mediatek.com>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
 <1468577274-6178-4-git-send-email-yt.shen@mediatek.com>
Message-ID: <1468823575.30644.33.camel@mtksdaap41>

Hi, YT:

One comment inline.


On Fri, 2016-07-15 at 18:07 +0800, YT Shen wrote:
> We need to acquire mutex before using the resources,
> and need to release it after finished.
> So we don't need to write registers in the blanking period.
> 
> Signed-off-by: YT Shen <yt.shen at mediatek.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_drm_crtc.c |   75 +++++++++++++++++++------------
>  drivers/gpu/drm/mediatek/mtk_drm_ddp.c  |   22 +++++++++
>  drivers/gpu/drm/mediatek/mtk_drm_ddp.h  |    2 +
>  drivers/gpu/drm/mediatek/mtk_drm_drv.h  |    1 +
>  4 files changed, 71 insertions(+), 29 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> index 24aa3ba..80d9641 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> @@ -315,6 +315,42 @@ static void mtk_crtc_ddp_hw_fini(struct mtk_drm_crtc *mtk_crtc)
>  	pm_runtime_put(drm->dev);
>  }
>  
> +static void mtk_crtc_ddp_config(struct drm_crtc *crtc)
> +{
> +	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
> +	struct mtk_crtc_state *state = to_mtk_crtc_state(mtk_crtc->base.state);
> +	struct mtk_ddp_comp *ovl = mtk_crtc->ddp_comp[0];
> +	unsigned int i;
> +
> +	/*
> +	 * TODO: instead of updating the registers here, we should prepare
> +	 * working registers in atomic_commit and let the hardware command
> +	 * queue update module registers on vblank.
> +	 */
> +	if (state->pending_config) {
> +		mtk_ddp_comp_config(ovl, state->pending_width,
> +				    state->pending_height,
> +				    state->pending_vrefresh);
> +
> +		state->pending_config = false;
> +	}
> +
> +	if (mtk_crtc->pending_planes) {
> +		for (i = 0; i < OVL_LAYER_NR; i++) {
> +			struct drm_plane *plane = &mtk_crtc->planes[i].base;
> +			struct mtk_plane_state *plane_state;
> +
> +			plane_state = to_mtk_plane_state(plane->state);
> +
> +			if (plane_state->pending.config) {
> +				mtk_ddp_comp_layer_config(ovl, i, plane_state);
> +				plane_state->pending.config = false;
> +			}
> +		}
> +		mtk_crtc->pending_planes = false;
> +	}
> +}
> +
>  static void mtk_drm_crtc_enable(struct drm_crtc *crtc)
>  {
>  	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
> @@ -391,6 +427,7 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
>  				      struct drm_crtc_state *old_crtc_state)
>  {
>  	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
> +	struct mtk_drm_private *priv = crtc->dev->dev_private;
>  	unsigned int pending_planes = 0;
>  	int i;
>  
> @@ -409,6 +446,12 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
>  	}
>  	if (pending_planes)
>  		mtk_crtc->pending_planes = true;
> +
> +	if (priv->data->shadow_register) {
> +		mtk_disp_mutex_acquire(mtk_crtc->mutex);
> +		mtk_crtc_ddp_config(crtc);
> +		mtk_disp_mutex_release(mtk_crtc->mutex);
> +	}
>  }
>  
>  static const struct drm_crtc_funcs mtk_crtc_funcs = {
> @@ -453,36 +496,10 @@ err_cleanup_crtc:
>  void mtk_crtc_ddp_irq(struct drm_crtc *crtc, struct mtk_ddp_comp *ovl)
>  {
>  	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
> -	struct mtk_crtc_state *state = to_mtk_crtc_state(mtk_crtc->base.state);
> -	unsigned int i;
> +	struct mtk_drm_private *priv = crtc->dev->dev_private;
>  
> -	/*
> -	 * TODO: instead of updating the registers here, we should prepare
> -	 * working registers in atomic_commit and let the hardware command
> -	 * queue update module registers on vblank.
> -	 */
> -	if (state->pending_config) {
> -		mtk_ddp_comp_config(ovl, state->pending_width,
> -				    state->pending_height,
> -				    state->pending_vrefresh);
> -
> -		state->pending_config = false;
> -	}
> -
> -	if (mtk_crtc->pending_planes) {
> -		for (i = 0; i < OVL_LAYER_NR; i++) {
> -			struct drm_plane *plane = &mtk_crtc->planes[i].base;
> -			struct mtk_plane_state *plane_state;
> -
> -			plane_state = to_mtk_plane_state(plane->state);
> -
> -			if (plane_state->pending.config) {
> -				mtk_ddp_comp_layer_config(ovl, i, plane_state);
> -				plane_state->pending.config = false;
> -			}
> -		}
> -		mtk_crtc->pending_planes = false;
> -	}
> +	if (!priv->data->shadow_register)
> +		mtk_crtc_ddp_config(crtc);
>  
>  	mtk_drm_finish_page_flip(mtk_crtc);
>  }
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
> index 8030769..fa53806 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
> @@ -12,6 +12,7 @@
>   */
>  
>  #include <linux/clk.h>
> +#include <linux/iopoll.h>
>  #include <linux/module.h>
>  #include <linux/of_device.h>
>  #include <linux/platform_device.h>
> @@ -32,6 +33,7 @@
>  #define DISP_REG_CONFIG_MMSYS_CG_CON0		0x100
>  
>  #define DISP_REG_MUTEX_EN(n)	(0x20 + 0x20 * (n))
> +#define DISP_REG_MUTEX(n)	(0x24 + 0x20 * (n))
>  #define DISP_REG_MUTEX_RST(n)	(0x28 + 0x20 * (n))
>  #define DISP_REG_MUTEX_MOD(n)	(0x2c + 0x20 * (n))
>  #define DISP_REG_MUTEX_SOF(n)	(0x30 + 0x20 * (n))
> @@ -300,6 +302,26 @@ void mtk_disp_mutex_disable(struct mtk_disp_mutex *mutex)
>  	writel(0, ddp->regs + DISP_REG_MUTEX_EN(mutex->id));
>  }
>  
> +void mtk_disp_mutex_acquire(struct mtk_disp_mutex *mutex)
> +{
> +	struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
> +					   mutex[mutex->id]);
> +	u32 tmp;
> +
> +	writel(1, ddp->regs + DISP_REG_MUTEX_EN(mutex->id));
> +	writel(1, ddp->regs + DISP_REG_MUTEX(mutex->id));
> +	readl_poll_timeout_atomic(ddp->regs + DISP_REG_MUTEX(mutex->id), tmp,
> +				  tmp & 0x2, 1, 10000);

Nothing to do with timeout? I think it should print error message here
or reset HW to recover it.

> +}
> +
> +void mtk_disp_mutex_release(struct mtk_disp_mutex *mutex)
> +{
> +	struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
> +					   mutex[mutex->id]);
> +
> +	writel(0, ddp->regs + DISP_REG_MUTEX(mutex->id));
> +}
> +
>  static int mtk_ddp_probe(struct platform_device *pdev)
>  {
>  	struct device *dev = &pdev->dev;
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp.h
> index 92c1175..f9a7991 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.h
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.h
> @@ -37,5 +37,7 @@ void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex,
>  				enum mtk_ddp_comp_id id);
>  void mtk_disp_mutex_unprepare(struct mtk_disp_mutex *mutex);
>  void mtk_disp_mutex_put(struct mtk_disp_mutex *mutex);
> +void mtk_disp_mutex_acquire(struct mtk_disp_mutex *mutex);
> +void mtk_disp_mutex_release(struct mtk_disp_mutex *mutex);
>  
>  #endif /* MTK_DRM_DDP_H */
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
> index fa0b106..94f8b66 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
> @@ -33,6 +33,7 @@ struct mtk_mmsys_driver_data {
>  	unsigned int main_len;
>  	const enum mtk_ddp_comp_id *ext_path;
>  	unsigned int ext_len;
> +	bool shadow_register;
>  };
>  
>  struct mtk_drm_private {




From ck.hu at mediatek.com  Sun Jul 17 23:58:53 2016
From: ck.hu at mediatek.com (CK Hu)
Date: Mon, 18 Jul 2016 14:58:53 +0800
Subject: [PATCH v4 4/8] drm/mediatek: add support for Mediatek SoC MT2701
In-Reply-To: <1468577274-6178-5-git-send-email-yt.shen@mediatek.com>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
 <1468577274-6178-5-git-send-email-yt.shen@mediatek.com>
Message-ID: <1468825133.30644.41.camel@mtksdaap41>

Hi, YT:

One comment inline.

On Fri, 2016-07-15 at 18:07 +0800, YT Shen wrote:
> This patch add support for the Mediatek MT2701 DISP subsystem.
> There is only one OVL engine in MT2701.
> 
> Signed-off-by: YT Shen <yt.shen at mediatek.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_disp_ovl.c     |    6 ++++
>  drivers/gpu/drm/mediatek/mtk_disp_rdma.c    |    6 ++++
>  drivers/gpu/drm/mediatek/mtk_drm_ddp.c      |   41 +++++++++++++++++++++++++++
>  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |    7 +++++
>  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |    1 +
>  drivers/gpu/drm/mediatek/mtk_drm_drv.c      |   31 ++++++++++++++++++++
>  6 files changed, 92 insertions(+)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> index eb5c05e..1da0a71 100644
> --- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> @@ -286,11 +286,17 @@ static int mtk_disp_ovl_remove(struct platform_device *pdev)
>  	return 0;
>  }
>  
> +static const struct mtk_ddp_comp_driver_data mt2701_ovl_driver_data = {
> +	.ovl = {0x0040, 1 << 12, 0}
> +};
> +
>  static const struct mtk_ddp_comp_driver_data mt8173_ovl_driver_data = {
>  	.ovl = {0x0f40, 0, 1 << 12}
>  };
>  
>  static const struct of_device_id mtk_disp_ovl_driver_dt_match[] = {
> +	{ .compatible = "mediatek,mt2701-disp-ovl",
> +	  .data = &mt2701_ovl_driver_data},
>  	{ .compatible = "mediatek,mt8173-disp-ovl",
>  	  .data = &mt8173_ovl_driver_data},
>  	{},
> diff --git a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
> index fb0db50..506a353 100644
> --- a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
> +++ b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
> @@ -225,11 +225,17 @@ static int mtk_disp_rdma_remove(struct platform_device *pdev)
>  	return 0;
>  }
>  
> +static const struct mtk_ddp_comp_driver_data mt2701_rdma_driver_data = {
> +	.rdma_fifo_pseudo_size = SZ_4K,
> +};
> +
>  static const struct mtk_ddp_comp_driver_data mt8173_rdma_driver_data = {
>  	.rdma_fifo_pseudo_size = SZ_8K,
>  };
>  
>  static const struct of_device_id mtk_disp_rdma_driver_dt_match[] = {
> +	{ .compatible = "mediatek,mt2701-disp-rdma",
> +	  .data = &mt2701_rdma_driver_data},
>  	{ .compatible = "mediatek,mt8173-disp-rdma",
>  	  .data = &mt8173_rdma_driver_data},
>  	{},
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
> index fa53806..ee0326a 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
> @@ -32,6 +32,10 @@
>  #define DISP_REG_CONFIG_DISP_RDMA1_MOUT_EN	0x0c8
>  #define DISP_REG_CONFIG_MMSYS_CG_CON0		0x100
>  
> +#define DISP_REG_CONFIG_DISP_OVL_MOUT_EN	0x030
> +#define DISP_REG_CONFIG_OUT_SEL			0x04c
> +#define DISP_REG_CONFIG_DSI_SEL			0x050
> +
>  #define DISP_REG_MUTEX_EN(n)	(0x20 + 0x20 * (n))
>  #define DISP_REG_MUTEX(n)	(0x24 + 0x20 * (n))
>  #define DISP_REG_MUTEX_RST(n)	(0x28 + 0x20 * (n))
> @@ -54,6 +58,13 @@
>  #define MT8173_MUTEX_MOD_DISP_PWM1		BIT(24)
>  #define MT8173_MUTEX_MOD_DISP_OD		BIT(25)
>  
> +#define MT2701_MUTEX_MOD_DISP_OVL		BIT(3)
> +#define MT2701_MUTEX_MOD_DISP_WDMA		BIT(6)
> +#define MT2701_MUTEX_MOD_DISP_COLOR		BIT(7)
> +#define MT2701_MUTEX_MOD_DISP_BLS		BIT(9)
> +#define MT2701_MUTEX_MOD_DISP_RDMA0		BIT(10)
> +#define MT2701_MUTEX_MOD_DISP_RDMA1		BIT(12)
> +
>  #define MUTEX_SOF_SINGLE_MODE		0
>  #define MUTEX_SOF_DSI0			1
>  #define MUTEX_SOF_DSI1			2
> @@ -69,6 +80,10 @@
>  #define DPI0_SEL_IN_RDMA1		0x1
>  #define COLOR1_SEL_IN_OVL1		0x1
>  
> +#define OVL_MOUT_EN_RDMA		0x1
> +#define BLS_TO_DSI_RDMA1_TO_DPI1	0x8
> +#define DSI_SEL_IN_BLS			0x0
> +
>  struct mtk_disp_mutex {
>  	int id;
>  	bool claimed;
> @@ -82,6 +97,15 @@ struct mtk_ddp {
>  	const unsigned int		*mutex_mod;
>  };
>  
> +static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = {
> +	[DDP_COMPONENT_BLS] = MT2701_MUTEX_MOD_DISP_BLS,
> +	[DDP_COMPONENT_COLOR0] = MT2701_MUTEX_MOD_DISP_COLOR,
> +	[DDP_COMPONENT_OVL0] = MT2701_MUTEX_MOD_DISP_OVL,
> +	[DDP_COMPONENT_RDMA0] = MT2701_MUTEX_MOD_DISP_RDMA0,
> +	[DDP_COMPONENT_RDMA1] = MT2701_MUTEX_MOD_DISP_RDMA1,
> +	[DDP_COMPONENT_WDMA0] = MT2701_MUTEX_MOD_DISP_WDMA,
> +};
> +
>  static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = {
>  	[DDP_COMPONENT_AAL] = MT8173_MUTEX_MOD_DISP_AAL,
>  	[DDP_COMPONENT_COLOR0] = MT8173_MUTEX_MOD_DISP_COLOR0,
> @@ -109,6 +133,9 @@ static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur,
>  	if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_COLOR0) {
>  		*addr = DISP_REG_CONFIG_DISP_OVL0_MOUT_EN;
>  		value = OVL0_MOUT_EN_COLOR0;
> +	} else if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_RDMA0) {
> +		*addr = DISP_REG_CONFIG_DISP_OVL_MOUT_EN;
> +		value = OVL_MOUT_EN_RDMA;
>  	} else if (cur == DDP_COMPONENT_OD && next == DDP_COMPONENT_RDMA0) {
>  		*addr = DISP_REG_CONFIG_DISP_OD_MOUT_EN;
>  		value = OD_MOUT_EN_RDMA0;
> @@ -146,6 +173,9 @@ static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur,
>  	} else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) {
>  		*addr = DISP_REG_CONFIG_DISP_COLOR1_SEL_IN;
>  		value = COLOR1_SEL_IN_OVL1;
> +	} else if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0) {
> +		*addr = DISP_REG_CONFIG_DSI_SEL;
> +		value = DSI_SEL_IN_BLS;
>  	} else {
>  		value = 0;
>  	}
> @@ -153,6 +183,14 @@ static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur,
>  	return value;
>  }
>  
> +static void mtk_ddp_sout_sel(void __iomem *config_regs,
> +			    enum mtk_ddp_comp_id cur, enum mtk_ddp_comp_id next)
> +{
> +	if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0)
> +		writel_relaxed(BLS_TO_DSI_RDMA1_TO_DPI1,
> +			       config_regs + DISP_REG_CONFIG_OUT_SEL);
> +}

I think all the connection related modification should be an independent
patch because it is common code. Like the shadow register patch
(https://patchwork.kernel.org/patch/9231531/) , even MT8173 do not have
that feature, we still split it out of this patch because it's not
MT2701-only feature. I think these connection may happen in some MTK
soc., so the connection related modification should not be placed in a
MT2701 patch.

> +
>  void mtk_ddp_add_comp_to_path(void __iomem *config_regs,
>  			      enum mtk_ddp_comp_id cur,
>  			      enum mtk_ddp_comp_id next)
> @@ -165,6 +203,8 @@ void mtk_ddp_add_comp_to_path(void __iomem *config_regs,
>  		writel_relaxed(reg, config_regs + addr);
>  	}
>  
> +	mtk_ddp_sout_sel(config_regs, cur, next);
> +
>  	value = mtk_ddp_sel_in(cur, next, &addr);
>  	if (value) {
>  		reg = readl_relaxed(config_regs + addr) | value;
> @@ -362,6 +402,7 @@ static int mtk_ddp_remove(struct platform_device *pdev)
>  }
>  
>  static const struct of_device_id ddp_driver_dt_match[] = {
> +	{ .compatible = "mediatek,mt2701-disp-mutex", .data = mt2701_mutex_mod},
>  	{ .compatible = "mediatek,mt8173-disp-mutex", .data = mt8173_mutex_mod},
>  	{},
>  };
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
> index 4b4e449..465819b 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
> @@ -112,6 +112,7 @@ struct mtk_ddp_comp_match {
>  
>  static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
>  	[DDP_COMPONENT_AAL]	= { MTK_DISP_AAL,	0, NULL },
> +	[DDP_COMPONENT_BLS]	= { MTK_DISP_PWM,	0, NULL },
>  	[DDP_COMPONENT_COLOR0]	= { MTK_DISP_COLOR,	0, &ddp_color },
>  	[DDP_COMPONENT_COLOR1]	= { MTK_DISP_COLOR,	1, &ddp_color },
>  	[DDP_COMPONENT_DPI0]	= { MTK_DPI,		0, NULL },
> @@ -130,11 +131,17 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
>  	[DDP_COMPONENT_WDMA1]	= { MTK_DISP_WDMA,	1, NULL },
>  };
>  
> +static const struct mtk_ddp_comp_driver_data mt2701_color_driver_data = {
> +	.color_offset = 0x0f00,
> +};
> +
>  static const struct mtk_ddp_comp_driver_data mt8173_color_driver_data = {
>  	.color_offset = 0x0c00,
>  };
>  
>  static const struct of_device_id mtk_disp_color_driver_dt_match[] = {
> +	{ .compatible = "mediatek,mt2701-disp-color",
> +	  .data = &mt2701_color_driver_data},
>  	{ .compatible = "mediatek,mt8173-disp-color",
>  	  .data = &mt8173_color_driver_data},
>  	{},
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
> index 53065c7..0850aa4 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
> @@ -40,6 +40,7 @@ enum mtk_ddp_comp_type {
>  
>  enum mtk_ddp_comp_id {
>  	DDP_COMPONENT_AAL,
> +	DDP_COMPONENT_BLS,
>  	DDP_COMPONENT_COLOR0,
>  	DDP_COMPONENT_COLOR1,
>  	DDP_COMPONENT_DPI0,
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
> index 80b4f54..13cf160 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
> @@ -109,6 +109,19 @@ static const struct drm_mode_config_funcs mtk_drm_mode_config_funcs = {
>  	.atomic_commit = mtk_atomic_commit,
>  };
>  
> +static const enum mtk_ddp_comp_id mt2701_mtk_ddp_main[] = {
> +	DDP_COMPONENT_OVL0,
> +	DDP_COMPONENT_RDMA0,
> +	DDP_COMPONENT_COLOR0,
> +	DDP_COMPONENT_BLS,
> +	DDP_COMPONENT_DSI0,
> +};
> +
> +static const enum mtk_ddp_comp_id mt2701_mtk_ddp_ext[] = {
> +	DDP_COMPONENT_RDMA1,
> +	DDP_COMPONENT_DPI0,
> +};
> +
>  static const enum mtk_ddp_comp_id mt8173_mtk_ddp_main[] = {
>  	DDP_COMPONENT_OVL0,
>  	DDP_COMPONENT_COLOR0,
> @@ -128,6 +141,14 @@ static const enum mtk_ddp_comp_id mt8173_mtk_ddp_ext[] = {
>  	DDP_COMPONENT_DPI0,
>  };
>  
> +static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = {
> +	.main_path = mt2701_mtk_ddp_main,
> +	.main_len = ARRAY_SIZE(mt2701_mtk_ddp_main),
> +	.ext_path = mt2701_mtk_ddp_ext,
> +	.ext_len = ARRAY_SIZE(mt2701_mtk_ddp_ext),
> +	.shadow_register = true,
> +};
> +
>  static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = {
>  	.main_path = mt8173_mtk_ddp_main,
>  	.main_len = ARRAY_SIZE(mt8173_mtk_ddp_main),
> @@ -331,16 +352,24 @@ static const struct component_master_ops mtk_drm_ops = {
>  };
>  
>  static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
> +	{ .compatible = "mediatek,mt2701-disp-ovl",   .data = (void *)MTK_DISP_OVL },
>  	{ .compatible = "mediatek,mt8173-disp-ovl",   .data = (void *)MTK_DISP_OVL },
> +	{ .compatible = "mediatek,mt2701-disp-rdma",  .data = (void *)MTK_DISP_RDMA },
>  	{ .compatible = "mediatek,mt8173-disp-rdma",  .data = (void *)MTK_DISP_RDMA },
> +	{ .compatible = "mediatek,mt2701-disp-wdma",  .data = (void *)MTK_DISP_WDMA },
>  	{ .compatible = "mediatek,mt8173-disp-wdma",  .data = (void *)MTK_DISP_WDMA },
> +	{ .compatible = "mediatek,mt2701-disp-color", .data = (void *)MTK_DISP_COLOR },
>  	{ .compatible = "mediatek,mt8173-disp-color", .data = (void *)MTK_DISP_COLOR },
>  	{ .compatible = "mediatek,mt8173-disp-aal",   .data = (void *)MTK_DISP_AAL},
>  	{ .compatible = "mediatek,mt8173-disp-gamma", .data = (void *)MTK_DISP_GAMMA, },
>  	{ .compatible = "mediatek,mt8173-disp-ufoe",  .data = (void *)MTK_DISP_UFOE },
> +	{ .compatible = "mediatek,mt2701-dsi",	      .data = (void *)MTK_DSI },
>  	{ .compatible = "mediatek,mt8173-dsi",        .data = (void *)MTK_DSI },
> +	{ .compatible = "mediatek,mt2701-dpi",	      .data = (void *)MTK_DPI },
>  	{ .compatible = "mediatek,mt8173-dpi",        .data = (void *)MTK_DPI },
> +	{ .compatible = "mediatek,mt2701-disp-mutex", .data = (void *)MTK_DISP_MUTEX },
>  	{ .compatible = "mediatek,mt8173-disp-mutex", .data = (void *)MTK_DISP_MUTEX },
> +	{ .compatible = "mediatek,mt2701-disp-pwm",   .data = (void *)MTK_DISP_PWM },
>  	{ .compatible = "mediatek,mt8173-disp-pwm",   .data = (void *)MTK_DISP_PWM },
>  	{ .compatible = "mediatek,mt8173-disp-od",    .data = (void *)MTK_DISP_OD },
>  	{ }
> @@ -514,6 +543,8 @@ static SIMPLE_DEV_PM_OPS(mtk_drm_pm_ops, mtk_drm_sys_suspend,
>  			 mtk_drm_sys_resume);
>  
>  static const struct of_device_id mtk_drm_of_ids[] = {
> +	{ .compatible = "mediatek,mt2701-mmsys",
> +	  .data = &mt2701_mmsys_driver_data},
>  	{ .compatible = "mediatek,mt8173-mmsys",
>  	  .data = &mt8173_mmsys_driver_data},
>  	{ }




From p.zabel at pengutronix.de  Mon Jul 18 01:36:32 2016
From: p.zabel at pengutronix.de (Philipp Zabel)
Date: Mon, 18 Jul 2016 10:36:32 +0200
Subject: [PATCH v4 3/8] drm/mediatek: add shadow register support
In-Reply-To: <1468823575.30644.33.camel@mtksdaap41>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
 <1468577274-6178-4-git-send-email-yt.shen@mediatek.com>
 <1468823575.30644.33.camel@mtksdaap41>
Message-ID: <1468830992.2994.6.camel@pengutronix.de>

Hi CK, YT,

Am Montag, den 18.07.2016, 14:32 +0800 schrieb CK Hu:
> Hi, YT:
> 
> One comment inline.
> 
> 
> On Fri, 2016-07-15 at 18:07 +0800, YT Shen wrote:
> > We need to acquire mutex before using the resources,
> > and need to release it after finished.
> > So we don't need to write registers in the blanking period.
> > 
> > Signed-off-by: YT Shen <yt.shen at mediatek.com>
> > ---
> >  drivers/gpu/drm/mediatek/mtk_drm_crtc.c |   75 +++++++++++++++++++------------
> >  drivers/gpu/drm/mediatek/mtk_drm_ddp.c  |   22 +++++++++
> >  drivers/gpu/drm/mediatek/mtk_drm_ddp.h  |    2 +
> >  drivers/gpu/drm/mediatek/mtk_drm_drv.h  |    1 +
> >  4 files changed, 71 insertions(+), 29 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> > index 24aa3ba..80d9641 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> > @@ -315,6 +315,42 @@ static void mtk_crtc_ddp_hw_fini(struct mtk_drm_crtc *mtk_crtc)
> >  	pm_runtime_put(drm->dev);
> >  }
> >  
> > +static void mtk_crtc_ddp_config(struct drm_crtc *crtc)
> > +{
> > +	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
> > +	struct mtk_crtc_state *state = to_mtk_crtc_state(mtk_crtc->base.state);
> > +	struct mtk_ddp_comp *ovl = mtk_crtc->ddp_comp[0];
> > +	unsigned int i;
> > +
> > +	/*
> > +	 * TODO: instead of updating the registers here, we should prepare
> > +	 * working registers in atomic_commit and let the hardware command
> > +	 * queue update module registers on vblank.
> > +	 */
> > +	if (state->pending_config) {
> > +		mtk_ddp_comp_config(ovl, state->pending_width,
> > +				    state->pending_height,
> > +				    state->pending_vrefresh);
> > +
> > +		state->pending_config = false;
> > +	}
> > +
> > +	if (mtk_crtc->pending_planes) {
> > +		for (i = 0; i < OVL_LAYER_NR; i++) {
> > +			struct drm_plane *plane = &mtk_crtc->planes[i].base;
> > +			struct mtk_plane_state *plane_state;
> > +
> > +			plane_state = to_mtk_plane_state(plane->state);
> > +
> > +			if (plane_state->pending.config) {
> > +				mtk_ddp_comp_layer_config(ovl, i, plane_state);
> > +				plane_state->pending.config = false;
> > +			}
> > +		}
> > +		mtk_crtc->pending_planes = false;
> > +	}
> > +}
> > +
> >  static void mtk_drm_crtc_enable(struct drm_crtc *crtc)
> >  {
> >  	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
> > @@ -391,6 +427,7 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
> >  				      struct drm_crtc_state *old_crtc_state)
> >  {
> >  	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
> > +	struct mtk_drm_private *priv = crtc->dev->dev_private;
> >  	unsigned int pending_planes = 0;
> >  	int i;
> >  
> > @@ -409,6 +446,12 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
> >  	}
> >  	if (pending_planes)
> >  		mtk_crtc->pending_planes = true;
> > +
> > +	if (priv->data->shadow_register) {
> > +		mtk_disp_mutex_acquire(mtk_crtc->mutex);
> > +		mtk_crtc_ddp_config(crtc);
> > +		mtk_disp_mutex_release(mtk_crtc->mutex);
> > +	}
> >  }
> >  
> >  static const struct drm_crtc_funcs mtk_crtc_funcs = {
> > @@ -453,36 +496,10 @@ err_cleanup_crtc:
> >  void mtk_crtc_ddp_irq(struct drm_crtc *crtc, struct mtk_ddp_comp *ovl)
> >  {
> >  	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
> > -	struct mtk_crtc_state *state = to_mtk_crtc_state(mtk_crtc->base.state);
> > -	unsigned int i;
> > +	struct mtk_drm_private *priv = crtc->dev->dev_private;
> >  
> > -	/*
> > -	 * TODO: instead of updating the registers here, we should prepare
> > -	 * working registers in atomic_commit and let the hardware command
> > -	 * queue update module registers on vblank.
> > -	 */
> > -	if (state->pending_config) {
> > -		mtk_ddp_comp_config(ovl, state->pending_width,
> > -				    state->pending_height,
> > -				    state->pending_vrefresh);
> > -
> > -		state->pending_config = false;
> > -	}
> > -
> > -	if (mtk_crtc->pending_planes) {
> > -		for (i = 0; i < OVL_LAYER_NR; i++) {
> > -			struct drm_plane *plane = &mtk_crtc->planes[i].base;
> > -			struct mtk_plane_state *plane_state;
> > -
> > -			plane_state = to_mtk_plane_state(plane->state);
> > -
> > -			if (plane_state->pending.config) {
> > -				mtk_ddp_comp_layer_config(ovl, i, plane_state);
> > -				plane_state->pending.config = false;
> > -			}
> > -		}
> > -		mtk_crtc->pending_planes = false;
> > -	}
> > +	if (!priv->data->shadow_register)
> > +		mtk_crtc_ddp_config(crtc);
> >  
> >  	mtk_drm_finish_page_flip(mtk_crtc);
> >  }
> > diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
> > index 8030769..fa53806 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
> > @@ -12,6 +12,7 @@
> >   */
> >  
> >  #include <linux/clk.h>
> > +#include <linux/iopoll.h>
> >  #include <linux/module.h>
> >  #include <linux/of_device.h>
> >  #include <linux/platform_device.h>
> > @@ -32,6 +33,7 @@
> >  #define DISP_REG_CONFIG_MMSYS_CG_CON0		0x100
> >  
> >  #define DISP_REG_MUTEX_EN(n)	(0x20 + 0x20 * (n))
> > +#define DISP_REG_MUTEX(n)	(0x24 + 0x20 * (n))
> >  #define DISP_REG_MUTEX_RST(n)	(0x28 + 0x20 * (n))
> >  #define DISP_REG_MUTEX_MOD(n)	(0x2c + 0x20 * (n))
> >  #define DISP_REG_MUTEX_SOF(n)	(0x30 + 0x20 * (n))
> > @@ -300,6 +302,26 @@ void mtk_disp_mutex_disable(struct mtk_disp_mutex *mutex)
> >  	writel(0, ddp->regs + DISP_REG_MUTEX_EN(mutex->id));
> >  }
> >  
> > +void mtk_disp_mutex_acquire(struct mtk_disp_mutex *mutex)
> > +{
> > +	struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
> > +					   mutex[mutex->id]);
> > +	u32 tmp;
> > +
> > +	writel(1, ddp->regs + DISP_REG_MUTEX_EN(mutex->id));
> > +	writel(1, ddp->regs + DISP_REG_MUTEX(mutex->id));
> > +	readl_poll_timeout_atomic(ddp->regs + DISP_REG_MUTEX(mutex->id), tmp,
> > +				  tmp & 0x2, 1, 10000);

Please add a descriptive #define for the 0x2 bit of the DISP_REG_MUTEX
registers.

> Nothing to do with timeout? I think it should print error message here
> or reset HW to recover it.

I assume that if mtk_disp_mutex_acquire is called while the hardware has
the mutex (during the shadow register update), this should wait until
the update is complete, since it can't back out from trying to acquire
the lock. Is that the case?

regards
Philipp



From john at phrozen.org  Mon Jul 18 05:09:00 2016
From: john at phrozen.org (John Crispin)
Date: Mon, 18 Jul 2016 14:09:00 +0200
Subject: [PATCH V9 1/2] regulator: Add document for MT6323 regulator
Message-ID: <1468843741-59637-1-git-send-email-john@phrozen.org>

From: John Crispin <blogic at openwrt.org>

Signed-off-by: John Crispin <blogic at openwrt.org>
Cc: devicetree at vger.kernel.org
Acked-by: Rob Herring <robh at kernel.org>
---
Changes in V9
* drop compatible string from devicetree

Changes in V7
* remove another compatible string
* small wording changes

Changes in V6
* remove the compatible string

Changes in V5
* regulator vs regulators

Changes in V4
* regulator is a subnode and not a property

 .../bindings/regulator/mt6323-regulator.txt        |  239 ++++++++++++++++++++
 1 file changed, 239 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/regulator/mt6323-regulator.txt

diff --git a/Documentation/devicetree/bindings/regulator/mt6323-regulator.txt b/Documentation/devicetree/bindings/regulator/mt6323-regulator.txt
new file mode 100644
index 0000000..9fd95e7
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/mt6323-regulator.txt
@@ -0,0 +1,239 @@
+Mediatek MT6323 Regulator Driver
+
+All voltage regulators are defined as subnodes of the regulators node. A list
+of regulators provided by this controller are defined as subnodes of the
+PMIC's node. Each regulator is named according to its regulator type,
+buck_<name> and ldo_<name>. The definition for each of these nodes is defined
+using the standard binding for regulators at
+Documentation/devicetree/bindings/regulator/regulator.txt.
+
+The valid names for regulators are::
+BUCK:
+  buck_vproc, buck_vsys, buck_vpa
+LDO:
+  ldo_vtcxo, ldo_vcn28, ldo_vcn33_bt, ldo_vcn33_wifi, ldo_va, ldo_vcama,
+  ldo_vio28, ldo_vusb, ldo_vmc, ldo_vmch, ldo_vemc3v3, ldo_vgp1, ldo_vgp2,
+  ldo_vgp3, ldo_vcn18, ldo_vsim1, ldo_vsim2, ldo_vrtc, ldo_vcamaf, ldo_vibr,
+  ldo_vrf18, ldo_vm, ldo_vio18, ldo_vcamd, ldo_vcamio
+
+Example:
+
+	pmic: mt6323 {
+		compatible = "mediatek,mt6323";
+
+		mt6323regulator: regulators {
+			mt6323_vproc_reg: buck_vproc{
+				regulator-name = "vproc";
+				regulator-min-microvolt = < 700000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-ramp-delay = <12500>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vsys_reg: buck_vsys{
+				regulator-name = "vsys";
+				regulator-min-microvolt = <1400000>;
+				regulator-max-microvolt = <2987500>;
+				regulator-ramp-delay = <25000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vpa_reg: buck_vpa{
+				regulator-name = "vpa";
+				regulator-min-microvolt = < 500000>;
+				regulator-max-microvolt = <3650000>;
+			};
+
+			mt6323_vtcxo_reg: ldo_vtcxo{
+				regulator-name = "vtcxo";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <90>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vcn28_reg: ldo_vcn28{
+				regulator-name = "vcn28";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <185>;
+			};
+
+			mt6323_vcn33_bt_reg: ldo_vcn33_bt{
+				regulator-name = "vcn33_bt";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3600000>;
+				regulator-enable-ramp-delay = <185>;
+			};
+
+			mt6323_vcn33_wifi_reg: ldo_vcn33_wifi{
+				regulator-name = "vcn33_wifi";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3600000>;
+				regulator-enable-ramp-delay = <185>;
+			};
+
+			mt6323_va_reg: ldo_va{
+				regulator-name = "va";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vcama_reg: ldo_vcama{
+				regulator-name = "vcama";
+				regulator-min-microvolt = <1500000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vio28_reg: ldo_vio28{
+				regulator-name = "vio28";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vusb_reg: ldo_vusb{
+				regulator-name = "vusb";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-boot-on;
+			};
+
+			mt6323_vmc_reg: ldo_vmc{
+				regulator-name = "vmc";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <36>;
+				regulator-boot-on;
+			};
+
+			mt6323_vmch_reg: ldo_vmch{
+				regulator-name = "vmch";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <36>;
+				regulator-boot-on;
+			};
+
+			mt6323_vemc3v3_reg: ldo_vemc3v3{
+				regulator-name = "vemc3v3";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <36>;
+				regulator-boot-on;
+			};
+
+			mt6323_vgp1_reg: ldo_vgp1{
+				regulator-name = "vgp1";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vgp2_reg: ldo_vgp2{
+				regulator-name = "vgp2";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vgp3_reg: ldo_vgp3{
+				regulator-name = "vgp3";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vcn18_reg: ldo_vcn18{
+				regulator-name = "vcn18";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vsim1_reg: ldo_vsim1{
+				regulator-name = "vsim1";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vsim2_reg: ldo_vsim2{
+				regulator-name = "vsim2";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vrtc_reg: ldo_vrtc{
+				regulator-name = "vrtc";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vcamaf_reg: ldo_vcamaf{
+				regulator-name = "vcamaf";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vibr_reg: ldo_vibr{
+				regulator-name = "vibr";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <36>;
+			};
+
+			mt6323_vrf18_reg: ldo_vrf18{
+				regulator-name = "vrf18";
+				regulator-min-microvolt = <1825000>;
+				regulator-max-microvolt = <1825000>;
+				regulator-enable-ramp-delay = <187>;
+			};
+
+			mt6323_vm_reg: ldo_vm{
+				regulator-name = "vm";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vio18_reg: ldo_vio18{
+				regulator-name = "vio18";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vcamd_reg: ldo_vcamd{
+				regulator-name = "vcamd";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vcamio_reg: ldo_vcamio{
+				regulator-name = "vcamio";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+		};
+	};
-- 
1.7.10.4



From john at phrozen.org  Mon Jul 18 05:09:01 2016
From: john at phrozen.org (John Crispin)
Date: Mon, 18 Jul 2016 14:09:01 +0200
Subject: [PATCH V9 2/2] regulator: mt6323: Add support for MT6323 regulator
In-Reply-To: <1468843741-59637-1-git-send-email-john@phrozen.org>
References: <1468843741-59637-1-git-send-email-john@phrozen.org>
Message-ID: <1468843741-59637-2-git-send-email-john@phrozen.org>

From: Chen Zhong <chen.zhong at mediatek.com>

The MT6323 is a regulator found on boards based on MediaTek MT7623 and
probably other SoCs. It is a so called pmic and connects as a slave to
SoC using SPI, wrapped inside the pmic-wrapper.

Signed-off-by: Chen Zhong <chen.zhong at mediatek.com>
Signed-off-by: John Crispin <blogic at openwrt.org>
---
This series was dropped from the v4.7 queue to avoid a merge conflict with
the series adding mt6323 support to the MFD driver. These patches were
merged during the v4.7 window, so this series is good to go for v4.8. The
relevant started with
commit feec4799ac4d ("mfd: mt6397: int_con and int_status may vary ...")
through to
commit 44760cf3bf0a ("mfd: mt6397: Add MT6323 support to MT6397 driver")

Changes in V9
* drop compatible string from devicetree

Changes in V6
* add back the set/get mode callbacks

Changes in V5
* remove the code that modifies constraints
* remove the code allows mode changes

Changes in V4:
* add id_table and of_match_table
* use short GPL text
* change MODULE_LICENSE to GPL V2

Changes in V2:
* send to the the proper maintainer

 drivers/regulator/Kconfig                  |    9 +
 drivers/regulator/Makefile                 |    1 +
 drivers/regulator/mt6323-regulator.c       |  432 ++++++++++++++++++++++++++++
 include/linux/regulator/mt6323-regulator.h |   52 ++++
 4 files changed, 494 insertions(+)
 create mode 100644 drivers/regulator/mt6323-regulator.c
 create mode 100644 include/linux/regulator/mt6323-regulator.h

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index ae9cbd6..6c88e31 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -498,6 +498,15 @@ config REGULATOR_MT6311
 	  This driver supports the control of different power rails of device
 	  through regulator interface.
 
+config REGULATOR_MT6323
+	tristate "MediaTek MT6323 PMIC"
+	depends on MFD_MT6397
+	help
+	  Say y here to select this option to enable the power regulator of
+	  MediaTek MT6323 PMIC.
+	  This driver supports the control of different power rails of device
+	  through regulator interface.
+
 config REGULATOR_MT6397
 	tristate "MediaTek MT6397 PMIC"
 	depends on MFD_MT6397
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 85a1d44..f3da9ee 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -65,6 +65,7 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
 obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
 obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
 obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
+obj-$(CONFIG_REGULATOR_MT6323)	+= mt6323-regulator.o
 obj-$(CONFIG_REGULATOR_MT6397)	+= mt6397-regulator.o
 obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
 obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
diff --git a/drivers/regulator/mt6323-regulator.c b/drivers/regulator/mt6323-regulator.c
new file mode 100644
index 0000000..28ebbda
--- /dev/null
+++ b/drivers/regulator/mt6323-regulator.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Chen Zhong <chen.zhong at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/mt6397/core.h>
+#include <linux/mfd/mt6323/registers.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/mt6323-regulator.h>
+#include <linux/regulator/of_regulator.h>
+
+#define MT6323_LDO_MODE_NORMAL	0
+#define MT6323_LDO_MODE_LP	1
+
+/*
+ * MT6323 regulators' information
+ *
+ * @desc: standard fields of regulator description.
+ * @qi: Mask for query enable signal status of regulators
+ * @vselon_reg: Register sections for hardware control mode of bucks
+ * @vselctrl_reg: Register for controlling the buck control mode.
+ * @vselctrl_mask: Mask for query buck's voltage control mode.
+ */
+struct mt6323_regulator_info {
+	struct regulator_desc desc;
+	u32 qi;
+	u32 vselon_reg;
+	u32 vselctrl_reg;
+	u32 vselctrl_mask;
+	u32 modeset_reg;
+	u32 modeset_mask;
+};
+
+#define MT6323_BUCK(match, vreg, min, max, step, volt_ranges, enreg,	\
+		vosel, vosel_mask, voselon, vosel_ctrl)			\
+[MT6323_ID_##vreg] = {							\
+	.desc = {							\
+		.name = #vreg,						\
+		.of_match = of_match_ptr(match),			\
+		.ops = &mt6323_volt_range_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6323_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = (max - min)/step + 1,			\
+		.linear_ranges = volt_ranges,				\
+		.n_linear_ranges = ARRAY_SIZE(volt_ranges),		\
+		.vsel_reg = vosel,					\
+		.vsel_mask = vosel_mask,				\
+		.enable_reg = enreg,					\
+		.enable_mask = BIT(0),					\
+	},								\
+	.qi = BIT(13),							\
+	.vselon_reg = voselon,						\
+	.vselctrl_reg = vosel_ctrl,					\
+	.vselctrl_mask = BIT(1),					\
+}
+
+#define MT6323_LDO(match, vreg, ldo_volt_table, enreg, enbit, vosel,	\
+		vosel_mask, _modeset_reg, _modeset_mask)		\
+[MT6323_ID_##vreg] = {							\
+	.desc = {							\
+		.name = #vreg,						\
+		.of_match = of_match_ptr(match),			\
+		.ops = &mt6323_volt_table_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6323_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = ARRAY_SIZE(ldo_volt_table),		\
+		.volt_table = ldo_volt_table,				\
+		.vsel_reg = vosel,					\
+		.vsel_mask = vosel_mask,				\
+		.enable_reg = enreg,					\
+		.enable_mask = BIT(enbit),				\
+	},								\
+	.qi = BIT(15),							\
+	.modeset_reg = _modeset_reg,					\
+	.modeset_mask = _modeset_mask,					\
+}
+
+#define MT6323_REG_FIXED(match, vreg, enreg, enbit, volt,		\
+		_modeset_reg, _modeset_mask)				\
+[MT6323_ID_##vreg] = {							\
+	.desc = {							\
+		.name = #vreg,						\
+		.of_match = of_match_ptr(match),			\
+		.ops = &mt6323_volt_fixed_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6323_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = 1,					\
+		.enable_reg = enreg,					\
+		.enable_mask = BIT(enbit),				\
+		.min_uV = volt,						\
+	},								\
+	.qi = BIT(15),							\
+	.modeset_reg = _modeset_reg,					\
+	.modeset_mask = _modeset_mask,					\
+}
+
+static const struct regulator_linear_range buck_volt_range1[] = {
+	REGULATOR_LINEAR_RANGE(700000, 0, 0x7f, 6250),
+};
+
+static const struct regulator_linear_range buck_volt_range2[] = {
+	REGULATOR_LINEAR_RANGE(1400000, 0, 0x7f, 12500),
+};
+
+static const struct regulator_linear_range buck_volt_range3[] = {
+	REGULATOR_LINEAR_RANGE(500000, 0, 0x3f, 50000),
+};
+
+static const u32 ldo_volt_table1[] = {
+	3300000, 3400000, 3500000, 3600000,
+};
+
+static const u32 ldo_volt_table2[] = {
+	1500000, 1800000, 2500000, 2800000,
+};
+
+static const u32 ldo_volt_table3[] = {
+	1800000, 3300000,
+};
+
+static const u32 ldo_volt_table4[] = {
+	3000000, 3300000,
+};
+
+static const u32 ldo_volt_table5[] = {
+	1200000, 1300000, 1500000, 1800000, 2000000, 2800000, 3000000, 3300000,
+};
+
+static const u32 ldo_volt_table6[] = {
+	1200000, 1300000, 1500000, 1800000, 2500000, 2800000, 3000000, 2000000,
+};
+
+static const u32 ldo_volt_table7[] = {
+	1200000, 1300000, 1500000, 1800000,
+};
+
+static const u32 ldo_volt_table8[] = {
+	1800000, 3000000,
+};
+
+static const u32 ldo_volt_table9[] = {
+	1200000, 1350000, 1500000, 1800000,
+};
+
+static const u32 ldo_volt_table10[] = {
+	1200000, 1300000, 1500000, 1800000,
+};
+
+static int mt6323_get_status(struct regulator_dev *rdev)
+{
+	int ret;
+	u32 regval;
+	struct mt6323_regulator_info *info = rdev_get_drvdata(rdev);
+
+	ret = regmap_read(rdev->regmap, info->desc.enable_reg, &regval);
+	if (ret != 0) {
+		dev_err(&rdev->dev, "Failed to get enable reg: %d\n", ret);
+		return ret;
+	}
+
+	return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF;
+}
+
+static int mt6323_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	int ret, val = 0;
+	struct mt6323_regulator_info *info = rdev_get_drvdata(rdev);
+
+	if (!info->modeset_mask) {
+		dev_err(&rdev->dev, "regulator %s doesn't support set_mode\n",
+			info->desc.name);
+		return -EINVAL;
+	}
+
+	switch (mode) {
+	case REGULATOR_MODE_STANDBY:
+		val = MT6323_LDO_MODE_LP;
+		break;
+	case REGULATOR_MODE_NORMAL:
+		val = MT6323_LDO_MODE_NORMAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	val <<= ffs(info->modeset_mask) - 1;
+
+	ret = regmap_update_bits(rdev->regmap, info->modeset_reg,
+				  info->modeset_mask, val);
+
+	return ret;
+}
+
+static unsigned int mt6323_ldo_get_mode(struct regulator_dev *rdev)
+{
+	unsigned int val;
+	unsigned int mode;
+	int ret;
+	struct mt6323_regulator_info *info = rdev_get_drvdata(rdev);
+
+	if (!info->modeset_mask) {
+		dev_err(&rdev->dev, "regulator %s doesn't support get_mode\n",
+			info->desc.name);
+		return -EINVAL;
+	}
+
+	ret = regmap_read(rdev->regmap, info->modeset_reg, &val);
+	if (ret < 0)
+		return ret;
+
+	val &= info->modeset_mask;
+	val >>= ffs(info->modeset_mask) - 1;
+
+	if (val & 0x1)
+		mode = REGULATOR_MODE_STANDBY;
+	else
+		mode = REGULATOR_MODE_NORMAL;
+
+	return mode;
+}
+
+static struct regulator_ops mt6323_volt_range_ops = {
+	.list_voltage = regulator_list_voltage_linear_range,
+	.map_voltage = regulator_map_voltage_linear_range,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_status = mt6323_get_status,
+};
+
+static struct regulator_ops mt6323_volt_table_ops = {
+	.list_voltage = regulator_list_voltage_table,
+	.map_voltage = regulator_map_voltage_iterate,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_status = mt6323_get_status,
+	.set_mode = mt6323_ldo_set_mode,
+	.get_mode = mt6323_ldo_get_mode,
+};
+
+static struct regulator_ops mt6323_volt_fixed_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_status = mt6323_get_status,
+	.set_mode = mt6323_ldo_set_mode,
+	.get_mode = mt6323_ldo_get_mode,
+};
+
+/* The array is indexed by id(MT6323_ID_XXX) */
+static struct mt6323_regulator_info mt6323_regulators[] = {
+	MT6323_BUCK("buck_vproc", VPROC, 700000, 1493750, 6250,
+		buck_volt_range1, MT6323_VPROC_CON7, MT6323_VPROC_CON9, 0x7f,
+		MT6323_VPROC_CON10, MT6323_VPROC_CON5),
+	MT6323_BUCK("buck_vsys", VSYS, 1400000, 2987500, 12500,
+		buck_volt_range2, MT6323_VSYS_CON7, MT6323_VSYS_CON9, 0x7f,
+		MT6323_VSYS_CON10, MT6323_VSYS_CON5),
+	MT6323_BUCK("buck_vpa", VPA, 500000, 3650000, 50000,
+		buck_volt_range3, MT6323_VPA_CON7, MT6323_VPA_CON9,
+		0x3f, MT6323_VPA_CON10, MT6323_VPA_CON5),
+	MT6323_REG_FIXED("ldo_vtcxo", VTCXO, MT6323_ANALDO_CON1, 10, 2800000,
+		MT6323_ANALDO_CON1, 0x2),
+	MT6323_REG_FIXED("ldo_vcn28", VCN28, MT6323_ANALDO_CON19, 12, 2800000,
+		MT6323_ANALDO_CON20, 0x2),
+	MT6323_LDO("ldo_vcn33_bt", VCN33_BT, ldo_volt_table1,
+		MT6323_ANALDO_CON16, 7, MT6323_ANALDO_CON16, 0xC,
+		MT6323_ANALDO_CON21, 0x2),
+	MT6323_LDO("ldo_vcn33_wifi", VCN33_WIFI, ldo_volt_table1,
+		MT6323_ANALDO_CON17, 12, MT6323_ANALDO_CON16, 0xC,
+		MT6323_ANALDO_CON21, 0x2),
+	MT6323_REG_FIXED("ldo_va", VA, MT6323_ANALDO_CON2, 14, 2800000,
+		MT6323_ANALDO_CON2, 0x2),
+	MT6323_LDO("ldo_vcama", VCAMA, ldo_volt_table2,
+		MT6323_ANALDO_CON4, 15, MT6323_ANALDO_CON10, 0x60, -1, 0),
+	MT6323_REG_FIXED("ldo_vio28", VIO28, MT6323_DIGLDO_CON0, 14, 2800000,
+		MT6323_DIGLDO_CON0, 0x2),
+	MT6323_REG_FIXED("ldo_vusb", VUSB, MT6323_DIGLDO_CON2, 14, 3300000,
+		MT6323_DIGLDO_CON2, 0x2),
+	MT6323_LDO("ldo_vmc", VMC, ldo_volt_table3,
+		MT6323_DIGLDO_CON3, 12, MT6323_DIGLDO_CON24, 0x10,
+		MT6323_DIGLDO_CON3, 0x2),
+	MT6323_LDO("ldo_vmch", VMCH, ldo_volt_table4,
+		MT6323_DIGLDO_CON5, 14, MT6323_DIGLDO_CON26, 0x80,
+		MT6323_DIGLDO_CON5, 0x2),
+	MT6323_LDO("ldo_vemc3v3", VEMC3V3, ldo_volt_table4,
+		MT6323_DIGLDO_CON6, 14, MT6323_DIGLDO_CON27, 0x80,
+		MT6323_DIGLDO_CON6, 0x2),
+	MT6323_LDO("ldo_vgp1", VGP1, ldo_volt_table5,
+		MT6323_DIGLDO_CON7, 15, MT6323_DIGLDO_CON28, 0xE0,
+		MT6323_DIGLDO_CON7, 0x2),
+	MT6323_LDO("ldo_vgp2", VGP2, ldo_volt_table6,
+		MT6323_DIGLDO_CON8, 15, MT6323_DIGLDO_CON29, 0xE0,
+		MT6323_DIGLDO_CON8, 0x2),
+	MT6323_LDO("ldo_vgp3", VGP3, ldo_volt_table7,
+		MT6323_DIGLDO_CON9, 15, MT6323_DIGLDO_CON30, 0x60,
+		MT6323_DIGLDO_CON9, 0x2),
+	MT6323_REG_FIXED("ldo_vcn18", VCN18, MT6323_DIGLDO_CON11, 14, 1800000,
+		MT6323_DIGLDO_CON11, 0x2),
+	MT6323_LDO("ldo_vsim1", VSIM1, ldo_volt_table8,
+		MT6323_DIGLDO_CON13, 15, MT6323_DIGLDO_CON34, 0x20,
+		MT6323_DIGLDO_CON13, 0x2),
+	MT6323_LDO("ldo_vsim2", VSIM2, ldo_volt_table8,
+		MT6323_DIGLDO_CON14, 15, MT6323_DIGLDO_CON35, 0x20,
+		MT6323_DIGLDO_CON14, 0x2),
+	MT6323_REG_FIXED("ldo_vrtc", VRTC, MT6323_DIGLDO_CON15, 8, 2800000,
+		-1, 0),
+	MT6323_LDO("ldo_vcamaf", VCAMAF, ldo_volt_table5,
+		MT6323_DIGLDO_CON31, 15, MT6323_DIGLDO_CON32, 0xE0,
+		MT6323_DIGLDO_CON31, 0x2),
+	MT6323_LDO("ldo_vibr", VIBR, ldo_volt_table5,
+		MT6323_DIGLDO_CON39, 15, MT6323_DIGLDO_CON40, 0xE0,
+		MT6323_DIGLDO_CON39, 0x2),
+	MT6323_REG_FIXED("ldo_vrf18", VRF18, MT6323_DIGLDO_CON45, 15, 1825000,
+		MT6323_DIGLDO_CON45, 0x2),
+	MT6323_LDO("ldo_vm", VM, ldo_volt_table9,
+		MT6323_DIGLDO_CON47, 14, MT6323_DIGLDO_CON48, 0x30,
+		MT6323_DIGLDO_CON47, 0x2),
+	MT6323_REG_FIXED("ldo_vio18", VIO18, MT6323_DIGLDO_CON49, 14, 1800000,
+		MT6323_DIGLDO_CON49, 0x2),
+	MT6323_LDO("ldo_vcamd", VCAMD, ldo_volt_table10,
+		MT6323_DIGLDO_CON51, 14, MT6323_DIGLDO_CON52, 0x60,
+		MT6323_DIGLDO_CON51, 0x2),
+	MT6323_REG_FIXED("ldo_vcamio", VCAMIO, MT6323_DIGLDO_CON53, 14, 1800000,
+		MT6323_DIGLDO_CON53, 0x2),
+};
+
+static int mt6323_set_buck_vosel_reg(struct platform_device *pdev)
+{
+	struct mt6397_chip *mt6323 = dev_get_drvdata(pdev->dev.parent);
+	int i;
+	u32 regval;
+
+	for (i = 0; i < MT6323_MAX_REGULATOR; i++) {
+		if (mt6323_regulators[i].vselctrl_reg) {
+			if (regmap_read(mt6323->regmap,
+				mt6323_regulators[i].vselctrl_reg,
+				&regval) < 0) {
+				dev_err(&pdev->dev,
+					"Failed to read buck ctrl\n");
+				return -EIO;
+			}
+
+			if (regval & mt6323_regulators[i].vselctrl_mask) {
+				mt6323_regulators[i].desc.vsel_reg =
+				mt6323_regulators[i].vselon_reg;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int mt6323_regulator_probe(struct platform_device *pdev)
+{
+	struct mt6397_chip *mt6323 = dev_get_drvdata(pdev->dev.parent);
+	struct regulator_config config = {};
+	struct regulator_dev *rdev;
+	int i;
+	u32 reg_value;
+
+	/* Query buck controller to select activated voltage register part */
+	if (mt6323_set_buck_vosel_reg(pdev))
+		return -EIO;
+
+	/* Read PMIC chip revision to update constraints and voltage table */
+	if (regmap_read(mt6323->regmap, MT6323_CID, &reg_value) < 0) {
+		dev_err(&pdev->dev, "Failed to read Chip ID\n");
+		return -EIO;
+	}
+	dev_info(&pdev->dev, "Chip ID = 0x%x\n", reg_value);
+
+	for (i = 0; i < MT6323_MAX_REGULATOR; i++) {
+		config.dev = &pdev->dev;
+		config.driver_data = &mt6323_regulators[i];
+		config.regmap = mt6323->regmap;
+		rdev = devm_regulator_register(&pdev->dev,
+				&mt6323_regulators[i].desc, &config);
+		if (IS_ERR(rdev)) {
+			dev_err(&pdev->dev, "failed to register %s\n",
+				mt6323_regulators[i].desc.name);
+			return PTR_ERR(rdev);
+		}
+	}
+	return 0;
+}
+
+static const struct platform_device_id mt6323_platform_ids[] = {
+	{"mt6323-regulator", 0},
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, mt6323_platform_ids);
+
+static const struct of_device_id mt6323_of_match[] = {
+	{ .compatible = "mediatek,mt6323-regulator", },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mt6323_of_match);
+
+static struct platform_driver mt6323_regulator_driver = {
+	.driver = {
+		.name = "mt6323-regulator",
+		.of_match_table = of_match_ptr(mt6323_of_match),
+	},
+	.probe = mt6323_regulator_probe,
+	.id_table = mt6323_platform_ids,
+};
+
+module_platform_driver(mt6323_regulator_driver);
+
+MODULE_AUTHOR("Chen Zhong <chen.zhong at mediatek.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6397 PMIC");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/regulator/mt6323-regulator.h b/include/linux/regulator/mt6323-regulator.h
new file mode 100644
index 0000000..67011cd
--- /dev/null
+++ b/include/linux/regulator/mt6323-regulator.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Chen Zhong <chen.zhong at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __LINUX_REGULATOR_MT6323_H
+#define __LINUX_REGULATOR_MT6323_H
+
+enum {
+	MT6323_ID_VPROC = 0,
+	MT6323_ID_VSYS,
+	MT6323_ID_VPA,
+	MT6323_ID_VTCXO,
+	MT6323_ID_VCN28,
+	MT6323_ID_VCN33_BT,
+	MT6323_ID_VCN33_WIFI,
+	MT6323_ID_VA,
+	MT6323_ID_VCAMA,
+	MT6323_ID_VIO28 = 9,
+	MT6323_ID_VUSB,
+	MT6323_ID_VMC,
+	MT6323_ID_VMCH,
+	MT6323_ID_VEMC3V3,
+	MT6323_ID_VGP1,
+	MT6323_ID_VGP2,
+	MT6323_ID_VGP3,
+	MT6323_ID_VCN18,
+	MT6323_ID_VSIM1,
+	MT6323_ID_VSIM2,
+	MT6323_ID_VRTC,
+	MT6323_ID_VCAMAF,
+	MT6323_ID_VIBR,
+	MT6323_ID_VRF18,
+	MT6323_ID_VM,
+	MT6323_ID_VIO18,
+	MT6323_ID_VCAMD,
+	MT6323_ID_VCAMIO,
+	MT6323_ID_RG_MAX,
+};
+
+#define MT6323_MAX_REGULATOR	MT6323_ID_RG_MAX
+
+#endif /* __LINUX_REGULATOR_MT6323_H */
-- 
1.7.10.4



From john at phrozen.org  Mon Jul 18 05:12:37 2016
From: john at phrozen.org (John Crispin)
Date: Mon, 18 Jul 2016 14:12:37 +0200
Subject: [PATCH V9 1/2] regulator: Add document for MT6323 regulator
In-Reply-To: <1468843741-59637-1-git-send-email-john@phrozen.org>
References: <1468843741-59637-1-git-send-email-john@phrozen.org>
Message-ID: <4cbdd86e-86ee-9a26-777e-340423863c66@phrozen.org>

ignore this one please, my script used the wrong SoB line will send V10
in a sec ... sorry for the noise

On 18/07/2016 14:09, John Crispin wrote:
> From: John Crispin <blogic at openwrt.org>
> 
> Signed-off-by: John Crispin <blogic at openwrt.org>
> Cc: devicetree at vger.kernel.org
> Acked-by: Rob Herring <robh at kernel.org>
> ---
> Changes in V9
> * drop compatible string from devicetree
> 
> Changes in V7
> * remove another compatible string
> * small wording changes
> 
> Changes in V6
> * remove the compatible string
> 
> Changes in V5
> * regulator vs regulators
> 
> Changes in V4
> * regulator is a subnode and not a property
> 
>  .../bindings/regulator/mt6323-regulator.txt        |  239 ++++++++++++++++++++
>  1 file changed, 239 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/regulator/mt6323-regulator.txt
> 
> diff --git a/Documentation/devicetree/bindings/regulator/mt6323-regulator.txt b/Documentation/devicetree/bindings/regulator/mt6323-regulator.txt
> new file mode 100644
> index 0000000..9fd95e7
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/regulator/mt6323-regulator.txt
> @@ -0,0 +1,239 @@
> +Mediatek MT6323 Regulator Driver
> +
> +All voltage regulators are defined as subnodes of the regulators node. A list
> +of regulators provided by this controller are defined as subnodes of the
> +PMIC's node. Each regulator is named according to its regulator type,
> +buck_<name> and ldo_<name>. The definition for each of these nodes is defined
> +using the standard binding for regulators at
> +Documentation/devicetree/bindings/regulator/regulator.txt.
> +
> +The valid names for regulators are::
> +BUCK:
> +  buck_vproc, buck_vsys, buck_vpa
> +LDO:
> +  ldo_vtcxo, ldo_vcn28, ldo_vcn33_bt, ldo_vcn33_wifi, ldo_va, ldo_vcama,
> +  ldo_vio28, ldo_vusb, ldo_vmc, ldo_vmch, ldo_vemc3v3, ldo_vgp1, ldo_vgp2,
> +  ldo_vgp3, ldo_vcn18, ldo_vsim1, ldo_vsim2, ldo_vrtc, ldo_vcamaf, ldo_vibr,
> +  ldo_vrf18, ldo_vm, ldo_vio18, ldo_vcamd, ldo_vcamio
> +
> +Example:
> +
> +	pmic: mt6323 {
> +		compatible = "mediatek,mt6323";
> +
> +		mt6323regulator: regulators {
> +			mt6323_vproc_reg: buck_vproc{
> +				regulator-name = "vproc";
> +				regulator-min-microvolt = < 700000>;
> +				regulator-max-microvolt = <1350000>;
> +				regulator-ramp-delay = <12500>;
> +				regulator-always-on;
> +				regulator-boot-on;
> +			};
> +
> +			mt6323_vsys_reg: buck_vsys{
> +				regulator-name = "vsys";
> +				regulator-min-microvolt = <1400000>;
> +				regulator-max-microvolt = <2987500>;
> +				regulator-ramp-delay = <25000>;
> +				regulator-always-on;
> +				regulator-boot-on;
> +			};
> +
> +			mt6323_vpa_reg: buck_vpa{
> +				regulator-name = "vpa";
> +				regulator-min-microvolt = < 500000>;
> +				regulator-max-microvolt = <3650000>;
> +			};
> +
> +			mt6323_vtcxo_reg: ldo_vtcxo{
> +				regulator-name = "vtcxo";
> +				regulator-min-microvolt = <2800000>;
> +				regulator-max-microvolt = <2800000>;
> +				regulator-enable-ramp-delay = <90>;
> +				regulator-always-on;
> +				regulator-boot-on;
> +			};
> +
> +			mt6323_vcn28_reg: ldo_vcn28{
> +				regulator-name = "vcn28";
> +				regulator-min-microvolt = <2800000>;
> +				regulator-max-microvolt = <2800000>;
> +				regulator-enable-ramp-delay = <185>;
> +			};
> +
> +			mt6323_vcn33_bt_reg: ldo_vcn33_bt{
> +				regulator-name = "vcn33_bt";
> +				regulator-min-microvolt = <3300000>;
> +				regulator-max-microvolt = <3600000>;
> +				regulator-enable-ramp-delay = <185>;
> +			};
> +
> +			mt6323_vcn33_wifi_reg: ldo_vcn33_wifi{
> +				regulator-name = "vcn33_wifi";
> +				regulator-min-microvolt = <3300000>;
> +				regulator-max-microvolt = <3600000>;
> +				regulator-enable-ramp-delay = <185>;
> +			};
> +
> +			mt6323_va_reg: ldo_va{
> +				regulator-name = "va";
> +				regulator-min-microvolt = <2800000>;
> +				regulator-max-microvolt = <2800000>;
> +				regulator-enable-ramp-delay = <216>;
> +				regulator-always-on;
> +				regulator-boot-on;
> +			};
> +
> +			mt6323_vcama_reg: ldo_vcama{
> +				regulator-name = "vcama";
> +				regulator-min-microvolt = <1500000>;
> +				regulator-max-microvolt = <2800000>;
> +				regulator-enable-ramp-delay = <216>;
> +			};
> +
> +			mt6323_vio28_reg: ldo_vio28{
> +				regulator-name = "vio28";
> +				regulator-min-microvolt = <2800000>;
> +				regulator-max-microvolt = <2800000>;
> +				regulator-enable-ramp-delay = <216>;
> +				regulator-always-on;
> +				regulator-boot-on;
> +			};
> +
> +			mt6323_vusb_reg: ldo_vusb{
> +				regulator-name = "vusb";
> +				regulator-min-microvolt = <3300000>;
> +				regulator-max-microvolt = <3300000>;
> +				regulator-enable-ramp-delay = <216>;
> +				regulator-boot-on;
> +			};
> +
> +			mt6323_vmc_reg: ldo_vmc{
> +				regulator-name = "vmc";
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <3300000>;
> +				regulator-enable-ramp-delay = <36>;
> +				regulator-boot-on;
> +			};
> +
> +			mt6323_vmch_reg: ldo_vmch{
> +				regulator-name = "vmch";
> +				regulator-min-microvolt = <3000000>;
> +				regulator-max-microvolt = <3300000>;
> +				regulator-enable-ramp-delay = <36>;
> +				regulator-boot-on;
> +			};
> +
> +			mt6323_vemc3v3_reg: ldo_vemc3v3{
> +				regulator-name = "vemc3v3";
> +				regulator-min-microvolt = <3000000>;
> +				regulator-max-microvolt = <3300000>;
> +				regulator-enable-ramp-delay = <36>;
> +				regulator-boot-on;
> +			};
> +
> +			mt6323_vgp1_reg: ldo_vgp1{
> +				regulator-name = "vgp1";
> +				regulator-min-microvolt = <1200000>;
> +				regulator-max-microvolt = <3300000>;
> +				regulator-enable-ramp-delay = <216>;
> +			};
> +
> +			mt6323_vgp2_reg: ldo_vgp2{
> +				regulator-name = "vgp2";
> +				regulator-min-microvolt = <1200000>;
> +				regulator-max-microvolt = <3000000>;
> +				regulator-enable-ramp-delay = <216>;
> +			};
> +
> +			mt6323_vgp3_reg: ldo_vgp3{
> +				regulator-name = "vgp3";
> +				regulator-min-microvolt = <1200000>;
> +				regulator-max-microvolt = <1800000>;
> +				regulator-enable-ramp-delay = <216>;
> +			};
> +
> +			mt6323_vcn18_reg: ldo_vcn18{
> +				regulator-name = "vcn18";
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +				regulator-enable-ramp-delay = <216>;
> +			};
> +
> +			mt6323_vsim1_reg: ldo_vsim1{
> +				regulator-name = "vsim1";
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <3000000>;
> +				regulator-enable-ramp-delay = <216>;
> +			};
> +
> +			mt6323_vsim2_reg: ldo_vsim2{
> +				regulator-name = "vsim2";
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <3000000>;
> +				regulator-enable-ramp-delay = <216>;
> +			};
> +
> +			mt6323_vrtc_reg: ldo_vrtc{
> +				regulator-name = "vrtc";
> +				regulator-min-microvolt = <2800000>;
> +				regulator-max-microvolt = <2800000>;
> +				regulator-always-on;
> +				regulator-boot-on;
> +			};
> +
> +			mt6323_vcamaf_reg: ldo_vcamaf{
> +				regulator-name = "vcamaf";
> +				regulator-min-microvolt = <1200000>;
> +				regulator-max-microvolt = <3300000>;
> +				regulator-enable-ramp-delay = <216>;
> +			};
> +
> +			mt6323_vibr_reg: ldo_vibr{
> +				regulator-name = "vibr";
> +				regulator-min-microvolt = <1200000>;
> +				regulator-max-microvolt = <3300000>;
> +				regulator-enable-ramp-delay = <36>;
> +			};
> +
> +			mt6323_vrf18_reg: ldo_vrf18{
> +				regulator-name = "vrf18";
> +				regulator-min-microvolt = <1825000>;
> +				regulator-max-microvolt = <1825000>;
> +				regulator-enable-ramp-delay = <187>;
> +			};
> +
> +			mt6323_vm_reg: ldo_vm{
> +				regulator-name = "vm";
> +				regulator-min-microvolt = <1200000>;
> +				regulator-max-microvolt = <1800000>;
> +				regulator-enable-ramp-delay = <216>;
> +				regulator-always-on;
> +				regulator-boot-on;
> +			};
> +
> +			mt6323_vio18_reg: ldo_vio18{
> +				regulator-name = "vio18";
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +				regulator-enable-ramp-delay = <216>;
> +				regulator-always-on;
> +				regulator-boot-on;
> +			};
> +
> +			mt6323_vcamd_reg: ldo_vcamd{
> +				regulator-name = "vcamd";
> +				regulator-min-microvolt = <1200000>;
> +				regulator-max-microvolt = <1800000>;
> +				regulator-enable-ramp-delay = <216>;
> +			};
> +
> +			mt6323_vcamio_reg: ldo_vcamio{
> +				regulator-name = "vcamio";
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +				regulator-enable-ramp-delay = <216>;
> +			};
> +		};
> +	};
> 


From john at phrozen.org  Mon Jul 18 05:12:50 2016
From: john at phrozen.org (John Crispin)
Date: Mon, 18 Jul 2016 14:12:50 +0200
Subject: [PATCH V9 2/2] regulator: mt6323: Add support for MT6323 regulator
In-Reply-To: <1468843741-59637-2-git-send-email-john@phrozen.org>
References: <1468843741-59637-1-git-send-email-john@phrozen.org>
 <1468843741-59637-2-git-send-email-john@phrozen.org>
Message-ID: <2616e51a-fc47-fbac-827d-957081642288@phrozen.org>

ignore this one please, my script used the wrong SoB line will send V10
in a sec ... sorry for the noise

On 18/07/2016 14:09, John Crispin wrote:
> From: Chen Zhong <chen.zhong at mediatek.com>
> 
> The MT6323 is a regulator found on boards based on MediaTek MT7623 and
> probably other SoCs. It is a so called pmic and connects as a slave to
> SoC using SPI, wrapped inside the pmic-wrapper.
> 
> Signed-off-by: Chen Zhong <chen.zhong at mediatek.com>
> Signed-off-by: John Crispin <blogic at openwrt.org>
> ---
> This series was dropped from the v4.7 queue to avoid a merge conflict with
> the series adding mt6323 support to the MFD driver. These patches were
> merged during the v4.7 window, so this series is good to go for v4.8. The
> relevant started with
> commit feec4799ac4d ("mfd: mt6397: int_con and int_status may vary ...")
> through to
> commit 44760cf3bf0a ("mfd: mt6397: Add MT6323 support to MT6397 driver")
> 
> Changes in V9
> * drop compatible string from devicetree
> 
> Changes in V6
> * add back the set/get mode callbacks
> 
> Changes in V5
> * remove the code that modifies constraints
> * remove the code allows mode changes
> 
> Changes in V4:
> * add id_table and of_match_table
> * use short GPL text
> * change MODULE_LICENSE to GPL V2
> 
> Changes in V2:
> * send to the the proper maintainer
> 
>  drivers/regulator/Kconfig                  |    9 +
>  drivers/regulator/Makefile                 |    1 +
>  drivers/regulator/mt6323-regulator.c       |  432 ++++++++++++++++++++++++++++
>  include/linux/regulator/mt6323-regulator.h |   52 ++++
>  4 files changed, 494 insertions(+)
>  create mode 100644 drivers/regulator/mt6323-regulator.c
>  create mode 100644 include/linux/regulator/mt6323-regulator.h
> 
> diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
> index ae9cbd6..6c88e31 100644
> --- a/drivers/regulator/Kconfig
> +++ b/drivers/regulator/Kconfig
> @@ -498,6 +498,15 @@ config REGULATOR_MT6311
>  	  This driver supports the control of different power rails of device
>  	  through regulator interface.
>  
> +config REGULATOR_MT6323
> +	tristate "MediaTek MT6323 PMIC"
> +	depends on MFD_MT6397
> +	help
> +	  Say y here to select this option to enable the power regulator of
> +	  MediaTek MT6323 PMIC.
> +	  This driver supports the control of different power rails of device
> +	  through regulator interface.
> +
>  config REGULATOR_MT6397
>  	tristate "MediaTek MT6397 PMIC"
>  	depends on MFD_MT6397
> diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
> index 85a1d44..f3da9ee 100644
> --- a/drivers/regulator/Makefile
> +++ b/drivers/regulator/Makefile
> @@ -65,6 +65,7 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
>  obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
>  obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
>  obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
> +obj-$(CONFIG_REGULATOR_MT6323)	+= mt6323-regulator.o
>  obj-$(CONFIG_REGULATOR_MT6397)	+= mt6397-regulator.o
>  obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
>  obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
> diff --git a/drivers/regulator/mt6323-regulator.c b/drivers/regulator/mt6323-regulator.c
> new file mode 100644
> index 0000000..28ebbda
> --- /dev/null
> +++ b/drivers/regulator/mt6323-regulator.c
> @@ -0,0 +1,432 @@
> +/*
> + * Copyright (c) 2016 MediaTek Inc.
> + * Author: Chen Zhong <chen.zhong at mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/mfd/mt6397/core.h>
> +#include <linux/mfd/mt6323/registers.h>
> +#include <linux/regulator/driver.h>
> +#include <linux/regulator/machine.h>
> +#include <linux/regulator/mt6323-regulator.h>
> +#include <linux/regulator/of_regulator.h>
> +
> +#define MT6323_LDO_MODE_NORMAL	0
> +#define MT6323_LDO_MODE_LP	1
> +
> +/*
> + * MT6323 regulators' information
> + *
> + * @desc: standard fields of regulator description.
> + * @qi: Mask for query enable signal status of regulators
> + * @vselon_reg: Register sections for hardware control mode of bucks
> + * @vselctrl_reg: Register for controlling the buck control mode.
> + * @vselctrl_mask: Mask for query buck's voltage control mode.
> + */
> +struct mt6323_regulator_info {
> +	struct regulator_desc desc;
> +	u32 qi;
> +	u32 vselon_reg;
> +	u32 vselctrl_reg;
> +	u32 vselctrl_mask;
> +	u32 modeset_reg;
> +	u32 modeset_mask;
> +};
> +
> +#define MT6323_BUCK(match, vreg, min, max, step, volt_ranges, enreg,	\
> +		vosel, vosel_mask, voselon, vosel_ctrl)			\
> +[MT6323_ID_##vreg] = {							\
> +	.desc = {							\
> +		.name = #vreg,						\
> +		.of_match = of_match_ptr(match),			\
> +		.ops = &mt6323_volt_range_ops,				\
> +		.type = REGULATOR_VOLTAGE,				\
> +		.id = MT6323_ID_##vreg,					\
> +		.owner = THIS_MODULE,					\
> +		.n_voltages = (max - min)/step + 1,			\
> +		.linear_ranges = volt_ranges,				\
> +		.n_linear_ranges = ARRAY_SIZE(volt_ranges),		\
> +		.vsel_reg = vosel,					\
> +		.vsel_mask = vosel_mask,				\
> +		.enable_reg = enreg,					\
> +		.enable_mask = BIT(0),					\
> +	},								\
> +	.qi = BIT(13),							\
> +	.vselon_reg = voselon,						\
> +	.vselctrl_reg = vosel_ctrl,					\
> +	.vselctrl_mask = BIT(1),					\
> +}
> +
> +#define MT6323_LDO(match, vreg, ldo_volt_table, enreg, enbit, vosel,	\
> +		vosel_mask, _modeset_reg, _modeset_mask)		\
> +[MT6323_ID_##vreg] = {							\
> +	.desc = {							\
> +		.name = #vreg,						\
> +		.of_match = of_match_ptr(match),			\
> +		.ops = &mt6323_volt_table_ops,				\
> +		.type = REGULATOR_VOLTAGE,				\
> +		.id = MT6323_ID_##vreg,					\
> +		.owner = THIS_MODULE,					\
> +		.n_voltages = ARRAY_SIZE(ldo_volt_table),		\
> +		.volt_table = ldo_volt_table,				\
> +		.vsel_reg = vosel,					\
> +		.vsel_mask = vosel_mask,				\
> +		.enable_reg = enreg,					\
> +		.enable_mask = BIT(enbit),				\
> +	},								\
> +	.qi = BIT(15),							\
> +	.modeset_reg = _modeset_reg,					\
> +	.modeset_mask = _modeset_mask,					\
> +}
> +
> +#define MT6323_REG_FIXED(match, vreg, enreg, enbit, volt,		\
> +		_modeset_reg, _modeset_mask)				\
> +[MT6323_ID_##vreg] = {							\
> +	.desc = {							\
> +		.name = #vreg,						\
> +		.of_match = of_match_ptr(match),			\
> +		.ops = &mt6323_volt_fixed_ops,				\
> +		.type = REGULATOR_VOLTAGE,				\
> +		.id = MT6323_ID_##vreg,					\
> +		.owner = THIS_MODULE,					\
> +		.n_voltages = 1,					\
> +		.enable_reg = enreg,					\
> +		.enable_mask = BIT(enbit),				\
> +		.min_uV = volt,						\
> +	},								\
> +	.qi = BIT(15),							\
> +	.modeset_reg = _modeset_reg,					\
> +	.modeset_mask = _modeset_mask,					\
> +}
> +
> +static const struct regulator_linear_range buck_volt_range1[] = {
> +	REGULATOR_LINEAR_RANGE(700000, 0, 0x7f, 6250),
> +};
> +
> +static const struct regulator_linear_range buck_volt_range2[] = {
> +	REGULATOR_LINEAR_RANGE(1400000, 0, 0x7f, 12500),
> +};
> +
> +static const struct regulator_linear_range buck_volt_range3[] = {
> +	REGULATOR_LINEAR_RANGE(500000, 0, 0x3f, 50000),
> +};
> +
> +static const u32 ldo_volt_table1[] = {
> +	3300000, 3400000, 3500000, 3600000,
> +};
> +
> +static const u32 ldo_volt_table2[] = {
> +	1500000, 1800000, 2500000, 2800000,
> +};
> +
> +static const u32 ldo_volt_table3[] = {
> +	1800000, 3300000,
> +};
> +
> +static const u32 ldo_volt_table4[] = {
> +	3000000, 3300000,
> +};
> +
> +static const u32 ldo_volt_table5[] = {
> +	1200000, 1300000, 1500000, 1800000, 2000000, 2800000, 3000000, 3300000,
> +};
> +
> +static const u32 ldo_volt_table6[] = {
> +	1200000, 1300000, 1500000, 1800000, 2500000, 2800000, 3000000, 2000000,
> +};
> +
> +static const u32 ldo_volt_table7[] = {
> +	1200000, 1300000, 1500000, 1800000,
> +};
> +
> +static const u32 ldo_volt_table8[] = {
> +	1800000, 3000000,
> +};
> +
> +static const u32 ldo_volt_table9[] = {
> +	1200000, 1350000, 1500000, 1800000,
> +};
> +
> +static const u32 ldo_volt_table10[] = {
> +	1200000, 1300000, 1500000, 1800000,
> +};
> +
> +static int mt6323_get_status(struct regulator_dev *rdev)
> +{
> +	int ret;
> +	u32 regval;
> +	struct mt6323_regulator_info *info = rdev_get_drvdata(rdev);
> +
> +	ret = regmap_read(rdev->regmap, info->desc.enable_reg, &regval);
> +	if (ret != 0) {
> +		dev_err(&rdev->dev, "Failed to get enable reg: %d\n", ret);
> +		return ret;
> +	}
> +
> +	return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF;
> +}
> +
> +static int mt6323_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode)
> +{
> +	int ret, val = 0;
> +	struct mt6323_regulator_info *info = rdev_get_drvdata(rdev);
> +
> +	if (!info->modeset_mask) {
> +		dev_err(&rdev->dev, "regulator %s doesn't support set_mode\n",
> +			info->desc.name);
> +		return -EINVAL;
> +	}
> +
> +	switch (mode) {
> +	case REGULATOR_MODE_STANDBY:
> +		val = MT6323_LDO_MODE_LP;
> +		break;
> +	case REGULATOR_MODE_NORMAL:
> +		val = MT6323_LDO_MODE_NORMAL;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	val <<= ffs(info->modeset_mask) - 1;
> +
> +	ret = regmap_update_bits(rdev->regmap, info->modeset_reg,
> +				  info->modeset_mask, val);
> +
> +	return ret;
> +}
> +
> +static unsigned int mt6323_ldo_get_mode(struct regulator_dev *rdev)
> +{
> +	unsigned int val;
> +	unsigned int mode;
> +	int ret;
> +	struct mt6323_regulator_info *info = rdev_get_drvdata(rdev);
> +
> +	if (!info->modeset_mask) {
> +		dev_err(&rdev->dev, "regulator %s doesn't support get_mode\n",
> +			info->desc.name);
> +		return -EINVAL;
> +	}
> +
> +	ret = regmap_read(rdev->regmap, info->modeset_reg, &val);
> +	if (ret < 0)
> +		return ret;
> +
> +	val &= info->modeset_mask;
> +	val >>= ffs(info->modeset_mask) - 1;
> +
> +	if (val & 0x1)
> +		mode = REGULATOR_MODE_STANDBY;
> +	else
> +		mode = REGULATOR_MODE_NORMAL;
> +
> +	return mode;
> +}
> +
> +static struct regulator_ops mt6323_volt_range_ops = {
> +	.list_voltage = regulator_list_voltage_linear_range,
> +	.map_voltage = regulator_map_voltage_linear_range,
> +	.set_voltage_sel = regulator_set_voltage_sel_regmap,
> +	.get_voltage_sel = regulator_get_voltage_sel_regmap,
> +	.set_voltage_time_sel = regulator_set_voltage_time_sel,
> +	.enable = regulator_enable_regmap,
> +	.disable = regulator_disable_regmap,
> +	.is_enabled = regulator_is_enabled_regmap,
> +	.get_status = mt6323_get_status,
> +};
> +
> +static struct regulator_ops mt6323_volt_table_ops = {
> +	.list_voltage = regulator_list_voltage_table,
> +	.map_voltage = regulator_map_voltage_iterate,
> +	.set_voltage_sel = regulator_set_voltage_sel_regmap,
> +	.get_voltage_sel = regulator_get_voltage_sel_regmap,
> +	.set_voltage_time_sel = regulator_set_voltage_time_sel,
> +	.enable = regulator_enable_regmap,
> +	.disable = regulator_disable_regmap,
> +	.is_enabled = regulator_is_enabled_regmap,
> +	.get_status = mt6323_get_status,
> +	.set_mode = mt6323_ldo_set_mode,
> +	.get_mode = mt6323_ldo_get_mode,
> +};
> +
> +static struct regulator_ops mt6323_volt_fixed_ops = {
> +	.list_voltage = regulator_list_voltage_linear,
> +	.enable = regulator_enable_regmap,
> +	.disable = regulator_disable_regmap,
> +	.is_enabled = regulator_is_enabled_regmap,
> +	.get_status = mt6323_get_status,
> +	.set_mode = mt6323_ldo_set_mode,
> +	.get_mode = mt6323_ldo_get_mode,
> +};
> +
> +/* The array is indexed by id(MT6323_ID_XXX) */
> +static struct mt6323_regulator_info mt6323_regulators[] = {
> +	MT6323_BUCK("buck_vproc", VPROC, 700000, 1493750, 6250,
> +		buck_volt_range1, MT6323_VPROC_CON7, MT6323_VPROC_CON9, 0x7f,
> +		MT6323_VPROC_CON10, MT6323_VPROC_CON5),
> +	MT6323_BUCK("buck_vsys", VSYS, 1400000, 2987500, 12500,
> +		buck_volt_range2, MT6323_VSYS_CON7, MT6323_VSYS_CON9, 0x7f,
> +		MT6323_VSYS_CON10, MT6323_VSYS_CON5),
> +	MT6323_BUCK("buck_vpa", VPA, 500000, 3650000, 50000,
> +		buck_volt_range3, MT6323_VPA_CON7, MT6323_VPA_CON9,
> +		0x3f, MT6323_VPA_CON10, MT6323_VPA_CON5),
> +	MT6323_REG_FIXED("ldo_vtcxo", VTCXO, MT6323_ANALDO_CON1, 10, 2800000,
> +		MT6323_ANALDO_CON1, 0x2),
> +	MT6323_REG_FIXED("ldo_vcn28", VCN28, MT6323_ANALDO_CON19, 12, 2800000,
> +		MT6323_ANALDO_CON20, 0x2),
> +	MT6323_LDO("ldo_vcn33_bt", VCN33_BT, ldo_volt_table1,
> +		MT6323_ANALDO_CON16, 7, MT6323_ANALDO_CON16, 0xC,
> +		MT6323_ANALDO_CON21, 0x2),
> +	MT6323_LDO("ldo_vcn33_wifi", VCN33_WIFI, ldo_volt_table1,
> +		MT6323_ANALDO_CON17, 12, MT6323_ANALDO_CON16, 0xC,
> +		MT6323_ANALDO_CON21, 0x2),
> +	MT6323_REG_FIXED("ldo_va", VA, MT6323_ANALDO_CON2, 14, 2800000,
> +		MT6323_ANALDO_CON2, 0x2),
> +	MT6323_LDO("ldo_vcama", VCAMA, ldo_volt_table2,
> +		MT6323_ANALDO_CON4, 15, MT6323_ANALDO_CON10, 0x60, -1, 0),
> +	MT6323_REG_FIXED("ldo_vio28", VIO28, MT6323_DIGLDO_CON0, 14, 2800000,
> +		MT6323_DIGLDO_CON0, 0x2),
> +	MT6323_REG_FIXED("ldo_vusb", VUSB, MT6323_DIGLDO_CON2, 14, 3300000,
> +		MT6323_DIGLDO_CON2, 0x2),
> +	MT6323_LDO("ldo_vmc", VMC, ldo_volt_table3,
> +		MT6323_DIGLDO_CON3, 12, MT6323_DIGLDO_CON24, 0x10,
> +		MT6323_DIGLDO_CON3, 0x2),
> +	MT6323_LDO("ldo_vmch", VMCH, ldo_volt_table4,
> +		MT6323_DIGLDO_CON5, 14, MT6323_DIGLDO_CON26, 0x80,
> +		MT6323_DIGLDO_CON5, 0x2),
> +	MT6323_LDO("ldo_vemc3v3", VEMC3V3, ldo_volt_table4,
> +		MT6323_DIGLDO_CON6, 14, MT6323_DIGLDO_CON27, 0x80,
> +		MT6323_DIGLDO_CON6, 0x2),
> +	MT6323_LDO("ldo_vgp1", VGP1, ldo_volt_table5,
> +		MT6323_DIGLDO_CON7, 15, MT6323_DIGLDO_CON28, 0xE0,
> +		MT6323_DIGLDO_CON7, 0x2),
> +	MT6323_LDO("ldo_vgp2", VGP2, ldo_volt_table6,
> +		MT6323_DIGLDO_CON8, 15, MT6323_DIGLDO_CON29, 0xE0,
> +		MT6323_DIGLDO_CON8, 0x2),
> +	MT6323_LDO("ldo_vgp3", VGP3, ldo_volt_table7,
> +		MT6323_DIGLDO_CON9, 15, MT6323_DIGLDO_CON30, 0x60,
> +		MT6323_DIGLDO_CON9, 0x2),
> +	MT6323_REG_FIXED("ldo_vcn18", VCN18, MT6323_DIGLDO_CON11, 14, 1800000,
> +		MT6323_DIGLDO_CON11, 0x2),
> +	MT6323_LDO("ldo_vsim1", VSIM1, ldo_volt_table8,
> +		MT6323_DIGLDO_CON13, 15, MT6323_DIGLDO_CON34, 0x20,
> +		MT6323_DIGLDO_CON13, 0x2),
> +	MT6323_LDO("ldo_vsim2", VSIM2, ldo_volt_table8,
> +		MT6323_DIGLDO_CON14, 15, MT6323_DIGLDO_CON35, 0x20,
> +		MT6323_DIGLDO_CON14, 0x2),
> +	MT6323_REG_FIXED("ldo_vrtc", VRTC, MT6323_DIGLDO_CON15, 8, 2800000,
> +		-1, 0),
> +	MT6323_LDO("ldo_vcamaf", VCAMAF, ldo_volt_table5,
> +		MT6323_DIGLDO_CON31, 15, MT6323_DIGLDO_CON32, 0xE0,
> +		MT6323_DIGLDO_CON31, 0x2),
> +	MT6323_LDO("ldo_vibr", VIBR, ldo_volt_table5,
> +		MT6323_DIGLDO_CON39, 15, MT6323_DIGLDO_CON40, 0xE0,
> +		MT6323_DIGLDO_CON39, 0x2),
> +	MT6323_REG_FIXED("ldo_vrf18", VRF18, MT6323_DIGLDO_CON45, 15, 1825000,
> +		MT6323_DIGLDO_CON45, 0x2),
> +	MT6323_LDO("ldo_vm", VM, ldo_volt_table9,
> +		MT6323_DIGLDO_CON47, 14, MT6323_DIGLDO_CON48, 0x30,
> +		MT6323_DIGLDO_CON47, 0x2),
> +	MT6323_REG_FIXED("ldo_vio18", VIO18, MT6323_DIGLDO_CON49, 14, 1800000,
> +		MT6323_DIGLDO_CON49, 0x2),
> +	MT6323_LDO("ldo_vcamd", VCAMD, ldo_volt_table10,
> +		MT6323_DIGLDO_CON51, 14, MT6323_DIGLDO_CON52, 0x60,
> +		MT6323_DIGLDO_CON51, 0x2),
> +	MT6323_REG_FIXED("ldo_vcamio", VCAMIO, MT6323_DIGLDO_CON53, 14, 1800000,
> +		MT6323_DIGLDO_CON53, 0x2),
> +};
> +
> +static int mt6323_set_buck_vosel_reg(struct platform_device *pdev)
> +{
> +	struct mt6397_chip *mt6323 = dev_get_drvdata(pdev->dev.parent);
> +	int i;
> +	u32 regval;
> +
> +	for (i = 0; i < MT6323_MAX_REGULATOR; i++) {
> +		if (mt6323_regulators[i].vselctrl_reg) {
> +			if (regmap_read(mt6323->regmap,
> +				mt6323_regulators[i].vselctrl_reg,
> +				&regval) < 0) {
> +				dev_err(&pdev->dev,
> +					"Failed to read buck ctrl\n");
> +				return -EIO;
> +			}
> +
> +			if (regval & mt6323_regulators[i].vselctrl_mask) {
> +				mt6323_regulators[i].desc.vsel_reg =
> +				mt6323_regulators[i].vselon_reg;
> +			}
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int mt6323_regulator_probe(struct platform_device *pdev)
> +{
> +	struct mt6397_chip *mt6323 = dev_get_drvdata(pdev->dev.parent);
> +	struct regulator_config config = {};
> +	struct regulator_dev *rdev;
> +	int i;
> +	u32 reg_value;
> +
> +	/* Query buck controller to select activated voltage register part */
> +	if (mt6323_set_buck_vosel_reg(pdev))
> +		return -EIO;
> +
> +	/* Read PMIC chip revision to update constraints and voltage table */
> +	if (regmap_read(mt6323->regmap, MT6323_CID, &reg_value) < 0) {
> +		dev_err(&pdev->dev, "Failed to read Chip ID\n");
> +		return -EIO;
> +	}
> +	dev_info(&pdev->dev, "Chip ID = 0x%x\n", reg_value);
> +
> +	for (i = 0; i < MT6323_MAX_REGULATOR; i++) {
> +		config.dev = &pdev->dev;
> +		config.driver_data = &mt6323_regulators[i];
> +		config.regmap = mt6323->regmap;
> +		rdev = devm_regulator_register(&pdev->dev,
> +				&mt6323_regulators[i].desc, &config);
> +		if (IS_ERR(rdev)) {
> +			dev_err(&pdev->dev, "failed to register %s\n",
> +				mt6323_regulators[i].desc.name);
> +			return PTR_ERR(rdev);
> +		}
> +	}
> +	return 0;
> +}
> +
> +static const struct platform_device_id mt6323_platform_ids[] = {
> +	{"mt6323-regulator", 0},
> +	{ /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(platform, mt6323_platform_ids);
> +
> +static const struct of_device_id mt6323_of_match[] = {
> +	{ .compatible = "mediatek,mt6323-regulator", },
> +	{ /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(of, mt6323_of_match);
> +
> +static struct platform_driver mt6323_regulator_driver = {
> +	.driver = {
> +		.name = "mt6323-regulator",
> +		.of_match_table = of_match_ptr(mt6323_of_match),
> +	},
> +	.probe = mt6323_regulator_probe,
> +	.id_table = mt6323_platform_ids,
> +};
> +
> +module_platform_driver(mt6323_regulator_driver);
> +
> +MODULE_AUTHOR("Chen Zhong <chen.zhong at mediatek.com>");
> +MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6397 PMIC");
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/linux/regulator/mt6323-regulator.h b/include/linux/regulator/mt6323-regulator.h
> new file mode 100644
> index 0000000..67011cd
> --- /dev/null
> +++ b/include/linux/regulator/mt6323-regulator.h
> @@ -0,0 +1,52 @@
> +/*
> + * Copyright (c) 2016 MediaTek Inc.
> + * Author: Chen Zhong <chen.zhong at mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#ifndef __LINUX_REGULATOR_MT6323_H
> +#define __LINUX_REGULATOR_MT6323_H
> +
> +enum {
> +	MT6323_ID_VPROC = 0,
> +	MT6323_ID_VSYS,
> +	MT6323_ID_VPA,
> +	MT6323_ID_VTCXO,
> +	MT6323_ID_VCN28,
> +	MT6323_ID_VCN33_BT,
> +	MT6323_ID_VCN33_WIFI,
> +	MT6323_ID_VA,
> +	MT6323_ID_VCAMA,
> +	MT6323_ID_VIO28 = 9,
> +	MT6323_ID_VUSB,
> +	MT6323_ID_VMC,
> +	MT6323_ID_VMCH,
> +	MT6323_ID_VEMC3V3,
> +	MT6323_ID_VGP1,
> +	MT6323_ID_VGP2,
> +	MT6323_ID_VGP3,
> +	MT6323_ID_VCN18,
> +	MT6323_ID_VSIM1,
> +	MT6323_ID_VSIM2,
> +	MT6323_ID_VRTC,
> +	MT6323_ID_VCAMAF,
> +	MT6323_ID_VIBR,
> +	MT6323_ID_VRF18,
> +	MT6323_ID_VM,
> +	MT6323_ID_VIO18,
> +	MT6323_ID_VCAMD,
> +	MT6323_ID_VCAMIO,
> +	MT6323_ID_RG_MAX,
> +};
> +
> +#define MT6323_MAX_REGULATOR	MT6323_ID_RG_MAX
> +
> +#endif /* __LINUX_REGULATOR_MT6323_H */
> 


From broonie at kernel.org  Mon Jul 18 05:16:38 2016
From: broonie at kernel.org (Mark Brown)
Date: Mon, 18 Jul 2016 13:16:38 +0100
Subject: [PATCH V9 2/2] regulator: mt6323: Add support for MT6323 regulator
In-Reply-To: <1468843741-59637-2-git-send-email-john@phrozen.org>
References: <1468843741-59637-1-git-send-email-john@phrozen.org>
 <1468843741-59637-2-git-send-email-john@phrozen.org>
Message-ID: <20160718121638.GT30372@sirena.org.uk>

On Mon, Jul 18, 2016 at 02:09:01PM +0200, John Crispin wrote:

> Changes in V9
> * drop compatible string from devicetree

Are you sure?

> +static const struct of_device_id mt6323_of_match[] = {
> +	{ .compatible = "mediatek,mt6323-regulator", },
> +	{ /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(of, mt6323_of_match);
> +
> +static struct platform_driver mt6323_regulator_driver = {
> +	.driver = {
> +		.name = "mt6323-regulator",
> +		.of_match_table = of_match_ptr(mt6323_of_match),
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mediatek/attachments/20160718/52f3a879/attachment.sig>

From hverkuil at xs4all.nl  Mon Jul 18 05:18:45 2016
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Mon, 18 Jul 2016 14:18:45 +0200
Subject: [PATCH 3/4] media: Add Mediatek MDP Driver
In-Reply-To: <1468498681-19955-4-git-send-email-minghsiu.tsai@mediatek.com>
References: <1468498681-19955-1-git-send-email-minghsiu.tsai@mediatek.com>
 <1468498681-19955-4-git-send-email-minghsiu.tsai@mediatek.com>
Message-ID: <41900916-26c8-014a-6a7f-de3c34a2592f@xs4all.nl>

On 07/14/2016 02:18 PM, Minghsiu Tsai wrote:
> Add MDP driver for MT8173
> 
> Signed-off-by: Minghsiu Tsai <minghsiu.tsai at mediatek.com>
> ---
>  drivers/media/platform/Kconfig                |   16 +
>  drivers/media/platform/Makefile               |    2 +
>  drivers/media/platform/mtk-mdp/Makefile       |    9 +
>  drivers/media/platform/mtk-mdp/mtk_mdp_comp.c |  159 +++
>  drivers/media/platform/mtk-mdp/mtk_mdp_comp.h |   72 ++
>  drivers/media/platform/mtk-mdp/mtk_mdp_core.c |  294 ++++++
>  drivers/media/platform/mtk-mdp/mtk_mdp_core.h |  233 +++++
>  drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h  |  126 +++
>  drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c  | 1304 +++++++++++++++++++++++++
>  drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h  |   22 +
>  drivers/media/platform/mtk-mdp/mtk_mdp_regs.c |  153 +++
>  drivers/media/platform/mtk-mdp/mtk_mdp_regs.h |   31 +
>  drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c  |  140 +++
>  drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h  |   41 +
>  14 files changed, 2602 insertions(+)
>  create mode 100644 drivers/media/platform/mtk-mdp/Makefile
>  create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_comp.c
>  create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_comp.h
>  create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_core.c
>  create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_core.h
>  create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h
>  create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
>  create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h
>  create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_regs.c
>  create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_regs.h
>  create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c
>  create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h
> 
> diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
> index 2c2670c..782b618 100644
> --- a/drivers/media/platform/Kconfig
> +++ b/drivers/media/platform/Kconfig
> @@ -166,6 +166,22 @@ config VIDEO_MEDIATEK_VPU
>  	    To compile this driver as a module, choose M here: the
>  	    module will be called mtk-vpu.
>  
> +config VIDEO_MEDIATEK_MDP
> +	tristate "Mediatek MDP driver"
> +	depends on MTK_IOMMU || COMPILE_TEST
> +	depends on VIDEO_DEV && VIDEO_V4L2
> +	depends on ARCH_MEDIATEK || COMPILE_TEST
> +	select VIDEOBUF2_DMA_CONTIG
> +	select V4L2_MEM2MEM_DEV
> +	select VIDEO_MEDIATEK_VPU
> +	default n
> +	---help---
> +	    It is a v4l2 driver and present in Mediatek MT8173 SoCs.
> +	    The driver supports for scaling and color space conversion.
> +
> +	    To compile this driver as a module, choose M here: the
> +	    module will be called mtk-mdp.
> +
>  config VIDEO_MEDIATEK_VCODEC
>  	tristate "Mediatek Video Codec driver"
>  	depends on MTK_IOMMU || COMPILE_TEST
> diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
> index c6b3b92..9c54f1a 100644
> --- a/drivers/media/platform/Makefile
> +++ b/drivers/media/platform/Makefile
> @@ -62,3 +62,5 @@ ccflags-y += -I$(srctree)/drivers/media/i2c
>  obj-$(CONFIG_VIDEO_MEDIATEK_VPU)	+= mtk-vpu/
>  
>  obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC)	+= mtk-vcodec/
> +
> +obj-$(CONFIG_VIDEO_MEDIATEK_MDP)	+= mtk-mdp/
> diff --git a/drivers/media/platform/mtk-mdp/Makefile b/drivers/media/platform/mtk-mdp/Makefile
> new file mode 100644
> index 0000000..f802569
> --- /dev/null
> +++ b/drivers/media/platform/mtk-mdp/Makefile
> @@ -0,0 +1,9 @@
> +mtk-mdp-y += mtk_mdp_core.o
> +mtk-mdp-y += mtk_mdp_comp.o
> +mtk-mdp-y += mtk_mdp_m2m.o
> +mtk-mdp-y += mtk_mdp_regs.o
> +mtk-mdp-y += mtk_mdp_vpu.o
> +
> +obj-$(CONFIG_VIDEO_MEDIATEK_MDP) += mtk-mdp.o
> +
> +ccflags-y += -I$(srctree)/drivers/media/platform/mtk-vpu
> diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_comp.c b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.c
> new file mode 100644
> index 0000000..aa8f9fd
> --- /dev/null
> +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.c
> @@ -0,0 +1,159 @@
> +/*
> + * Copyright (c) 2016 MediaTek Inc.
> + * Author: Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/device.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_platform.h>
> +#include <soc/mediatek/smi.h>
> +
> +#include "mtk_mdp_comp.h"
> +
> +
> +static const char * const mtk_mdp_comp_stem[MTK_MDP_COMP_TYPE_MAX] = {
> +	"mdp_rdma",
> +	"mdp_rsz",
> +	"mdp_wdma",
> +	"mdp_wrot",
> +};
> +
> +struct mtk_mdp_comp_match {
> +	enum mtk_mdp_comp_type type;
> +	int alias_id;
> +};
> +
> +static const struct mtk_mdp_comp_match mtk_mdp_matches[MTK_MDP_COMP_ID_MAX] = {
> +	{ MTK_MDP_RDMA,	0 },
> +	{ MTK_MDP_RDMA,	1 },
> +	{ MTK_MDP_RSZ,	0 },
> +	{ MTK_MDP_RSZ,	1 },
> +	{ MTK_MDP_RSZ,	2 },
> +	{ MTK_MDP_WDMA,	0 },
> +	{ MTK_MDP_WROT,	0 },
> +	{ MTK_MDP_WROT,	1 },
> +};
> +
> +int mtk_mdp_comp_get_id(struct device *dev, struct device_node *node,
> +			enum mtk_mdp_comp_type comp_type)
> +{
> +	int id = of_alias_get_id(node, mtk_mdp_comp_stem[comp_type]);
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(mtk_mdp_matches); i++) {
> +		if (comp_type == mtk_mdp_matches[i].type &&
> +		    id == mtk_mdp_matches[i].alias_id)
> +			return i;
> +	}
> +
> +	dev_err(dev, "Failed to get id. type: %d, id: %d\n", comp_type, id);
> +
> +	return -EINVAL;
> +}
> +
> +void mtk_mdp_comp_clock_on(struct device *dev, struct mtk_mdp_comp *comp)
> +{
> +	int i, err;
> +
> +	if (comp->larb_dev) {
> +		err = mtk_smi_larb_get(comp->larb_dev);
> +		if (err)
> +			dev_err(dev,
> +				"failed to get larb, err %d. type:%d id:%d\n",
> +				err, comp->type, comp->id);
> +	}
> +
> +	for (i = 0; i < ARRAY_SIZE(comp->clk); i++) {
> +		if (!comp->clk[i])
> +			continue;
> +		err = clk_prepare_enable(comp->clk[i]);
> +		if (err)
> +			dev_err(dev,
> +			"failed to enable clock, err %d. type:%d id:%d i:%d\n",
> +				err, comp->type, comp->id, i);
> +	}
> +}
> +
> +void mtk_mdp_comp_clock_off(struct device *dev, struct mtk_mdp_comp *comp)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(comp->clk); i++) {
> +		if (!comp->clk[i])
> +			continue;
> +		clk_disable_unprepare(comp->clk[i]);
> +	}
> +
> +	if (comp->larb_dev)
> +		mtk_smi_larb_put(comp->larb_dev);
> +}
> +
> +int mtk_mdp_comp_init(struct device *dev, struct device_node *node,
> +		      struct mtk_mdp_comp *comp, enum mtk_mdp_comp_id comp_id)
> +{
> +	struct device_node *larb_node;
> +	struct platform_device *larb_pdev;
> +	int i;
> +
> +	if (comp_id < 0 || comp_id >= MTK_MDP_COMP_ID_MAX) {
> +		dev_err(dev, "Invalid comp_id %d\n", comp_id);
> +		return -EINVAL;
> +	}
> +
> +	comp->dev_node = of_node_get(node);
> +	comp->id = comp_id;
> +	comp->type = mtk_mdp_matches[comp_id].type;
> +	comp->regs = of_iomap(node, 0);
> +
> +	for (i = 0; i < ARRAY_SIZE(comp->clk); i++) {
> +		comp->clk[i] = of_clk_get(node, i);
> +
> +		/* Only RDMA needs two clocks */
> +		if (comp->type != MTK_MDP_RDMA)
> +			break;
> +	}
> +
> +	/* Only DMA capable components need the LARB property */
> +	comp->larb_dev = NULL;
> +	if (comp->type != MTK_MDP_RDMA &&
> +	    comp->type != MTK_MDP_WDMA &&
> +	    comp->type != MTK_MDP_WROT)
> +		return 0;
> +
> +	larb_node = of_parse_phandle(node, "mediatek,larb", 0);
> +	if (!larb_node) {
> +		dev_err(dev,
> +			"Missing mediadek,larb phandle in %s node\n",
> +			node->full_name);
> +		return -EINVAL;
> +	}
> +
> +	larb_pdev = of_find_device_by_node(larb_node);
> +	if (!larb_pdev) {
> +		dev_warn(dev, "Waiting for larb device %s\n",
> +			 larb_node->full_name);
> +		of_node_put(larb_node);
> +		return -EPROBE_DEFER;
> +	}
> +	of_node_put(larb_node);
> +
> +	comp->larb_dev = &larb_pdev->dev;
> +
> +	return 0;
> +}
> +
> +void mtk_mdp_comp_deinit(struct device *dev, struct mtk_mdp_comp *comp)
> +{
> +	of_node_put(comp->dev_node);
> +}
> diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_comp.h b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.h
> new file mode 100644
> index 0000000..63b3983
> --- /dev/null
> +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.h
> @@ -0,0 +1,72 @@
> +/*
> + * Copyright (c) 2016 MediaTek Inc.
> + * Author: Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#ifndef __MTK_MDP_COMP_H__
> +#define __MTK_MDP_COMP_H__
> +
> +/**
> + * enum mtk_mdp_comp_type - the MDP component
> + * @MTK_MDP_RDMA:	Read DMA
> + * @MTK_MDP_RSZ:	Riszer
> + * @MTK_MDP_WDMA:	Write DMA
> + * @MTK_MDP_WROT:	Write DMA with rotation
> + */
> +enum mtk_mdp_comp_type {
> +	MTK_MDP_RDMA,
> +	MTK_MDP_RSZ,
> +	MTK_MDP_WDMA,
> +	MTK_MDP_WROT,
> +	MTK_MDP_COMP_TYPE_MAX,
> +};
> +
> +enum mtk_mdp_comp_id {
> +	MTK_MDP_COMP_RDMA0,
> +	MTK_MDP_COMP_RDMA1,
> +	MTK_MDP_COMP_RSZ0,
> +	MTK_MDP_COMP_RSZ1,
> +	MTK_MDP_COMP_RSZ2,
> +	MTK_MDP_COMP_WDMA,
> +	MTK_MDP_COMP_WROT0,
> +	MTK_MDP_COMP_WROT1,
> +	MTK_MDP_COMP_ID_MAX,
> +};
> +
> +/**
> + * struct mtk_mdp_comp - the MDP's function component data
> + * @dev_node:	component device node
> + * @clk:	clocks required for component
> + * @regs:	Mapped address of component registers.
> + * @larb_dev:	SMI device required for component
> + * @type:	component type
> + * @id:		component ID
> + */
> +struct mtk_mdp_comp {
> +	struct device_node	*dev_node;
> +	struct clk		*clk[2];
> +	void __iomem		*regs;
> +	struct device		*larb_dev;
> +	enum mtk_mdp_comp_type	type;
> +	enum mtk_mdp_comp_id	id;
> +};
> +
> +int mtk_mdp_comp_init(struct device *dev, struct device_node *node,
> +		      struct mtk_mdp_comp *comp, enum mtk_mdp_comp_id comp_id);
> +void mtk_mdp_comp_deinit(struct device *dev, struct mtk_mdp_comp *comp);
> +int mtk_mdp_comp_get_id(struct device *dev, struct device_node *node,
> +			enum mtk_mdp_comp_type comp_type);
> +void mtk_mdp_comp_clock_on(struct device *dev, struct mtk_mdp_comp *comp);
> +void mtk_mdp_comp_clock_off(struct device *dev, struct mtk_mdp_comp *comp);
> +
> +
> +#endif /* __MTK_MDP_COMP_H__ */
> diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c
> new file mode 100644
> index 0000000..8a81dd9
> --- /dev/null
> +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c
> @@ -0,0 +1,294 @@
> +/*
> + * Copyright (c) 2015-2016 MediaTek Inc.
> + * Author: Houlong Wei <houlong.wei at mediatek.com>
> + *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/device.h>
> +#include <linux/errno.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/workqueue.h>
> +#include <soc/mediatek/smi.h>
> +
> +#include "mtk_mdp_core.h"
> +#include "mtk_mdp_m2m.h"
> +#include "mtk_vpu.h"
> +
> +/* MDP debug log level (0-3). 3 shows all the logs. */
> +int mtk_mdp_dbg_level;
> +EXPORT_SYMBOL(mtk_mdp_dbg_level);
> +
> +module_param(mtk_mdp_dbg_level, int, S_IRUGO | S_IWUSR);
> +
> +static const struct of_device_id mtk_mdp_comp_dt_ids[] = {
> +	{
> +		.compatible = "mediatek,mt8173-mdp-rdma",
> +		.data = (void *)MTK_MDP_RDMA
> +	}, {
> +		.compatible = "mediatek,mt8173-mdp-rsz",
> +		.data = (void *)MTK_MDP_RSZ
> +	}, {
> +		.compatible = "mediatek,mt8173-mdp-wdma",
> +		.data = (void *)MTK_MDP_WDMA
> +	}, {
> +		.compatible = "mediatek,mt8173-mdp-wrot",
> +		.data = (void *)MTK_MDP_WROT
> +	}
> +};
> +
> +static const struct of_device_id mtk_mdp_of_ids[] = {
> +	{ .compatible = "mediatek,mt8173-mdp", },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, mtk_mdp_of_ids);
> +
> +static void mtk_mdp_clock_on(struct mtk_mdp_dev *mdp)
> +{
> +	struct device *dev = &mdp->pdev->dev;
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(mdp->comp); i++)
> +		mtk_mdp_comp_clock_on(dev, mdp->comp[i]);
> +}
> +
> +static void mtk_mdp_clock_off(struct mtk_mdp_dev *mdp)
> +{
> +	struct device *dev = &mdp->pdev->dev;
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(mdp->comp); i++)
> +		mtk_mdp_comp_clock_off(dev, mdp->comp[i]);
> +}
> +
> +static void mtk_mdp_wdt_worker(struct work_struct *work)
> +{
> +	struct mtk_mdp_dev *mdp =
> +			container_of(work, struct mtk_mdp_dev, wdt_work);
> +	struct mtk_mdp_ctx *ctx;
> +
> +	mtk_mdp_err("Watchdog timeout");
> +
> +	list_for_each_entry(ctx, &mdp->ctx_list, list) {
> +		mtk_mdp_dbg(0, "[%d] Change as state error", ctx->id);
> +		mtk_mdp_ctx_state_lock_set(ctx, MTK_MDP_CTX_ERROR);
> +	}
> +}
> +
> +static void mtk_mdp_reset_handler(void *priv)
> +{
> +	struct mtk_mdp_dev *mdp = priv;
> +
> +	queue_work(mdp->wdt_wq, &mdp->wdt_work);
> +}
> +
> +static int mtk_mdp_probe(struct platform_device *pdev)
> +{
> +	struct mtk_mdp_dev *mdp;
> +	struct device *dev = &pdev->dev;
> +	struct device_node *node;
> +	int i, ret = 0;
> +
> +	mdp = devm_kzalloc(dev, sizeof(*mdp), GFP_KERNEL);
> +	if (!mdp)
> +		return -ENOMEM;
> +
> +	mdp->id = pdev->id;
> +	mdp->pdev = pdev;
> +	INIT_LIST_HEAD(&mdp->ctx_list);
> +
> +	mutex_init(&mdp->lock);
> +	mutex_init(&mdp->vpulock);
> +
> +	/* Iterate over sibling MDP function blocks */
> +	for_each_child_of_node(dev->of_node->parent, node) {
> +		const struct of_device_id *of_id;
> +		enum mtk_mdp_comp_type comp_type;
> +		int comp_id;
> +		struct mtk_mdp_comp *comp;
> +
> +		of_id = of_match_node(mtk_mdp_comp_dt_ids, node);
> +		if (!of_id)
> +			continue;
> +
> +		if (!of_device_is_available(node)) {
> +			dev_err(dev, "Skipping disabled component %s\n",
> +				node->full_name);
> +			continue;
> +		}
> +
> +		comp_type = (enum mtk_mdp_comp_type)of_id->data;
> +		comp_id = mtk_mdp_comp_get_id(dev, node, comp_type);
> +		if (comp_id < 0) {
> +			dev_warn(dev, "Skipping unknown component %s\n",
> +				 node->full_name);
> +			continue;
> +		}
> +
> +		comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL);
> +		if (!comp) {
> +			ret = -ENOMEM;
> +			goto err_comp;
> +		}
> +		mdp->comp[comp_id] = comp;
> +
> +		ret = mtk_mdp_comp_init(dev, node, comp, comp_id);
> +		if (ret)
> +			goto err_comp;
> +	}
> +
> +	mdp->job_wq = create_singlethread_workqueue(MTK_MDP_MODULE_NAME);
> +	if (!mdp->job_wq) {
> +		dev_err(&pdev->dev, "unable to alloc job workqueue\n");
> +		ret = -ENOMEM;
> +		goto err_alloc_job_wq;
> +	}
> +
> +	mdp->wdt_wq = create_singlethread_workqueue("mdp_wdt_wq");
> +	if (!mdp->wdt_wq) {
> +		dev_err(&pdev->dev, "unable to alloc wdt workqueue\n");
> +		ret = -ENOMEM;
> +		goto err_alloc_wdt_wq;
> +	}
> +	INIT_WORK(&mdp->wdt_work, mtk_mdp_wdt_worker);
> +
> +	ret = v4l2_device_register(dev, &mdp->v4l2_dev);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Failed to register v4l2 device\n");
> +		ret = -EINVAL;
> +		goto err_dev_register;
> +	}
> +
> +	ret = mtk_mdp_register_m2m_device(mdp);
> +	if (ret) {
> +		v4l2_err(&mdp->v4l2_dev, "Failed to init mem2mem device\n");
> +		goto err_m2m_register;
> +	}
> +
> +	mdp->vpu_dev = vpu_get_plat_device(pdev);
> +	vpu_wdt_reg_handler(mdp->vpu_dev, mtk_mdp_reset_handler, mdp,
> +			    VPU_RST_MDP);
> +
> +	platform_set_drvdata(pdev, mdp);
> +
> +	vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32));
> +
> +	pm_runtime_enable(dev);
> +	dev_dbg(dev, "mdp-%d registered successfully\n", mdp->id);
> +
> +	return 0;
> +
> +err_m2m_register:
> +	v4l2_device_unregister(&mdp->v4l2_dev);
> +
> +err_dev_register:
> +	destroy_workqueue(mdp->wdt_wq);
> +
> +err_alloc_wdt_wq:
> +	destroy_workqueue(mdp->job_wq);
> +
> +err_alloc_job_wq:
> +
> +err_comp:
> +	for (i = 0; i < ARRAY_SIZE(mdp->comp); i++)
> +		mtk_mdp_comp_deinit(dev, mdp->comp[i]);
> +
> +	dev_dbg(dev, "err %d\n", ret);
> +	return ret;
> +}
> +
> +static int mtk_mdp_remove(struct platform_device *pdev)
> +{
> +	struct mtk_mdp_dev *mdp = platform_get_drvdata(pdev);
> +	int i;
> +
> +	pm_runtime_disable(&pdev->dev);
> +	vb2_dma_contig_clear_max_seg_size(&pdev->dev);
> +	mtk_mdp_unregister_m2m_device(mdp);
> +	v4l2_device_unregister(&mdp->v4l2_dev);
> +
> +	flush_workqueue(mdp->job_wq);
> +	destroy_workqueue(mdp->job_wq);
> +
> +	for (i = 0; i < ARRAY_SIZE(mdp->comp); i++)
> +		mtk_mdp_comp_deinit(&pdev->dev, mdp->comp[i]);
> +
> +	dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
> +	return 0;
> +}
> +
> +#if defined(CONFIG_PM_RUNTIME) || defined(CONFIG_PM_SLEEP)
> +static int mtk_mdp_pm_suspend(struct device *dev)
> +{
> +	struct mtk_mdp_dev *mdp = dev_get_drvdata(dev);
> +
> +	mtk_mdp_clock_off(mdp);
> +
> +	return 0;
> +}
> +
> +static int mtk_mdp_pm_resume(struct device *dev)
> +{
> +	struct mtk_mdp_dev *mdp = dev_get_drvdata(dev);
> +
> +	mtk_mdp_clock_on(mdp);
> +
> +	return 0;
> +}
> +#endif /* CONFIG_PM_RUNTIME || CONFIG_PM_SLEEP */
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int mtk_mdp_suspend(struct device *dev)
> +{
> +	if (pm_runtime_suspended(dev))
> +		return 0;
> +
> +	return mtk_mdp_pm_suspend(dev);
> +}
> +
> +static int mtk_mdp_resume(struct device *dev)
> +{
> +	if (pm_runtime_suspended(dev))
> +		return 0;
> +
> +	return mtk_mdp_pm_resume(dev);
> +}
> +#endif /* CONFIG_PM_SLEEP */
> +
> +static const struct dev_pm_ops mtk_mdp_pm_ops = {
> +	SET_SYSTEM_SLEEP_PM_OPS(mtk_mdp_suspend, mtk_mdp_resume)
> +	SET_RUNTIME_PM_OPS(mtk_mdp_pm_suspend, mtk_mdp_pm_resume, NULL)
> +};
> +
> +static struct platform_driver mtk_mdp_driver = {
> +	.probe		= mtk_mdp_probe,
> +	.remove		= mtk_mdp_remove,
> +	.driver = {
> +		.name	= MTK_MDP_MODULE_NAME,
> +		.owner	= THIS_MODULE,
> +		.pm	= &mtk_mdp_pm_ops,
> +		.of_match_table = mtk_mdp_of_ids,
> +	}
> +};
> +
> +module_platform_driver(mtk_mdp_driver);
> +
> +MODULE_AUTHOR("Houlong Wei <houlong.wei at mediatek.com>");
> +MODULE_DESCRIPTION("Mediatek image processor driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.h b/drivers/media/platform/mtk-mdp/mtk_mdp_core.h
> new file mode 100644
> index 0000000..9046968
> --- /dev/null
> +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.h
> @@ -0,0 +1,233 @@
> +/*
> + * Copyright (c) 2015-2016 MediaTek Inc.
> + * Author: Houlong Wei <houlong.wei at mediatek.com>
> + *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#ifndef __MTK_MDP_CORE_H__
> +#define __MTK_MDP_CORE_H__
> +
> +#include <linux/videodev2.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-mem2mem.h>
> +#include <media/videobuf2-core.h>
> +#include <media/videobuf2-dma-contig.h>
> +
> +#include "mtk_mdp_vpu.h"
> +#include "mtk_mdp_comp.h"
> +
> +
> +#define MTK_MDP_MODULE_NAME		"mtk-mdp"
> +
> +#define MTK_MDP_SHUTDOWN_TIMEOUT	((100*HZ)/1000) /* 100ms */
> +#define MTK_MDP_MAX_CTRL_NUM		10
> +
> +#define MTK_MDP_FMT_FLAG_OUTPUT		BIT(0)
> +#define MTK_MDP_FMT_FLAG_CAPTURE	BIT(1)
> +
> +#define MTK_MDP_SRC_FMT			BIT(1)
> +#define MTK_MDP_DST_FMT			BIT(2)
> +#define MTK_MDP_CTX_ERROR		BIT(5)
> +
> +/**
> + * struct mtk_mdp_fmt - the driver's internal color format data
> + * @name: format description
> + * @pixelformat: the fourcc code for this format, 0 if not applicable
> + * @num_planes: number of physically non-contiguous data planes
> + * @depth: per plane driver's private 'number of bits per pixel'
> + * @flags: flags indicating which operation mode format applies to
> +	   MTK_MDP_FMT_FLAG_OUTPUT is used in OUTPUT stream
> +	   MTK_MDP_FMT_FLAG_CAPTURE is used in CAPTURE stream
> + */
> +struct mtk_mdp_fmt {
> +	char	*name;
> +	u32	pixelformat;
> +	u16	num_planes;
> +	u8	depth[VIDEO_MAX_PLANES];
> +	u32	flags;
> +};
> +
> +/**
> + * struct mtk_mdp_addr - the image processor physical address set
> + * @addr:	address of planes
> + */
> +struct mtk_mdp_addr {
> +	dma_addr_t addr[MTK_MDP_MAX_NUM_PLANE];
> +};
> +
> +/* struct mtk_mdp_ctrls - the image processor control set
> + * @rotate: rotation degree
> + * @hflip: horizontal flip
> + * @vflip: vertical flip
> + * @global_alpha: the alpha value of current frame
> + */
> +struct mtk_mdp_ctrls {
> +	struct v4l2_ctrl *rotate;
> +	struct v4l2_ctrl *hflip;
> +	struct v4l2_ctrl *vflip;
> +	struct v4l2_ctrl *global_alpha;
> +};
> +
> +/**
> + * struct mtk_mdp_frame - source/target frame properties
> + * @width:	SRC : SRCIMG_WIDTH, DST : OUTPUTDMA_WHOLE_IMG_WIDTH
> + * @height:	SRC : SRCIMG_HEIGHT, DST : OUTPUTDMA_WHOLE_IMG_HEIGHT
> + * @crop:	cropped(source)/scaled(destination) size
> + * @payload:	image size in bytes (w x h x bpp)
> + * @pitch:	bytes per line of image in memory
> + * @addr:	image frame buffer physical addresses
> + * @fmt:	color format pointer
> + * @alpha:	frame's alpha value
> + */
> +struct mtk_mdp_frame {
> +	u32				width;
> +	u32				height;
> +	struct v4l2_rect		crop;
> +	unsigned long			payload[VIDEO_MAX_PLANES];
> +	unsigned int			pitch[VIDEO_MAX_PLANES];
> +	struct mtk_mdp_addr		addr;
> +	const struct mtk_mdp_fmt	*fmt;
> +	u8				alpha;
> +};
> +
> +/**
> + * struct mtk_mdp_variant - image processor variant information
> + * @pix_max:		maximum limit of image size
> + * @pix_min:		minimun limit of image size
> + * @pix_align:		alignement of image
> + * @h_scale_up_max:	maximum scale-up in horizontal
> + * @v_scale_up_max:	maximum scale-up in vertical
> + * @h_scale_down_max:	maximum scale-down in horizontal
> + * @v_scale_down_max:	maximum scale-down in vertical
> + */
> +struct mtk_mdp_variant {
> +	struct mtk_mdp_pix_limit	*pix_max;
> +	struct mtk_mdp_pix_limit	*pix_min;
> +	struct mtk_mdp_pix_align	*pix_align;
> +	u16				h_scale_up_max;
> +	u16				v_scale_up_max;
> +	u16				h_scale_down_max;
> +	u16				v_scale_down_max;
> +};
> +
> +/**
> + * struct mtk_mdp_dev - abstraction for image processor entity
> + * @lock:	the mutex protecting this data structure
> + * @vpulock:	the mutex protecting the communication with VPU
> + * @pdev:	pointer to the image processor platform device
> + * @variant:	the IP variant information
> + * @id:		image processor device index (0..MTK_MDP_MAX_DEVS)
> + * @comp:	MDP function components
> + * @m2m_dev:	v4l2 memory-to-memory device data
> + * @ctx_list:	list of struct mtk_mdp_ctx
> + * @vdev:	video device for image processor driver
> + * @v4l2_dev:	V4L2 device to register video devices for.
> + * @job_wq:	processor work queue
> + * @vpu_dev:	VPU platform device
> + * @ctx_num:	counter of active MTK MDP context
> + * @id_counter:	An integer id given to the next opened context
> + * @wdt_wq:	work queue for VPU watchdog
> + * @wdt_work:	worker for VPU watchdog
> + */
> +struct mtk_mdp_dev {
> +	struct mutex			lock;
> +	struct mutex			vpulock;
> +	struct platform_device		*pdev;
> +	struct mtk_mdp_variant		*variant;
> +	u16				id;
> +	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 v4l2_device		v4l2_dev;
> +	struct workqueue_struct		*job_wq;
> +	struct platform_device		*vpu_dev;
> +	int				ctx_num;
> +	unsigned long			id_counter;
> +	struct workqueue_struct		*wdt_wq;
> +	struct work_struct		wdt_work;
> +};
> +
> +/**
> + * mtk_mdp_ctx - the device context data
> + * @list:		link to ctx_list of mtk_mdp_dev
> + * @s_frame:		source frame properties
> + * @d_frame:		destination frame properties
> + * @id:			index of the context that this structure describes
> + * @flags:		additional flags for image conversion
> + * @state:		flags to keep track of user configuration
> +			Protected by slock
> + * @rotation:		rotates the image by specified angle
> + * @hflip:		mirror the picture horizontally
> + * @vflip:		mirror the picture vertically
> + * @mdp_dev:		the image processor device this context applies to
> + * @m2m_ctx:		memory-to-memory device context
> + * @fh:			v4l2 file handle
> + * @ctrl_handler:	v4l2 controls handler
> + * @ctrls		image processor control set
> + * @ctrls_rdy:		true if the control handler is initialized
> + * @vpu:		VPU instance
> + * @slock:		the mutex protecting mtp_mdp_ctx.state
> + * @work:		worker for image processing
> + */
> +struct mtk_mdp_ctx {
> +	struct list_head		list;
> +	struct mtk_mdp_frame		s_frame;
> +	struct mtk_mdp_frame		d_frame;
> +	u32				flags;
> +	u32				state;
> +	int				id;
> +	int				rotation;
> +	u32				hflip:1;
> +	u32				vflip:1;
> +	struct mtk_mdp_dev		*mdp_dev;
> +	struct v4l2_m2m_ctx		*m2m_ctx;
> +	struct v4l2_fh			fh;
> +	struct v4l2_ctrl_handler	ctrl_handler;
> +	struct mtk_mdp_ctrls		ctrls;
> +	bool				ctrls_rdy;
> +
> +	struct mtk_mdp_vpu		vpu;
> +	struct mutex			slock;
> +	struct work_struct		work;
> +};
> +
> +extern int mtk_mdp_dbg_level;
> +
> +#if defined(DEBUG)
> +
> +#define mtk_mdp_dbg(level, fmt, args...)				 \
> +	do {								 \
> +		if (mtk_mdp_dbg_level >= level)				 \
> +			pr_info("[MTK_MDP] level=%d %s(),%d: " fmt "\n", \
> +				level, __func__, __LINE__, ##args);	 \
> +	} while (0)
> +
> +#define mtk_mdp_err(fmt, args...)					\
> +	pr_err("[MTK_MDP][ERROR] %s:%d: " fmt "\n", __func__, __LINE__, \
> +	       ##args)
> +
> +
> +#define mtk_mdp_dbg_enter()  mtk_mdp_dbg(3, "+")
> +#define mtk_mdp_dbg_leave()  mtk_mdp_dbg(3, "-")
> +
> +#else
> +
> +#define mtk_mdp_dbg(level, fmt, args...)
> +#define mtk_mdp_err(fmt, args...)
> +#define mtk_mdp_dbg_enter()
> +#define mtk_mdp_dbg_leave()
> +
> +#endif
> +
> +#endif /* __MTK_MDP_CORE_H__ */
> diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h b/drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h
> new file mode 100644
> index 0000000..78e2cc0
> --- /dev/null
> +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h
> @@ -0,0 +1,126 @@
> +/*
> + * Copyright (c) 2015-2016 MediaTek Inc.
> + * Author: Houlong Wei <houlong.wei at mediatek.com>
> + *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#ifndef __MTK_MDP_IPI_H__
> +#define __MTK_MDP_IPI_H__
> +
> +#define MTK_MDP_MAX_NUM_PLANE		3
> +
> +enum mdp_ipi_msgid {
> +	AP_MDP_INIT		= 0xd000,
> +	AP_MDP_DEINIT		= 0xd001,
> +	AP_MDP_PROCESS		= 0xd002,
> +
> +	VPU_MDP_INIT_ACK	= 0xe000,
> +	VPU_MDP_DEINIT_ACK	= 0xe001,
> +	VPU_MDP_PROCESS_ACK	= 0xe002
> +};
> +
> +#pragma pack(push, 4)
> +
> +/**
> + * struct mdp_ipi_init - for AP_MDP_INIT
> + * @msg_id   : AP_MDP_INIT
> + * @ipi_id   : IPI_MDP
> + * @ap_inst  : AP mtk_mdp_vpu address
> + */
> +struct mdp_ipi_init {
> +	uint32_t msg_id;
> +	uint32_t ipi_id;
> +	uint64_t ap_inst;
> +};
> +
> +/**
> + * struct mdp_ipi_comm - for AP_MDP_PROCESS, AP_MDP_DEINIT
> + * @msg_id        : AP_MDP_PROCESS, AP_MDP_DEINIT
> + * @ipi_id        : IPI_MDP
> + * @ap_inst       : AP mtk_mdp_vpu address
> + * @vpu_inst_addr : VPU MDP instance address
> + */
> +struct mdp_ipi_comm {
> +	uint32_t msg_id;
> +	uint32_t ipi_id;
> +	uint64_t ap_inst;
> +	uint32_t vpu_inst_addr;
> +};
> +
> +/**
> + * struct mdp_ipi_comm_ack - for VPU_MDP_DEINIT_ACK, VPU_MDP_PROCESS_ACK
> + * @msg_id        : VPU_MDP_DEINIT_ACK, VPU_MDP_PROCESS_ACK
> + * @ipi_id        : IPI_MDP
> + * @ap_inst       : AP mtk_mdp_vpu address
> + * @vpu_inst_addr : VPU MDP instance address
> + * @status        : VPU exeuction result
> + */
> +struct mdp_ipi_comm_ack {
> +	uint32_t msg_id;
> +	uint32_t ipi_id;
> +	uint64_t ap_inst;
> +	uint32_t vpu_inst_addr;
> +	int32_t status;
> +};
> +
> +/**
> + * struct mdp_config - configured for source/destination image
> + * @x        : left
> + * @y        : top
> + * @w        : width
> + * @h        : height
> + * @w_stride : bytes in horizontal
> + * @h_stride : bytes in vertical
> + * @crop_x   : cropped left
> + * @crop_y   : cropped top
> + * @crop_w   : cropped width
> + * @crop_h   : cropped height
> + * @format   : color format
> + */
> +struct mdp_config {
> +	int32_t x;
> +	int32_t y;
> +	int32_t w;
> +	int32_t h;
> +	int32_t w_stride;
> +	int32_t h_stride;
> +	int32_t crop_x;
> +	int32_t crop_y;
> +	int32_t crop_w;
> +	int32_t crop_h;
> +	int32_t format;
> +};
> +
> +struct mdp_buffer {
> +	uint64_t addr_mva[MTK_MDP_MAX_NUM_PLANE];
> +	int32_t plane_size[MTK_MDP_MAX_NUM_PLANE];
> +	int32_t plane_num;
> +};
> +
> +struct mdp_config_misc {
> +	int32_t orientation; /* 0, 90, 180, 270 */
> +	int32_t hflip; /* 1 will enable the flip */
> +	int32_t vflip; /* 1 will enable the flip */
> +	int32_t alpha; /* global alpha */
> +};
> +
> +struct mdp_process_vsi {
> +	struct mdp_config src_config;
> +	struct mdp_buffer src_buffer;
> +	struct mdp_config dst_config;
> +	struct mdp_buffer dst_buffer;
> +	struct mdp_config_misc misc;
> +};
> +
> +#pragma pack(pop)
> +
> +#endif /* __MTK_MDP_IPI_H__ */
> diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
> new file mode 100644
> index 0000000..e3ea97d
> --- /dev/null
> +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
> @@ -0,0 +1,1304 @@
> +/*
> + * Copyright (c) 2015-2016 MediaTek Inc.
> + * Author: Houlong Wei <houlong.wei at mediatek.com>
> + *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/workqueue.h>
> +#include <media/v4l2-event.h>
> +#include <media/v4l2-ioctl.h>
> +
> +#include "mtk_mdp_core.h"
> +#include "mtk_mdp_m2m.h"
> +#include "mtk_mdp_regs.h"
> +#include "mtk_vpu.h"
> +
> +
> +/**
> + *  struct mtk_mdp_pix_limit - image pixel size limits
> + *  @org_w: source pixel width
> + *  @org_h: source pixel height
> + *  @target_rot_dis_w: pixel dst scaled width with the rotator is off
> + *  @target_rot_dis_h: pixel dst scaled height with the rotator is off
> + *  @target_rot_en_w: pixel dst scaled width with the rotator is on
> + *  @target_rot_en_h: pixel dst scaled height with the rotator is on
> + */
> +struct mtk_mdp_pix_limit {
> +	u16 org_w;
> +	u16 org_h;
> +	u16 target_rot_dis_w;
> +	u16 target_rot_dis_h;
> +	u16 target_rot_en_w;
> +	u16 target_rot_en_h;
> +};
> +
> +/**
> + *  struct mtk_mdp_pix_align - alignement of image
> + *  @org_w: source alignment of width
> + *  @org_h: source alignment of height
> + *  @target_w: dst alignment of width
> + *  @target_h: dst alignment of height
> + */
> +struct mtk_mdp_pix_align {
> +	u16 org_w;
> +	u16 org_h;
> +	u16 target_w;
> +	u16 target_h;
> +};
> +
> +static const struct mtk_mdp_fmt mtk_mdp_formats[] = {
> +	{
> +		.name		= "YUV420 MT21. 2p, Y/CbCr",
> +		.pixelformat	= V4L2_PIX_FMT_MT21,
> +		.depth		= { 8, 4 },
> +		.num_planes	= 2,
> +		.flags		= MTK_MDP_FMT_FLAG_OUTPUT,
> +	}, {
> +		.name		= "YUV420 non-contig. 2p, Y/CbCr",
> +		.pixelformat	= V4L2_PIX_FMT_NV12M,
> +		.depth		= { 8, 4 },
> +		.num_planes	= 2,
> +		.flags		= MTK_MDP_FMT_FLAG_OUTPUT |
> +				  MTK_MDP_FMT_FLAG_CAPTURE,
> +	}, {
> +		.name		= "YUV420 non-contig. 3p, Y/Cb/Cr",
> +		.pixelformat	= V4L2_PIX_FMT_YUV420M,
> +		.depth		= { 8, 2, 2 },
> +		.num_planes	= 3,
> +		.flags		= MTK_MDP_FMT_FLAG_OUTPUT |
> +				  MTK_MDP_FMT_FLAG_CAPTURE,
> +	}
> +};
> +
> +static struct mtk_mdp_pix_limit mtk_mdp_size_max = {
> +	.target_rot_dis_w	= 4096,
> +	.target_rot_dis_h	= 4096,
> +	.target_rot_en_w	= 4096,
> +	.target_rot_en_h	= 4096,
> +};
> +
> +static struct mtk_mdp_pix_limit mtk_mdp_size_min = {
> +	.org_w			= 16,
> +	.org_h			= 16,
> +	.target_rot_dis_w	= 16,
> +	.target_rot_dis_h	= 16,
> +	.target_rot_en_w	= 16,
> +	.target_rot_en_h	= 16,
> +};
> +
> +static struct mtk_mdp_pix_align mtk_mdp_size_align = {
> +	.org_w			= 16,
> +	.org_h			= 16,
> +	.target_w		= 2,
> +	.target_h		= 2,
> +};
> +
> +static struct mtk_mdp_variant mtk_mdp_default_variant = {
> +	.pix_max		= &mtk_mdp_size_max,
> +	.pix_min		= &mtk_mdp_size_min,
> +	.pix_align		= &mtk_mdp_size_align,
> +	.h_scale_up_max		= 32,
> +	.v_scale_up_max		= 32,
> +	.h_scale_down_max	= 32,
> +	.v_scale_down_max	= 128,
> +};
> +
> +static const struct mtk_mdp_fmt *mtk_mdp_find_fmt(u32 pixelformat, u32 type)
> +{
> +	u32 i, flag;
> +
> +	flag = V4L2_TYPE_IS_OUTPUT(type) ? MTK_MDP_FMT_FLAG_OUTPUT :
> +					   MTK_MDP_FMT_FLAG_CAPTURE;
> +
> +	for (i = 0; i < ARRAY_SIZE(mtk_mdp_formats); ++i) {
> +		if (!(mtk_mdp_formats[i].flags & flag))
> +			continue;
> +		if (mtk_mdp_formats[i].pixelformat == pixelformat)
> +			return &mtk_mdp_formats[i];
> +	}
> +	return NULL;
> +}
> +
> +static const struct mtk_mdp_fmt *mtk_mdp_find_fmt_by_index(u32 index, u32 type)
> +{
> +	u32 i, flag, num = 0;
> +
> +	flag = V4L2_TYPE_IS_OUTPUT(type) ? MTK_MDP_FMT_FLAG_OUTPUT :
> +					   MTK_MDP_FMT_FLAG_CAPTURE;
> +
> +	for (i = 0; i < ARRAY_SIZE(mtk_mdp_formats); ++i) {
> +		if (!(mtk_mdp_formats[i].flags & flag))
> +			continue;
> +		if (index == num)
> +			return &mtk_mdp_formats[i];
> +		num++;
> +	}
> +	return NULL;
> +}
> +
> +static void mtk_mdp_bound_align_image(u32 *w, unsigned int wmin,
> +				      unsigned int wmax, unsigned int align_w,
> +				      u32 *h, unsigned int hmin,
> +				      unsigned int hmax, unsigned int align_h)
> +{
> +	int org_w, org_h, step_w, step_h;
> +	int walign, halign;
> +
> +	org_w = *w;
> +	org_h = *h;
> +	walign = ffs(align_w) - 1;
> +	halign = ffs(align_h) - 1;
> +	v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
> +
> +	step_w = 1 << walign;
> +	step_h = 1 << halign;
> +	if (*w < org_w && (*w + step_w) <= wmax)
> +		*w += step_w;
> +	if (*h < org_h && (*h + step_h) <= hmax)
> +		*h += step_h;
> +}
> +
> +static const struct mtk_mdp_fmt *mtk_mdp_try_fmt_mplane(struct mtk_mdp_ctx *ctx,
> +							struct v4l2_format *f)
> +{
> +	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
> +	struct mtk_mdp_variant *variant = mdp->variant;
> +	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
> +	const struct mtk_mdp_fmt *fmt;
> +	u32 max_w, max_h, align_w, align_h;
> +	u32 min_w, min_h, org_w, org_h;
> +	int i;
> +
> +	fmt = mtk_mdp_find_fmt(pix_mp->pixelformat, f->type);
> +	if (!fmt)
> +		fmt = mtk_mdp_find_fmt_by_index(0, f->type);
> +	if (!fmt) {
> +		dev_dbg(&ctx->mdp_dev->pdev->dev,
> +			"pixelformat format 0x%X invalid\n",
> +			pix_mp->pixelformat);
> +		return NULL;
> +	}
> +
> +	pix_mp->field = V4L2_FIELD_NONE;
> +	pix_mp->pixelformat = fmt->pixelformat;
> +	memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
> +
> +	max_w = variant->pix_max->target_rot_dis_w;
> +	max_h = variant->pix_max->target_rot_dis_h;
> +
> +	align_w = variant->pix_align->org_w;
> +	align_h = variant->pix_align->org_h;
> +
> +	if (V4L2_TYPE_IS_OUTPUT(f->type)) {
> +		min_w = variant->pix_min->org_w;
> +		min_h = variant->pix_min->org_h;
> +	} else {
> +		min_w = variant->pix_min->target_rot_dis_w;
> +		min_h = variant->pix_min->target_rot_dis_h;
> +	}
> +
> +	mtk_mdp_dbg(2, "[%d] type:%d, wxh:%ux%u, align:%ux%u, max:%ux%u",
> +		    ctx->id, f->type, pix_mp->width, pix_mp->height,
> +		    align_w, align_h, max_w, max_h);
> +	/*
> +	 * To check if image size is modified to adjust parameter against
> +	 * hardware abilities
> +	 */
> +	org_w = pix_mp->width;
> +	org_h = pix_mp->height;
> +
> +	mtk_mdp_bound_align_image(&pix_mp->width, min_w, max_w, align_w,
> +				  &pix_mp->height, min_h, max_h, align_h);
> +
> +	if (org_w != pix_mp->width || org_h != pix_mp->height)
> +		mtk_mdp_dbg(1, "[%d] size change:%ux%u to %ux%u", ctx->id,
> +			    org_w, org_h, pix_mp->width, pix_mp->height);
> +	pix_mp->num_planes = fmt->num_planes;
> +
> +	for (i = 0; i < pix_mp->num_planes; ++i) {
> +		int bpl = (pix_mp->width * fmt->depth[i]) >> 3;
> +		int sizeimage = bpl * pix_mp->height;
> +
> +		pix_mp->plane_fmt[i].bytesperline = bpl;
> +		if (pix_mp->plane_fmt[i].sizeimage < sizeimage)
> +			pix_mp->plane_fmt[i].sizeimage = sizeimage;
> +		memset(pix_mp->plane_fmt[i].reserved, 0,
> +		       sizeof(pix_mp->plane_fmt[i].reserved));
> +		mtk_mdp_dbg(2, "[%d] p%d, bpl:%d, sizeimage:%u (%u)", ctx->id,
> +			    i, bpl, pix_mp->plane_fmt[i].sizeimage, sizeimage);
> +	}
> +
> +	return fmt;
> +}
> +
> +static struct mtk_mdp_frame *mtk_mdp_ctx_get_frame(struct mtk_mdp_ctx *ctx,
> +					    enum v4l2_buf_type type)
> +{
> +	if (V4L2_TYPE_IS_OUTPUT(type))
> +		return &ctx->s_frame;
> +	return &ctx->d_frame;
> +}
> +
> +static void mtk_mdp_check_crop_change(u32 new_w, u32 new_h, u32 *w, u32 *h)
> +{
> +	if (new_w != *w || new_h != *h) {
> +		mtk_mdp_dbg(1, "size change:%dx%d to %dx%d",
> +			    *w, *h, new_w, new_h);
> +
> +		*w = new_w;
> +		*h = new_h;
> +	}
> +}
> +
> +static int mtk_mdp_try_crop(struct mtk_mdp_ctx *ctx, struct v4l2_crop *cr)
> +{
> +	struct mtk_mdp_frame *frame;
> +	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
> +	struct mtk_mdp_variant *variant = mdp->variant;
> +	u32 align_w, align_h, new_w, new_h;
> +	u32 min_w, min_h, max_w, max_h;
> +
> +	if (cr->c.top < 0 || cr->c.left < 0) {
> +		dev_err(&ctx->mdp_dev->pdev->dev,
> +			"doesn't support negative values for top & left\n");
> +		return -EINVAL;
> +	}
> +
> +	mtk_mdp_dbg(2, "[%d] type:%d, set wxh:%dx%d", ctx->id, cr->type,
> +		    cr->c.width, cr->c.height);
> +
> +	frame = mtk_mdp_ctx_get_frame(ctx, cr->type);
> +	max_w = frame->width;
> +	max_h = frame->height;
> +	new_w = cr->c.width;
> +	new_h = cr->c.height;
> +
> +	if (V4L2_TYPE_IS_OUTPUT(cr->type)) {
> +		align_w = 1;
> +		align_h = 1;
> +		min_w = 64;
> +		min_h = 32;
> +	} else {
> +		align_w = variant->pix_align->target_w;
> +		align_h = variant->pix_align->target_h;
> +		if (ctx->ctrls.rotate->val == 90 ||
> +		    ctx->ctrls.rotate->val == 270) {
> +			max_w = frame->height;
> +			max_h = frame->width;
> +			min_w = variant->pix_min->target_rot_en_w;
> +			min_h = variant->pix_min->target_rot_en_h;
> +			new_w = cr->c.height;
> +			new_h = cr->c.width;
> +		} else {
> +			min_w = variant->pix_min->target_rot_dis_w;
> +			min_h = variant->pix_min->target_rot_dis_h;
> +		}
> +	}
> +
> +	mtk_mdp_dbg(2, "[%d] align:%dx%d, min:%dx%d, new:%dx%d", ctx->id,
> +		    align_w, align_h, min_w, min_h, new_w, new_h);
> +
> +	mtk_mdp_bound_align_image(&new_w, min_w, max_w, align_w,
> +				  &new_h, min_h, max_h, align_h);
> +
> +	if (!V4L2_TYPE_IS_OUTPUT(cr->type) &&
> +		(ctx->ctrls.rotate->val == 90 ||
> +		ctx->ctrls.rotate->val == 270))
> +		mtk_mdp_check_crop_change(new_h, new_w,
> +					  &cr->c.width, &cr->c.height);
> +	else
> +		mtk_mdp_check_crop_change(new_w, new_h,
> +					  &cr->c.width, &cr->c.height);
> +
> +	/* adjust left/top if cropping rectangle is out of bounds */
> +	/* Need to add code to algin left value with 2's multiple */
> +	if (cr->c.left + new_w > max_w)
> +		cr->c.left = max_w - new_w;
> +	if (cr->c.top + new_h > max_h)
> +		cr->c.top = max_h - new_h;
> +
> +	if (cr->c.left & 1)
> +		cr->c.left -= 1;
> +
> +	mtk_mdp_dbg(2, "[%d] crop l,t,w,h:%d,%d,%d,%d, max:%dx%d", ctx->id,
> +		    cr->c.left, cr->c.top, cr->c.width,
> +		    cr->c.height, max_w, max_h);
> +	return 0;
> +}
> +
> +static inline struct mtk_mdp_ctx *fh_to_ctx(struct v4l2_fh *fh)
> +{
> +	return container_of(fh, struct mtk_mdp_ctx, fh);
> +}
> +
> +static inline struct mtk_mdp_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl)
> +{
> +	return container_of(ctrl->handler, struct mtk_mdp_ctx, ctrl_handler);
> +}
> +
> +void mtk_mdp_ctx_state_lock_set(struct mtk_mdp_ctx *ctx, u32 state)
> +{
> +	mutex_lock(&ctx->slock);
> +	ctx->state |= state;
> +	mutex_unlock(&ctx->slock);
> +}
> +
> +static void mtk_mdp_ctx_state_lock_clear(struct mtk_mdp_ctx *ctx, u32 state)
> +{
> +	mutex_lock(&ctx->slock);
> +	ctx->state &= ~state;
> +	mutex_unlock(&ctx->slock);
> +}
> +
> +static bool mtk_mdp_ctx_state_is_set(struct mtk_mdp_ctx *ctx, u32 mask)
> +{
> +	bool ret;
> +
> +	mutex_lock(&ctx->slock);
> +	ret = (ctx->state & mask) == mask;
> +	mutex_unlock(&ctx->slock);
> +	return ret;
> +}
> +
> +static void mtk_mdp_ctx_lock(struct vb2_queue *vq)
> +{
> +	struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vq);
> +
> +	mutex_lock(&ctx->mdp_dev->lock);
> +}
> +
> +static void mtk_mdp_ctx_unlock(struct vb2_queue *vq)
> +{
> +	struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vq);
> +
> +	mutex_unlock(&ctx->mdp_dev->lock);
> +}
> +
> +static void mtk_mdp_set_frame_size(struct mtk_mdp_frame *frame, int width,
> +				   int height)
> +{
> +	frame->width = width;
> +	frame->height = height;
> +	frame->crop.width = width;
> +	frame->crop.height = height;
> +	frame->crop.left = 0;
> +	frame->crop.top = 0;
> +}
> +
> +static int mtk_mdp_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
> +{
> +	struct mtk_mdp_ctx *ctx = q->drv_priv;
> +	int ret;
> +
> +	ret = pm_runtime_get_sync(&ctx->mdp_dev->pdev->dev);
> +	if (ret < 0)
> +		mtk_mdp_dbg(1, "[%d] pm_runtime_get_sync failed:%d",
> +			    ctx->id, ret);
> +
> +	return 0;
> +}
> +
> +static void *mtk_mdp_m2m_buf_remove(struct mtk_mdp_ctx *ctx,
> +				    enum v4l2_buf_type type)
> +{
> +	if (V4L2_TYPE_IS_OUTPUT(type))
> +		return v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
> +	else
> +		return v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
> +}
> +
> +static void mtk_mdp_m2m_stop_streaming(struct vb2_queue *q)
> +{
> +	struct mtk_mdp_ctx *ctx = q->drv_priv;
> +	struct vb2_buffer *vb;
> +
> +	vb = mtk_mdp_m2m_buf_remove(ctx, q->type);
> +	while (vb != NULL) {
> +		v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_ERROR);
> +		vb = mtk_mdp_m2m_buf_remove(ctx, q->type);
> +	}
> +
> +	pm_runtime_put(&ctx->mdp_dev->pdev->dev);
> +}
> +
> +static void mtk_mdp_m2m_job_abort(void *priv)
> +{
> +}
> +
> +/* The color format (num_planes) must be already configured. */
> +static void mtk_mdp_prepare_addr(struct mtk_mdp_ctx *ctx,
> +				 struct vb2_buffer *vb,
> +				 struct mtk_mdp_frame *frame,
> +				 struct mtk_mdp_addr *addr)
> +{
> +	u32 pix_size, planes, i;
> +
> +	pix_size = frame->width * frame->height;
> +	planes = min_t(u32, frame->fmt->num_planes, ARRAY_SIZE(addr->addr));
> +	for (i = 0; i < planes; i++)
> +		addr->addr[i] = vb2_dma_contig_plane_dma_addr(vb, i);
> +
> +	mtk_mdp_dbg(3, "[%d] planes:%d, size:%d, addr:%p,%p,%p",
> +		    ctx->id, planes, pix_size, (void *)addr->addr[0],
> +		    (void *)addr->addr[1], (void *)addr->addr[2]);
> +}
> +
> +static void mtk_mdp_m2m_get_bufs(struct mtk_mdp_ctx *ctx)
> +{
> +	struct mtk_mdp_frame *s_frame, *d_frame;
> +	struct vb2_buffer *src_vb, *dst_vb;
> +	struct vb2_v4l2_buffer *src_vbuf, *dst_vbuf;
> +
> +	s_frame = &ctx->s_frame;
> +	d_frame = &ctx->d_frame;
> +
> +	src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
> +	mtk_mdp_prepare_addr(ctx, src_vb, s_frame, &s_frame->addr);
> +
> +	dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
> +	mtk_mdp_prepare_addr(ctx, dst_vb, d_frame, &d_frame->addr);
> +
> +	src_vbuf = to_vb2_v4l2_buffer(src_vb);
> +	dst_vbuf = to_vb2_v4l2_buffer(dst_vb);
> +	dst_vbuf->vb2_buf.timestamp = src_vbuf->vb2_buf.timestamp;
> +}
> +
> +static void mtk_mdp_process_done(void *priv, int vb_state)
> +{
> +	struct mtk_mdp_dev *mdp = priv;
> +	struct mtk_mdp_ctx *ctx;
> +	struct vb2_buffer *src_vb, *dst_vb;
> +	struct vb2_v4l2_buffer *src_vbuf = NULL, *dst_vbuf = NULL;
> +
> +	ctx = v4l2_m2m_get_curr_priv(mdp->m2m_dev);
> +	if (!ctx)
> +		return;
> +
> +	src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
> +	src_vbuf = to_vb2_v4l2_buffer(src_vb);
> +	dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
> +	dst_vbuf = to_vb2_v4l2_buffer(dst_vb);
> +
> +	dst_vbuf->vb2_buf.timestamp = src_vbuf->vb2_buf.timestamp;
> +	dst_vbuf->timecode = src_vbuf->timecode;
> +	dst_vbuf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
> +	dst_vbuf->flags |= src_vbuf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
> +
> +	v4l2_m2m_buf_done(src_vbuf, vb_state);
> +	v4l2_m2m_buf_done(dst_vbuf, vb_state);
> +	v4l2_m2m_job_finish(ctx->mdp_dev->m2m_dev, ctx->m2m_ctx);
> +}
> +
> +static void mtk_mdp_m2m_worker(struct work_struct *work)
> +{
> +	struct mtk_mdp_ctx *ctx =
> +				container_of(work, struct mtk_mdp_ctx, work);
> +	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
> +	enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
> +	int ret;
> +
> +	if (mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_CTX_ERROR)) {
> +		dev_err(&mdp->pdev->dev, "ctx is in error state");
> +		goto worker_end;
> +	}
> +
> +	mtk_mdp_m2m_get_bufs(ctx);
> +
> +	mtk_mdp_hw_set_input_addr(ctx, &ctx->s_frame.addr);
> +	mtk_mdp_hw_set_output_addr(ctx, &ctx->d_frame.addr);
> +
> +	mtk_mdp_hw_set_in_size(ctx);
> +	mtk_mdp_hw_set_in_image_format(ctx);
> +
> +	mtk_mdp_hw_set_out_size(ctx);
> +	mtk_mdp_hw_set_out_image_format(ctx);
> +
> +	mtk_mdp_hw_set_rotation(ctx);
> +	mtk_mdp_hw_set_global_alpha(ctx);
> +
> +	ret = mtk_mdp_vpu_process(&ctx->vpu);
> +	if (ret) {
> +		dev_err(&mdp->pdev->dev, "processing failed: %d", ret);
> +		goto worker_end;
> +	}
> +
> +	buf_state = VB2_BUF_STATE_DONE;
> +
> +worker_end:
> +	mtk_mdp_process_done(mdp, buf_state);
> +}
> +
> +static void mtk_mdp_m2m_device_run(void *priv)
> +{
> +	struct mtk_mdp_ctx *ctx = priv;
> +
> +	queue_work(ctx->mdp_dev->job_wq, &ctx->work);
> +}
> +
> +static int mtk_mdp_m2m_queue_setup(struct vb2_queue *vq,
> +			unsigned int *num_buffers, unsigned int *num_planes,
> +			unsigned int sizes[], struct device *alloc_devs[])
> +{
> +	struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vq);
> +	struct mtk_mdp_frame *frame;
> +	int i;
> +
> +	frame = mtk_mdp_ctx_get_frame(ctx, vq->type);
> +	*num_planes = frame->fmt->num_planes;
> +	for (i = 0; i < frame->fmt->num_planes; i++)
> +		sizes[i] = frame->payload[i];
> +	mtk_mdp_dbg(2, "[%d] type:%d, planes:%d, buffers:%d, size:%u,%u",
> +		    ctx->id, vq->type, *num_planes, *num_buffers,
> +		    sizes[0], sizes[1]);
> +	return 0;
> +}
> +
> +static int mtk_mdp_m2m_buf_prepare(struct vb2_buffer *vb)
> +{
> +	struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
> +	struct mtk_mdp_frame *frame;
> +	int i;
> +
> +	frame = mtk_mdp_ctx_get_frame(ctx, vb->vb2_queue->type);
> +
> +	if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
> +		for (i = 0; i < frame->fmt->num_planes; i++)
> +			vb2_set_plane_payload(vb, i, frame->payload[i]);
> +	}
> +
> +	return 0;
> +}
> +
> +static void mtk_mdp_m2m_buf_queue(struct vb2_buffer *vb)
> +{
> +	struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
> +
> +	v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb));
> +}
> +
> +static struct vb2_ops mtk_mdp_m2m_qops = {
> +	.queue_setup	 = mtk_mdp_m2m_queue_setup,
> +	.buf_prepare	 = mtk_mdp_m2m_buf_prepare,
> +	.buf_queue	 = mtk_mdp_m2m_buf_queue,
> +	.wait_prepare	 = mtk_mdp_ctx_unlock,
> +	.wait_finish	 = mtk_mdp_ctx_lock,
> +	.stop_streaming	 = mtk_mdp_m2m_stop_streaming,
> +	.start_streaming = mtk_mdp_m2m_start_streaming,
> +};
> +
> +static int mtk_mdp_m2m_querycap(struct file *file, void *fh,
> +				struct v4l2_capability *cap)
> +{
> +	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
> +	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
> +
> +	strlcpy(cap->driver, MTK_MDP_MODULE_NAME, sizeof(cap->driver));
> +	strlcpy(cap->card, mdp->pdev->name, sizeof(cap->card));
> +	strlcpy(cap->bus_info, "platform:mt8173", sizeof(cap->bus_info));
> +	cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
> +	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;

Fill in the new device_caps field of struct video_device instead. Once done
you can drop these two lines as the core will fill them in for you.

> +
> +	return 0;
> +}
> +
> +static int mtk_mdp_enum_fmt_mplane(struct v4l2_fmtdesc *f, u32 type)
> +{
> +	const struct mtk_mdp_fmt *fmt;
> +
> +	fmt = mtk_mdp_find_fmt_by_index(f->index, type);
> +	if (!fmt)
> +		return -EINVAL;
> +
> +	strlcpy(f->description, fmt->name, sizeof(f->description));

Drop this line. The v4l2 core will this in for you. You can probably drop fmt->name
as well.

> +	f->pixelformat = fmt->pixelformat;
> +
> +	return 0;
> +}
> +
> +static int mtk_mdp_m2m_enum_fmt_mplane_vid_cap(struct file *file, void *priv,
> +				       struct v4l2_fmtdesc *f)
> +{
> +	return mtk_mdp_enum_fmt_mplane(f, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
> +}
> +
> +static int mtk_mdp_m2m_enum_fmt_mplane_vid_out(struct file *file, void *priv,
> +				       struct v4l2_fmtdesc *f)
> +{
> +	return mtk_mdp_enum_fmt_mplane(f, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
> +}
> +
> +static int mtk_mdp_g_fmt_mplane(struct mtk_mdp_ctx *ctx, struct v4l2_format *f)
> +{
> +	struct mtk_mdp_frame *frame;
> +	struct v4l2_pix_format_mplane *pix_mp;
> +	int i;
> +
> +	mtk_mdp_dbg(2, "[%d] type:%d", ctx->id, f->type);
> +
> +	frame = mtk_mdp_ctx_get_frame(ctx, f->type);
> +	pix_mp = &f->fmt.pix_mp;
> +
> +	pix_mp->width = frame->width;
> +	pix_mp->height = frame->height;
> +	pix_mp->field = V4L2_FIELD_NONE;
> +	pix_mp->pixelformat = frame->fmt->pixelformat;
> +	pix_mp->num_planes = frame->fmt->num_planes;
> +	mtk_mdp_dbg(2, "[%d] wxh:%dx%d", ctx->id,
> +		    pix_mp->width, pix_mp->height);
> +
> +	for (i = 0; i < pix_mp->num_planes; ++i) {
> +		pix_mp->plane_fmt[i].bytesperline = (frame->width *
> +			frame->fmt->depth[i]) / 8;
> +		pix_mp->plane_fmt[i].sizeimage =
> +			 pix_mp->plane_fmt[i].bytesperline * frame->height;
> +
> +		mtk_mdp_dbg(2, "[%d] p%d, bpl:%d, sizeimage:%d", ctx->id, i,
> +			    pix_mp->plane_fmt[i].bytesperline,
> +			    pix_mp->plane_fmt[i].sizeimage);
> +	}

Since this is a codec you will need to pass the colorspace-related format
fields from the video output format to the video capture format.

I have added tests to v4l2-compliance to check for that. See also the
vim2m reference driver and this vim2m patch:

https://patchwork.linuxtv.org/patch/35562/

> +
> +	return 0;
> +}
> +
> +static int mtk_mdp_m2m_g_fmt_mplane(struct file *file, void *fh,
> +				    struct v4l2_format *f)
> +{
> +	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
> +
> +	return mtk_mdp_g_fmt_mplane(ctx, f);
> +}
> +
> +static int mtk_mdp_m2m_try_fmt_mplane(struct file *file, void *fh,
> +				      struct v4l2_format *f)
> +{
> +	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
> +
> +	if (!mtk_mdp_try_fmt_mplane(ctx, f))
> +		return -EINVAL;
> +	return 0;
> +}
> +
> +static int mtk_mdp_m2m_s_fmt_mplane(struct file *file, void *fh,
> +				    struct v4l2_format *f)
> +{
> +	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
> +	struct vb2_queue *vq;
> +	struct mtk_mdp_frame *frame;
> +	struct v4l2_pix_format_mplane *pix;
> +	const struct mtk_mdp_fmt *fmt;
> +	int i;
> +
> +	mtk_mdp_dbg(2, "[%d] type:%d", ctx->id, f->type);
> +
> +	frame = mtk_mdp_ctx_get_frame(ctx, f->type);
> +	fmt = mtk_mdp_try_fmt_mplane(ctx, f);
> +	if (!fmt) {
> +		mtk_mdp_err("[%d] try_fmt failed, type:%d", ctx->id, f->type);
> +		return -EINVAL;
> +	}
> +	frame->fmt = fmt;
> +
> +	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
> +	if (vb2_is_streaming(vq)) {
> +		dev_info(&ctx->mdp_dev->pdev->dev, "queue %d busy", f->type);
> +		return -EBUSY;
> +	}
> +
> +	pix = &f->fmt.pix_mp;
> +	for (i = 0; i < frame->fmt->num_planes; i++) {
> +		frame->payload[i] = pix->plane_fmt[i].sizeimage;
> +		frame->pitch[i] = pix->plane_fmt[i].bytesperline;
> +	}
> +
> +	mtk_mdp_set_frame_size(frame, pix->width, pix->height);
> +
> +	if (V4L2_TYPE_IS_OUTPUT(f->type))
> +		mtk_mdp_ctx_state_lock_set(ctx, MTK_MDP_SRC_FMT);
> +	else
> +		mtk_mdp_ctx_state_lock_set(ctx, MTK_MDP_DST_FMT);
> +
> +	mtk_mdp_dbg(2, "[%d] type:%d, frame:%dx%d", ctx->id, f->type,
> +		    frame->width, frame->height);
> +
> +	return 0;
> +}
> +
> +static int mtk_mdp_m2m_reqbufs(struct file *file, void *fh,
> +			       struct v4l2_requestbuffers *reqbufs)
> +{
> +	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
> +
> +	if (reqbufs->count == 0) {
> +		if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
> +			mtk_mdp_ctx_state_lock_clear(ctx, MTK_MDP_SRC_FMT);
> +		else
> +			mtk_mdp_ctx_state_lock_clear(ctx, MTK_MDP_DST_FMT);
> +	}
> +
> +	return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
> +}
> +
> +static int mtk_mdp_m2m_querybuf(struct file *file, void *fh,
> +				struct v4l2_buffer *buf)
> +{
> +	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
> +
> +	return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
> +}

Can't you use the v4l2_m2m_ioctl_* helpers here? See v4l2-mem2mem.h.

> +
> +static int mtk_mdp_m2m_qbuf(struct file *file, void *fh,
> +			    struct v4l2_buffer *buf)
> +{
> +	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
> +
> +	return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
> +}
> +
> +static int mtk_mdp_m2m_dqbuf(struct file *file, void *fh,
> +			     struct v4l2_buffer *buf)
> +{
> +	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
> +
> +	return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
> +}
> +
> +static int mtk_mdp_m2m_streamon(struct file *file, void *fh,
> +				enum v4l2_buf_type type)
> +{
> +	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
> +
> +	/* The source and target color format need to be set */
> +	if (V4L2_TYPE_IS_OUTPUT(type)) {
> +		if (!mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_SRC_FMT))
> +			return -EINVAL;
> +	} else if (!mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_DST_FMT)) {
> +		return -EINVAL;
> +	}
> +
> +	return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
> +}
> +
> +static int mtk_mdp_m2m_streamoff(struct file *file, void *fh,
> +			    enum v4l2_buf_type type)
> +{
> +	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
> +
> +	return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
> +}
> +
> +/*
> + * Return true if rectangle a is enclosed in rectangle b, or false otherwise.
> + */
> +static bool mtk_mdp_m2m_is_rectangle_enclosed(struct v4l2_rect *a,
> +					     struct v4l2_rect *b)
> +{
> +	if (a->left < b->left || a->top < b->top)
> +		return false;
> +
> +	if (a->left + a->width > b->left + b->width)
> +		return false;
> +
> +	if (a->top + a->height > b->top + b->height)
> +		return false;
> +
> +	return true;
> +}
> +
> +static int mtk_mdp_m2m_g_selection(struct file *file, void *fh,
> +				   struct v4l2_selection *s)
> +{
> +	struct mtk_mdp_frame *frame;
> +	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
> +
> +	if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
> +	    (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
> +		return -EINVAL;
> +
> +	frame = mtk_mdp_ctx_get_frame(ctx, s->type);
> +
> +	switch (s->target) {
> +	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
> +	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
> +	case V4L2_SEL_TGT_CROP_BOUNDS:
> +	case V4L2_SEL_TGT_CROP_DEFAULT:
> +		s->r.left = 0;
> +		s->r.top = 0;
> +		s->r.width = frame->width;
> +		s->r.height = frame->height;
> +		return 0;
> +
> +	case V4L2_SEL_TGT_COMPOSE:
> +	case V4L2_SEL_TGT_CROP:
> +		s->r.left = frame->crop.left;
> +		s->r.top = frame->crop.top;
> +		s->r.width = frame->crop.width;
> +		s->r.height = frame->crop.height;
> +		return 0;
> +	}

This is almost certainly wrong. Unless I am mistaken you support cropping of
the memory buffer for video output, and composing into a memory buffer for video
capture. That's the standard behavior for codecs.

The code above reports both composing and cropping for both capture and output,
and that's not right. Same in s_selection.

> +
> +	return -EINVAL;
> +}
> +
> +static int mtk_mdp_check_scaler_ratio(struct mtk_mdp_variant *var, int src_w,
> +				      int src_h, int dst_w, int dst_h, int rot)
> +{
> +	int tmp_w, tmp_h;
> +
> +	if (rot == 90 || rot == 270) {
> +		tmp_w = dst_h;
> +		tmp_h = dst_w;
> +	} else {
> +		tmp_w = dst_w;
> +		tmp_h = dst_h;
> +	}
> +
> +	if ((src_w / tmp_w) > var->h_scale_down_max ||
> +	    (src_h / tmp_h) > var->v_scale_down_max ||
> +	    (tmp_w / src_w) > var->h_scale_up_max ||
> +	    (tmp_h / src_h) > var->v_scale_up_max)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static int mtk_mdp_m2m_s_selection(struct file *file, void *fh,
> +				   struct v4l2_selection *s)
> +{
> +	struct mtk_mdp_frame *frame;
> +	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
> +	struct v4l2_crop cr;
> +	struct mtk_mdp_variant *variant = ctx->mdp_dev->variant;
> +	int ret;
> +
> +	cr.type = s->type;
> +	cr.c = s->r;
> +
> +	if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
> +	    (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
> +		return -EINVAL;
> +
> +	ret = mtk_mdp_try_crop(ctx, &cr);
> +	if (ret)
> +		return ret;
> +
> +	if (s->flags & V4L2_SEL_FLAG_LE &&
> +	    !mtk_mdp_m2m_is_rectangle_enclosed(&cr.c, &s->r))
> +		return -ERANGE;
> +
> +	if (s->flags & V4L2_SEL_FLAG_GE &&
> +	    !mtk_mdp_m2m_is_rectangle_enclosed(&s->r, &cr.c))
> +		return -ERANGE;
> +
> +	s->r = cr.c;
> +
> +	switch (s->target) {
> +	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
> +	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
> +	case V4L2_SEL_TGT_COMPOSE:
> +		frame = &ctx->s_frame;
> +		break;
> +
> +	case V4L2_SEL_TGT_CROP_BOUNDS:
> +	case V4L2_SEL_TGT_CROP:
> +	case V4L2_SEL_TGT_CROP_DEFAULT:
> +		frame = &ctx->d_frame;
> +		break;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	/* Check to see if scaling ratio is within supported range */
> +	if (mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_DST_FMT | MTK_MDP_SRC_FMT)) {
> +		if (V4L2_TYPE_IS_OUTPUT(s->type)) {
> +			ret = mtk_mdp_check_scaler_ratio(variant, cr.c.width,
> +				cr.c.height, ctx->d_frame.crop.width,
> +				ctx->d_frame.crop.height,
> +				ctx->ctrls.rotate->val);
> +		} else {
> +			ret = mtk_mdp_check_scaler_ratio(variant,
> +				ctx->s_frame.crop.width,
> +				ctx->s_frame.crop.height, cr.c.width,
> +				cr.c.height, ctx->ctrls.rotate->val);
> +		}
> +
> +		if (ret) {
> +			dev_info(&ctx->mdp_dev->pdev->dev,
> +				"Out of scaler range");
> +			return -EINVAL;
> +		}
> +	}
> +
> +	frame->crop = cr.c;
> +
> +	return 0;
> +}
> +
> +static const struct v4l2_ioctl_ops mtk_mdp_m2m_ioctl_ops = {
> +	.vidioc_querycap		= mtk_mdp_m2m_querycap,
> +	.vidioc_enum_fmt_vid_cap_mplane	= mtk_mdp_m2m_enum_fmt_mplane_vid_cap,
> +	.vidioc_enum_fmt_vid_out_mplane	= mtk_mdp_m2m_enum_fmt_mplane_vid_out,
> +	.vidioc_g_fmt_vid_cap_mplane	= mtk_mdp_m2m_g_fmt_mplane,
> +	.vidioc_g_fmt_vid_out_mplane	= mtk_mdp_m2m_g_fmt_mplane,
> +	.vidioc_try_fmt_vid_cap_mplane	= mtk_mdp_m2m_try_fmt_mplane,
> +	.vidioc_try_fmt_vid_out_mplane	= mtk_mdp_m2m_try_fmt_mplane,
> +	.vidioc_s_fmt_vid_cap_mplane	= mtk_mdp_m2m_s_fmt_mplane,
> +	.vidioc_s_fmt_vid_out_mplane	= mtk_mdp_m2m_s_fmt_mplane,
> +	.vidioc_reqbufs			= mtk_mdp_m2m_reqbufs,
> +	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,
> +	.vidioc_expbuf			= v4l2_m2m_ioctl_expbuf,
> +	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
> +	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
> +	.vidioc_querybuf		= mtk_mdp_m2m_querybuf,
> +	.vidioc_qbuf			= mtk_mdp_m2m_qbuf,
> +	.vidioc_dqbuf			= mtk_mdp_m2m_dqbuf,
> +	.vidioc_streamon		= mtk_mdp_m2m_streamon,
> +	.vidioc_streamoff		= mtk_mdp_m2m_streamoff,
> +	.vidioc_g_selection		= mtk_mdp_m2m_g_selection,
> +	.vidioc_s_selection		= mtk_mdp_m2m_s_selection
> +};
> +
> +static int mtk_mdp_m2m_queue_init(void *priv, struct vb2_queue *src_vq,
> +				  struct vb2_queue *dst_vq)
> +{
> +	struct mtk_mdp_ctx *ctx = priv;
> +	int ret;
> +
> +	memset(src_vq, 0, sizeof(*src_vq));
> +	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
> +	src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
> +	src_vq->drv_priv = ctx;
> +	src_vq->ops = &mtk_mdp_m2m_qops;
> +	src_vq->mem_ops = &vb2_dma_contig_memops;
> +	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
> +	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;

Shouldn't src_vq->dev be filled in here?

> +
> +	ret = vb2_queue_init(src_vq);
> +	if (ret)
> +		return ret;
> +
> +	memset(dst_vq, 0, sizeof(*dst_vq));
> +	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
> +	dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
> +	dst_vq->drv_priv = ctx;
> +	dst_vq->ops = &mtk_mdp_m2m_qops;
> +	dst_vq->mem_ops = &vb2_dma_contig_memops;
> +	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
> +	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;

and here?

Otherwise the dma-contig code won't know the right struct device pointer to
use for the DMA.

I'm a bit surprised that this works, actually.

> +
> +	return vb2_queue_init(dst_vq);
> +}
> +
> +static int mtk_mdp_s_ctrl(struct v4l2_ctrl *ctrl)
> +{
> +	struct mtk_mdp_ctx *ctx = ctrl_to_ctx(ctrl);
> +	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
> +	struct mtk_mdp_variant *variant = mdp->variant;
> +	u32 state = MTK_MDP_DST_FMT | MTK_MDP_SRC_FMT;
> +	int ret = 0;
> +
> +	if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
> +		return 0;
> +
> +	switch (ctrl->id) {
> +	case V4L2_CID_HFLIP:
> +		ctx->hflip = ctrl->val;
> +		break;
> +	case V4L2_CID_VFLIP:
> +		ctx->vflip = ctrl->val;
> +		break;
> +	case V4L2_CID_ROTATE:
> +		if (mtk_mdp_ctx_state_is_set(ctx, state)) {
> +			ret = mtk_mdp_check_scaler_ratio(variant,
> +					ctx->s_frame.crop.width,
> +					ctx->s_frame.crop.height,
> +					ctx->d_frame.crop.width,
> +					ctx->d_frame.crop.height,
> +					ctx->ctrls.rotate->val);
> +
> +			if (ret)
> +				return -EINVAL;
> +		}
> +
> +		ctx->rotation = ctrl->val;
> +		break;
> +	case V4L2_CID_ALPHA_COMPONENT:
> +		ctx->d_frame.alpha = ctrl->val;
> +		break;
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct v4l2_ctrl_ops mtk_mdp_ctrl_ops = {
> +	.s_ctrl = mtk_mdp_s_ctrl,
> +};
> +
> +static int mtk_mdp_ctrls_create(struct mtk_mdp_ctx *ctx)
> +{
> +	v4l2_ctrl_handler_init(&ctx->ctrl_handler, MTK_MDP_MAX_CTRL_NUM);
> +
> +	ctx->ctrls.rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler,
> +			&mtk_mdp_ctrl_ops, V4L2_CID_ROTATE, 0, 270, 90, 0);
> +	ctx->ctrls.hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
> +					     &mtk_mdp_ctrl_ops,
> +					     V4L2_CID_HFLIP,
> +					     0, 1, 1, 0);
> +	ctx->ctrls.vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
> +					     &mtk_mdp_ctrl_ops,
> +					     V4L2_CID_VFLIP,
> +					     0, 1, 1, 0);
> +	ctx->ctrls.global_alpha = v4l2_ctrl_new_std(&ctx->ctrl_handler,
> +						    &mtk_mdp_ctrl_ops,
> +						    V4L2_CID_ALPHA_COMPONENT,
> +						    0, 255, 1, 0);
> +	ctx->ctrls_rdy = ctx->ctrl_handler.error == 0;
> +
> +	if (ctx->ctrl_handler.error) {
> +		int err = ctx->ctrl_handler.error;
> +
> +		v4l2_ctrl_handler_free(&ctx->ctrl_handler);
> +		dev_err(&ctx->mdp_dev->pdev->dev,
> +			"Failed to create control handlers\n");
> +		return err;
> +	}
> +
> +	return 0;
> +}
> +
> +static void mtk_mdp_set_default_params(struct mtk_mdp_ctx *ctx)
> +{
> +	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
> +	struct mtk_mdp_frame *frame;
> +
> +	frame = mtk_mdp_ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
> +	frame->fmt = mtk_mdp_find_fmt_by_index(0,
> +					V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
> +	frame->width = mdp->variant->pix_min->org_w;
> +	frame->height = mdp->variant->pix_min->org_h;
> +	frame->payload[0] = frame->width * frame->height;
> +	frame->payload[1] = frame->payload[0] / 2;
> +
> +	frame = mtk_mdp_ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
> +	frame->fmt = mtk_mdp_find_fmt_by_index(0,
> +					V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
> +	frame->width = mdp->variant->pix_min->target_rot_dis_w;
> +	frame->height = mdp->variant->pix_min->target_rot_dis_h;
> +	frame->payload[0] = frame->width * frame->height;
> +	frame->payload[1] = frame->payload[0] / 2;
> +
> +}
> +
> +static int mtk_mdp_m2m_open(struct file *file)
> +{
> +	struct mtk_mdp_dev *mdp = video_drvdata(file);
> +	struct video_device *vfd = video_devdata(file);
> +	struct mtk_mdp_ctx *ctx = NULL;
> +	int ret;
> +
> +	if (mutex_lock_interruptible(&mdp->lock))
> +		return -ERESTARTSYS;
> +
> +	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> +	if (!ctx) {
> +		ret = -ENOMEM;
> +		goto err_ctx_alloc;
> +	}
> +
> +	mutex_init(&ctx->slock);
> +	ctx->id = mdp->id_counter++;
> +	v4l2_fh_init(&ctx->fh, vfd);
> +	file->private_data = &ctx->fh;
> +	ret = mtk_mdp_ctrls_create(ctx);
> +	if (ret)
> +		goto error_ctrls;
> +
> +	/* Use separate control handler per file handle */
> +	ctx->fh.ctrl_handler = &ctx->ctrl_handler;
> +	v4l2_fh_add(&ctx->fh);
> +	INIT_LIST_HEAD(&ctx->list);
> +
> +	ctx->mdp_dev = mdp;
> +	mtk_mdp_set_default_params(ctx);
> +
> +	INIT_WORK(&ctx->work, mtk_mdp_m2m_worker);
> +	ctx->m2m_ctx = v4l2_m2m_ctx_init(mdp->m2m_dev, ctx,
> +					 mtk_mdp_m2m_queue_init);
> +	if (IS_ERR(ctx->m2m_ctx)) {
> +		dev_err(&mdp->pdev->dev, "Failed to initialize m2m context");
> +		ret = PTR_ERR(ctx->m2m_ctx);
> +		goto error_m2m_ctx;
> +	}
> +	ctx->fh.m2m_ctx = ctx->m2m_ctx;
> +	if (mdp->ctx_num++ == 0) {
> +		ret = vpu_load_firmware(mdp->vpu_dev);
> +		if (ret < 0) {
> +			dev_err(&mdp->pdev->dev,
> +				"vpu_load_firmware failed %d\n", ret);
> +			goto err_load_vpu;
> +		}
> +
> +		ret = mtk_mdp_vpu_register(mdp->pdev);
> +		if (ret < 0) {
> +			dev_err(&mdp->pdev->dev,
> +				"mdp_vpu register failed %d\n", ret);
> +			goto err_load_vpu;
> +		}
> +	}
> +
> +	ret = mtk_mdp_vpu_init(&ctx->vpu);
> +	if (ret < 0) {
> +		dev_err(&mdp->pdev->dev, "Initialize vpu failed %d\n", ret);
> +		ret = -EINVAL;
> +		goto err_load_vpu;
> +	}
> +	list_add(&ctx->list, &mdp->ctx_list);
> +	mutex_unlock(&mdp->lock);
> +
> +	mtk_mdp_dbg(0, "%s [%d]", dev_name(&mdp->pdev->dev), ctx->id);
> +
> +	return 0;
> +
> +err_load_vpu:
> +	mdp->ctx_num--;
> +	v4l2_m2m_ctx_release(ctx->m2m_ctx);
> +error_m2m_ctx:
> +	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
> +error_ctrls:
> +	v4l2_fh_del(&ctx->fh);
> +	v4l2_fh_exit(&ctx->fh);
> +err_ctx_alloc:
> +	kfree(ctx);
> +	mutex_unlock(&mdp->lock);
> +
> +	return ret;
> +}
> +
> +static int mtk_mdp_m2m_release(struct file *file)
> +{
> +	struct mtk_mdp_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
> +
> +	flush_workqueue(mdp->job_wq);
> +	mutex_lock(&mdp->lock);
> +	v4l2_m2m_ctx_release(ctx->m2m_ctx);
> +	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
> +	v4l2_fh_del(&ctx->fh);
> +	v4l2_fh_exit(&ctx->fh);
> +	mtk_mdp_vpu_deinit(&ctx->vpu);
> +	mdp->ctx_num--;
> +	list_del_init(&ctx->list);
> +
> +	mtk_mdp_dbg(0, "%s [%d]", dev_name(&mdp->pdev->dev), ctx->id);
> +
> +	mutex_unlock(&mdp->lock);
> +	kfree(ctx);
> +
> +	return 0;
> +}
> +
> +static unsigned int mtk_mdp_m2m_poll(struct file *file,
> +				     struct poll_table_struct *wait)
> +{
> +	struct mtk_mdp_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
> +	int ret;
> +
> +	if (mutex_lock_interruptible(&mdp->lock))
> +		return -ERESTARTSYS;
> +
> +	ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
> +	mutex_unlock(&mdp->lock);
> +
> +	return ret;
> +}
> +
> +static int mtk_mdp_m2m_mmap(struct file *file, struct vm_area_struct *vma)
> +{
> +	struct mtk_mdp_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
> +	int ret;
> +
> +	if (mutex_lock_interruptible(&mdp->lock))
> +		return -ERESTARTSYS;
> +
> +	ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
> +	mutex_unlock(&mdp->lock);
> +
> +	return ret;

Can you use the v4l2-mem2mem helpers for mmap and poll?

> +}
> +
> +static const struct v4l2_file_operations mtk_mdp_m2m_fops = {
> +	.owner		= THIS_MODULE,
> +	.open		= mtk_mdp_m2m_open,
> +	.release	= mtk_mdp_m2m_release,
> +	.poll		= mtk_mdp_m2m_poll,
> +	.unlocked_ioctl	= video_ioctl2,
> +	.mmap		= mtk_mdp_m2m_mmap,
> +};
> +
> +static struct v4l2_m2m_ops mtk_mdp_m2m_ops = {
> +	.device_run	= mtk_mdp_m2m_device_run,
> +	.job_abort	= mtk_mdp_m2m_job_abort,
> +};
> +
> +int mtk_mdp_register_m2m_device(struct mtk_mdp_dev *mdp)
> +{
> +	struct device *dev = &mdp->pdev->dev;
> +	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",
> +		 MTK_MDP_MODULE_NAME);
> +	video_set_drvdata(&mdp->vdev, mdp);
> +
> +	mdp->m2m_dev = v4l2_m2m_init(&mtk_mdp_m2m_ops);
> +	if (IS_ERR(mdp->m2m_dev)) {
> +		dev_err(dev, "failed to initialize v4l2-m2m device\n");
> +		ret = PTR_ERR(mdp->m2m_dev);
> +		goto err_m2m_init;
> +	}
> +
> +	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);
> +	return 0;
> +
> +err_vdev_register:
> +	v4l2_m2m_release(mdp->m2m_dev);
> +err_m2m_init:
> +	video_device_release(&mdp->vdev);
> +
> +	return ret;
> +}
> +
> +void mtk_mdp_unregister_m2m_device(struct mtk_mdp_dev *mdp)
> +{
> +	video_device_release(&mdp->vdev);
> +	v4l2_m2m_release(mdp->m2m_dev);
> +}
> diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h
> new file mode 100644
> index 0000000..45afd36
> --- /dev/null
> +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h
> @@ -0,0 +1,22 @@
> +/*
> + * Copyright (c) 2016 MediaTek Inc.
> + * Author: Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#ifndef __MTK_MDP_M2M_H__
> +#define __MTK_MDP_M2M_H__
> +
> +void mtk_mdp_ctx_state_lock_set(struct mtk_mdp_ctx *ctx, u32 state);
> +int mtk_mdp_register_m2m_device(struct mtk_mdp_dev *mdp);
> +void mtk_mdp_unregister_m2m_device(struct mtk_mdp_dev *mdp);
> +
> +#endif /* __MTK_MDP_M2M_H__ */
> diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_regs.c b/drivers/media/platform/mtk-mdp/mtk_mdp_regs.c
> new file mode 100644
> index 0000000..063e7b1
> --- /dev/null
> +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_regs.c
> @@ -0,0 +1,153 @@
> +/*
> + * Copyright (c) 2015-2016 MediaTek Inc.
> + * Author: Houlong Wei <houlong.wei at mediatek.com>
> + *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#include <linux/platform_device.h>
> +
> +#include "mtk_mdp_core.h"
> +#include "mtk_mdp_regs.h"
> +
> +
> +#define MDP_COLORFMT_PACK(VIDEO, PLANE, COPLANE, HF, VF, BITS, GROUP, SWAP, ID)\
> +	(((VIDEO) << 27) | ((PLANE) << 24) | ((COPLANE) << 22) |\
> +	((HF) << 20) | ((VF) << 18) | ((BITS) << 8) | ((GROUP) << 6) |\
> +	((SWAP) << 5) | ((ID) << 0))
> +
> +enum MDP_COLOR_ENUM {
> +	MDP_COLOR_UNKNOWN = 0,
> +	MDP_COLOR_NV12 = MDP_COLORFMT_PACK(0, 2, 1, 1, 1, 8, 1, 0, 12),
> +	MDP_COLOR_I420 = MDP_COLORFMT_PACK(0, 3, 0, 1, 1, 8, 1, 0, 8),
> +	/* Mediatek proprietary format */
> +	MDP_COLOR_420_MT21 = MDP_COLORFMT_PACK(5, 2, 1, 1, 1, 256, 1, 0, 12),
> +};
> +
> +static int32_t mtk_mdp_map_color_format(int v4l2_format)
> +{
> +	switch (v4l2_format) {
> +	case V4L2_PIX_FMT_NV12M:
> +	case V4L2_PIX_FMT_NV12:
> +		return MDP_COLOR_NV12;
> +	case V4L2_PIX_FMT_MT21:
> +		return MDP_COLOR_420_MT21;
> +	case V4L2_PIX_FMT_YUV420M:
> +	case V4L2_PIX_FMT_YUV420:
> +		return MDP_COLOR_I420;
> +	}
> +
> +	mtk_mdp_err("Unknown format 0x%x", v4l2_format);
> +
> +	return MDP_COLOR_UNKNOWN;
> +}
> +
> +void mtk_mdp_hw_set_input_addr(struct mtk_mdp_ctx *ctx,
> +			       struct mtk_mdp_addr *addr)
> +{
> +	struct mdp_buffer *src_buf = &ctx->vpu.vsi->src_buffer;
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(addr->addr); i++)
> +		src_buf->addr_mva[i] = (uint64_t)addr->addr[i];
> +}
> +
> +void mtk_mdp_hw_set_output_addr(struct mtk_mdp_ctx *ctx,
> +				struct mtk_mdp_addr *addr)
> +{
> +	struct mdp_buffer *dst_buf = &ctx->vpu.vsi->dst_buffer;
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(addr->addr); i++)
> +		dst_buf->addr_mva[i] = (uint64_t)addr->addr[i];
> +}
> +
> +void mtk_mdp_hw_set_in_size(struct mtk_mdp_ctx *ctx)
> +{
> +	struct mtk_mdp_frame *frame = &ctx->s_frame;
> +	struct mdp_config *config = &ctx->vpu.vsi->src_config;
> +
> +	/* Set input pixel offset */
> +	config->crop_x = frame->crop.left;
> +	config->crop_y = frame->crop.top;
> +
> +	/* Set input cropped size */
> +	config->crop_w = frame->crop.width;
> +	config->crop_h = frame->crop.height;
> +
> +	/* Set input original size */
> +	config->x = 0;
> +	config->y = 0;
> +	config->w = frame->width;
> +	config->h = frame->height;
> +}
> +
> +void mtk_mdp_hw_set_in_image_format(struct mtk_mdp_ctx *ctx)
> +{
> +	unsigned int i;
> +	struct mtk_mdp_frame *frame = &ctx->s_frame;
> +	struct mdp_config *config = &ctx->vpu.vsi->src_config;
> +	struct mdp_buffer *src_buf = &ctx->vpu.vsi->src_buffer;
> +
> +	src_buf->plane_num = frame->fmt->num_planes;
> +	config->format = mtk_mdp_map_color_format(frame->fmt->pixelformat);
> +	config->w_stride = 0; /* MDP will calculate it by color format. */
> +	config->h_stride = 0; /* MDP will calculate it by color format. */
> +
> +	for (i = 0; i < src_buf->plane_num; i++)
> +		src_buf->plane_size[i] = frame->payload[i];
> +}
> +
> +void mtk_mdp_hw_set_out_size(struct mtk_mdp_ctx *ctx)
> +{
> +	struct mtk_mdp_frame *frame = &ctx->d_frame;
> +	struct mdp_config *config = &ctx->vpu.vsi->dst_config;
> +
> +	config->crop_x = frame->crop.left;
> +	config->crop_y = frame->crop.top;
> +	config->crop_w = frame->crop.width;
> +	config->crop_h = frame->crop.height;
> +	config->x = 0;
> +	config->y = 0;
> +	config->w = frame->width;
> +	config->h = frame->height;
> +}
> +
> +void mtk_mdp_hw_set_out_image_format(struct mtk_mdp_ctx *ctx)
> +{
> +	unsigned int i;
> +	struct mtk_mdp_frame *frame = &ctx->d_frame;
> +	struct mdp_config *config = &ctx->vpu.vsi->dst_config;
> +	struct mdp_buffer *dst_buf = &ctx->vpu.vsi->dst_buffer;
> +
> +	dst_buf->plane_num = frame->fmt->num_planes;
> +	config->format = mtk_mdp_map_color_format(frame->fmt->pixelformat);
> +	config->w_stride = 0; /* MDP will calculate it by color format. */
> +	config->h_stride = 0; /* MDP will calculate it by color format. */
> +	for (i = 0; i < dst_buf->plane_num; i++)
> +		dst_buf->plane_size[i] = frame->payload[i];
> +}
> +
> +void mtk_mdp_hw_set_rotation(struct mtk_mdp_ctx *ctx)
> +{
> +	struct mdp_config_misc *misc = &ctx->vpu.vsi->misc;
> +
> +	misc->orientation = ctx->ctrls.rotate->val;
> +	misc->hflip = ctx->ctrls.hflip->val;
> +	misc->vflip = ctx->ctrls.vflip->val;
> +}
> +
> +void mtk_mdp_hw_set_global_alpha(struct mtk_mdp_ctx *ctx)
> +{
> +	struct mdp_config_misc *misc = &ctx->vpu.vsi->misc;
> +
> +	misc->alpha = ctx->ctrls.global_alpha->val;
> +}
> diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_regs.h b/drivers/media/platform/mtk-mdp/mtk_mdp_regs.h
> new file mode 100644
> index 0000000..42bd057
> --- /dev/null
> +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_regs.h
> @@ -0,0 +1,31 @@
> +/*
> + * Copyright (c) 2016 MediaTek Inc.
> + * Author: Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#ifndef __MTK_MDP_REGS_H__
> +#define __MTK_MDP_REGS_H__
> +
> +
> +void mtk_mdp_hw_set_input_addr(struct mtk_mdp_ctx *ctx,
> +			       struct mtk_mdp_addr *addr);
> +void mtk_mdp_hw_set_output_addr(struct mtk_mdp_ctx *ctx,
> +				struct mtk_mdp_addr *addr);
> +void mtk_mdp_hw_set_in_size(struct mtk_mdp_ctx *ctx);
> +void mtk_mdp_hw_set_in_image_format(struct mtk_mdp_ctx *ctx);
> +void mtk_mdp_hw_set_out_size(struct mtk_mdp_ctx *ctx);
> +void mtk_mdp_hw_set_out_image_format(struct mtk_mdp_ctx *ctx);
> +void mtk_mdp_hw_set_rotation(struct mtk_mdp_ctx *ctx);
> +void mtk_mdp_hw_set_global_alpha(struct mtk_mdp_ctx *ctx);
> +
> +
> +#endif /* __MTK_MDP_REGS_H__ */
> diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c b/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c
> new file mode 100644
> index 0000000..850376a
> --- /dev/null
> +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c
> @@ -0,0 +1,140 @@
> +/*
> + * Copyright (c) 2015-2016 MediaTek Inc.
> + * Author: Houlong Wei <houlong.wei at mediatek.com>
> + *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#include "mtk_mdp_core.h"
> +#include "mtk_mdp_vpu.h"
> +#include "mtk_vpu.h"
> +
> +
> +static inline struct mtk_mdp_ctx *vpu_to_ctx(struct mtk_mdp_vpu *vpu)
> +{
> +	return container_of(vpu, struct mtk_mdp_ctx, vpu);
> +}
> +
> +static void mtk_mdp_vpu_handle_init_ack(struct mdp_ipi_comm_ack *msg)
> +{
> +	struct mtk_mdp_vpu *vpu = (struct mtk_mdp_vpu *)msg->ap_inst;
> +
> +	/* mapping VPU address to kernel virtual address */
> +	vpu->vsi = (struct mdp_process_vsi *)
> +			vpu_mapping_dm_addr(vpu->pdev, msg->vpu_inst_addr);
> +	vpu->inst_addr = msg->vpu_inst_addr;
> +}
> +
> +static void mtk_mdp_vpu_ipi_handler(void *data, unsigned int len, void *priv)
> +{
> +	unsigned int msg_id = *(unsigned int *)data;
> +	struct mdp_ipi_comm_ack *msg = (struct mdp_ipi_comm_ack *)data;
> +	struct mtk_mdp_vpu *vpu = (struct mtk_mdp_vpu *)msg->ap_inst;
> +	struct mtk_mdp_ctx *ctx;
> +
> +	vpu->failure = msg->status;
> +	if (!vpu->failure) {
> +		switch (msg_id) {
> +		case VPU_MDP_INIT_ACK:
> +			mtk_mdp_vpu_handle_init_ack(data);
> +			break;
> +		case VPU_MDP_DEINIT_ACK:
> +		case VPU_MDP_PROCESS_ACK:
> +			break;
> +		default:
> +			ctx = vpu_to_ctx(vpu);
> +			dev_err(&ctx->mdp_dev->pdev->dev,
> +				"handle unknown ipi msg:0x%x\n",
> +				msg_id);
> +			break;
> +		}
> +	} else {
> +		ctx = vpu_to_ctx(vpu);
> +		mtk_mdp_dbg(0, "[%d]:msg 0x%x, failure:%d", ctx->id,
> +			    msg_id, vpu->failure);
> +	}
> +}
> +
> +int mtk_mdp_vpu_register(struct platform_device *pdev)
> +{
> +	struct mtk_mdp_dev *mdp = platform_get_drvdata(pdev);
> +	int err;
> +
> +	err = vpu_ipi_register(mdp->vpu_dev, IPI_MDP,
> +			       mtk_mdp_vpu_ipi_handler, "mdp_vpu", NULL);
> +	if (err)
> +		dev_err(&mdp->pdev->dev,
> +			"vpu_ipi_registration fail status=%d\n", err);
> +
> +	return err;
> +}
> +
> +static int mtk_mdp_vpu_send_msg(void *msg, int len, struct mtk_mdp_vpu *vpu,
> +				int id)
> +{
> +	struct mtk_mdp_ctx *ctx = vpu_to_ctx(vpu);
> +	int err;
> +
> +	mutex_lock(&ctx->mdp_dev->vpulock);
> +	err = vpu_ipi_send(vpu->pdev, (enum ipi_id)id, msg, len);
> +	if (err) {
> +		mutex_unlock(&ctx->mdp_dev->vpulock);
> +		dev_err(&ctx->mdp_dev->pdev->dev,
> +			"vpu_ipi_send fail status %d\n", err);
> +	}
> +	mutex_unlock(&ctx->mdp_dev->vpulock);
> +
> +	return err;
> +}
> +
> +static int mtk_mdp_vpu_send_ap_ipi(struct mtk_mdp_vpu *vpu, uint32_t msg_id)
> +{
> +	int err;
> +	struct mdp_ipi_comm msg;
> +
> +	msg.msg_id = msg_id;
> +	msg.ipi_id = IPI_MDP;
> +	msg.vpu_inst_addr = vpu->inst_addr;
> +	msg.ap_inst = (uint64_t)vpu;
> +	err = mtk_mdp_vpu_send_msg((void *)&msg, sizeof(msg), vpu, IPI_MDP);
> +	if (!err && vpu->failure)
> +		err = -EINVAL;
> +
> +	return err;
> +}
> +
> +int mtk_mdp_vpu_init(struct mtk_mdp_vpu *vpu)
> +{
> +	int err;
> +	struct mdp_ipi_init msg;
> +	struct mtk_mdp_ctx *ctx = vpu_to_ctx(vpu);
> +
> +	vpu->pdev = ctx->mdp_dev->vpu_dev;
> +
> +	msg.msg_id = AP_MDP_INIT;
> +	msg.ipi_id = IPI_MDP;
> +	msg.ap_inst = (uint64_t)vpu;
> +	err = mtk_mdp_vpu_send_msg((void *)&msg, sizeof(msg), vpu, IPI_MDP);
> +	if (!err && vpu->failure)
> +		err = -EINVAL;
> +
> +	return err;
> +}
> +
> +int mtk_mdp_vpu_deinit(struct mtk_mdp_vpu *vpu)
> +{
> +	return mtk_mdp_vpu_send_ap_ipi(vpu, AP_MDP_DEINIT);
> +}
> +
> +int mtk_mdp_vpu_process(struct mtk_mdp_vpu *vpu)
> +{
> +	return mtk_mdp_vpu_send_ap_ipi(vpu, AP_MDP_PROCESS);
> +}
> diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h b/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h
> new file mode 100644
> index 0000000..df4bdda
> --- /dev/null
> +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h
> @@ -0,0 +1,41 @@
> +/*
> + * Copyright (c) 2015-2016 MediaTek Inc.
> + * Author: Houlong Wei <houlong.wei at mediatek.com>
> + *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#ifndef __MTK_MDP_VPU_H__
> +#define __MTK_MDP_VPU_H__
> +
> +#include "mtk_mdp_ipi.h"
> +
> +
> +/**
> + * struct mtk_mdp_vpu - VPU instance for MDP
> + * @pdev	: pointer to the VPU platform device
> + * @inst_addr	: VPU MDP instance address
> + * @failure	: VPU execution result status
> + * @vsi		: VPU shared information
> + */
> +struct mtk_mdp_vpu {
> +	struct platform_device	*pdev;
> +	uint32_t		inst_addr;
> +	int32_t			failure;
> +	struct mdp_process_vsi	*vsi;
> +};
> +
> +int mtk_mdp_vpu_register(struct platform_device *pdev);
> +int mtk_mdp_vpu_init(struct mtk_mdp_vpu *vpu);
> +int mtk_mdp_vpu_deinit(struct mtk_mdp_vpu *vpu);
> +int mtk_mdp_vpu_process(struct mtk_mdp_vpu *vpu);
> +
> +#endif /* __MTK_MDP_VPU_H__ */
> 

Regards,

	Hans


From john at phrozen.org  Mon Jul 18 05:19:08 2016
From: john at phrozen.org (John Crispin)
Date: Mon, 18 Jul 2016 14:19:08 +0200
Subject: [PATCH V9 2/2] regulator: mt6323: Add support for MT6323 regulator
In-Reply-To: <20160718121638.GT30372@sirena.org.uk>
References: <1468843741-59637-1-git-send-email-john@phrozen.org>
 <1468843741-59637-2-git-send-email-john@phrozen.org>
 <20160718121638.GT30372@sirena.org.uk>
Message-ID: <2cfa2662-29af-5c9a-7e74-bdb0c22b83c3@phrozen.org>



On 18/07/2016 14:16, Mark Brown wrote:
> On Mon, Jul 18, 2016 at 02:09:01PM +0200, John Crispin wrote:
> 
>> Changes in V9
>> * drop compatible string from devicetree
> 
> Are you sure?
> 
>> +static const struct of_device_id mt6323_of_match[] = {
>> +	{ .compatible = "mediatek,mt6323-regulator", },
>> +	{ /* sentinel */ },
>> +};
>> +MODULE_DEVICE_TABLE(of, mt6323_of_match);
>> +
>> +static struct platform_driver mt6323_regulator_driver = {
>> +	.driver = {
>> +		.name = "mt6323-regulator",
>> +		.of_match_table = of_match_ptr(mt6323_of_match),



i was in the wrong folder while sending the patch so i ended up sending
the wrong patch with the wrong email account. sorry about the noise V10
coming up :/


From tiffany.lin at mediatek.com  Mon Jul 18 05:28:15 2016
From: tiffany.lin at mediatek.com (tiffany lin)
Date: Mon, 18 Jul 2016 20:28:15 +0800
Subject: [PATCH] vcodec: mediatek: Add g/s_selection support for V4L2
 Encoder
In-Reply-To: <bb96276a-8e6c-a535-6fd3-fe4327238f65@xs4all.nl>
References: <1464594768-1993-1-git-send-email-tiffany.lin@mediatek.com>
 <4ca82842-968d-a5e2-587d-752c71713607@xs4all.nl>
 <1468477674.32454.36.camel@mtksdaap41>
 <bb96276a-8e6c-a535-6fd3-fe4327238f65@xs4all.nl>
Message-ID: <1468844895.12740.15.camel@mtksdaap41>

On Fri, 2016-07-15 at 19:50 +0200, Hans Verkuil wrote:
> On 07/14/2016 08:27 AM, tiffany lin wrote:
> > Hi Hans,
> > 
> > 
> > On Mon, 2016-07-11 at 06:32 +0200, Hans Verkuil wrote:
> >> Hi Tiffany,
> >>
> >> My apologies for the delay, but here is my review at last:
> >>
> >> On 05/30/2016 09:52 AM, Tiffany Lin wrote:
> >>> This patch add g/s_selection support for MT8173
> >>>
> >>> Signed-off-by: Tiffany Lin <tiffany.lin at mediatek.com>
> >>> ---
> >>>  drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c |   74 ++++++++++++++++++++
> >>>  1 file changed, 74 insertions(+)
> >>>
> >>> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
> >>> index 6e72d73..23ef9a1 100644
> >>> --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
> >>> +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
> >>> @@ -630,6 +630,77 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
> >>>  	return vidioc_try_fmt(f, fmt);
> >>>  }
> >>>  
> >>> +static int vidioc_venc_g_selection(struct file *file, void *priv,
> >>> +				     struct v4l2_selection *s)
> >>> +{
> >>> +	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
> >>> +	struct mtk_q_data *q_data;
> >>> +
> >>> +	/* crop means compose for output devices */
> >>> +	switch (s->target) {
> >>> +	case V4L2_SEL_TGT_CROP_DEFAULT:
> >>> +	case V4L2_SEL_TGT_CROP_BOUNDS:
> >>> +	case V4L2_SEL_TGT_CROP:
> >>> +	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
> >>> +	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
> >>> +	case V4L2_SEL_TGT_COMPOSE:
> >>> +		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
> >>> +			mtk_v4l2_err("Invalid s->type = %d", s->type);
> >>> +			return -EINVAL;
> >>> +		}
> >>> +		break;
> >>> +	default:
> >>> +		mtk_v4l2_err("Invalid s->target = %d", s->target);
> >>> +		return -EINVAL;
> >>> +	}
> >>> +
> >>> +	q_data = mtk_venc_get_q_data(ctx, s->type);
> >>> +	if (!q_data)
> >>> +		return -EINVAL;
> >>> +
> >>> +	s->r.top = 0;
> >>> +	s->r.left = 0;
> >>> +	s->r.width = q_data->visible_width;
> >>> +	s->r.height = q_data->visible_height;
> >>> +
> >>> +	return 0;
> >>> +}
> >>> +
> >>> +static int vidioc_venc_s_selection(struct file *file, void *priv,
> >>> +				     struct v4l2_selection *s)
> >>> +{
> >>> +	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
> >>> +	struct mtk_q_data *q_data;
> >>> +
> >>> +	switch (s->target) {
> >>> +	case V4L2_SEL_TGT_CROP_DEFAULT:
> >>> +	case V4L2_SEL_TGT_CROP_BOUNDS:
> >>> +	case V4L2_SEL_TGT_CROP:
> >>> +	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
> >>> +	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
> >>> +	case V4L2_SEL_TGT_COMPOSE:
> >>> +		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
> >>> +			mtk_v4l2_err("Invalid s->type = %d", s->type);
> >>> +			return -EINVAL;
> >>> +		}
> >>> +		break;
> >>> +	default:
> >>> +		mtk_v4l2_err("Invalid s->target = %d", s->target);
> >>> +		return -EINVAL;
> >>> +	}
> >>> +
> >>> +	q_data = mtk_venc_get_q_data(ctx, s->type);
> >>> +	if (!q_data)
> >>> +		return -EINVAL;
> >>> +
> >>> +	s->r.top = 0;
> >>> +	s->r.left = 0;
> >>> +	q_data->visible_width = s->r.width;
> >>> +	q_data->visible_height = s->r.height;
> >>
> >> This makes no sense.
> >>
> >> See this page:
> >>
> >> https://hverkuil.home.xs4all.nl/spec/media.html#selection-api
> >>
> >> For the video output direction (memory -> HW encoder) the data source is
> >> the memory, the data sink is the HW encoder. For the video capture direction
> >> (HW encoder -> memory) the data source is the HW encoder and the data sink
> >> is the memory.
> >>
> >> Usually for m2m devices the video output direction may support cropping and
> >> the video capture direction may support composing.
> >>
> >> It's not clear what you intend here, especially since you set left and right
> >> to 0. That's not what the selection operation is supposed to do.
> >>
> > I am confused about about g/s_selection.
> > If application want to configure encode area and crop meta-data, it
> > should set crop info to OUTPUT queue, is that right?
> > if user space still use g/s_crop ioctl, in 
> > v4l_g_crop and v4l_s_crop, it set target to V4L2_SEL_TGT_COMPOSE_ACTIVE
> > when buf type is V4L2_TYPE_IS_OUTPUT.
> > 
> > It looks like when work with g/s_crop ioctl, command set to OUTPUT
> > buffer will use target V4L2_SEL_TGT_COMPOSE_ACTIVE.
> 
> Correct. The semantics of g/s_crop for output devices is really weird
> and g/s_crop is generally useless for mem2mem devices.
> 
> You should completely ignore the old g/s_crop and only look at g/s_selection.
> 
> > When work with g/s_selection ictol, command set to OUTPUT buffer will
> > use V4L2_SEL_TGT_CROP_ACTIVE.
> > Is this correct behavior?
> 
> Yes. What this means is that userspace has to use g/s_selection for
> mem2mem devices since g/s_crop changes the wrong thing: compose instead
> of crop for OUTPUT and crop instead of compose for CAPTURE.
> 
> The g/s_selection ioctls were added to solve this problem with g/s_crop.
> It always confuses people and it was due to a lack of foresight when the
> old crop API was designed: it was made for video capture where you
> crop on the hardware side (in the video receiver), and for video output it
> would compose the image in the video transmitter's total frame (usually
> 720x480/576). None of this applies in general to memory-to-memory devices.
> 

Understood now.

Now I am trying to figure out how to make this function right.
Our encoder only support crop range from (0, 0) to (width, height), so
if s->r.top and s->r.left not 0, I will return -EINVAL.


Another thing is that in v4l2-compliance test, it has testLegacyCrop.
It looks like we still need to support 
 V4L2_SEL_TGT_COMPOSE_DEFAULT:
 V4L2_SEL_TGT_COMPOSE_BOUNDS:
 V4L2_SEL_TGT_COMPOSE:
to pass v4l2 compliance test, Or it will fail in 
fail: v4l2-test-formats.cpp(1318): !doioctl(node, VIDIOC_G_SELECTION,
&sel)
fail: v4l2-test-formats.cpp(1336): testLegacyCrop(node)
test Cropping: FAIL

I don't understand the following testing code.

        /*
         * If either CROPCAP or G_CROP works, then G_SELECTION should
         * work as well.
         * If neither CROPCAP nor G_CROP work, then G_SELECTION
shouldn't
         * work either.
         */
        if (!doioctl(node, VIDIOC_CROPCAP, &cap)) {
                fail_on_test(doioctl(node, VIDIOC_G_SELECTION, &sel));

                // Checks for invalid types
                if (cap.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
                        cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
                else
                        cap.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
                fail_on_test(doioctl(node, VIDIOC_CROPCAP, &cap) !=
EINVAL);
                cap.type = 0xff;
                fail_on_test(doioctl(node, VIDIOC_CROPCAP, &cap) !=
EINVAL);
        } else {
                fail_on_test(!doioctl(node, VIDIOC_G_SELECTION, &sel));
-> fail here
        }

When test OUTPUT queue, it fail because v4l_cropcap will fail when
s.target = V4L2_SEL_TGT_COMPOSE_BOUNDS.
If VIDIOC_CROPCAP ioctl fail, VIDIOC_G_SELECTION should fail.
But VIDIOC_G_SELECTION target on CROP not COMPOSE and it success.


best regards,
Tiffany



> Regards,
> 
> 	Hans
> 
> > 
> > 
> > static int v4l_g_crop(const struct v4l2_ioctl_ops *ops,
> > 				struct file *file, void *fh, void *arg)
> > {
> > 	struct v4l2_crop *p = arg;
> > 	struct v4l2_selection s = {
> > 		.type = p->type,
> > 	};
> > 	int ret;
> > 
> > 	if (ops->vidioc_g_crop)
> > 		return ops->vidioc_g_crop(file, fh, p);
> > 	/* simulate capture crop using selection api */
> > 
> > 	/* crop means compose for output devices */
> > 	if (V4L2_TYPE_IS_OUTPUT(p->type))
> > 		s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE;
> > 	else
> > 		s.target = V4L2_SEL_TGT_CROP_ACTIVE;
> > 
> > 	ret = ops->vidioc_g_selection(file, fh, &s);
> > 
> > 	/* copying results to old structure on success */
> > 	if (!ret)
> > 		p->c = s.r;
> > 	return ret;
> > }
> > 
> > static int v4l_s_crop(const struct v4l2_ioctl_ops *ops,
> > 				struct file *file, void *fh, void *arg)
> > {
> > 	struct v4l2_crop *p = arg;
> > 	struct v4l2_selection s = {
> > 		.type = p->type,
> > 		.r = p->c,
> > 	};
> > 
> > 	if (ops->vidioc_s_crop)
> > 		return ops->vidioc_s_crop(file, fh, p);
> > 	/* simulate capture crop using selection api */
> > 
> > 	/* crop means compose for output devices */
> > 	if (V4L2_TYPE_IS_OUTPUT(p->type))
> > 		s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE;
> > 	else
> > 		s.target = V4L2_SEL_TGT_CROP_ACTIVE;
> > 
> > 	return ops->vidioc_s_selection(file, fh, &s);
> > }
> > 
> > 
> > best regards,
> > Tiffany
> > 
> > 
> > 
> > 
> >> Regards,
> >>
> >> 	Hans
> >>
> >>> +
> >>> +	return 0;
> >>> +}
> >>> +
> >>>  static int vidioc_venc_qbuf(struct file *file, void *priv,
> >>>  			    struct v4l2_buffer *buf)
> >>>  {
> >>> @@ -688,6 +759,9 @@ const struct v4l2_ioctl_ops mtk_venc_ioctl_ops = {
> >>>  
> >>>  	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,
> >>>  	.vidioc_prepare_buf		= v4l2_m2m_ioctl_prepare_buf,
> >>> +
> >>> +	.vidioc_g_selection		= vidioc_venc_g_selection,
> >>> +	.vidioc_s_selection		= vidioc_venc_s_selection,
> >>>  };
> >>>  
> >>>  static int vb2ops_venc_queue_setup(struct vb2_queue *vq,
> >>>
> > 
> > 
> > --
> > 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
> > 




From john at phrozen.org  Mon Jul 18 05:40:50 2016
From: john at phrozen.org (John Crispin)
Date: Mon, 18 Jul 2016 14:40:50 +0200
Subject: [PATCH V10 1/2] regulator: Add document for MT6323 regulator
Message-ID: <1468845651-64011-1-git-send-email-john@phrozen.org>

Signed-off-by: John Crispin <john at phrozen.org>
Cc: devicetree at vger.kernel.org
Acked-by: Rob Herring <robh at kernel.org>
---
Changes in V10
* use correct SoB
* drop compatible string from devicetree binding

Changes in V7
* remove another compatible string
* small wording changes

Changes in V6
* remove the compatible string

Changes in V5
* regulator vs regulators

Changes in V4
* regulator is a subnode and not a property

 .../bindings/regulator/mt6323-regulator.txt        |  237 ++++++++++++++++++++
 1 file changed, 237 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/regulator/mt6323-regulator.txt

diff --git a/Documentation/devicetree/bindings/regulator/mt6323-regulator.txt b/Documentation/devicetree/bindings/regulator/mt6323-regulator.txt
new file mode 100644
index 0000000..c35d878
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/mt6323-regulator.txt
@@ -0,0 +1,237 @@
+Mediatek MT6323 Regulator Driver
+
+All voltage regulators are defined as subnodes of the regulators node. A list
+of regulators provided by this controller are defined as subnodes of the
+PMIC's node. Each regulator is named according to its regulator type,
+buck_<name> and ldo_<name>. The definition for each of these nodes is defined
+using the standard binding for regulators at
+Documentation/devicetree/bindings/regulator/regulator.txt.
+
+The valid names for regulators are::
+BUCK:
+  buck_vproc, buck_vsys, buck_vpa
+LDO:
+  ldo_vtcxo, ldo_vcn28, ldo_vcn33_bt, ldo_vcn33_wifi, ldo_va, ldo_vcama,
+  ldo_vio28, ldo_vusb, ldo_vmc, ldo_vmch, ldo_vemc3v3, ldo_vgp1, ldo_vgp2,
+  ldo_vgp3, ldo_vcn18, ldo_vsim1, ldo_vsim2, ldo_vrtc, ldo_vcamaf, ldo_vibr,
+  ldo_vrf18, ldo_vm, ldo_vio18, ldo_vcamd, ldo_vcamio
+
+Example:
+
+	pmic: mt6323 {
+		mt6323regulator: regulators {
+			mt6323_vproc_reg: buck_vproc{
+				regulator-name = "vproc";
+				regulator-min-microvolt = < 700000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-ramp-delay = <12500>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vsys_reg: buck_vsys{
+				regulator-name = "vsys";
+				regulator-min-microvolt = <1400000>;
+				regulator-max-microvolt = <2987500>;
+				regulator-ramp-delay = <25000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vpa_reg: buck_vpa{
+				regulator-name = "vpa";
+				regulator-min-microvolt = < 500000>;
+				regulator-max-microvolt = <3650000>;
+			};
+
+			mt6323_vtcxo_reg: ldo_vtcxo{
+				regulator-name = "vtcxo";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <90>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vcn28_reg: ldo_vcn28{
+				regulator-name = "vcn28";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <185>;
+			};
+
+			mt6323_vcn33_bt_reg: ldo_vcn33_bt{
+				regulator-name = "vcn33_bt";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3600000>;
+				regulator-enable-ramp-delay = <185>;
+			};
+
+			mt6323_vcn33_wifi_reg: ldo_vcn33_wifi{
+				regulator-name = "vcn33_wifi";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3600000>;
+				regulator-enable-ramp-delay = <185>;
+			};
+
+			mt6323_va_reg: ldo_va{
+				regulator-name = "va";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vcama_reg: ldo_vcama{
+				regulator-name = "vcama";
+				regulator-min-microvolt = <1500000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vio28_reg: ldo_vio28{
+				regulator-name = "vio28";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vusb_reg: ldo_vusb{
+				regulator-name = "vusb";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-boot-on;
+			};
+
+			mt6323_vmc_reg: ldo_vmc{
+				regulator-name = "vmc";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <36>;
+				regulator-boot-on;
+			};
+
+			mt6323_vmch_reg: ldo_vmch{
+				regulator-name = "vmch";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <36>;
+				regulator-boot-on;
+			};
+
+			mt6323_vemc3v3_reg: ldo_vemc3v3{
+				regulator-name = "vemc3v3";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <36>;
+				regulator-boot-on;
+			};
+
+			mt6323_vgp1_reg: ldo_vgp1{
+				regulator-name = "vgp1";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vgp2_reg: ldo_vgp2{
+				regulator-name = "vgp2";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vgp3_reg: ldo_vgp3{
+				regulator-name = "vgp3";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vcn18_reg: ldo_vcn18{
+				regulator-name = "vcn18";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vsim1_reg: ldo_vsim1{
+				regulator-name = "vsim1";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vsim2_reg: ldo_vsim2{
+				regulator-name = "vsim2";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vrtc_reg: ldo_vrtc{
+				regulator-name = "vrtc";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vcamaf_reg: ldo_vcamaf{
+				regulator-name = "vcamaf";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vibr_reg: ldo_vibr{
+				regulator-name = "vibr";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <36>;
+			};
+
+			mt6323_vrf18_reg: ldo_vrf18{
+				regulator-name = "vrf18";
+				regulator-min-microvolt = <1825000>;
+				regulator-max-microvolt = <1825000>;
+				regulator-enable-ramp-delay = <187>;
+			};
+
+			mt6323_vm_reg: ldo_vm{
+				regulator-name = "vm";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vio18_reg: ldo_vio18{
+				regulator-name = "vio18";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vcamd_reg: ldo_vcamd{
+				regulator-name = "vcamd";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vcamio_reg: ldo_vcamio{
+				regulator-name = "vcamio";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+		};
+	};
-- 
1.7.10.4



From john at phrozen.org  Mon Jul 18 05:40:51 2016
From: john at phrozen.org (John Crispin)
Date: Mon, 18 Jul 2016 14:40:51 +0200
Subject: [PATCH V10 2/2] regulator: mt6323: Add support for MT6323 regulator
In-Reply-To: <1468845651-64011-1-git-send-email-john@phrozen.org>
References: <1468845651-64011-1-git-send-email-john@phrozen.org>
Message-ID: <1468845651-64011-2-git-send-email-john@phrozen.org>

From: Chen Zhong <chen.zhong at mediatek.com>

The MT6323 is a regulator found on boards based on MediaTek MT7623 and
probably other SoCs. It is a so called pmic and connects as a slave to
SoC using SPI, wrapped inside the pmic-wrapper.

Signed-off-by: Chen Zhong <chen.zhong at mediatek.com>
Signed-off-by: John Crispin <john at phrozen.org>
---
This series was dropped from the v4.7 queue to avoid a merge conflict with
the series adding mt6323 support to the MFD driver. These patches were
merged during the v4.7 window, so this series is good to go for v4.8. The
relevant series started with
commit feec4799ac4d ("mfd: mt6397: int_con and int_status may vary ...")
through to
commit 44760cf3bf0a ("mfd: mt6397: Add MT6323 support to MT6397 driver")

Changes in V10
* use correct SoB
* drop compatible string from devicetree binding

Changes in V6
* add back the set/get mode callbacks

Changes in V5
* remove the code that modifies constraints
* remove the code allows mode changes

Changes in V4:
* add id_table and of_match_table
* use short GPL text
* change MODULE_LICENSE to GPL V2

Changes in V2:
* send to the the proper maintainer

 drivers/regulator/Kconfig                  |    9 +
 drivers/regulator/Makefile                 |    1 +
 drivers/regulator/mt6323-regulator.c       |  425 ++++++++++++++++++++++++++++
 include/linux/regulator/mt6323-regulator.h |   52 ++++
 4 files changed, 487 insertions(+)
 create mode 100644 drivers/regulator/mt6323-regulator.c
 create mode 100644 include/linux/regulator/mt6323-regulator.h

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index ae9cbd6..6c88e31 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -498,6 +498,15 @@ config REGULATOR_MT6311
 	  This driver supports the control of different power rails of device
 	  through regulator interface.
 
+config REGULATOR_MT6323
+	tristate "MediaTek MT6323 PMIC"
+	depends on MFD_MT6397
+	help
+	  Say y here to select this option to enable the power regulator of
+	  MediaTek MT6323 PMIC.
+	  This driver supports the control of different power rails of device
+	  through regulator interface.
+
 config REGULATOR_MT6397
 	tristate "MediaTek MT6397 PMIC"
 	depends on MFD_MT6397
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 85a1d44..f3da9ee 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -65,6 +65,7 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
 obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
 obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
 obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
+obj-$(CONFIG_REGULATOR_MT6323)	+= mt6323-regulator.o
 obj-$(CONFIG_REGULATOR_MT6397)	+= mt6397-regulator.o
 obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
 obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
diff --git a/drivers/regulator/mt6323-regulator.c b/drivers/regulator/mt6323-regulator.c
new file mode 100644
index 0000000..927cc23
--- /dev/null
+++ b/drivers/regulator/mt6323-regulator.c
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Chen Zhong <chen.zhong at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/mt6397/core.h>
+#include <linux/mfd/mt6323/registers.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/mt6323-regulator.h>
+#include <linux/regulator/of_regulator.h>
+
+#define MT6323_LDO_MODE_NORMAL	0
+#define MT6323_LDO_MODE_LP	1
+
+/*
+ * MT6323 regulators' information
+ *
+ * @desc: standard fields of regulator description.
+ * @qi: Mask for query enable signal status of regulators
+ * @vselon_reg: Register sections for hardware control mode of bucks
+ * @vselctrl_reg: Register for controlling the buck control mode.
+ * @vselctrl_mask: Mask for query buck's voltage control mode.
+ */
+struct mt6323_regulator_info {
+	struct regulator_desc desc;
+	u32 qi;
+	u32 vselon_reg;
+	u32 vselctrl_reg;
+	u32 vselctrl_mask;
+	u32 modeset_reg;
+	u32 modeset_mask;
+};
+
+#define MT6323_BUCK(match, vreg, min, max, step, volt_ranges, enreg,	\
+		vosel, vosel_mask, voselon, vosel_ctrl)			\
+[MT6323_ID_##vreg] = {							\
+	.desc = {							\
+		.name = #vreg,						\
+		.of_match = of_match_ptr(match),			\
+		.ops = &mt6323_volt_range_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6323_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = (max - min)/step + 1,			\
+		.linear_ranges = volt_ranges,				\
+		.n_linear_ranges = ARRAY_SIZE(volt_ranges),		\
+		.vsel_reg = vosel,					\
+		.vsel_mask = vosel_mask,				\
+		.enable_reg = enreg,					\
+		.enable_mask = BIT(0),					\
+	},								\
+	.qi = BIT(13),							\
+	.vselon_reg = voselon,						\
+	.vselctrl_reg = vosel_ctrl,					\
+	.vselctrl_mask = BIT(1),					\
+}
+
+#define MT6323_LDO(match, vreg, ldo_volt_table, enreg, enbit, vosel,	\
+		vosel_mask, _modeset_reg, _modeset_mask)		\
+[MT6323_ID_##vreg] = {							\
+	.desc = {							\
+		.name = #vreg,						\
+		.of_match = of_match_ptr(match),			\
+		.ops = &mt6323_volt_table_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6323_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = ARRAY_SIZE(ldo_volt_table),		\
+		.volt_table = ldo_volt_table,				\
+		.vsel_reg = vosel,					\
+		.vsel_mask = vosel_mask,				\
+		.enable_reg = enreg,					\
+		.enable_mask = BIT(enbit),				\
+	},								\
+	.qi = BIT(15),							\
+	.modeset_reg = _modeset_reg,					\
+	.modeset_mask = _modeset_mask,					\
+}
+
+#define MT6323_REG_FIXED(match, vreg, enreg, enbit, volt,		\
+		_modeset_reg, _modeset_mask)				\
+[MT6323_ID_##vreg] = {							\
+	.desc = {							\
+		.name = #vreg,						\
+		.of_match = of_match_ptr(match),			\
+		.ops = &mt6323_volt_fixed_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6323_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = 1,					\
+		.enable_reg = enreg,					\
+		.enable_mask = BIT(enbit),				\
+		.min_uV = volt,						\
+	},								\
+	.qi = BIT(15),							\
+	.modeset_reg = _modeset_reg,					\
+	.modeset_mask = _modeset_mask,					\
+}
+
+static const struct regulator_linear_range buck_volt_range1[] = {
+	REGULATOR_LINEAR_RANGE(700000, 0, 0x7f, 6250),
+};
+
+static const struct regulator_linear_range buck_volt_range2[] = {
+	REGULATOR_LINEAR_RANGE(1400000, 0, 0x7f, 12500),
+};
+
+static const struct regulator_linear_range buck_volt_range3[] = {
+	REGULATOR_LINEAR_RANGE(500000, 0, 0x3f, 50000),
+};
+
+static const u32 ldo_volt_table1[] = {
+	3300000, 3400000, 3500000, 3600000,
+};
+
+static const u32 ldo_volt_table2[] = {
+	1500000, 1800000, 2500000, 2800000,
+};
+
+static const u32 ldo_volt_table3[] = {
+	1800000, 3300000,
+};
+
+static const u32 ldo_volt_table4[] = {
+	3000000, 3300000,
+};
+
+static const u32 ldo_volt_table5[] = {
+	1200000, 1300000, 1500000, 1800000, 2000000, 2800000, 3000000, 3300000,
+};
+
+static const u32 ldo_volt_table6[] = {
+	1200000, 1300000, 1500000, 1800000, 2500000, 2800000, 3000000, 2000000,
+};
+
+static const u32 ldo_volt_table7[] = {
+	1200000, 1300000, 1500000, 1800000,
+};
+
+static const u32 ldo_volt_table8[] = {
+	1800000, 3000000,
+};
+
+static const u32 ldo_volt_table9[] = {
+	1200000, 1350000, 1500000, 1800000,
+};
+
+static const u32 ldo_volt_table10[] = {
+	1200000, 1300000, 1500000, 1800000,
+};
+
+static int mt6323_get_status(struct regulator_dev *rdev)
+{
+	int ret;
+	u32 regval;
+	struct mt6323_regulator_info *info = rdev_get_drvdata(rdev);
+
+	ret = regmap_read(rdev->regmap, info->desc.enable_reg, &regval);
+	if (ret != 0) {
+		dev_err(&rdev->dev, "Failed to get enable reg: %d\n", ret);
+		return ret;
+	}
+
+	return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF;
+}
+
+static int mt6323_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	int ret, val = 0;
+	struct mt6323_regulator_info *info = rdev_get_drvdata(rdev);
+
+	if (!info->modeset_mask) {
+		dev_err(&rdev->dev, "regulator %s doesn't support set_mode\n",
+			info->desc.name);
+		return -EINVAL;
+	}
+
+	switch (mode) {
+	case REGULATOR_MODE_STANDBY:
+		val = MT6323_LDO_MODE_LP;
+		break;
+	case REGULATOR_MODE_NORMAL:
+		val = MT6323_LDO_MODE_NORMAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	val <<= ffs(info->modeset_mask) - 1;
+
+	ret = regmap_update_bits(rdev->regmap, info->modeset_reg,
+				  info->modeset_mask, val);
+
+	return ret;
+}
+
+static unsigned int mt6323_ldo_get_mode(struct regulator_dev *rdev)
+{
+	unsigned int val;
+	unsigned int mode;
+	int ret;
+	struct mt6323_regulator_info *info = rdev_get_drvdata(rdev);
+
+	if (!info->modeset_mask) {
+		dev_err(&rdev->dev, "regulator %s doesn't support get_mode\n",
+			info->desc.name);
+		return -EINVAL;
+	}
+
+	ret = regmap_read(rdev->regmap, info->modeset_reg, &val);
+	if (ret < 0)
+		return ret;
+
+	val &= info->modeset_mask;
+	val >>= ffs(info->modeset_mask) - 1;
+
+	if (val & 0x1)
+		mode = REGULATOR_MODE_STANDBY;
+	else
+		mode = REGULATOR_MODE_NORMAL;
+
+	return mode;
+}
+
+static struct regulator_ops mt6323_volt_range_ops = {
+	.list_voltage = regulator_list_voltage_linear_range,
+	.map_voltage = regulator_map_voltage_linear_range,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_status = mt6323_get_status,
+};
+
+static struct regulator_ops mt6323_volt_table_ops = {
+	.list_voltage = regulator_list_voltage_table,
+	.map_voltage = regulator_map_voltage_iterate,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_status = mt6323_get_status,
+	.set_mode = mt6323_ldo_set_mode,
+	.get_mode = mt6323_ldo_get_mode,
+};
+
+static struct regulator_ops mt6323_volt_fixed_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_status = mt6323_get_status,
+	.set_mode = mt6323_ldo_set_mode,
+	.get_mode = mt6323_ldo_get_mode,
+};
+
+/* The array is indexed by id(MT6323_ID_XXX) */
+static struct mt6323_regulator_info mt6323_regulators[] = {
+	MT6323_BUCK("buck_vproc", VPROC, 700000, 1493750, 6250,
+		buck_volt_range1, MT6323_VPROC_CON7, MT6323_VPROC_CON9, 0x7f,
+		MT6323_VPROC_CON10, MT6323_VPROC_CON5),
+	MT6323_BUCK("buck_vsys", VSYS, 1400000, 2987500, 12500,
+		buck_volt_range2, MT6323_VSYS_CON7, MT6323_VSYS_CON9, 0x7f,
+		MT6323_VSYS_CON10, MT6323_VSYS_CON5),
+	MT6323_BUCK("buck_vpa", VPA, 500000, 3650000, 50000,
+		buck_volt_range3, MT6323_VPA_CON7, MT6323_VPA_CON9,
+		0x3f, MT6323_VPA_CON10, MT6323_VPA_CON5),
+	MT6323_REG_FIXED("ldo_vtcxo", VTCXO, MT6323_ANALDO_CON1, 10, 2800000,
+		MT6323_ANALDO_CON1, 0x2),
+	MT6323_REG_FIXED("ldo_vcn28", VCN28, MT6323_ANALDO_CON19, 12, 2800000,
+		MT6323_ANALDO_CON20, 0x2),
+	MT6323_LDO("ldo_vcn33_bt", VCN33_BT, ldo_volt_table1,
+		MT6323_ANALDO_CON16, 7, MT6323_ANALDO_CON16, 0xC,
+		MT6323_ANALDO_CON21, 0x2),
+	MT6323_LDO("ldo_vcn33_wifi", VCN33_WIFI, ldo_volt_table1,
+		MT6323_ANALDO_CON17, 12, MT6323_ANALDO_CON16, 0xC,
+		MT6323_ANALDO_CON21, 0x2),
+	MT6323_REG_FIXED("ldo_va", VA, MT6323_ANALDO_CON2, 14, 2800000,
+		MT6323_ANALDO_CON2, 0x2),
+	MT6323_LDO("ldo_vcama", VCAMA, ldo_volt_table2,
+		MT6323_ANALDO_CON4, 15, MT6323_ANALDO_CON10, 0x60, -1, 0),
+	MT6323_REG_FIXED("ldo_vio28", VIO28, MT6323_DIGLDO_CON0, 14, 2800000,
+		MT6323_DIGLDO_CON0, 0x2),
+	MT6323_REG_FIXED("ldo_vusb", VUSB, MT6323_DIGLDO_CON2, 14, 3300000,
+		MT6323_DIGLDO_CON2, 0x2),
+	MT6323_LDO("ldo_vmc", VMC, ldo_volt_table3,
+		MT6323_DIGLDO_CON3, 12, MT6323_DIGLDO_CON24, 0x10,
+		MT6323_DIGLDO_CON3, 0x2),
+	MT6323_LDO("ldo_vmch", VMCH, ldo_volt_table4,
+		MT6323_DIGLDO_CON5, 14, MT6323_DIGLDO_CON26, 0x80,
+		MT6323_DIGLDO_CON5, 0x2),
+	MT6323_LDO("ldo_vemc3v3", VEMC3V3, ldo_volt_table4,
+		MT6323_DIGLDO_CON6, 14, MT6323_DIGLDO_CON27, 0x80,
+		MT6323_DIGLDO_CON6, 0x2),
+	MT6323_LDO("ldo_vgp1", VGP1, ldo_volt_table5,
+		MT6323_DIGLDO_CON7, 15, MT6323_DIGLDO_CON28, 0xE0,
+		MT6323_DIGLDO_CON7, 0x2),
+	MT6323_LDO("ldo_vgp2", VGP2, ldo_volt_table6,
+		MT6323_DIGLDO_CON8, 15, MT6323_DIGLDO_CON29, 0xE0,
+		MT6323_DIGLDO_CON8, 0x2),
+	MT6323_LDO("ldo_vgp3", VGP3, ldo_volt_table7,
+		MT6323_DIGLDO_CON9, 15, MT6323_DIGLDO_CON30, 0x60,
+		MT6323_DIGLDO_CON9, 0x2),
+	MT6323_REG_FIXED("ldo_vcn18", VCN18, MT6323_DIGLDO_CON11, 14, 1800000,
+		MT6323_DIGLDO_CON11, 0x2),
+	MT6323_LDO("ldo_vsim1", VSIM1, ldo_volt_table8,
+		MT6323_DIGLDO_CON13, 15, MT6323_DIGLDO_CON34, 0x20,
+		MT6323_DIGLDO_CON13, 0x2),
+	MT6323_LDO("ldo_vsim2", VSIM2, ldo_volt_table8,
+		MT6323_DIGLDO_CON14, 15, MT6323_DIGLDO_CON35, 0x20,
+		MT6323_DIGLDO_CON14, 0x2),
+	MT6323_REG_FIXED("ldo_vrtc", VRTC, MT6323_DIGLDO_CON15, 8, 2800000,
+		-1, 0),
+	MT6323_LDO("ldo_vcamaf", VCAMAF, ldo_volt_table5,
+		MT6323_DIGLDO_CON31, 15, MT6323_DIGLDO_CON32, 0xE0,
+		MT6323_DIGLDO_CON31, 0x2),
+	MT6323_LDO("ldo_vibr", VIBR, ldo_volt_table5,
+		MT6323_DIGLDO_CON39, 15, MT6323_DIGLDO_CON40, 0xE0,
+		MT6323_DIGLDO_CON39, 0x2),
+	MT6323_REG_FIXED("ldo_vrf18", VRF18, MT6323_DIGLDO_CON45, 15, 1825000,
+		MT6323_DIGLDO_CON45, 0x2),
+	MT6323_LDO("ldo_vm", VM, ldo_volt_table9,
+		MT6323_DIGLDO_CON47, 14, MT6323_DIGLDO_CON48, 0x30,
+		MT6323_DIGLDO_CON47, 0x2),
+	MT6323_REG_FIXED("ldo_vio18", VIO18, MT6323_DIGLDO_CON49, 14, 1800000,
+		MT6323_DIGLDO_CON49, 0x2),
+	MT6323_LDO("ldo_vcamd", VCAMD, ldo_volt_table10,
+		MT6323_DIGLDO_CON51, 14, MT6323_DIGLDO_CON52, 0x60,
+		MT6323_DIGLDO_CON51, 0x2),
+	MT6323_REG_FIXED("ldo_vcamio", VCAMIO, MT6323_DIGLDO_CON53, 14, 1800000,
+		MT6323_DIGLDO_CON53, 0x2),
+};
+
+static int mt6323_set_buck_vosel_reg(struct platform_device *pdev)
+{
+	struct mt6397_chip *mt6323 = dev_get_drvdata(pdev->dev.parent);
+	int i;
+	u32 regval;
+
+	for (i = 0; i < MT6323_MAX_REGULATOR; i++) {
+		if (mt6323_regulators[i].vselctrl_reg) {
+			if (regmap_read(mt6323->regmap,
+				mt6323_regulators[i].vselctrl_reg,
+				&regval) < 0) {
+				dev_err(&pdev->dev,
+					"Failed to read buck ctrl\n");
+				return -EIO;
+			}
+
+			if (regval & mt6323_regulators[i].vselctrl_mask) {
+				mt6323_regulators[i].desc.vsel_reg =
+				mt6323_regulators[i].vselon_reg;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int mt6323_regulator_probe(struct platform_device *pdev)
+{
+	struct mt6397_chip *mt6323 = dev_get_drvdata(pdev->dev.parent);
+	struct regulator_config config = {};
+	struct regulator_dev *rdev;
+	int i;
+	u32 reg_value;
+
+	/* Query buck controller to select activated voltage register part */
+	if (mt6323_set_buck_vosel_reg(pdev))
+		return -EIO;
+
+	/* Read PMIC chip revision to update constraints and voltage table */
+	if (regmap_read(mt6323->regmap, MT6323_CID, &reg_value) < 0) {
+		dev_err(&pdev->dev, "Failed to read Chip ID\n");
+		return -EIO;
+	}
+	dev_info(&pdev->dev, "Chip ID = 0x%x\n", reg_value);
+
+	for (i = 0; i < MT6323_MAX_REGULATOR; i++) {
+		config.dev = &pdev->dev;
+		config.driver_data = &mt6323_regulators[i];
+		config.regmap = mt6323->regmap;
+		rdev = devm_regulator_register(&pdev->dev,
+				&mt6323_regulators[i].desc, &config);
+		if (IS_ERR(rdev)) {
+			dev_err(&pdev->dev, "failed to register %s\n",
+				mt6323_regulators[i].desc.name);
+			return PTR_ERR(rdev);
+		}
+	}
+	return 0;
+}
+
+static const struct platform_device_id mt6323_platform_ids[] = {
+	{"mt6323-regulator", 0},
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, mt6323_platform_ids);
+
+static struct platform_driver mt6323_regulator_driver = {
+	.driver = {
+		.name = "mt6323-regulator",
+	},
+	.probe = mt6323_regulator_probe,
+	.id_table = mt6323_platform_ids,
+};
+
+module_platform_driver(mt6323_regulator_driver);
+
+MODULE_AUTHOR("Chen Zhong <chen.zhong at mediatek.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6397 PMIC");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/regulator/mt6323-regulator.h b/include/linux/regulator/mt6323-regulator.h
new file mode 100644
index 0000000..67011cd
--- /dev/null
+++ b/include/linux/regulator/mt6323-regulator.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Chen Zhong <chen.zhong at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __LINUX_REGULATOR_MT6323_H
+#define __LINUX_REGULATOR_MT6323_H
+
+enum {
+	MT6323_ID_VPROC = 0,
+	MT6323_ID_VSYS,
+	MT6323_ID_VPA,
+	MT6323_ID_VTCXO,
+	MT6323_ID_VCN28,
+	MT6323_ID_VCN33_BT,
+	MT6323_ID_VCN33_WIFI,
+	MT6323_ID_VA,
+	MT6323_ID_VCAMA,
+	MT6323_ID_VIO28 = 9,
+	MT6323_ID_VUSB,
+	MT6323_ID_VMC,
+	MT6323_ID_VMCH,
+	MT6323_ID_VEMC3V3,
+	MT6323_ID_VGP1,
+	MT6323_ID_VGP2,
+	MT6323_ID_VGP3,
+	MT6323_ID_VCN18,
+	MT6323_ID_VSIM1,
+	MT6323_ID_VSIM2,
+	MT6323_ID_VRTC,
+	MT6323_ID_VCAMAF,
+	MT6323_ID_VIBR,
+	MT6323_ID_VRF18,
+	MT6323_ID_VM,
+	MT6323_ID_VIO18,
+	MT6323_ID_VCAMD,
+	MT6323_ID_VCAMIO,
+	MT6323_ID_RG_MAX,
+};
+
+#define MT6323_MAX_REGULATOR	MT6323_ID_RG_MAX
+
+#endif /* __LINUX_REGULATOR_MT6323_H */
-- 
1.7.10.4



From hverkuil at xs4all.nl  Mon Jul 18 05:44:45 2016
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Mon, 18 Jul 2016 14:44:45 +0200
Subject: [PATCH] vcodec: mediatek: Add g/s_selection support for V4L2
 Encoder
In-Reply-To: <1468844895.12740.15.camel@mtksdaap41>
References: <1464594768-1993-1-git-send-email-tiffany.lin@mediatek.com>
 <4ca82842-968d-a5e2-587d-752c71713607@xs4all.nl>
 <1468477674.32454.36.camel@mtksdaap41>
 <bb96276a-8e6c-a535-6fd3-fe4327238f65@xs4all.nl>
 <1468844895.12740.15.camel@mtksdaap41>
Message-ID: <f2c031e2-82ca-90f4-0900-4dc961a90f58@xs4all.nl>

On 07/18/2016 02:28 PM, tiffany lin wrote:
> Understood now.
> 
> Now I am trying to figure out how to make this function right.
> Our encoder only support crop range from (0, 0) to (width, height), so
> if s->r.top and s->r.left not 0, I will return -EINVAL.
> 
> 
> Another thing is that in v4l2-compliance test, it has testLegacyCrop.
> It looks like we still need to support 
>  V4L2_SEL_TGT_COMPOSE_DEFAULT:
>  V4L2_SEL_TGT_COMPOSE_BOUNDS:
>  V4L2_SEL_TGT_COMPOSE:
> to pass v4l2 compliance test, Or it will fail in 
> fail: v4l2-test-formats.cpp(1318): !doioctl(node, VIDIOC_G_SELECTION,
> &sel)
> fail: v4l2-test-formats.cpp(1336): testLegacyCrop(node)
> test Cropping: FAIL

Against which kernel are you testing? In the current media_tree master
there is a bug in drivers/media/v4l2-core/v4l2-ioctl.c, v4l_cropcap():

This code:

if (WARN_ON(!ops->vidioc_cropcap && !ops->vidioc_cropcap))

should be:

if (WARN_ON(!ops->vidioc_cropcap && !ops->vidioc_g_selection))

The fix is waiting for a pull from Linus.

Also update to the latest v4l2-compliance: I've made some changes that
might affect this. And I added additional checks to verify if all the
colorspace-related format fields are properly propagated from the
output format to the capture format.

Regards,

	Hans

> 
> I don't understand the following testing code.
> 
>         /*
>          * If either CROPCAP or G_CROP works, then G_SELECTION should
>          * work as well.
>          * If neither CROPCAP nor G_CROP work, then G_SELECTION
> shouldn't
>          * work either.
>          */
>         if (!doioctl(node, VIDIOC_CROPCAP, &cap)) {
>                 fail_on_test(doioctl(node, VIDIOC_G_SELECTION, &sel));
> 
>                 // Checks for invalid types
>                 if (cap.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
>                         cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
>                 else
>                         cap.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
>                 fail_on_test(doioctl(node, VIDIOC_CROPCAP, &cap) !=
> EINVAL);
>                 cap.type = 0xff;
>                 fail_on_test(doioctl(node, VIDIOC_CROPCAP, &cap) !=
> EINVAL);
>         } else {
>                 fail_on_test(!doioctl(node, VIDIOC_G_SELECTION, &sel));
> -> fail here
>         }
> 
> When test OUTPUT queue, it fail because v4l_cropcap will fail when
> s.target = V4L2_SEL_TGT_COMPOSE_BOUNDS.
> If VIDIOC_CROPCAP ioctl fail, VIDIOC_G_SELECTION should fail.
> But VIDIOC_G_SELECTION target on CROP not COMPOSE and it success.
> 
> 
> best regards,
> Tiffany
> 
> 
> 
>> Regards,
>>
>> 	Hans
>>
>>>
>>>
>>> static int v4l_g_crop(const struct v4l2_ioctl_ops *ops,
>>> 				struct file *file, void *fh, void *arg)
>>> {
>>> 	struct v4l2_crop *p = arg;
>>> 	struct v4l2_selection s = {
>>> 		.type = p->type,
>>> 	};
>>> 	int ret;
>>>
>>> 	if (ops->vidioc_g_crop)
>>> 		return ops->vidioc_g_crop(file, fh, p);
>>> 	/* simulate capture crop using selection api */
>>>
>>> 	/* crop means compose for output devices */
>>> 	if (V4L2_TYPE_IS_OUTPUT(p->type))
>>> 		s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE;
>>> 	else
>>> 		s.target = V4L2_SEL_TGT_CROP_ACTIVE;
>>>
>>> 	ret = ops->vidioc_g_selection(file, fh, &s);
>>>
>>> 	/* copying results to old structure on success */
>>> 	if (!ret)
>>> 		p->c = s.r;
>>> 	return ret;
>>> }
>>>
>>> static int v4l_s_crop(const struct v4l2_ioctl_ops *ops,
>>> 				struct file *file, void *fh, void *arg)
>>> {
>>> 	struct v4l2_crop *p = arg;
>>> 	struct v4l2_selection s = {
>>> 		.type = p->type,
>>> 		.r = p->c,
>>> 	};
>>>
>>> 	if (ops->vidioc_s_crop)
>>> 		return ops->vidioc_s_crop(file, fh, p);
>>> 	/* simulate capture crop using selection api */
>>>
>>> 	/* crop means compose for output devices */
>>> 	if (V4L2_TYPE_IS_OUTPUT(p->type))
>>> 		s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE;
>>> 	else
>>> 		s.target = V4L2_SEL_TGT_CROP_ACTIVE;
>>>
>>> 	return ops->vidioc_s_selection(file, fh, &s);
>>> }
>>>
>>>
>>> best regards,
>>> Tiffany
>>>
>>>
>>>
>>>
>>>> Regards,
>>>>
>>>> 	Hans
>>>>
>>>>> +
>>>>> +	return 0;
>>>>> +}
>>>>> +
>>>>>  static int vidioc_venc_qbuf(struct file *file, void *priv,
>>>>>  			    struct v4l2_buffer *buf)
>>>>>  {
>>>>> @@ -688,6 +759,9 @@ const struct v4l2_ioctl_ops mtk_venc_ioctl_ops = {
>>>>>  
>>>>>  	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,
>>>>>  	.vidioc_prepare_buf		= v4l2_m2m_ioctl_prepare_buf,
>>>>> +
>>>>> +	.vidioc_g_selection		= vidioc_venc_g_selection,
>>>>> +	.vidioc_s_selection		= vidioc_venc_s_selection,
>>>>>  };
>>>>>  
>>>>>  static int vb2ops_venc_queue_setup(struct vb2_queue *vq,
>>>>>
>>>
>>>
>>> --
>>> 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
>>>
> 
> 


From broonie at kernel.org  Mon Jul 18 05:46:45 2016
From: broonie at kernel.org (Mark Brown)
Date: Mon, 18 Jul 2016 13:46:45 +0100
Subject: Applied "regulator: Add document for MT6323 regulator" to the
 regulator tree
In-Reply-To: <1468845651-64011-1-git-send-email-john@phrozen.org>
Message-ID: <E1bP7wb-0001p5-BP@debutante>

The patch

   regulator: Add document for MT6323 regulator

has been applied to the regulator tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From d236b3ee5bb13f53ed60ccc6f704a13b923d2952 Mon Sep 17 00:00:00 2001
From: John Crispin <john at phrozen.org>
Date: Mon, 18 Jul 2016 14:40:50 +0200
Subject: [PATCH] regulator: Add document for MT6323 regulator

Signed-off-by: John Crispin <john at phrozen.org>
Cc: devicetree at vger.kernel.org
Acked-by: Rob Herring <robh at kernel.org>
Signed-off-by: Mark Brown <broonie at kernel.org>
---
 .../bindings/regulator/mt6323-regulator.txt        | 237 +++++++++++++++++++++
 1 file changed, 237 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/regulator/mt6323-regulator.txt

diff --git a/Documentation/devicetree/bindings/regulator/mt6323-regulator.txt b/Documentation/devicetree/bindings/regulator/mt6323-regulator.txt
new file mode 100644
index 000000000000..c35d878b0960
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/mt6323-regulator.txt
@@ -0,0 +1,237 @@
+Mediatek MT6323 Regulator Driver
+
+All voltage regulators are defined as subnodes of the regulators node. A list
+of regulators provided by this controller are defined as subnodes of the
+PMIC's node. Each regulator is named according to its regulator type,
+buck_<name> and ldo_<name>. The definition for each of these nodes is defined
+using the standard binding for regulators at
+Documentation/devicetree/bindings/regulator/regulator.txt.
+
+The valid names for regulators are::
+BUCK:
+  buck_vproc, buck_vsys, buck_vpa
+LDO:
+  ldo_vtcxo, ldo_vcn28, ldo_vcn33_bt, ldo_vcn33_wifi, ldo_va, ldo_vcama,
+  ldo_vio28, ldo_vusb, ldo_vmc, ldo_vmch, ldo_vemc3v3, ldo_vgp1, ldo_vgp2,
+  ldo_vgp3, ldo_vcn18, ldo_vsim1, ldo_vsim2, ldo_vrtc, ldo_vcamaf, ldo_vibr,
+  ldo_vrf18, ldo_vm, ldo_vio18, ldo_vcamd, ldo_vcamio
+
+Example:
+
+	pmic: mt6323 {
+		mt6323regulator: regulators {
+			mt6323_vproc_reg: buck_vproc{
+				regulator-name = "vproc";
+				regulator-min-microvolt = < 700000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-ramp-delay = <12500>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vsys_reg: buck_vsys{
+				regulator-name = "vsys";
+				regulator-min-microvolt = <1400000>;
+				regulator-max-microvolt = <2987500>;
+				regulator-ramp-delay = <25000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vpa_reg: buck_vpa{
+				regulator-name = "vpa";
+				regulator-min-microvolt = < 500000>;
+				regulator-max-microvolt = <3650000>;
+			};
+
+			mt6323_vtcxo_reg: ldo_vtcxo{
+				regulator-name = "vtcxo";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <90>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vcn28_reg: ldo_vcn28{
+				regulator-name = "vcn28";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <185>;
+			};
+
+			mt6323_vcn33_bt_reg: ldo_vcn33_bt{
+				regulator-name = "vcn33_bt";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3600000>;
+				regulator-enable-ramp-delay = <185>;
+			};
+
+			mt6323_vcn33_wifi_reg: ldo_vcn33_wifi{
+				regulator-name = "vcn33_wifi";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3600000>;
+				regulator-enable-ramp-delay = <185>;
+			};
+
+			mt6323_va_reg: ldo_va{
+				regulator-name = "va";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vcama_reg: ldo_vcama{
+				regulator-name = "vcama";
+				regulator-min-microvolt = <1500000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vio28_reg: ldo_vio28{
+				regulator-name = "vio28";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vusb_reg: ldo_vusb{
+				regulator-name = "vusb";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-boot-on;
+			};
+
+			mt6323_vmc_reg: ldo_vmc{
+				regulator-name = "vmc";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <36>;
+				regulator-boot-on;
+			};
+
+			mt6323_vmch_reg: ldo_vmch{
+				regulator-name = "vmch";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <36>;
+				regulator-boot-on;
+			};
+
+			mt6323_vemc3v3_reg: ldo_vemc3v3{
+				regulator-name = "vemc3v3";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <36>;
+				regulator-boot-on;
+			};
+
+			mt6323_vgp1_reg: ldo_vgp1{
+				regulator-name = "vgp1";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vgp2_reg: ldo_vgp2{
+				regulator-name = "vgp2";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vgp3_reg: ldo_vgp3{
+				regulator-name = "vgp3";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vcn18_reg: ldo_vcn18{
+				regulator-name = "vcn18";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vsim1_reg: ldo_vsim1{
+				regulator-name = "vsim1";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vsim2_reg: ldo_vsim2{
+				regulator-name = "vsim2";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vrtc_reg: ldo_vrtc{
+				regulator-name = "vrtc";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vcamaf_reg: ldo_vcamaf{
+				regulator-name = "vcamaf";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vibr_reg: ldo_vibr{
+				regulator-name = "vibr";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <36>;
+			};
+
+			mt6323_vrf18_reg: ldo_vrf18{
+				regulator-name = "vrf18";
+				regulator-min-microvolt = <1825000>;
+				regulator-max-microvolt = <1825000>;
+				regulator-enable-ramp-delay = <187>;
+			};
+
+			mt6323_vm_reg: ldo_vm{
+				regulator-name = "vm";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vio18_reg: ldo_vio18{
+				regulator-name = "vio18";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vcamd_reg: ldo_vcamd{
+				regulator-name = "vcamd";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vcamio_reg: ldo_vcamio{
+				regulator-name = "vcamio";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+		};
+	};
-- 
2.8.1



From broonie at kernel.org  Mon Jul 18 05:46:42 2016
From: broonie at kernel.org (Mark Brown)
Date: Mon, 18 Jul 2016 13:46:42 +0100
Subject: Applied "regulator: mt6323: Add support for MT6323 regulator" to the
 regulator tree
In-Reply-To: <1468845651-64011-2-git-send-email-john@phrozen.org>
Message-ID: <E1bP7wY-0001o9-Cf@debutante>

The patch

   regulator: mt6323: Add support for MT6323 regulator

has been applied to the regulator tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 2fdf829236183e5be559a2b4d13c29926b79b2d4 Mon Sep 17 00:00:00 2001
From: Chen Zhong <chen.zhong at mediatek.com>
Date: Mon, 18 Jul 2016 14:40:51 +0200
Subject: [PATCH] regulator: mt6323: Add support for MT6323 regulator

The MT6323 is a regulator found on boards based on MediaTek MT7623 and
probably other SoCs. It is a so called pmic and connects as a slave to
SoC using SPI, wrapped inside the pmic-wrapper.

Signed-off-by: Chen Zhong <chen.zhong at mediatek.com>
Signed-off-by: John Crispin <john at phrozen.org>
Signed-off-by: Mark Brown <broonie at kernel.org>
---
 drivers/regulator/Kconfig                  |   9 +
 drivers/regulator/Makefile                 |   1 +
 drivers/regulator/mt6323-regulator.c       | 425 +++++++++++++++++++++++++++++
 include/linux/regulator/mt6323-regulator.h |  52 ++++
 4 files changed, 487 insertions(+)
 create mode 100644 drivers/regulator/mt6323-regulator.c
 create mode 100644 include/linux/regulator/mt6323-regulator.h

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 144cbf5b3e5a..53b30b46c1c5 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -498,6 +498,15 @@ config REGULATOR_MT6311
 	  This driver supports the control of different power rails of device
 	  through regulator interface.
 
+config REGULATOR_MT6323
+	tristate "MediaTek MT6323 PMIC"
+	depends on MFD_MT6397
+	help
+	  Say y here to select this option to enable the power regulator of
+	  MediaTek MT6323 PMIC.
+	  This driver supports the control of different power rails of device
+	  through regulator interface.
+
 config REGULATOR_MT6397
 	tristate "MediaTek MT6397 PMIC"
 	depends on MFD_MT6397
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 85a1d44a3939..f3da9eea9ab6 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -65,6 +65,7 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
 obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
 obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
 obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
+obj-$(CONFIG_REGULATOR_MT6323)	+= mt6323-regulator.o
 obj-$(CONFIG_REGULATOR_MT6397)	+= mt6397-regulator.o
 obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
 obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
diff --git a/drivers/regulator/mt6323-regulator.c b/drivers/regulator/mt6323-regulator.c
new file mode 100644
index 000000000000..927cc23b1c30
--- /dev/null
+++ b/drivers/regulator/mt6323-regulator.c
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Chen Zhong <chen.zhong at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/mt6397/core.h>
+#include <linux/mfd/mt6323/registers.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/mt6323-regulator.h>
+#include <linux/regulator/of_regulator.h>
+
+#define MT6323_LDO_MODE_NORMAL	0
+#define MT6323_LDO_MODE_LP	1
+
+/*
+ * MT6323 regulators' information
+ *
+ * @desc: standard fields of regulator description.
+ * @qi: Mask for query enable signal status of regulators
+ * @vselon_reg: Register sections for hardware control mode of bucks
+ * @vselctrl_reg: Register for controlling the buck control mode.
+ * @vselctrl_mask: Mask for query buck's voltage control mode.
+ */
+struct mt6323_regulator_info {
+	struct regulator_desc desc;
+	u32 qi;
+	u32 vselon_reg;
+	u32 vselctrl_reg;
+	u32 vselctrl_mask;
+	u32 modeset_reg;
+	u32 modeset_mask;
+};
+
+#define MT6323_BUCK(match, vreg, min, max, step, volt_ranges, enreg,	\
+		vosel, vosel_mask, voselon, vosel_ctrl)			\
+[MT6323_ID_##vreg] = {							\
+	.desc = {							\
+		.name = #vreg,						\
+		.of_match = of_match_ptr(match),			\
+		.ops = &mt6323_volt_range_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6323_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = (max - min)/step + 1,			\
+		.linear_ranges = volt_ranges,				\
+		.n_linear_ranges = ARRAY_SIZE(volt_ranges),		\
+		.vsel_reg = vosel,					\
+		.vsel_mask = vosel_mask,				\
+		.enable_reg = enreg,					\
+		.enable_mask = BIT(0),					\
+	},								\
+	.qi = BIT(13),							\
+	.vselon_reg = voselon,						\
+	.vselctrl_reg = vosel_ctrl,					\
+	.vselctrl_mask = BIT(1),					\
+}
+
+#define MT6323_LDO(match, vreg, ldo_volt_table, enreg, enbit, vosel,	\
+		vosel_mask, _modeset_reg, _modeset_mask)		\
+[MT6323_ID_##vreg] = {							\
+	.desc = {							\
+		.name = #vreg,						\
+		.of_match = of_match_ptr(match),			\
+		.ops = &mt6323_volt_table_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6323_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = ARRAY_SIZE(ldo_volt_table),		\
+		.volt_table = ldo_volt_table,				\
+		.vsel_reg = vosel,					\
+		.vsel_mask = vosel_mask,				\
+		.enable_reg = enreg,					\
+		.enable_mask = BIT(enbit),				\
+	},								\
+	.qi = BIT(15),							\
+	.modeset_reg = _modeset_reg,					\
+	.modeset_mask = _modeset_mask,					\
+}
+
+#define MT6323_REG_FIXED(match, vreg, enreg, enbit, volt,		\
+		_modeset_reg, _modeset_mask)				\
+[MT6323_ID_##vreg] = {							\
+	.desc = {							\
+		.name = #vreg,						\
+		.of_match = of_match_ptr(match),			\
+		.ops = &mt6323_volt_fixed_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6323_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = 1,					\
+		.enable_reg = enreg,					\
+		.enable_mask = BIT(enbit),				\
+		.min_uV = volt,						\
+	},								\
+	.qi = BIT(15),							\
+	.modeset_reg = _modeset_reg,					\
+	.modeset_mask = _modeset_mask,					\
+}
+
+static const struct regulator_linear_range buck_volt_range1[] = {
+	REGULATOR_LINEAR_RANGE(700000, 0, 0x7f, 6250),
+};
+
+static const struct regulator_linear_range buck_volt_range2[] = {
+	REGULATOR_LINEAR_RANGE(1400000, 0, 0x7f, 12500),
+};
+
+static const struct regulator_linear_range buck_volt_range3[] = {
+	REGULATOR_LINEAR_RANGE(500000, 0, 0x3f, 50000),
+};
+
+static const u32 ldo_volt_table1[] = {
+	3300000, 3400000, 3500000, 3600000,
+};
+
+static const u32 ldo_volt_table2[] = {
+	1500000, 1800000, 2500000, 2800000,
+};
+
+static const u32 ldo_volt_table3[] = {
+	1800000, 3300000,
+};
+
+static const u32 ldo_volt_table4[] = {
+	3000000, 3300000,
+};
+
+static const u32 ldo_volt_table5[] = {
+	1200000, 1300000, 1500000, 1800000, 2000000, 2800000, 3000000, 3300000,
+};
+
+static const u32 ldo_volt_table6[] = {
+	1200000, 1300000, 1500000, 1800000, 2500000, 2800000, 3000000, 2000000,
+};
+
+static const u32 ldo_volt_table7[] = {
+	1200000, 1300000, 1500000, 1800000,
+};
+
+static const u32 ldo_volt_table8[] = {
+	1800000, 3000000,
+};
+
+static const u32 ldo_volt_table9[] = {
+	1200000, 1350000, 1500000, 1800000,
+};
+
+static const u32 ldo_volt_table10[] = {
+	1200000, 1300000, 1500000, 1800000,
+};
+
+static int mt6323_get_status(struct regulator_dev *rdev)
+{
+	int ret;
+	u32 regval;
+	struct mt6323_regulator_info *info = rdev_get_drvdata(rdev);
+
+	ret = regmap_read(rdev->regmap, info->desc.enable_reg, &regval);
+	if (ret != 0) {
+		dev_err(&rdev->dev, "Failed to get enable reg: %d\n", ret);
+		return ret;
+	}
+
+	return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF;
+}
+
+static int mt6323_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	int ret, val = 0;
+	struct mt6323_regulator_info *info = rdev_get_drvdata(rdev);
+
+	if (!info->modeset_mask) {
+		dev_err(&rdev->dev, "regulator %s doesn't support set_mode\n",
+			info->desc.name);
+		return -EINVAL;
+	}
+
+	switch (mode) {
+	case REGULATOR_MODE_STANDBY:
+		val = MT6323_LDO_MODE_LP;
+		break;
+	case REGULATOR_MODE_NORMAL:
+		val = MT6323_LDO_MODE_NORMAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	val <<= ffs(info->modeset_mask) - 1;
+
+	ret = regmap_update_bits(rdev->regmap, info->modeset_reg,
+				  info->modeset_mask, val);
+
+	return ret;
+}
+
+static unsigned int mt6323_ldo_get_mode(struct regulator_dev *rdev)
+{
+	unsigned int val;
+	unsigned int mode;
+	int ret;
+	struct mt6323_regulator_info *info = rdev_get_drvdata(rdev);
+
+	if (!info->modeset_mask) {
+		dev_err(&rdev->dev, "regulator %s doesn't support get_mode\n",
+			info->desc.name);
+		return -EINVAL;
+	}
+
+	ret = regmap_read(rdev->regmap, info->modeset_reg, &val);
+	if (ret < 0)
+		return ret;
+
+	val &= info->modeset_mask;
+	val >>= ffs(info->modeset_mask) - 1;
+
+	if (val & 0x1)
+		mode = REGULATOR_MODE_STANDBY;
+	else
+		mode = REGULATOR_MODE_NORMAL;
+
+	return mode;
+}
+
+static struct regulator_ops mt6323_volt_range_ops = {
+	.list_voltage = regulator_list_voltage_linear_range,
+	.map_voltage = regulator_map_voltage_linear_range,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_status = mt6323_get_status,
+};
+
+static struct regulator_ops mt6323_volt_table_ops = {
+	.list_voltage = regulator_list_voltage_table,
+	.map_voltage = regulator_map_voltage_iterate,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_status = mt6323_get_status,
+	.set_mode = mt6323_ldo_set_mode,
+	.get_mode = mt6323_ldo_get_mode,
+};
+
+static struct regulator_ops mt6323_volt_fixed_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_status = mt6323_get_status,
+	.set_mode = mt6323_ldo_set_mode,
+	.get_mode = mt6323_ldo_get_mode,
+};
+
+/* The array is indexed by id(MT6323_ID_XXX) */
+static struct mt6323_regulator_info mt6323_regulators[] = {
+	MT6323_BUCK("buck_vproc", VPROC, 700000, 1493750, 6250,
+		buck_volt_range1, MT6323_VPROC_CON7, MT6323_VPROC_CON9, 0x7f,
+		MT6323_VPROC_CON10, MT6323_VPROC_CON5),
+	MT6323_BUCK("buck_vsys", VSYS, 1400000, 2987500, 12500,
+		buck_volt_range2, MT6323_VSYS_CON7, MT6323_VSYS_CON9, 0x7f,
+		MT6323_VSYS_CON10, MT6323_VSYS_CON5),
+	MT6323_BUCK("buck_vpa", VPA, 500000, 3650000, 50000,
+		buck_volt_range3, MT6323_VPA_CON7, MT6323_VPA_CON9,
+		0x3f, MT6323_VPA_CON10, MT6323_VPA_CON5),
+	MT6323_REG_FIXED("ldo_vtcxo", VTCXO, MT6323_ANALDO_CON1, 10, 2800000,
+		MT6323_ANALDO_CON1, 0x2),
+	MT6323_REG_FIXED("ldo_vcn28", VCN28, MT6323_ANALDO_CON19, 12, 2800000,
+		MT6323_ANALDO_CON20, 0x2),
+	MT6323_LDO("ldo_vcn33_bt", VCN33_BT, ldo_volt_table1,
+		MT6323_ANALDO_CON16, 7, MT6323_ANALDO_CON16, 0xC,
+		MT6323_ANALDO_CON21, 0x2),
+	MT6323_LDO("ldo_vcn33_wifi", VCN33_WIFI, ldo_volt_table1,
+		MT6323_ANALDO_CON17, 12, MT6323_ANALDO_CON16, 0xC,
+		MT6323_ANALDO_CON21, 0x2),
+	MT6323_REG_FIXED("ldo_va", VA, MT6323_ANALDO_CON2, 14, 2800000,
+		MT6323_ANALDO_CON2, 0x2),
+	MT6323_LDO("ldo_vcama", VCAMA, ldo_volt_table2,
+		MT6323_ANALDO_CON4, 15, MT6323_ANALDO_CON10, 0x60, -1, 0),
+	MT6323_REG_FIXED("ldo_vio28", VIO28, MT6323_DIGLDO_CON0, 14, 2800000,
+		MT6323_DIGLDO_CON0, 0x2),
+	MT6323_REG_FIXED("ldo_vusb", VUSB, MT6323_DIGLDO_CON2, 14, 3300000,
+		MT6323_DIGLDO_CON2, 0x2),
+	MT6323_LDO("ldo_vmc", VMC, ldo_volt_table3,
+		MT6323_DIGLDO_CON3, 12, MT6323_DIGLDO_CON24, 0x10,
+		MT6323_DIGLDO_CON3, 0x2),
+	MT6323_LDO("ldo_vmch", VMCH, ldo_volt_table4,
+		MT6323_DIGLDO_CON5, 14, MT6323_DIGLDO_CON26, 0x80,
+		MT6323_DIGLDO_CON5, 0x2),
+	MT6323_LDO("ldo_vemc3v3", VEMC3V3, ldo_volt_table4,
+		MT6323_DIGLDO_CON6, 14, MT6323_DIGLDO_CON27, 0x80,
+		MT6323_DIGLDO_CON6, 0x2),
+	MT6323_LDO("ldo_vgp1", VGP1, ldo_volt_table5,
+		MT6323_DIGLDO_CON7, 15, MT6323_DIGLDO_CON28, 0xE0,
+		MT6323_DIGLDO_CON7, 0x2),
+	MT6323_LDO("ldo_vgp2", VGP2, ldo_volt_table6,
+		MT6323_DIGLDO_CON8, 15, MT6323_DIGLDO_CON29, 0xE0,
+		MT6323_DIGLDO_CON8, 0x2),
+	MT6323_LDO("ldo_vgp3", VGP3, ldo_volt_table7,
+		MT6323_DIGLDO_CON9, 15, MT6323_DIGLDO_CON30, 0x60,
+		MT6323_DIGLDO_CON9, 0x2),
+	MT6323_REG_FIXED("ldo_vcn18", VCN18, MT6323_DIGLDO_CON11, 14, 1800000,
+		MT6323_DIGLDO_CON11, 0x2),
+	MT6323_LDO("ldo_vsim1", VSIM1, ldo_volt_table8,
+		MT6323_DIGLDO_CON13, 15, MT6323_DIGLDO_CON34, 0x20,
+		MT6323_DIGLDO_CON13, 0x2),
+	MT6323_LDO("ldo_vsim2", VSIM2, ldo_volt_table8,
+		MT6323_DIGLDO_CON14, 15, MT6323_DIGLDO_CON35, 0x20,
+		MT6323_DIGLDO_CON14, 0x2),
+	MT6323_REG_FIXED("ldo_vrtc", VRTC, MT6323_DIGLDO_CON15, 8, 2800000,
+		-1, 0),
+	MT6323_LDO("ldo_vcamaf", VCAMAF, ldo_volt_table5,
+		MT6323_DIGLDO_CON31, 15, MT6323_DIGLDO_CON32, 0xE0,
+		MT6323_DIGLDO_CON31, 0x2),
+	MT6323_LDO("ldo_vibr", VIBR, ldo_volt_table5,
+		MT6323_DIGLDO_CON39, 15, MT6323_DIGLDO_CON40, 0xE0,
+		MT6323_DIGLDO_CON39, 0x2),
+	MT6323_REG_FIXED("ldo_vrf18", VRF18, MT6323_DIGLDO_CON45, 15, 1825000,
+		MT6323_DIGLDO_CON45, 0x2),
+	MT6323_LDO("ldo_vm", VM, ldo_volt_table9,
+		MT6323_DIGLDO_CON47, 14, MT6323_DIGLDO_CON48, 0x30,
+		MT6323_DIGLDO_CON47, 0x2),
+	MT6323_REG_FIXED("ldo_vio18", VIO18, MT6323_DIGLDO_CON49, 14, 1800000,
+		MT6323_DIGLDO_CON49, 0x2),
+	MT6323_LDO("ldo_vcamd", VCAMD, ldo_volt_table10,
+		MT6323_DIGLDO_CON51, 14, MT6323_DIGLDO_CON52, 0x60,
+		MT6323_DIGLDO_CON51, 0x2),
+	MT6323_REG_FIXED("ldo_vcamio", VCAMIO, MT6323_DIGLDO_CON53, 14, 1800000,
+		MT6323_DIGLDO_CON53, 0x2),
+};
+
+static int mt6323_set_buck_vosel_reg(struct platform_device *pdev)
+{
+	struct mt6397_chip *mt6323 = dev_get_drvdata(pdev->dev.parent);
+	int i;
+	u32 regval;
+
+	for (i = 0; i < MT6323_MAX_REGULATOR; i++) {
+		if (mt6323_regulators[i].vselctrl_reg) {
+			if (regmap_read(mt6323->regmap,
+				mt6323_regulators[i].vselctrl_reg,
+				&regval) < 0) {
+				dev_err(&pdev->dev,
+					"Failed to read buck ctrl\n");
+				return -EIO;
+			}
+
+			if (regval & mt6323_regulators[i].vselctrl_mask) {
+				mt6323_regulators[i].desc.vsel_reg =
+				mt6323_regulators[i].vselon_reg;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int mt6323_regulator_probe(struct platform_device *pdev)
+{
+	struct mt6397_chip *mt6323 = dev_get_drvdata(pdev->dev.parent);
+	struct regulator_config config = {};
+	struct regulator_dev *rdev;
+	int i;
+	u32 reg_value;
+
+	/* Query buck controller to select activated voltage register part */
+	if (mt6323_set_buck_vosel_reg(pdev))
+		return -EIO;
+
+	/* Read PMIC chip revision to update constraints and voltage table */
+	if (regmap_read(mt6323->regmap, MT6323_CID, &reg_value) < 0) {
+		dev_err(&pdev->dev, "Failed to read Chip ID\n");
+		return -EIO;
+	}
+	dev_info(&pdev->dev, "Chip ID = 0x%x\n", reg_value);
+
+	for (i = 0; i < MT6323_MAX_REGULATOR; i++) {
+		config.dev = &pdev->dev;
+		config.driver_data = &mt6323_regulators[i];
+		config.regmap = mt6323->regmap;
+		rdev = devm_regulator_register(&pdev->dev,
+				&mt6323_regulators[i].desc, &config);
+		if (IS_ERR(rdev)) {
+			dev_err(&pdev->dev, "failed to register %s\n",
+				mt6323_regulators[i].desc.name);
+			return PTR_ERR(rdev);
+		}
+	}
+	return 0;
+}
+
+static const struct platform_device_id mt6323_platform_ids[] = {
+	{"mt6323-regulator", 0},
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, mt6323_platform_ids);
+
+static struct platform_driver mt6323_regulator_driver = {
+	.driver = {
+		.name = "mt6323-regulator",
+	},
+	.probe = mt6323_regulator_probe,
+	.id_table = mt6323_platform_ids,
+};
+
+module_platform_driver(mt6323_regulator_driver);
+
+MODULE_AUTHOR("Chen Zhong <chen.zhong at mediatek.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6397 PMIC");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/regulator/mt6323-regulator.h b/include/linux/regulator/mt6323-regulator.h
new file mode 100644
index 000000000000..67011cd1ce55
--- /dev/null
+++ b/include/linux/regulator/mt6323-regulator.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Chen Zhong <chen.zhong at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __LINUX_REGULATOR_MT6323_H
+#define __LINUX_REGULATOR_MT6323_H
+
+enum {
+	MT6323_ID_VPROC = 0,
+	MT6323_ID_VSYS,
+	MT6323_ID_VPA,
+	MT6323_ID_VTCXO,
+	MT6323_ID_VCN28,
+	MT6323_ID_VCN33_BT,
+	MT6323_ID_VCN33_WIFI,
+	MT6323_ID_VA,
+	MT6323_ID_VCAMA,
+	MT6323_ID_VIO28 = 9,
+	MT6323_ID_VUSB,
+	MT6323_ID_VMC,
+	MT6323_ID_VMCH,
+	MT6323_ID_VEMC3V3,
+	MT6323_ID_VGP1,
+	MT6323_ID_VGP2,
+	MT6323_ID_VGP3,
+	MT6323_ID_VCN18,
+	MT6323_ID_VSIM1,
+	MT6323_ID_VSIM2,
+	MT6323_ID_VRTC,
+	MT6323_ID_VCAMAF,
+	MT6323_ID_VIBR,
+	MT6323_ID_VRF18,
+	MT6323_ID_VM,
+	MT6323_ID_VIO18,
+	MT6323_ID_VCAMD,
+	MT6323_ID_VCAMIO,
+	MT6323_ID_RG_MAX,
+};
+
+#define MT6323_MAX_REGULATOR	MT6323_ID_RG_MAX
+
+#endif /* __LINUX_REGULATOR_MT6323_H */
-- 
2.8.1



From ulf.hansson at linaro.org  Mon Jul 18 05:50:10 2016
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Mon, 18 Jul 2016 14:50:10 +0200
Subject: [PATCH 2/3] mmc: mmc: do not use CMD13 to get status after speed
 mode switch
In-Reply-To: <CAOCOHw67NAinC6dEX0KsDn02kuXyNwznm3-bhptSVvQH0V1dqQ@mail.gmail.com>
References: <1463647662-27426-1-git-send-email-chaotian.jing@mediatek.com>
 <1463647662-27426-3-git-send-email-chaotian.jing@mediatek.com>
 <CAOCOHw67NAinC6dEX0KsDn02kuXyNwznm3-bhptSVvQH0V1dqQ@mail.gmail.com>
Message-ID: <CAPDyKFroGBShATJcQ=b2H=k85F+z9=hixpp3Go-j79ZvvLGAwQ@mail.gmail.com>

On 16 July 2016 at 00:10, Bjorn Andersson <bjorn.andersson at linaro.org> wrote:
> On Thu, May 19, 2016 at 1:47 AM, Chaotian Jing
> <chaotian.jing at mediatek.com> wrote:
>> Per JEDEC spec, it is not recommended to use CMD13 to get card status
>> after speed mode switch. below are two reason about this:
>> 1. CMD13 cannot be guaranteed due to the asynchronous operation.
>> Therefore it is not recommended to use CMD13 to check busy completion
>> of the timing change indication.
>> 2. After switch to HS200, CMD13 will get response of 0x800, and even the
>> busy signal gets de-asserted, the response of CMD13 is aslo 0x800.
>>
>> Signed-off-by: Chaotian Jing <chaotian.jing at mediatek.com>
>> ---
>>  drivers/mmc/core/mmc.c | 112 ++++++++++++++++++++-----------------------------
>>  1 file changed, 45 insertions(+), 67 deletions(-)
>>
>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> [..]
>> @@ -1274,20 +1254,18 @@ static int mmc_select_hs200(struct mmc_card *card)
>>                 err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>>                                    EXT_CSD_HS_TIMING, val,
>>                                    card->ext_csd.generic_cmd6_time,
>> -                                  true, send_status, true);
>> +                                  true, false, true);
>>                 if (err)
>>                         goto err;
>>                 old_timing = host->ios.timing;
>>                 mmc_set_timing(host, MMC_TIMING_MMC_HS200);
>> -               if (!send_status) {
>> -                       err = mmc_switch_status(card);
>> -                       /*
>> -                        * mmc_select_timing() assumes timing has not changed if
>> -                        * it is a switch error.
>> -                        */
>> -                       if (err == -EBADMSG)
>> -                               mmc_set_timing(host, old_timing);
>> -               }
>> +               err = mmc_switch_status(card);
>> +               /*
>> +                * mmc_select_timing() assumes timing has not changed if
>> +                * it is a switch error.
>> +                */
>> +               if (err == -EBADMSG)
>> +                       mmc_set_timing(host, old_timing);
>
> Sorry for not spotting this earlier, but with the move of the call of
> mmc_switch_status() to after mmc_set_timing() we get following error
> with sdhci-msm:

Thanks for reporting!

>
> mmc0: mmc_select_hs200 failed, error -110
> mmc0: error -110 whilst initialising MMC card
> mmc0: Reset 0x1 never completed.
> sdhci: =========== REGISTER DUMP (mmc0)===========
> sdhci: Sys addr: 0x00000000 | Version: 0x00002e02
> sdhci: Blk size: 0x00004000 | Blk cnt: 0x00000000
> sdhci: Argument: 0x00000000 | Trn mode: 0x00000000
> sdhci: Present: 0x01f80000 | Host ctl: 0x00000000
> sdhci: Power: 0x00000000 | Blk gap: 0x00000000
> sdhci: Wake-up: 0x00000000 | Clock: 0x00000003
> sdhci: Timeout: 0x00000000 | Int stat: 0x00000000
> sdhci: Int enab: 0x00000000 | Sig enab: 0x00000000
> sdhci: AC12 err: 0x00000000 | Slot int: 0x00000000
> sdhci: Caps: 0x322dc8b2 | Caps_1: 0x00008007
> sdhci: Cmd: 0x00000000 | Max curr: 0x00000000
> sdhci: Host ctl2: 0x00000000
> sdhci: ADMA Err: 0x00000000 | ADMA Ptr: 0x0000000000000000
> sdhci: ===========================================
>
> But I if I understand the commit correctly this is the intention of
> the patch (not the error, but the move).

I tried dropping this change from my next branch, but there are some
more changes on top that prevents a "clean" drop. It's certainly
doable, but perhaps we can try to narrow down the problem to see if
this could/should be fixed in the sdhci msm driver instead!?

I also noticed that below submitted change, which *isn't* applied for
next, might be related.
https://patchwork.kernel.org/patch/9197881/

>
> Regards,
> Bjorn
>
>>         }
>>  err:
>>         if (err)
>> --
>> 1.8.1.1.dirty
>>

Kind regards
Uffe


From georgi.djakov at linaro.org  Mon Jul 18 06:38:32 2016
From: georgi.djakov at linaro.org (Georgi Djakov)
Date: Mon, 18 Jul 2016 16:38:32 +0300
Subject: [PATCH 2/3] mmc: mmc: do not use CMD13 to get status after speed
 mode switch
In-Reply-To: <CAPDyKFroGBShATJcQ=b2H=k85F+z9=hixpp3Go-j79ZvvLGAwQ@mail.gmail.com>
References: <1463647662-27426-1-git-send-email-chaotian.jing@mediatek.com>
 <1463647662-27426-3-git-send-email-chaotian.jing@mediatek.com>
 <CAOCOHw67NAinC6dEX0KsDn02kuXyNwznm3-bhptSVvQH0V1dqQ@mail.gmail.com>
 <CAPDyKFroGBShATJcQ=b2H=k85F+z9=hixpp3Go-j79ZvvLGAwQ@mail.gmail.com>
Message-ID: <578CDBD8.2050806@linaro.org>

On 07/18/2016 03:50 PM, Ulf Hansson wrote:
> On 16 July 2016 at 00:10, Bjorn Andersson <bjorn.andersson at linaro.org> wrote:
>> On Thu, May 19, 2016 at 1:47 AM, Chaotian Jing
>> <chaotian.jing at mediatek.com> wrote:
>>> Per JEDEC spec, it is not recommended to use CMD13 to get card status
>>> after speed mode switch. below are two reason about this:
>>> 1. CMD13 cannot be guaranteed due to the asynchronous operation.
>>> Therefore it is not recommended to use CMD13 to check busy completion
>>> of the timing change indication.
>>> 2. After switch to HS200, CMD13 will get response of 0x800, and even the
>>> busy signal gets de-asserted, the response of CMD13 is aslo 0x800.
>>>
>>> Signed-off-by: Chaotian Jing <chaotian.jing at mediatek.com>
>>> ---
>>>  drivers/mmc/core/mmc.c | 112 ++++++++++++++++++++-----------------------------
>>>  1 file changed, 45 insertions(+), 67 deletions(-)
>>>
>>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> [..]
>>> @@ -1274,20 +1254,18 @@ static int mmc_select_hs200(struct mmc_card *card)
>>>                 err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>>>                                    EXT_CSD_HS_TIMING, val,
>>>                                    card->ext_csd.generic_cmd6_time,
>>> -                                  true, send_status, true);
>>> +                                  true, false, true);
>>>                 if (err)
>>>                         goto err;
>>>                 old_timing = host->ios.timing;
>>>                 mmc_set_timing(host, MMC_TIMING_MMC_HS200);
>>> -               if (!send_status) {
>>> -                       err = mmc_switch_status(card);
>>> -                       /*
>>> -                        * mmc_select_timing() assumes timing has not changed if
>>> -                        * it is a switch error.
>>> -                        */
>>> -                       if (err == -EBADMSG)
>>> -                               mmc_set_timing(host, old_timing);
>>> -               }
>>> +               err = mmc_switch_status(card);
>>> +               /*
>>> +                * mmc_select_timing() assumes timing has not changed if
>>> +                * it is a switch error.
>>> +                */
>>> +               if (err == -EBADMSG)
>>> +                       mmc_set_timing(host, old_timing);
>>
>> Sorry for not spotting this earlier, but with the move of the call of
>> mmc_switch_status() to after mmc_set_timing() we get following error
>> with sdhci-msm:
> 
> Thanks for reporting!
> 
>>
>> mmc0: mmc_select_hs200 failed, error -110
>> mmc0: error -110 whilst initialising MMC card
>> mmc0: Reset 0x1 never completed.
>> sdhci: =========== REGISTER DUMP (mmc0)===========
>> sdhci: Sys addr: 0x00000000 | Version: 0x00002e02
>> sdhci: Blk size: 0x00004000 | Blk cnt: 0x00000000
>> sdhci: Argument: 0x00000000 | Trn mode: 0x00000000
>> sdhci: Present: 0x01f80000 | Host ctl: 0x00000000
>> sdhci: Power: 0x00000000 | Blk gap: 0x00000000
>> sdhci: Wake-up: 0x00000000 | Clock: 0x00000003
>> sdhci: Timeout: 0x00000000 | Int stat: 0x00000000
>> sdhci: Int enab: 0x00000000 | Sig enab: 0x00000000
>> sdhci: AC12 err: 0x00000000 | Slot int: 0x00000000
>> sdhci: Caps: 0x322dc8b2 | Caps_1: 0x00008007
>> sdhci: Cmd: 0x00000000 | Max curr: 0x00000000
>> sdhci: Host ctl2: 0x00000000
>> sdhci: ADMA Err: 0x00000000 | ADMA Ptr: 0x0000000000000000
>> sdhci: ===========================================
>>
>> But I if I understand the commit correctly this is the intention of
>> the patch (not the error, but the move).
> 
> I tried dropping this change from my next branch, but there are some
> more changes on top that prevents a "clean" drop. It's certainly
> doable, but perhaps we can try to narrow down the problem to see if
> this could/should be fixed in the sdhci msm driver instead!?

Yes, i am working on it. Seems that if we just ignore the -ETIMEDOUT
returned by mmc_switch_status() everything works as before. Currently
i am expecting more information about this controller specifics, in
order to understand if this could be fixed with a change in the driver
only.

> 
> I also noticed that below submitted change, which *isn't* applied for
> next, might be related.
> https://patchwork.kernel.org/patch/9197881/
> 

It is not related to this issue, but it is good to have when this is
resolved, otherwise we will see the dumpregs output (pr_err now),
when controller is initialized without a card in the SD slot.

Thanks,
Georgi


From computersforpeace at gmail.com  Mon Jul 18 10:32:41 2016
From: computersforpeace at gmail.com (Brian Norris)
Date: Mon, 18 Jul 2016 10:32:41 -0700
Subject: [PATCH -next] mtd: mtk-nor: remove duplicated include from
 mtk-quadspi.c
In-Reply-To: <1466184076-11714-1-git-send-email-weiyj_lk@163.com>
References: <1466184076-11714-1-git-send-email-weiyj_lk@163.com>
Message-ID: <20160718173241.GK76613@google.com>

On Fri, Jun 17, 2016 at 05:21:16PM +0000, weiyj_lk at 163.com wrote:
> From: Wei Yongjun <yongjun_wei at trendmicro.com.cn>
> 
> Remove duplicated include.
> 
> Signed-off-by: Wei Yongjun <yongjun_wei at trendmicro.com.cn>

Applied to l2-mtd.git


From jic23 at kernel.org  Mon Jul 18 10:12:13 2016
From: jic23 at kernel.org (Jonathan Cameron)
Date: Mon, 18 Jul 2016 18:12:13 +0100
Subject: [PATCH v4 2/3] iio: adc: mt2701: Add Mediatek auxadc driver for
 mt2701.
In-Reply-To: <1468219197-9572-3-git-send-email-zhiyong.tao@mediatek.com>
References: <1468219197-9572-1-git-send-email-zhiyong.tao@mediatek.com>
 <1468219197-9572-3-git-send-email-zhiyong.tao@mediatek.com>
Message-ID: <82fa5ffa-52be-e1ec-83dd-dd92b3f3ef5d@kernel.org>

On 11/07/16 07:39, Zhiyong Tao wrote:
> Add Mediatek auxadc driver based on iio.
> It will register a device in iio and support iio.
> So thermal can read auxadc channel to sample data by iio device.
> It is tested successfully on mt2701 platform.
> Mt8173 and mt6577 platforms are not tested.
> But the expectation is compatible.
> 
> Signed-off-by: Zhiyong Tao <zhiyong.tao at mediatek.com>
Looks good to me.  Couple of really minor points / questions inline...

Just one thing to confirm... (you probably already answered this!)
What are the units of the voltage channels?

Jonathan
> ---
>  drivers/iio/adc/Kconfig         |   13 ++
>  drivers/iio/adc/Makefile        |    1 +
>  drivers/iio/adc/mt6577_auxadc.c |  294 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 308 insertions(+)
>  create mode 100644 drivers/iio/adc/mt6577_auxadc.c
> 
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 25378c5..14929fc 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -305,6 +305,19 @@ config MCP3422
>  	  This driver can also be built as a module. If so, the module will be
>  	  called mcp3422.
>  
> +config MEDIATEK_MT6577_AUXADC
> +        tristate "MediaTek AUXADC driver"
> +        depends on ARCH_MEDIATEK || COMPILE_TEST
> +        depends on HAS_IOMEM
> +        help
> +          Say yes here to enable support for MediaTek mt65xx AUXADC.
> +
> +          The driver supports immediate mode operation to read from one of sixteen
> +          channels (external or internal).
> +
> +          This driver can also be built as a module. If so, the module will be
> +          called mt6577_auxadc.
> +
>  config MEN_Z188_ADC
>  	tristate "MEN 16z188 ADC IP Core support"
>  	depends on MCB
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index 38638d4..8306347 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -30,6 +30,7 @@ obj-$(CONFIG_MAX1027) += max1027.o
>  obj-$(CONFIG_MAX1363) += max1363.o
>  obj-$(CONFIG_MCP320X) += mcp320x.o
>  obj-$(CONFIG_MCP3422) += mcp3422.o
> +obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
>  obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
>  obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
>  obj-$(CONFIG_NAU7802) += nau7802.o
> diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c
> new file mode 100644
> index 0000000..c7cc901
> --- /dev/null
> +++ b/drivers/iio/adc/mt6577_auxadc.c
> @@ -0,0 +1,294 @@
> +/*
> + * Copyright (c) 2016 MediaTek Inc.
> + * Author: Zhiyong Tao <zhiyong.tao at mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/iopoll.h>
> +#include <linux/io.h>
> +#include <linux/iio/iio.h>
> +
> +/* Register definitions */
> +#define MT6577_AUXADC_CON0                    0x00
> +#define MT6577_AUXADC_CON1                    0x04
> +#define MT6577_AUXADC_CON2                    0x10
> +#define MT6577_AUXADC_STA                     BIT(0)
> +
> +#define MT6577_AUXADC_DAT0                    0x14
> +#define MT6577_AUXADC_RDY0                    BIT(12)
> +
> +#define MT6577_AUXADC_MISC                    0x94
> +#define MT6577_AUXADC_PDN_EN                  BIT(14)
> +
> +#define MT6577_AUXADC_DAT_MASK                0xfff
> +#define MT6577_AUXADC_SLEEP_US                1000
> +#define MT6577_AUXADC_TIMEOUT_US              10000
> +#define MT6577_AUXADC_POWER_READY_MS          1
> +#define MT6577_AUXADC_SAMPLE_READY_US         25
> +
> +struct mt6577_auxadc_device {
> +	void __iomem *reg_base;
> +	struct clk *adc_clk;
> +	struct mutex lock;
> +};
> +
> +#define MT6577_AUXADC_CHANNEL(idx) {				    \
> +		.type = IIO_VOLTAGE,				    \
> +		.indexed = 1,					    \
> +		.channel = (idx),				    \
> +		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
> +}
> +
> +static const struct iio_chan_spec mt6577_auxadc_iio_channels[] = {
> +	MT6577_AUXADC_CHANNEL(0),
> +	MT6577_AUXADC_CHANNEL(1),
> +	MT6577_AUXADC_CHANNEL(2),
> +	MT6577_AUXADC_CHANNEL(3),
> +	MT6577_AUXADC_CHANNEL(4),
> +	MT6577_AUXADC_CHANNEL(5),
> +	MT6577_AUXADC_CHANNEL(6),
> +	MT6577_AUXADC_CHANNEL(7),
> +	MT6577_AUXADC_CHANNEL(8),
> +	MT6577_AUXADC_CHANNEL(9),
> +	MT6577_AUXADC_CHANNEL(10),
> +	MT6577_AUXADC_CHANNEL(11),
> +	MT6577_AUXADC_CHANNEL(12),
> +	MT6577_AUXADC_CHANNEL(13),
> +	MT6577_AUXADC_CHANNEL(14),
> +	MT6577_AUXADC_CHANNEL(15),
> +};
> +
> +static int mt6577_auxadc_read(struct iio_dev *indio_dev,
> +			      struct iio_chan_spec const *chan)
> +{
> +	u32 rawdata, val;
> +	void __iomem *reg_channel;
> +	int ret;
> +	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
> +
> +	reg_channel = adc_dev->reg_base + MT6577_AUXADC_DAT0 +
> +		      chan->channel * 0x04;
> +
> +	mutex_lock(&adc_dev->lock);
> +
> +	val = readl(adc_dev->reg_base + MT6577_AUXADC_CON1);
> +	val &= ~(1 << chan->channel);
> +	writel(val, adc_dev->reg_base + MT6577_AUXADC_CON1);
> +
> +	/* read channel and make sure old ready bit == 0 */
> +	ret = readl_poll_timeout(reg_channel, val,
> +				 ((val & MT6577_AUXADC_RDY0) == 0),
> +				 MT6577_AUXADC_SLEEP_US,
> +				 MT6577_AUXADC_TIMEOUT_US);
> +	if (ret < 0) {
> +		dev_err(indio_dev->dev.parent,
> +			"wait for channel[%d] ready bit clear time out\n",
> +			chan->channel);
> +
> +		mutex_unlock(&adc_dev->lock);
> +
> +		return -ETIMEDOUT;
> +	}
> +
> +	/* set bit to trigger sample */
> +	val = readl(adc_dev->reg_base + MT6577_AUXADC_CON1);
> +	val |= 1 << chan->channel;
> +	writel(val, adc_dev->reg_base + MT6577_AUXADC_CON1);
> +
> +	/* we must delay here for hardware sample channel data */
> +	udelay(MT6577_AUXADC_SAMPLE_READY_US);
> +
> +	/* check MTK_AUXADC_CON2 if auxadc is idle */
> +	ret = readl_poll_timeout(adc_dev->reg_base + MT6577_AUXADC_CON2, val,
> +				 ((val & MT6577_AUXADC_STA) == 0),
> +				 MT6577_AUXADC_SLEEP_US,
> +				 MT6577_AUXADC_TIMEOUT_US);
> +	if (ret < 0) {
> +		dev_err(indio_dev->dev.parent,
> +			"wait for auxadc idle time out\n");
> +
> +		mutex_unlock(&adc_dev->lock);
> +
> +		return -ETIMEDOUT;
> +	}
> +
> +	/* read channel and make sure ready bit == 1 */
> +	ret = readl_poll_timeout(reg_channel, val,
> +				 ((val & MT6577_AUXADC_RDY0) != 0),
> +				 MT6577_AUXADC_SLEEP_US,
> +				 MT6577_AUXADC_TIMEOUT_US);
> +	if (ret < 0) {
> +		dev_err(indio_dev->dev.parent,
> +			"wait for channel[%d] data ready time out\n",
> +			chan->channel);
> +
> +		mutex_unlock(&adc_dev->lock);
> +
> +		return -ETIMEDOUT;
> +	}
> +
> +	/* read data */
> +	rawdata = readl(reg_channel) & MT6577_AUXADC_DAT_MASK;
> +
> +	mutex_unlock(&adc_dev->lock);
> +
> +	return rawdata;
> +}
> +
> +static int mt6577_auxadc_read_raw(struct iio_dev *indio_dev,
> +				  struct iio_chan_spec const *chan,
> +				  int *val,
> +				  int *val2,
> +				  long info)
> +{
> +	switch (info) {
> +	case IIO_CHAN_INFO_PROCESSED:
> +		*val = mt6577_auxadc_read(indio_dev, chan);
> +		if (*val < 0) {
> +			dev_err(indio_dev->dev.parent,
> +				"failed to sample data on channel[%d]\n",
> +				chan->channel);
> +			return *val;
> +		}
> +		return IIO_VAL_INT;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static const struct iio_info mt6577_auxadc_info = {
> +	.driver_module = THIS_MODULE,
> +	.read_raw = &mt6577_auxadc_read_raw,
> +};
> +
> +static int mt6577_auxadc_probe(struct platform_device *pdev)
> +{
> +	struct mt6577_auxadc_device *adc_dev;
> +	unsigned long adc_clk_rate;
> +	struct resource *res;
> +	struct iio_dev *indio_dev;
> +	int ret;
> +	u32 val;
> +
> +	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
> +	if (!indio_dev)
> +		return -ENOMEM;
> +
> +	adc_dev = iio_priv(indio_dev);
> +	indio_dev->dev.parent = &pdev->dev;
> +	indio_dev->name = dev_name(&pdev->dev);
> +	indio_dev->info = &mt6577_auxadc_info;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->channels = mt6577_auxadc_iio_channels;
> +	indio_dev->num_channels = ARRAY_SIZE(mt6577_auxadc_iio_channels);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	adc_dev->reg_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(adc_dev->reg_base)) {
> +		dev_err(&pdev->dev, "failed to get auxadc base address.\n");
> +		return PTR_ERR(adc_dev->reg_base);
> +	}
> +
> +	adc_dev->adc_clk = devm_clk_get(&pdev->dev, "main");
> +	if (IS_ERR(adc_dev->adc_clk)) {
> +		dev_err(&pdev->dev, "failed to get auxadc clock\n");
> +		return PTR_ERR(adc_dev->adc_clk);
> +	}
> +
> +	ret = clk_prepare_enable(adc_dev->adc_clk);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to enable auxadc clock\n");
> +		return ret;
> +	}
> +
> +	adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
> +	if (!adc_clk_rate) {
> +		dev_err(&pdev->dev, "null clock rate!\n");
> +		goto err_disable_clk;
> +	}
> +
> +	mutex_init(&adc_dev->lock);
> +
> +	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
> +	val |= MT6577_AUXADC_PDN_EN;
> +	writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
> +	mdelay(MT6577_AUXADC_POWER_READY_MS);
> +
> +	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
> +	if ((val & MT6577_AUXADC_PDN_EN) == 0) {
That's a high level of paranoia... Any reason to believe this might fail?
> +		dev_err(&pdev->dev, "failed to enable auxadc power!\n");
> +		goto err_disable_clk;
> +	}
> +
> +	platform_set_drvdata(pdev, indio_dev);
> +
> +	ret = iio_device_register(indio_dev);
> +	if (ret < 0) {
I'd have slightly preferred that this error unwind block was also
moved to on a goto.  Makes it easier to review as the error block then
matches remove (with expected differences!)  Really small point however.

> +		dev_err(&pdev->dev, "failed to register iio device!\n");
> +		val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
> +		val &= ~MT6577_AUXADC_PDN_EN;
> +		writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
> +		goto err_disable_clk;
> +	}
> +
> +	return 0;
> +
> +err_disable_clk:
> +	clk_disable_unprepare(adc_dev->adc_clk);
> +	return -EINVAL;
> +}
> +
> +static int mt6577_auxadc_remove(struct platform_device *pdev)
> +{
> +	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
> +	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
> +	u32 val;
> +
> +	iio_device_unregister(indio_dev);
> +
> +	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
> +	val &= ~MT6577_AUXADC_PDN_EN;
> +	writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
> +
> +	clk_disable_unprepare(adc_dev->adc_clk);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mt6577_auxadc_of_match[] = {
> +	{ .compatible = "mediatek,mt2701-auxadc", },
> +	{ .compatible = "mediatek,mt8173-auxadc", },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, mt6577_auxadc_of_match);
> +
> +static struct platform_driver mt6577_auxadc_driver = {
> +	.driver = {
> +		.name   = "mt6577-auxadc",
> +		.of_match_table = mt6577_auxadc_of_match,
> +	},
> +	.probe	= mt6577_auxadc_probe,
> +	.remove	= mt6577_auxadc_remove,
> +};
> +module_platform_driver(mt6577_auxadc_driver);
> +
> +MODULE_AUTHOR("Zhiyong Tao <zhiyong.tao at mediatek.com>");
> +MODULE_DESCRIPTION("MTK AUXADC Device Driver");
> +MODULE_LICENSE("GPL v2");
> 



From ck.hu at mediatek.com  Mon Jul 18 22:39:27 2016
From: ck.hu at mediatek.com (CK Hu)
Date: Tue, 19 Jul 2016 13:39:27 +0800
Subject: [PATCH v4 5/8] drm/mediatek: add dsi interrupt control
In-Reply-To: <1468577274-6178-6-git-send-email-yt.shen@mediatek.com>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
 <1468577274-6178-6-git-send-email-yt.shen@mediatek.com>
Message-ID: <1468906767.30644.66.camel@mtksdaap41>

Hi, YT:

Some comments inline.

On Fri, 2016-07-15 at 18:07 +0800, YT Shen wrote:
> From: shaoming chen <shaoming.chen at mediatek.com>
> 
> add dsi interrupt control
> 
> Signed-off-by: shaoming chen <shaoming.chen at mediatek.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_dsi.c |  130 ++++++++++++++++++++++++++++++++++++
>  1 file changed, 130 insertions(+)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
> index 2d808e5..de5ad7f 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dsi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
> @@ -18,6 +18,7 @@
>  #include <drm/drm_panel.h>
>  #include <linux/clk.h>
>  #include <linux/component.h>
> +#include <linux/irq.h>
>  #include <linux/of.h>
>  #include <linux/of_platform.h>
>  #include <linux/of_graph.h>
> @@ -32,6 +33,13 @@
>  
>  #define DSI_START		0x00
>  
> +#define DSI_INTEN		0x08
> +
> +#define DSI_INTSTA		0x0c
> +#define LPRX_RD_RDY_INT_FLAG	BIT(0)
> +#define CMD_DONE_INT_FLAG	BIT(1)
> +#define DSI_BUSY		BIT(31)

Why need LPRX_RD_RDY_INT_FLAG, CMD_DONE_INT_FLAG, and DSI_BUSY? Maybe
these three should be moved to other patch.

> +
>  #define DSI_CON_CTRL		0x10
>  #define DSI_RESET			BIT(0)
>  #define DSI_EN				BIT(1)
> @@ -74,6 +82,9 @@
>  
>  #define DSI_HSTX_CKL_WC		0x64
>  
> +#define DSI_RACK		0x84
> +#define RACK			BIT(0)
> +
>  #define DSI_PHY_LCCON		0x104
>  #define LC_HS_TX_EN			BIT(0)
>  #define LC_ULPM_EN			BIT(1)
> @@ -134,6 +145,18 @@ struct mtk_dsi {
>  	struct videomode vm;
>  	int refcount;
>  	bool enabled;
> +	int irq_num, irq_data;
> +};
> +
> +enum {
> +	DSI_INT_SLEEPOUT_DONE_FLAG	= BIT(6),
> +	DSI_INT_VM_CMD_DONE_FLAG	= BIT(5),
> +	DSI_INT_EXT_TE_RDY_FLAG		= BIT(4),
> +	DSI_INT_VM_DONE_FLAG		= BIT(3),
> +	DSI_INT_TE_RDY_FLAG		= BIT(2),
> +	DSI_INT_CMD_DONE_FLAG		= BIT(1),
> +	DSI_INT_LPRX_RD_RDY_FLAG	= BIT(0),
> +	DSI_INT_ALL_BITS		= (0x7f)
>  };

I think you should use '#define' instead of 'enum'. The code would be
like below, and these definition should be moved to after DSI_INTEN or
DSI_INTSTA.

#define DSI_INT_LPRX_RD_RDY_FLAG	BIT(0)
#define DSI_INT_CMD_DONE_FLAG		BIT(1)
#define DSI_INT_TE_RDY_FLAG		BIT(2)
#define DSI_INT_VM_DONE_FLAG		BIT(3)
#define DSI_INT_EXT_TE_RDY_FLAG		BIT(4)
#define DSI_INT_VM_CMD_DONE_FLAG	BIT(5)
#define DSI_INT_SLEEPOUT_DONE_FLAG	BIT(6)
#define DSI_INT_ALL_BITS		(DSI_INT_LPRX_RD_RDY_FLAG | \
					DSI_INT_CMD_DONE_FLAG | \
					DSI_INT_TE_RDY_FLAG | \
					DSI_INT_VM_DONE_FLAG | \
					DSI_INT_EXT_TE_RDY_FLAG | \
					DSI_INT_VM_CMD_DONE_FLAG | \
					DSI_INT_SLEEPOUT_DONE_FLAG)

>  
>  static inline struct mtk_dsi *encoder_to_dsi(struct drm_encoder *e)
> @@ -440,6 +463,94 @@ static void mtk_dsi_start(struct mtk_dsi *dsi)
>  	writel(1, dsi->regs + DSI_START);
>  }
>  
> +static void mtk_dsi_set_interrupt_enable(struct mtk_dsi *dsi)
> +{
> +	u32 inten = DSI_INT_ALL_BITS;
> +
> +	if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO)
> +		inten &= ~(DSI_INT_TE_RDY_FLAG | DSI_INT_EXT_TE_RDY_FLAG);
> +
> +	writel(inten, dsi->regs + DSI_INTEN);
> +}
> +
> +static void mtk_dsi_irq_wakeup(struct mtk_dsi *dsi, u32 irq_bit)
> +{
> +	dsi->irq_data |= irq_bit;
> +}
> +
> +static irqreturn_t mtk_dsi_irq(int irq, void *dev_id)
> +{
> +	struct mtk_dsi *dsi = dev_id;
> +
> +	u32 status, tmp;
> +
> +	status = readl(dsi->regs + DSI_INTSTA);
> +
> +	if (status & DSI_INT_LPRX_RD_RDY_FLAG) {
> +		/* write clear RD_RDY interrupt */
> +		/* write clear RD_RDY interrupt must be before DSI_RACK */
> +		/* because CMD_DONE will raise after DSI_RACK, */
> +		/* so write clear RD_RDY after that will clear CMD_DONE too */
> +		do {
> +			/* send read ACK */
> +			mtk_dsi_mask(dsi, DSI_RACK, RACK, RACK);
> +			tmp = readl(dsi->regs + DSI_INTSTA);
> +		} while (tmp & DSI_BUSY);
> +
> +		mtk_dsi_mask(dsi, DSI_INTSTA, DSI_INT_LPRX_RD_RDY_FLAG, 0);
> +		mtk_dsi_irq_wakeup(dsi, DSI_INT_LPRX_RD_RDY_FLAG);
> +	}
> +
> +	if (status & DSI_INT_CMD_DONE_FLAG) {
> +		mtk_dsi_mask(dsi, DSI_INTSTA, DSI_INT_CMD_DONE_FLAG, 0);
> +		mtk_dsi_irq_wakeup(dsi, DSI_INT_CMD_DONE_FLAG);
> +	}
> +
> +	if (status & DSI_INT_TE_RDY_FLAG) {
> +		mtk_dsi_mask(dsi, DSI_INTSTA, DSI_INT_TE_RDY_FLAG, 0);
> +		mtk_dsi_irq_wakeup(dsi, DSI_INT_TE_RDY_FLAG);
> +	}
> +
> +	if (status & DSI_INT_VM_DONE_FLAG) {
> +		mtk_dsi_mask(dsi, DSI_INTSTA, DSI_INT_VM_DONE_FLAG, 0);
> +		mtk_dsi_irq_wakeup(dsi, DSI_INT_VM_DONE_FLAG);
> +	}
> +
> +	if (status & DSI_INT_EXT_TE_RDY_FLAG) {
> +		mtk_dsi_mask(dsi, DSI_INTSTA, DSI_INT_EXT_TE_RDY_FLAG, 0);
> +		mtk_dsi_irq_wakeup(dsi, DSI_INT_EXT_TE_RDY_FLAG);
> +	}
> +
> +	if (status & DSI_INT_VM_CMD_DONE_FLAG) {
> +		mtk_dsi_mask(dsi, DSI_INTSTA, DSI_INT_VM_CMD_DONE_FLAG, 0);
> +		mtk_dsi_irq_wakeup(dsi, DSI_INT_VM_CMD_DONE_FLAG);
> +	}
> +
> +	if (status & DSI_INT_SLEEPOUT_DONE_FLAG) {
> +		mtk_dsi_mask(dsi, DSI_INTSTA, DSI_INT_SLEEPOUT_DONE_FLAG, 0);
> +		mtk_dsi_irq_wakeup(dsi, DSI_INT_SLEEPOUT_DONE_FLAG);
> +	}

All these 'if' statement do the same thing and I think these could be
merge as:

status = readl(dsi->regs + DSI_INTSTA) & DSI_INT_ALL_BITS);
if (status) {
	mtk_dsi_mask(dsi, DSI_INTSTA, status, 0);
	mtk_dsi_irq_wakeup(dsi, status);
}

> +
> +	return IRQ_HANDLED;
> +}
> +
> +static s32 mtk_dsi_wait_for_irq_timeout(struct mtk_dsi *dsi, u32 irq_bit,
> +					u32 timeout_ms)
> +{
> +	while (timeout_ms--) {
> +		if (dsi->irq_data & irq_bit) {
> +			dsi->irq_data &= ~irq_bit;
> +			return 0;
> +		}
> +
> +		usleep_range(1000, 1100);
> +	}

I think it's better to use wait_event() or something else. Polling with
sleep could not react immediately.

> +
> +	dsi->irq_data = 0;

Why clear all bit after wait one bit timeout?

> +
> +	return -1;
> +}
> +
>  static void mtk_dsi_poweroff(struct mtk_dsi *dsi)
>  {
>  	if (WARN_ON(dsi->refcount == 0))
> @@ -488,6 +599,7 @@ static void mtk_output_dsi_enable(struct mtk_dsi *dsi)
>  
>  	dsi_ps_control_vact(dsi);
>  	dsi_config_vdo_timing(dsi);
> +	mtk_dsi_set_interrupt_enable(dsi);
>  
>  	dsi_set_mode(dsi);
>  	dsi_clk_hs_mode(dsi, 1);
> @@ -883,6 +995,24 @@ static int mtk_dsi_probe(struct platform_device *pdev)
>  		return ret;
>  	}
>  
> +	dsi->irq_num = platform_get_irq(pdev, 0);

You use irq_num only in this function, why keep it in dsi structure?

> +	if (dsi->irq_num < 0) {
> +		dev_err(&pdev->dev, "failed to request dsi irq resource\n");
> +		ret = dsi->irq_num;
> +		return -EPROBE_DEFER;
> +	}
> +
> +	irq_set_status_flags(dsi->irq_num, IRQ_TYPE_LEVEL_LOW);
> +	ret = devm_request_irq(&pdev->dev, dsi->irq_num, mtk_dsi_irq,
> +			       IRQF_TRIGGER_LOW, dev_name(&pdev->dev), dsi);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to request mediatek dsi irq\n");
> +		return -EPROBE_DEFER;
> +	}
> +
> +	dsi->irq_data = 0;
> +	dev_info(dev, "dsi irq num is 0x%x\n", dsi->irq_num);
> +
>  	platform_set_drvdata(pdev, dsi);
>  
>  	return component_add(&pdev->dev, &mtk_dsi_component_ops);

Regards,
CK



From jamesjj.liao at mediatek.com  Tue Jul 19 00:04:39 2016
From: jamesjj.liao at mediatek.com (James Liao)
Date: Tue, 19 Jul 2016 15:04:39 +0800
Subject: [PATCH v8 0/4] Mediatek MT2701 SCPSYS power domain support 
Message-ID: <1468911883-41882-1-git-send-email-jamesjj.liao@mediatek.com>

This series is based on v4.7-rc1 and adds scpsys power domain support
for Mediatek MT2701.

To share the code between MT2701 and MT8173, this patchset also refined
original mtk-scpsys.c to separate common codes and platform codes, so
that mtk-scpsys.c can support new SoCs more easily.

MT8173 and MT2701 scpsys init level are now subsys_init. Please refer to [1]
to see discussion details.

changes since v7:
- Add clk_id for each scp_domain_data define.
- Minor coding style changes.

changes since v6:
- Minor changes in the dt-binding document.

changes since v5:
- Rebase to v4.6-rc1.
- Add dependent clocks for MFG, ISP, ETH and HIF power domains.
- Add "ethif" as a dependent clock in scpsys dt-binding document.

changes since v4:
- Rebase to v4.5-rc4.
- Remove mtk-scpsys.h and Merge its code into mtk-scpsys.c.
- Add names for every controlling registers and bits.
- Include dt-bindings headers at the beginning of mtk-scpsys.c.
- Sort compatible string in dt-binding documents.

changes since v3:
- Implement MT8173 and MT2701 scpsys drivers in a signle file.
- Remove naming of registers that can't be shared among SoCs.

changes since v2:
- Rebase to mbgg/linux-mediatek v4.4-next/soc [1].
- Remove MTK_SCPSYS_MT8173 and MTK_SCPSYS_MT2701.
- Modify scpsys dt-binding document to support MT2701.

changes since v1:
- Make MTK_SCPSYS in Kconfig invisible from users.
- Add comments for changing scpsys init level to subsys_init.

[1] http://lists.infradead.org/pipermail/linux-mediatek/2015-December/003416.html

James Liao (2):
  soc: mediatek: Refine scpsys to support multiple platform
  soc: mediatek: Init MT8173 scpsys driver earlier

Shunli Wang (2):
  soc: mediatek: Add MT2701 power dt-bindings
  soc: mediatek: Add MT2701 scpsys driver

 .../devicetree/bindings/soc/mediatek/scpsys.txt    |  13 +-
 drivers/soc/mediatek/Kconfig                       |   2 +-
 drivers/soc/mediatek/mtk-scpsys.c                  | 500 +++++++++++++++------
 include/dt-bindings/power/mt2701-power.h           |  27 ++
 4 files changed, 391 insertions(+), 151 deletions(-)
 create mode 100644 include/dt-bindings/power/mt2701-power.h

--
1.9.1



From jamesjj.liao at mediatek.com  Tue Jul 19 00:04:41 2016
From: jamesjj.liao at mediatek.com (James Liao)
Date: Tue, 19 Jul 2016 15:04:41 +0800
Subject: [PATCH v8 2/4] soc: mediatek: Init MT8173 scpsys driver earlier
In-Reply-To: <1468911883-41882-1-git-send-email-jamesjj.liao@mediatek.com>
References: <1468911883-41882-1-git-send-email-jamesjj.liao@mediatek.com>
Message-ID: <1468911883-41882-3-git-send-email-jamesjj.liao@mediatek.com>

Some power domain comsumers may init before module_init.
So the power domain provider (scpsys) need to be initialized
earlier too.

Take an example for our IOMMU (M4U) and SMI. SMI is a bridge
between IOMMU and multimedia HW. SMI is responsible to
enable/disable iommu and help transfer data for each multimedia
HW. Both of them have to wait until the power and clocks are
enabled.

So scpsys driver should be initialized before SMI, and SMI should
be initialized before IOMMU, and then init IOMMU consumers
(display/vdec/venc/camera etc.).

IOMMU is subsys_init by default. So we need to init scpsys driver
before subsys_init.

Signed-off-by: James Liao <jamesjj.liao at mediatek.com>
Reviewed-by: Kevin Hilman <khilman at baylibre.com>
---
 drivers/soc/mediatek/mtk-scpsys.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
index 1f3555a..e806cb7 100644
--- a/drivers/soc/mediatek/mtk-scpsys.c
+++ b/drivers/soc/mediatek/mtk-scpsys.c
@@ -618,4 +618,21 @@ static struct platform_driver scpsys_drv = {
 		.of_match_table = of_match_ptr(of_scpsys_match_tbl),
 	},
 };
-builtin_platform_driver(scpsys_drv);
+
+static int __init scpsys_drv_init(void)
+{
+	return platform_driver_register(&scpsys_drv);
+}
+
+/*
+ * There are some Mediatek drivers which depend on the power domain driver need
+ * to probe in earlier initcall levels. So scpsys driver also need to probe
+ * earlier.
+ *
+ * IOMMU(M4U) and SMI drivers for example. SMI is a bridge between IOMMU and
+ * multimedia HW. IOMMU depends on SMI, and SMI is a power domain consumer,
+ * so the proper probe sequence should be scpsys -> SMI -> IOMMU driver.
+ * IOMMU drivers are initialized during subsys_init by default, so we need to
+ * move SMI and scpsys drivers to subsys_init or earlier init levels.
+ */
+subsys_initcall(scpsys_drv_init);
-- 
1.9.1



From jamesjj.liao at mediatek.com  Tue Jul 19 00:04:42 2016
From: jamesjj.liao at mediatek.com (James Liao)
Date: Tue, 19 Jul 2016 15:04:42 +0800
Subject: [PATCH v8 3/4] soc: mediatek: Add MT2701 power dt-bindings
In-Reply-To: <1468911883-41882-1-git-send-email-jamesjj.liao@mediatek.com>
References: <1468911883-41882-1-git-send-email-jamesjj.liao@mediatek.com>
Message-ID: <1468911883-41882-4-git-send-email-jamesjj.liao@mediatek.com>

From: Shunli Wang <shunli.wang at mediatek.com>

Add power dt-bindings for MT2701.

Signed-off-by: Shunli Wang <shunli.wang at mediatek.com>
Signed-off-by: James Liao <jamesjj.liao at mediatek.com>
Acked-by: Rob Herring <robh at kernel.org>
Reviewed-by: Kevin Hilman <khilman at baylibre.com>
---
 .../devicetree/bindings/soc/mediatek/scpsys.txt    | 13 +++++++----
 include/dt-bindings/power/mt2701-power.h           | 27 ++++++++++++++++++++++
 2 files changed, 35 insertions(+), 5 deletions(-)
 create mode 100644 include/dt-bindings/power/mt2701-power.h

diff --git a/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt b/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
index e8f15e3..16fe94d 100644
--- a/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
+++ b/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
@@ -9,17 +9,20 @@ domain control.
 
 The driver implements the Generic PM domain bindings described in
 power/power_domain.txt. It provides the power domains defined in
-include/dt-bindings/power/mt8173-power.h.
+include/dt-bindings/power/mt8173-power.h and mt2701-power.h.
 
 Required properties:
-- compatible: Must be "mediatek,mt8173-scpsys"
+- compatible: Should be one of:
+	- "mediatek,mt2701-scpsys"
+	- "mediatek,mt8173-scpsys"
 - #power-domain-cells: Must be 1
 - reg: Address range of the SCPSYS unit
 - infracfg: must contain a phandle to the infracfg controller
 - clock, clock-names: clocks according to the common clock binding.
-                      The clocks needed "mm", "mfg", "venc" and "venc_lt".
-		      These are the clocks which hardware needs to be enabled
-		      before enabling certain power domains.
+                      These are clocks which hardware needs to be
+                      enabled before enabling certain power domains.
+	Required clocks for MT2701: "mm", "mfg", "ethif"
+	Required clocks for MT8173: "mm", "mfg", "venc", "venc_lt"
 
 Optional properties:
 - vdec-supply: Power supply for the vdec power domain
diff --git a/include/dt-bindings/power/mt2701-power.h b/include/dt-bindings/power/mt2701-power.h
new file mode 100644
index 0000000..64cc826
--- /dev/null
+++ b/include/dt-bindings/power/mt2701-power.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 MediaTek Inc.
+ *
+ * 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.
+ */
+
+#ifndef _DT_BINDINGS_POWER_MT2701_POWER_H
+#define _DT_BINDINGS_POWER_MT2701_POWER_H
+
+#define MT2701_POWER_DOMAIN_CONN	0
+#define MT2701_POWER_DOMAIN_DISP	1
+#define MT2701_POWER_DOMAIN_MFG		2
+#define MT2701_POWER_DOMAIN_VDEC	3
+#define MT2701_POWER_DOMAIN_ISP		4
+#define MT2701_POWER_DOMAIN_BDP		5
+#define MT2701_POWER_DOMAIN_ETH		6
+#define MT2701_POWER_DOMAIN_HIF		7
+#define MT2701_POWER_DOMAIN_IFR_MSC	8
+
+#endif /* _DT_BINDINGS_POWER_MT2701_POWER_H */
-- 
1.9.1



From jamesjj.liao at mediatek.com  Tue Jul 19 00:04:43 2016
From: jamesjj.liao at mediatek.com (James Liao)
Date: Tue, 19 Jul 2016 15:04:43 +0800
Subject: [PATCH v8 4/4] soc: mediatek: Add MT2701 scpsys driver
In-Reply-To: <1468911883-41882-1-git-send-email-jamesjj.liao@mediatek.com>
References: <1468911883-41882-1-git-send-email-jamesjj.liao@mediatek.com>
Message-ID: <1468911883-41882-5-git-send-email-jamesjj.liao@mediatek.com>

From: Shunli Wang <shunli.wang at mediatek.com>

Add scpsys driver for MT2701.

mtk-scpsys now supports MT8173 (arm64) and MT2701 (arm). So it should
be enabled on both arm64 and arm platforms.

Signed-off-by: Shunli Wang <shunli.wang at mediatek.com>
Signed-off-by: James Liao <jamesjj.liao at mediatek.com>
Reviewed-by: Kevin Hilman <khilman at baylibre.com>
---
 drivers/soc/mediatek/Kconfig      |   2 +-
 drivers/soc/mediatek/mtk-scpsys.c | 120 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 119 insertions(+), 3 deletions(-)

diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
index 0a4ea80..609bb34 100644
--- a/drivers/soc/mediatek/Kconfig
+++ b/drivers/soc/mediatek/Kconfig
@@ -23,7 +23,7 @@ config MTK_PMIC_WRAP
 config MTK_SCPSYS
 	bool "MediaTek SCPSYS Support"
 	depends on ARCH_MEDIATEK || COMPILE_TEST
-	default ARM64 && ARCH_MEDIATEK
+	default ARCH_MEDIATEK
 	select REGMAP
 	select MTK_INFRACFG
 	select PM_GENERIC_DOMAINS if PM
diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
index e806cb7..b94b4e4 100644
--- a/drivers/soc/mediatek/mtk-scpsys.c
+++ b/drivers/soc/mediatek/mtk-scpsys.c
@@ -20,6 +20,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/soc/mediatek/infracfg.h>
 
+#include <dt-bindings/power/mt2701-power.h>
 #include <dt-bindings/power/mt8173-power.h>
 
 #define SPM_VDE_PWR_CON			0x0210
@@ -27,8 +28,13 @@
 #define SPM_VEN_PWR_CON			0x0230
 #define SPM_ISP_PWR_CON			0x0238
 #define SPM_DIS_PWR_CON			0x023c
+#define SPM_CONN_PWR_CON		0x0280
 #define SPM_VEN2_PWR_CON		0x0298
-#define SPM_AUDIO_PWR_CON		0x029c
+#define SPM_AUDIO_PWR_CON		0x029c	/* MT8173 */
+#define SPM_BDP_PWR_CON			0x029c	/* MT2701 */
+#define SPM_ETH_PWR_CON			0x02a0
+#define SPM_HIF_PWR_CON			0x02a4
+#define SPM_IFR_MSC_PWR_CON		0x02a8
 #define SPM_MFG_2D_PWR_CON		0x02c0
 #define SPM_MFG_ASYNC_PWR_CON		0x02c4
 #define SPM_USB_PWR_CON			0x02cc
@@ -42,10 +48,15 @@
 #define PWR_ON_2ND_BIT			BIT(3)
 #define PWR_CLK_DIS_BIT			BIT(4)
 
+#define PWR_STATUS_CONN			BIT(1)
 #define PWR_STATUS_DISP			BIT(3)
 #define PWR_STATUS_MFG			BIT(4)
 #define PWR_STATUS_ISP			BIT(5)
 #define PWR_STATUS_VDEC			BIT(7)
+#define PWR_STATUS_BDP			BIT(14)
+#define PWR_STATUS_ETH			BIT(15)
+#define PWR_STATUS_HIF			BIT(16)
+#define PWR_STATUS_IFR_MSC		BIT(17)
 #define PWR_STATUS_VENC_LT		BIT(20)
 #define PWR_STATUS_VENC			BIT(21)
 #define PWR_STATUS_MFG_2D		BIT(22)
@@ -59,6 +70,7 @@ enum clk_id {
 	CLK_MFG,
 	CLK_VENC,
 	CLK_VENC_LT,
+	CLK_ETHIF,
 	CLK_MAX,
 };
 
@@ -321,7 +333,8 @@ static void init_clks(struct platform_device *pdev, struct clk *clk[CLK_MAX])
 		CLK_MM,
 		CLK_MFG,
 		CLK_VENC,
-		CLK_VENC_LT
+		CLK_VENC_LT,
+		CLK_ETHIF
 	};
 
 	static const char * const clk_names[] = {
@@ -329,6 +342,7 @@ static void init_clks(struct platform_device *pdev, struct clk *clk[CLK_MAX])
 		"mfg",
 		"venc",
 		"venc_lt",
+		"ethif",
 	};
 
 	int i;
@@ -460,6 +474,105 @@ static void mtk_register_power_domains(struct platform_device *pdev,
 }
 
 /*
+ * MT2701 power domain support
+ */
+
+static const struct scp_domain_data scp_domain_data_mt2701[] = {
+	[MT2701_POWER_DOMAIN_CONN] = {
+		.name = "conn",
+		.sta_mask = PWR_STATUS_CONN,
+		.ctl_offs = SPM_CONN_PWR_CON,
+		.bus_prot_mask = 0x0104,
+		.clk_id = {CLK_NONE},
+		.active_wakeup = true,
+	},
+	[MT2701_POWER_DOMAIN_DISP] = {
+		.name = "disp",
+		.sta_mask = PWR_STATUS_DISP,
+		.ctl_offs = SPM_DIS_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.clk_id = {CLK_MM},
+		.bus_prot_mask = 0x0002,
+		.active_wakeup = true,
+	},
+	[MT2701_POWER_DOMAIN_MFG] = {
+		.name = "mfg",
+		.sta_mask = PWR_STATUS_MFG,
+		.ctl_offs = SPM_MFG_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.sram_pdn_ack_bits = GENMASK(12, 12),
+		.clk_id = {CLK_MFG},
+		.active_wakeup = true,
+	},
+	[MT2701_POWER_DOMAIN_VDEC] = {
+		.name = "vdec",
+		.sta_mask = PWR_STATUS_VDEC,
+		.ctl_offs = SPM_VDE_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.sram_pdn_ack_bits = GENMASK(12, 12),
+		.clk_id = {CLK_MM},
+		.active_wakeup = true,
+	},
+	[MT2701_POWER_DOMAIN_ISP] = {
+		.name = "isp",
+		.sta_mask = PWR_STATUS_ISP,
+		.ctl_offs = SPM_ISP_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.sram_pdn_ack_bits = GENMASK(13, 12),
+		.clk_id = {CLK_MM},
+		.active_wakeup = true,
+	},
+	[MT2701_POWER_DOMAIN_BDP] = {
+		.name = "bdp",
+		.sta_mask = PWR_STATUS_BDP,
+		.ctl_offs = SPM_BDP_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.clk_id = {CLK_NONE},
+		.active_wakeup = true,
+	},
+	[MT2701_POWER_DOMAIN_ETH] = {
+		.name = "eth",
+		.sta_mask = PWR_STATUS_ETH,
+		.ctl_offs = SPM_ETH_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.sram_pdn_ack_bits = GENMASK(15, 12),
+		.clk_id = {CLK_ETHIF},
+		.active_wakeup = true,
+	},
+	[MT2701_POWER_DOMAIN_HIF] = {
+		.name = "hif",
+		.sta_mask = PWR_STATUS_HIF,
+		.ctl_offs = SPM_HIF_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.sram_pdn_ack_bits = GENMASK(15, 12),
+		.clk_id = {CLK_ETHIF},
+		.active_wakeup = true,
+	},
+	[MT2701_POWER_DOMAIN_IFR_MSC] = {
+		.name = "ifr_msc",
+		.sta_mask = PWR_STATUS_IFR_MSC,
+		.ctl_offs = SPM_IFR_MSC_PWR_CON,
+		.clk_id = {CLK_NONE},
+		.active_wakeup = true,
+	},
+};
+
+#define NUM_DOMAINS_MT2701	ARRAY_SIZE(scp_domain_data_mt2701)
+
+static int __init scpsys_probe_mt2701(struct platform_device *pdev)
+{
+	struct scp *scp;
+
+	scp = init_scp(pdev, scp_domain_data_mt2701, NUM_DOMAINS_MT2701);
+	if (IS_ERR(scp))
+		return PTR_ERR(scp);
+
+	mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT2701);
+
+	return 0;
+}
+
+/*
  * MT8173 power domain support
  */
 
@@ -588,6 +701,9 @@ static int __init scpsys_probe_mt8173(struct platform_device *pdev)
 
 static const struct of_device_id of_scpsys_match_tbl[] = {
 	{
+		.compatible = "mediatek,mt2701-scpsys",
+		.data = scpsys_probe_mt2701,
+	}, {
 		.compatible = "mediatek,mt8173-scpsys",
 		.data = scpsys_probe_mt8173,
 	}, {
-- 
1.9.1



From jamesjj.liao at mediatek.com  Tue Jul 19 00:04:40 2016
From: jamesjj.liao at mediatek.com (James Liao)
Date: Tue, 19 Jul 2016 15:04:40 +0800
Subject: [PATCH v8 1/4] soc: mediatek: Refine scpsys to support multiple
 platform
In-Reply-To: <1468911883-41882-1-git-send-email-jamesjj.liao@mediatek.com>
References: <1468911883-41882-1-git-send-email-jamesjj.liao@mediatek.com>
Message-ID: <1468911883-41882-2-git-send-email-jamesjj.liao@mediatek.com>

Refine scpsys driver common code to support multiple SoC / platform.

Signed-off-by: James Liao <jamesjj.liao at mediatek.com>
Reviewed-by: Kevin Hilman <khilman at baylibre.com>
---
 drivers/soc/mediatek/mtk-scpsys.c | 363 +++++++++++++++++++++++---------------
 1 file changed, 220 insertions(+), 143 deletions(-)

diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
index 837effe..1f3555a 100644
--- a/drivers/soc/mediatek/mtk-scpsys.c
+++ b/drivers/soc/mediatek/mtk-scpsys.c
@@ -11,17 +11,15 @@
  * GNU General Public License for more details.
  */
 #include <linux/clk.h>
-#include <linux/delay.h>
+#include <linux/init.h>
 #include <linux/io.h>
-#include <linux/kernel.h>
 #include <linux/mfd/syscon.h>
-#include <linux/init.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/pm_domain.h>
-#include <linux/regmap.h>
-#include <linux/soc/mediatek/infracfg.h>
 #include <linux/regulator/consumer.h>
+#include <linux/soc/mediatek/infracfg.h>
+
 #include <dt-bindings/power/mt8173-power.h>
 
 #define SPM_VDE_PWR_CON			0x0210
@@ -34,6 +32,7 @@
 #define SPM_MFG_2D_PWR_CON		0x02c0
 #define SPM_MFG_ASYNC_PWR_CON		0x02c4
 #define SPM_USB_PWR_CON			0x02cc
+
 #define SPM_PWR_STATUS			0x060c
 #define SPM_PWR_STATUS_2ND		0x0610
 
@@ -55,12 +54,12 @@
 #define PWR_STATUS_USB			BIT(25)
 
 enum clk_id {
-	MT8173_CLK_NONE,
-	MT8173_CLK_MM,
-	MT8173_CLK_MFG,
-	MT8173_CLK_VENC,
-	MT8173_CLK_VENC_LT,
-	MT8173_CLK_MAX,
+	CLK_NONE,
+	CLK_MM,
+	CLK_MFG,
+	CLK_VENC,
+	CLK_VENC_LT,
+	CLK_MAX,
 };
 
 #define MAX_CLKS	2
@@ -76,98 +75,6 @@ struct scp_domain_data {
 	bool active_wakeup;
 };
 
-static const struct scp_domain_data scp_domain_data[] = {
-	[MT8173_POWER_DOMAIN_VDEC] = {
-		.name = "vdec",
-		.sta_mask = PWR_STATUS_VDEC,
-		.ctl_offs = SPM_VDE_PWR_CON,
-		.sram_pdn_bits = GENMASK(11, 8),
-		.sram_pdn_ack_bits = GENMASK(12, 12),
-		.clk_id = {MT8173_CLK_MM},
-	},
-	[MT8173_POWER_DOMAIN_VENC] = {
-		.name = "venc",
-		.sta_mask = PWR_STATUS_VENC,
-		.ctl_offs = SPM_VEN_PWR_CON,
-		.sram_pdn_bits = GENMASK(11, 8),
-		.sram_pdn_ack_bits = GENMASK(15, 12),
-		.clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC},
-	},
-	[MT8173_POWER_DOMAIN_ISP] = {
-		.name = "isp",
-		.sta_mask = PWR_STATUS_ISP,
-		.ctl_offs = SPM_ISP_PWR_CON,
-		.sram_pdn_bits = GENMASK(11, 8),
-		.sram_pdn_ack_bits = GENMASK(13, 12),
-		.clk_id = {MT8173_CLK_MM},
-	},
-	[MT8173_POWER_DOMAIN_MM] = {
-		.name = "mm",
-		.sta_mask = PWR_STATUS_DISP,
-		.ctl_offs = SPM_DIS_PWR_CON,
-		.sram_pdn_bits = GENMASK(11, 8),
-		.sram_pdn_ack_bits = GENMASK(12, 12),
-		.clk_id = {MT8173_CLK_MM},
-		.bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
-			MT8173_TOP_AXI_PROT_EN_MM_M1,
-	},
-	[MT8173_POWER_DOMAIN_VENC_LT] = {
-		.name = "venc_lt",
-		.sta_mask = PWR_STATUS_VENC_LT,
-		.ctl_offs = SPM_VEN2_PWR_CON,
-		.sram_pdn_bits = GENMASK(11, 8),
-		.sram_pdn_ack_bits = GENMASK(15, 12),
-		.clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC_LT},
-	},
-	[MT8173_POWER_DOMAIN_AUDIO] = {
-		.name = "audio",
-		.sta_mask = PWR_STATUS_AUDIO,
-		.ctl_offs = SPM_AUDIO_PWR_CON,
-		.sram_pdn_bits = GENMASK(11, 8),
-		.sram_pdn_ack_bits = GENMASK(15, 12),
-		.clk_id = {MT8173_CLK_NONE},
-	},
-	[MT8173_POWER_DOMAIN_USB] = {
-		.name = "usb",
-		.sta_mask = PWR_STATUS_USB,
-		.ctl_offs = SPM_USB_PWR_CON,
-		.sram_pdn_bits = GENMASK(11, 8),
-		.sram_pdn_ack_bits = GENMASK(15, 12),
-		.clk_id = {MT8173_CLK_NONE},
-		.active_wakeup = true,
-	},
-	[MT8173_POWER_DOMAIN_MFG_ASYNC] = {
-		.name = "mfg_async",
-		.sta_mask = PWR_STATUS_MFG_ASYNC,
-		.ctl_offs = SPM_MFG_ASYNC_PWR_CON,
-		.sram_pdn_bits = GENMASK(11, 8),
-		.sram_pdn_ack_bits = 0,
-		.clk_id = {MT8173_CLK_MFG},
-	},
-	[MT8173_POWER_DOMAIN_MFG_2D] = {
-		.name = "mfg_2d",
-		.sta_mask = PWR_STATUS_MFG_2D,
-		.ctl_offs = SPM_MFG_2D_PWR_CON,
-		.sram_pdn_bits = GENMASK(11, 8),
-		.sram_pdn_ack_bits = GENMASK(13, 12),
-		.clk_id = {MT8173_CLK_NONE},
-	},
-	[MT8173_POWER_DOMAIN_MFG] = {
-		.name = "mfg",
-		.sta_mask = PWR_STATUS_MFG,
-		.ctl_offs = SPM_MFG_PWR_CON,
-		.sram_pdn_bits = GENMASK(13, 8),
-		.sram_pdn_ack_bits = GENMASK(21, 16),
-		.clk_id = {MT8173_CLK_NONE},
-		.bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
-			MT8173_TOP_AXI_PROT_EN_MFG_M0 |
-			MT8173_TOP_AXI_PROT_EN_MFG_M1 |
-			MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT,
-	},
-};
-
-#define NUM_DOMAINS	ARRAY_SIZE(scp_domain_data)
-
 struct scp;
 
 struct scp_domain {
@@ -179,7 +86,7 @@ struct scp_domain {
 };
 
 struct scp {
-	struct scp_domain domains[NUM_DOMAINS];
+	struct scp_domain *domains;
 	struct genpd_onecell_data pd_data;
 	struct device *dev;
 	void __iomem *base;
@@ -408,57 +315,69 @@ static bool scpsys_active_wakeup(struct device *dev)
 	return scpd->data->active_wakeup;
 }
 
-static int scpsys_probe(struct platform_device *pdev)
+static void init_clks(struct platform_device *pdev, struct clk *clk[CLK_MAX])
+{
+	enum clk_id clk_ids[] = {
+		CLK_MM,
+		CLK_MFG,
+		CLK_VENC,
+		CLK_VENC_LT
+	};
+
+	static const char * const clk_names[] = {
+		"mm",
+		"mfg",
+		"venc",
+		"venc_lt",
+	};
+
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(clk_ids); i++)
+		clk[clk_ids[i]] = devm_clk_get(&pdev->dev, clk_names[i]);
+}
+
+static struct scp *init_scp(struct platform_device *pdev,
+			const struct scp_domain_data *scp_domain_data, int num)
 {
 	struct genpd_onecell_data *pd_data;
 	struct resource *res;
-	int i, j, ret;
+	int i, j;
 	struct scp *scp;
-	struct clk *clk[MT8173_CLK_MAX];
+	struct clk *clk[CLK_MAX];
 
 	scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL);
 	if (!scp)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	scp->dev = &pdev->dev;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	scp->base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(scp->base))
-		return PTR_ERR(scp->base);
-
-	pd_data = &scp->pd_data;
-
-	pd_data->domains = devm_kzalloc(&pdev->dev,
-			sizeof(*pd_data->domains) * NUM_DOMAINS, GFP_KERNEL);
-	if (!pd_data->domains)
-		return -ENOMEM;
-
-	clk[MT8173_CLK_MM] = devm_clk_get(&pdev->dev, "mm");
-	if (IS_ERR(clk[MT8173_CLK_MM]))
-		return PTR_ERR(clk[MT8173_CLK_MM]);
-
-	clk[MT8173_CLK_MFG] = devm_clk_get(&pdev->dev, "mfg");
-	if (IS_ERR(clk[MT8173_CLK_MFG]))
-		return PTR_ERR(clk[MT8173_CLK_MFG]);
-
-	clk[MT8173_CLK_VENC] = devm_clk_get(&pdev->dev, "venc");
-	if (IS_ERR(clk[MT8173_CLK_VENC]))
-		return PTR_ERR(clk[MT8173_CLK_VENC]);
-
-	clk[MT8173_CLK_VENC_LT] = devm_clk_get(&pdev->dev, "venc_lt");
-	if (IS_ERR(clk[MT8173_CLK_VENC_LT]))
-		return PTR_ERR(clk[MT8173_CLK_VENC_LT]);
+		return ERR_CAST(scp->base);
 
 	scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
 			"infracfg");
 	if (IS_ERR(scp->infracfg)) {
 		dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n",
 				PTR_ERR(scp->infracfg));
-		return PTR_ERR(scp->infracfg);
+		return ERR_CAST(scp->infracfg);
 	}
 
-	for (i = 0; i < NUM_DOMAINS; i++) {
+	scp->domains = devm_kzalloc(&pdev->dev,
+				sizeof(*scp->domains) * num, GFP_KERNEL);
+	if (!scp->domains)
+		return ERR_PTR(-ENOMEM);
+
+	pd_data = &scp->pd_data;
+
+	pd_data->domains = devm_kzalloc(&pdev->dev,
+			sizeof(*pd_data->domains) * num, GFP_KERNEL);
+	if (!pd_data->domains)
+		return ERR_PTR(-ENOMEM);
+
+	for (i = 0; i < num; i++) {
 		struct scp_domain *scpd = &scp->domains[i];
 		const struct scp_domain_data *data = &scp_domain_data[i];
 
@@ -467,13 +386,15 @@ static int scpsys_probe(struct platform_device *pdev)
 			if (PTR_ERR(scpd->supply) == -ENODEV)
 				scpd->supply = NULL;
 			else
-				return PTR_ERR(scpd->supply);
+				return ERR_CAST(scpd->supply);
 		}
 	}
 
-	pd_data->num_domains = NUM_DOMAINS;
+	pd_data->num_domains = num;
 
-	for (i = 0; i < NUM_DOMAINS; i++) {
+	init_clks(pdev, clk);
+
+	for (i = 0; i < num; i++) {
 		struct scp_domain *scpd = &scp->domains[i];
 		struct generic_pm_domain *genpd = &scpd->genpd;
 		const struct scp_domain_data *data = &scp_domain_data[i];
@@ -482,13 +403,37 @@ static int scpsys_probe(struct platform_device *pdev)
 		scpd->scp = scp;
 
 		scpd->data = data;
-		for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++)
-			scpd->clk[j] = clk[data->clk_id[j]];
+
+		for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
+			struct clk *c = clk[data->clk_id[j]];
+
+			if (IS_ERR(c)) {
+				dev_err(&pdev->dev, "%s: clk unavailable\n",
+					data->name);
+				return ERR_CAST(c);
+			}
+
+			scpd->clk[j] = c;
+		}
 
 		genpd->name = data->name;
 		genpd->power_off = scpsys_power_off;
 		genpd->power_on = scpsys_power_on;
 		genpd->dev_ops.active_wakeup = scpsys_active_wakeup;
+	}
+
+	return scp;
+}
+
+static void mtk_register_power_domains(struct platform_device *pdev,
+				struct scp *scp, int num)
+{
+	struct genpd_onecell_data *pd_data;
+	int i, ret;
+
+	for (i = 0; i < num; i++) {
+		struct scp_domain *scpd = &scp->domains[i];
+		struct generic_pm_domain *genpd = &scpd->genpd;
 
 		/*
 		 * Initially turn on all domains to make the domains usable
@@ -507,6 +452,123 @@ static int scpsys_probe(struct platform_device *pdev)
 	 * valid.
 	 */
 
+	pd_data = &scp->pd_data;
+
+	ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data);
+	if (ret)
+		dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret);
+}
+
+/*
+ * MT8173 power domain support
+ */
+
+static const struct scp_domain_data scp_domain_data_mt8173[] = {
+	[MT8173_POWER_DOMAIN_VDEC] = {
+		.name = "vdec",
+		.sta_mask = PWR_STATUS_VDEC,
+		.ctl_offs = SPM_VDE_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.sram_pdn_ack_bits = GENMASK(12, 12),
+		.clk_id = {CLK_MM},
+	},
+	[MT8173_POWER_DOMAIN_VENC] = {
+		.name = "venc",
+		.sta_mask = PWR_STATUS_VENC,
+		.ctl_offs = SPM_VEN_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.sram_pdn_ack_bits = GENMASK(15, 12),
+		.clk_id = {CLK_MM, CLK_VENC},
+	},
+	[MT8173_POWER_DOMAIN_ISP] = {
+		.name = "isp",
+		.sta_mask = PWR_STATUS_ISP,
+		.ctl_offs = SPM_ISP_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.sram_pdn_ack_bits = GENMASK(13, 12),
+		.clk_id = {CLK_MM},
+	},
+	[MT8173_POWER_DOMAIN_MM] = {
+		.name = "mm",
+		.sta_mask = PWR_STATUS_DISP,
+		.ctl_offs = SPM_DIS_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.sram_pdn_ack_bits = GENMASK(12, 12),
+		.clk_id = {CLK_MM},
+		.bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
+			MT8173_TOP_AXI_PROT_EN_MM_M1,
+	},
+	[MT8173_POWER_DOMAIN_VENC_LT] = {
+		.name = "venc_lt",
+		.sta_mask = PWR_STATUS_VENC_LT,
+		.ctl_offs = SPM_VEN2_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.sram_pdn_ack_bits = GENMASK(15, 12),
+		.clk_id = {CLK_MM, CLK_VENC_LT},
+	},
+	[MT8173_POWER_DOMAIN_AUDIO] = {
+		.name = "audio",
+		.sta_mask = PWR_STATUS_AUDIO,
+		.ctl_offs = SPM_AUDIO_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.sram_pdn_ack_bits = GENMASK(15, 12),
+		.clk_id = {CLK_NONE},
+	},
+	[MT8173_POWER_DOMAIN_USB] = {
+		.name = "usb",
+		.sta_mask = PWR_STATUS_USB,
+		.ctl_offs = SPM_USB_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.sram_pdn_ack_bits = GENMASK(15, 12),
+		.clk_id = {CLK_NONE},
+		.active_wakeup = true,
+	},
+	[MT8173_POWER_DOMAIN_MFG_ASYNC] = {
+		.name = "mfg_async",
+		.sta_mask = PWR_STATUS_MFG_ASYNC,
+		.ctl_offs = SPM_MFG_ASYNC_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.sram_pdn_ack_bits = 0,
+		.clk_id = {CLK_MFG},
+	},
+	[MT8173_POWER_DOMAIN_MFG_2D] = {
+		.name = "mfg_2d",
+		.sta_mask = PWR_STATUS_MFG_2D,
+		.ctl_offs = SPM_MFG_2D_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.sram_pdn_ack_bits = GENMASK(13, 12),
+		.clk_id = {CLK_NONE},
+	},
+	[MT8173_POWER_DOMAIN_MFG] = {
+		.name = "mfg",
+		.sta_mask = PWR_STATUS_MFG,
+		.ctl_offs = SPM_MFG_PWR_CON,
+		.sram_pdn_bits = GENMASK(13, 8),
+		.sram_pdn_ack_bits = GENMASK(21, 16),
+		.clk_id = {CLK_NONE},
+		.bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
+			MT8173_TOP_AXI_PROT_EN_MFG_M0 |
+			MT8173_TOP_AXI_PROT_EN_MFG_M1 |
+			MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT,
+	},
+};
+
+#define NUM_DOMAINS_MT8173	ARRAY_SIZE(scp_domain_data_mt8173)
+
+static int __init scpsys_probe_mt8173(struct platform_device *pdev)
+{
+	struct scp *scp;
+	struct genpd_onecell_data *pd_data;
+	int ret;
+
+	scp = init_scp(pdev, scp_domain_data_mt8173, NUM_DOMAINS_MT8173);
+	if (IS_ERR(scp))
+		return PTR_ERR(scp);
+
+	mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT8173);
+
+	pd_data = &scp->pd_data;
+
 	ret = pm_genpd_add_subdomain(pd_data->domains[MT8173_POWER_DOMAIN_MFG_ASYNC],
 		pd_data->domains[MT8173_POWER_DOMAIN_MFG_2D]);
 	if (ret && IS_ENABLED(CONFIG_PM))
@@ -517,21 +579,36 @@ static int scpsys_probe(struct platform_device *pdev)
 	if (ret && IS_ENABLED(CONFIG_PM))
 		dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret);
 
-	ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data);
-	if (ret)
-		dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret);
-
 	return 0;
 }
 
+/*
+ * scpsys driver init
+ */
+
 static const struct of_device_id of_scpsys_match_tbl[] = {
 	{
 		.compatible = "mediatek,mt8173-scpsys",
+		.data = scpsys_probe_mt8173,
 	}, {
 		/* sentinel */
 	}
 };
 
+static int scpsys_probe(struct platform_device *pdev)
+{
+	int (*probe)(struct platform_device *);
+	const struct of_device_id *of_id;
+
+	of_id = of_match_node(of_scpsys_match_tbl, pdev->dev.of_node);
+	if (!of_id || !of_id->data)
+		return -EINVAL;
+
+	probe = of_id->data;
+
+	return probe(pdev);
+}
+
 static struct platform_driver scpsys_drv = {
 	.probe = scpsys_probe,
 	.driver = {
-- 
1.9.1



From ulf.hansson at linaro.org  Tue Jul 19 02:31:35 2016
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Tue, 19 Jul 2016 11:31:35 +0200
Subject: [PATCH 2/3] mmc: mmc: do not use CMD13 to get status after speed
 mode switch
In-Reply-To: <578CDBD8.2050806@linaro.org>
References: <1463647662-27426-1-git-send-email-chaotian.jing@mediatek.com>
 <1463647662-27426-3-git-send-email-chaotian.jing@mediatek.com>
 <CAOCOHw67NAinC6dEX0KsDn02kuXyNwznm3-bhptSVvQH0V1dqQ@mail.gmail.com>
 <CAPDyKFroGBShATJcQ=b2H=k85F+z9=hixpp3Go-j79ZvvLGAwQ@mail.gmail.com>
 <578CDBD8.2050806@linaro.org>
Message-ID: <CAPDyKFo0438H8odWks6HeD6E64+oyXYMHESv=pxqQyJe_9oaWA@mail.gmail.com>

On 18 July 2016 at 15:38, Georgi Djakov <georgi.djakov at linaro.org> wrote:
> On 07/18/2016 03:50 PM, Ulf Hansson wrote:
>> On 16 July 2016 at 00:10, Bjorn Andersson <bjorn.andersson at linaro.org> wrote:
>>> On Thu, May 19, 2016 at 1:47 AM, Chaotian Jing
>>> <chaotian.jing at mediatek.com> wrote:
>>>> Per JEDEC spec, it is not recommended to use CMD13 to get card status
>>>> after speed mode switch. below are two reason about this:
>>>> 1. CMD13 cannot be guaranteed due to the asynchronous operation.
>>>> Therefore it is not recommended to use CMD13 to check busy completion
>>>> of the timing change indication.
>>>> 2. After switch to HS200, CMD13 will get response of 0x800, and even the
>>>> busy signal gets de-asserted, the response of CMD13 is aslo 0x800.
>>>>
>>>> Signed-off-by: Chaotian Jing <chaotian.jing at mediatek.com>
>>>> ---
>>>>  drivers/mmc/core/mmc.c | 112 ++++++++++++++++++++-----------------------------
>>>>  1 file changed, 45 insertions(+), 67 deletions(-)
>>>>
>>>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>>> [..]
>>>> @@ -1274,20 +1254,18 @@ static int mmc_select_hs200(struct mmc_card *card)
>>>>                 err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>>>>                                    EXT_CSD_HS_TIMING, val,
>>>>                                    card->ext_csd.generic_cmd6_time,
>>>> -                                  true, send_status, true);
>>>> +                                  true, false, true);
>>>>                 if (err)
>>>>                         goto err;
>>>>                 old_timing = host->ios.timing;
>>>>                 mmc_set_timing(host, MMC_TIMING_MMC_HS200);
>>>> -               if (!send_status) {
>>>> -                       err = mmc_switch_status(card);
>>>> -                       /*
>>>> -                        * mmc_select_timing() assumes timing has not changed if
>>>> -                        * it is a switch error.
>>>> -                        */
>>>> -                       if (err == -EBADMSG)
>>>> -                               mmc_set_timing(host, old_timing);
>>>> -               }
>>>> +               err = mmc_switch_status(card);
>>>> +               /*
>>>> +                * mmc_select_timing() assumes timing has not changed if
>>>> +                * it is a switch error.
>>>> +                */
>>>> +               if (err == -EBADMSG)
>>>> +                       mmc_set_timing(host, old_timing);
>>>
>>> Sorry for not spotting this earlier, but with the move of the call of
>>> mmc_switch_status() to after mmc_set_timing() we get following error
>>> with sdhci-msm:
>>
>> Thanks for reporting!
>>
>>>
>>> mmc0: mmc_select_hs200 failed, error -110
>>> mmc0: error -110 whilst initialising MMC card
>>> mmc0: Reset 0x1 never completed.
>>> sdhci: =========== REGISTER DUMP (mmc0)===========
>>> sdhci: Sys addr: 0x00000000 | Version: 0x00002e02
>>> sdhci: Blk size: 0x00004000 | Blk cnt: 0x00000000
>>> sdhci: Argument: 0x00000000 | Trn mode: 0x00000000
>>> sdhci: Present: 0x01f80000 | Host ctl: 0x00000000
>>> sdhci: Power: 0x00000000 | Blk gap: 0x00000000
>>> sdhci: Wake-up: 0x00000000 | Clock: 0x00000003
>>> sdhci: Timeout: 0x00000000 | Int stat: 0x00000000
>>> sdhci: Int enab: 0x00000000 | Sig enab: 0x00000000
>>> sdhci: AC12 err: 0x00000000 | Slot int: 0x00000000
>>> sdhci: Caps: 0x322dc8b2 | Caps_1: 0x00008007
>>> sdhci: Cmd: 0x00000000 | Max curr: 0x00000000
>>> sdhci: Host ctl2: 0x00000000
>>> sdhci: ADMA Err: 0x00000000 | ADMA Ptr: 0x0000000000000000
>>> sdhci: ===========================================
>>>
>>> But I if I understand the commit correctly this is the intention of
>>> the patch (not the error, but the move).
>>
>> I tried dropping this change from my next branch, but there are some
>> more changes on top that prevents a "clean" drop. It's certainly
>> doable, but perhaps we can try to narrow down the problem to see if
>> this could/should be fixed in the sdhci msm driver instead!?
>
> Yes, i am working on it. Seems that if we just ignore the -ETIMEDOUT
> returned by mmc_switch_status() everything works as before. Currently
> i am expecting more information about this controller specifics, in
> order to understand if this could be fixed with a change in the driver
> only.

Thanks for looking into this!

>
>>
>> I also noticed that below submitted change, which *isn't* applied for
>> next, might be related.
>> https://patchwork.kernel.org/patch/9197881/
>>
>
> It is not related to this issue, but it is good to have when this is
> resolved, otherwise we will see the dumpregs output (pr_err now),
> when controller is initialized without a card in the SD slot.

Okay, thanks for clarifying. Although, I need an ack from Adrian
before I apply it.

>
> Thanks,
> Georgi

Kind regards
Uffe


From yt.shen at mediatek.com  Tue Jul 19 04:08:38 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Tue, 19 Jul 2016 19:08:38 +0800
Subject: [PATCH v4 5/8] drm/mediatek: add dsi interrupt control
In-Reply-To: <1468906767.30644.66.camel@mtksdaap41>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
 <1468577274-6178-6-git-send-email-yt.shen@mediatek.com>
 <1468906767.30644.66.camel@mtksdaap41>
Message-ID: <1468926518.24098.33.camel@mtksdaap41>

Hi CK,

On Tue, 2016-07-19 at 13:39 +0800, CK Hu wrote:
> Hi, YT:
> 
> Some comments inline.
> 
> On Fri, 2016-07-15 at 18:07 +0800, YT Shen wrote:
> > From: shaoming chen <shaoming.chen at mediatek.com>
> > 
> > add dsi interrupt control
> > 
> > Signed-off-by: shaoming chen <shaoming.chen at mediatek.com>
> > ---
> >  drivers/gpu/drm/mediatek/mtk_dsi.c |  130 ++++++++++++++++++++++++++++++++++++
> >  1 file changed, 130 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
> > index 2d808e5..de5ad7f 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_dsi.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
> > @@ -18,6 +18,7 @@
> >  #include <drm/drm_panel.h>
> >  #include <linux/clk.h>
> >  #include <linux/component.h>
> > +#include <linux/irq.h>
> >  #include <linux/of.h>
> >  #include <linux/of_platform.h>
> >  #include <linux/of_graph.h>
> > @@ -32,6 +33,13 @@
> >  
> >  #define DSI_START		0x00
> >  
> > +#define DSI_INTEN		0x08
> > +
> > +#define DSI_INTSTA		0x0c
> > +#define LPRX_RD_RDY_INT_FLAG	BIT(0)
> > +#define CMD_DONE_INT_FLAG	BIT(1)
> > +#define DSI_BUSY		BIT(31)
> 
> Why need LPRX_RD_RDY_INT_FLAG, CMD_DONE_INT_FLAG, and DSI_BUSY? Maybe
> these three should be moved to other patch.
OK.

> 
> > +
> >  #define DSI_CON_CTRL		0x10
> >  #define DSI_RESET			BIT(0)
> >  #define DSI_EN				BIT(1)
> > @@ -74,6 +82,9 @@
> >  
> >  #define DSI_HSTX_CKL_WC		0x64
> >  
> > +#define DSI_RACK		0x84
> > +#define RACK			BIT(0)
> > +
> >  #define DSI_PHY_LCCON		0x104
> >  #define LC_HS_TX_EN			BIT(0)
> >  #define LC_ULPM_EN			BIT(1)
> > @@ -134,6 +145,18 @@ struct mtk_dsi {
> >  	struct videomode vm;
> >  	int refcount;
> >  	bool enabled;
> > +	int irq_num, irq_data;
> > +};
> > +
> > +enum {
> > +	DSI_INT_SLEEPOUT_DONE_FLAG	= BIT(6),
> > +	DSI_INT_VM_CMD_DONE_FLAG	= BIT(5),
> > +	DSI_INT_EXT_TE_RDY_FLAG		= BIT(4),
> > +	DSI_INT_VM_DONE_FLAG		= BIT(3),
> > +	DSI_INT_TE_RDY_FLAG		= BIT(2),
> > +	DSI_INT_CMD_DONE_FLAG		= BIT(1),
> > +	DSI_INT_LPRX_RD_RDY_FLAG	= BIT(0),
> > +	DSI_INT_ALL_BITS		= (0x7f)
> >  };
> 
> I think you should use '#define' instead of 'enum'. The code would be
> like below, and these definition should be moved to after DSI_INTEN or
> DSI_INTSTA.
> 
> #define DSI_INT_LPRX_RD_RDY_FLAG	BIT(0)
> #define DSI_INT_CMD_DONE_FLAG		BIT(1)
> #define DSI_INT_TE_RDY_FLAG		BIT(2)
> #define DSI_INT_VM_DONE_FLAG		BIT(3)
> #define DSI_INT_EXT_TE_RDY_FLAG		BIT(4)
> #define DSI_INT_VM_CMD_DONE_FLAG	BIT(5)
> #define DSI_INT_SLEEPOUT_DONE_FLAG	BIT(6)
> #define DSI_INT_ALL_BITS		(DSI_INT_LPRX_RD_RDY_FLAG | \
> 					DSI_INT_CMD_DONE_FLAG | \
> 					DSI_INT_TE_RDY_FLAG | \
> 					DSI_INT_VM_DONE_FLAG | \
> 					DSI_INT_EXT_TE_RDY_FLAG | \
> 					DSI_INT_VM_CMD_DONE_FLAG | \
> 					DSI_INT_SLEEPOUT_DONE_FLAG)
> 
I will update this part in the next version.

> >  
> >  static inline struct mtk_dsi *encoder_to_dsi(struct drm_encoder *e)
> > @@ -440,6 +463,94 @@ static void mtk_dsi_start(struct mtk_dsi *dsi)
> >  	writel(1, dsi->regs + DSI_START);
> >  }
> >  
> > +static void mtk_dsi_set_interrupt_enable(struct mtk_dsi *dsi)
> > +{
> > +	u32 inten = DSI_INT_ALL_BITS;
> > +
> > +	if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO)
> > +		inten &= ~(DSI_INT_TE_RDY_FLAG | DSI_INT_EXT_TE_RDY_FLAG);
> > +
> > +	writel(inten, dsi->regs + DSI_INTEN);
> > +}
> > +
> > +static void mtk_dsi_irq_wakeup(struct mtk_dsi *dsi, u32 irq_bit)
> > +{
> > +	dsi->irq_data |= irq_bit;
> > +}
> > +
> > +static irqreturn_t mtk_dsi_irq(int irq, void *dev_id)
> > +{
> > +	struct mtk_dsi *dsi = dev_id;
> > +
> > +	u32 status, tmp;
> > +
> > +	status = readl(dsi->regs + DSI_INTSTA);
> > +
> > +	if (status & DSI_INT_LPRX_RD_RDY_FLAG) {
> > +		/* write clear RD_RDY interrupt */
> > +		/* write clear RD_RDY interrupt must be before DSI_RACK */
> > +		/* because CMD_DONE will raise after DSI_RACK, */
> > +		/* so write clear RD_RDY after that will clear CMD_DONE too */
> > +		do {
> > +			/* send read ACK */
> > +			mtk_dsi_mask(dsi, DSI_RACK, RACK, RACK);
> > +			tmp = readl(dsi->regs + DSI_INTSTA);
> > +		} while (tmp & DSI_BUSY);
> > +
> > +		mtk_dsi_mask(dsi, DSI_INTSTA, DSI_INT_LPRX_RD_RDY_FLAG, 0);
> > +		mtk_dsi_irq_wakeup(dsi, DSI_INT_LPRX_RD_RDY_FLAG);
> > +	}
> > +
> > +	if (status & DSI_INT_CMD_DONE_FLAG) {
> > +		mtk_dsi_mask(dsi, DSI_INTSTA, DSI_INT_CMD_DONE_FLAG, 0);
> > +		mtk_dsi_irq_wakeup(dsi, DSI_INT_CMD_DONE_FLAG);
> > +	}
> > +
> > +	if (status & DSI_INT_TE_RDY_FLAG) {
> > +		mtk_dsi_mask(dsi, DSI_INTSTA, DSI_INT_TE_RDY_FLAG, 0);
> > +		mtk_dsi_irq_wakeup(dsi, DSI_INT_TE_RDY_FLAG);
> > +	}
> > +
> > +	if (status & DSI_INT_VM_DONE_FLAG) {
> > +		mtk_dsi_mask(dsi, DSI_INTSTA, DSI_INT_VM_DONE_FLAG, 0);
> > +		mtk_dsi_irq_wakeup(dsi, DSI_INT_VM_DONE_FLAG);
> > +	}
> > +
> > +	if (status & DSI_INT_EXT_TE_RDY_FLAG) {
> > +		mtk_dsi_mask(dsi, DSI_INTSTA, DSI_INT_EXT_TE_RDY_FLAG, 0);
> > +		mtk_dsi_irq_wakeup(dsi, DSI_INT_EXT_TE_RDY_FLAG);
> > +	}
> > +
> > +	if (status & DSI_INT_VM_CMD_DONE_FLAG) {
> > +		mtk_dsi_mask(dsi, DSI_INTSTA, DSI_INT_VM_CMD_DONE_FLAG, 0);
> > +		mtk_dsi_irq_wakeup(dsi, DSI_INT_VM_CMD_DONE_FLAG);
> > +	}
> > +
> > +	if (status & DSI_INT_SLEEPOUT_DONE_FLAG) {
> > +		mtk_dsi_mask(dsi, DSI_INTSTA, DSI_INT_SLEEPOUT_DONE_FLAG, 0);
> > +		mtk_dsi_irq_wakeup(dsi, DSI_INT_SLEEPOUT_DONE_FLAG);
> > +	}
> 
> All these 'if' statement do the same thing and I think these could be
> merge as:
> 
> status = readl(dsi->regs + DSI_INTSTA) & DSI_INT_ALL_BITS);
> if (status) {
> 	mtk_dsi_mask(dsi, DSI_INTSTA, status, 0);
> 	mtk_dsi_irq_wakeup(dsi, status);
> }
Will do.

> 
> > +
> > +	return IRQ_HANDLED;
> > +}
> > +
> > +static s32 mtk_dsi_wait_for_irq_timeout(struct mtk_dsi *dsi, u32 irq_bit,
> > +					u32 timeout_ms)
> > +{
> > +	while (timeout_ms--) {
> > +		if (dsi->irq_data & irq_bit) {
> > +			dsi->irq_data &= ~irq_bit;
> > +			return 0;
> > +		}
> > +
> > +		usleep_range(1000, 1100);
> > +	}
> 
> I think it's better to use wait_event() or something else. Polling with
> sleep could not react immediately.
Will check.

> 
> > +
> > +	dsi->irq_data = 0;
> 
> Why clear all bit after wait one bit timeout?
Will check.

> 
> > +
> > +	return -1;
> > +}
> > +
> >  static void mtk_dsi_poweroff(struct mtk_dsi *dsi)
> >  {
> >  	if (WARN_ON(dsi->refcount == 0))
> > @@ -488,6 +599,7 @@ static void mtk_output_dsi_enable(struct mtk_dsi *dsi)
> >  
> >  	dsi_ps_control_vact(dsi);
> >  	dsi_config_vdo_timing(dsi);
> > +	mtk_dsi_set_interrupt_enable(dsi);
> >  
> >  	dsi_set_mode(dsi);
> >  	dsi_clk_hs_mode(dsi, 1);
> > @@ -883,6 +995,24 @@ static int mtk_dsi_probe(struct platform_device *pdev)
> >  		return ret;
> >  	}
> >  
> > +	dsi->irq_num = platform_get_irq(pdev, 0);
> 
> You use irq_num only in this function, why keep it in dsi structure?
OK, will remove it from dsi structure.

Regards,
yt.shen

> 
> > +	if (dsi->irq_num < 0) {
> > +		dev_err(&pdev->dev, "failed to request dsi irq resource\n");
> > +		ret = dsi->irq_num;
> > +		return -EPROBE_DEFER;
> > +	}
> > +
> > +	irq_set_status_flags(dsi->irq_num, IRQ_TYPE_LEVEL_LOW);
> > +	ret = devm_request_irq(&pdev->dev, dsi->irq_num, mtk_dsi_irq,
> > +			       IRQF_TRIGGER_LOW, dev_name(&pdev->dev), dsi);
> > +	if (ret) {
> > +		dev_err(&pdev->dev, "failed to request mediatek dsi irq\n");
> > +		return -EPROBE_DEFER;
> > +	}
> > +
> > +	dsi->irq_data = 0;
> > +	dev_info(dev, "dsi irq num is 0x%x\n", dsi->irq_num);
> > +
> >  	platform_set_drvdata(pdev, dsi);
> >  
> >  	return component_add(&pdev->dev, &mtk_dsi_component_ops);
> 
> Regards,
> CK
> 




From yt.shen at mediatek.com  Tue Jul 19 04:09:30 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Tue, 19 Jul 2016 19:09:30 +0800
Subject: [PATCH v4 4/8] drm/mediatek: add support for Mediatek SoC MT2701
In-Reply-To: <1468825133.30644.41.camel@mtksdaap41>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
 <1468577274-6178-5-git-send-email-yt.shen@mediatek.com>
 <1468825133.30644.41.camel@mtksdaap41>
Message-ID: <1468926570.24098.34.camel@mtksdaap41>

Hi CK,

On Mon, 2016-07-18 at 14:58 +0800, CK Hu wrote:
> Hi, YT:
> 
> One comment inline.
> 
> On Fri, 2016-07-15 at 18:07 +0800, YT Shen wrote:
> > This patch add support for the Mediatek MT2701 DISP subsystem.
> > There is only one OVL engine in MT2701.
> > 
> > Signed-off-by: YT Shen <yt.shen at mediatek.com>
> > ---
> >  drivers/gpu/drm/mediatek/mtk_disp_ovl.c     |    6 ++++
> >  drivers/gpu/drm/mediatek/mtk_disp_rdma.c    |    6 ++++
> >  drivers/gpu/drm/mediatek/mtk_drm_ddp.c      |   41 +++++++++++++++++++++++++++
> >  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |    7 +++++
> >  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |    1 +
> >  drivers/gpu/drm/mediatek/mtk_drm_drv.c      |   31 ++++++++++++++++++++
> >  6 files changed, 92 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> > index eb5c05e..1da0a71 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> > @@ -286,11 +286,17 @@ static int mtk_disp_ovl_remove(struct platform_device *pdev)
> >  	return 0;
> >  }
> >  
> > +static const struct mtk_ddp_comp_driver_data mt2701_ovl_driver_data = {
> > +	.ovl = {0x0040, 1 << 12, 0}
> > +};
> > +
> >  static const struct mtk_ddp_comp_driver_data mt8173_ovl_driver_data = {
> >  	.ovl = {0x0f40, 0, 1 << 12}
> >  };
> >  
> >  static const struct of_device_id mtk_disp_ovl_driver_dt_match[] = {
> > +	{ .compatible = "mediatek,mt2701-disp-ovl",
> > +	  .data = &mt2701_ovl_driver_data},
> >  	{ .compatible = "mediatek,mt8173-disp-ovl",
> >  	  .data = &mt8173_ovl_driver_data},
> >  	{},
> > diff --git a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
> > index fb0db50..506a353 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
> > @@ -225,11 +225,17 @@ static int mtk_disp_rdma_remove(struct platform_device *pdev)
> >  	return 0;
> >  }
> >  
> > +static const struct mtk_ddp_comp_driver_data mt2701_rdma_driver_data = {
> > +	.rdma_fifo_pseudo_size = SZ_4K,
> > +};
> > +
> >  static const struct mtk_ddp_comp_driver_data mt8173_rdma_driver_data = {
> >  	.rdma_fifo_pseudo_size = SZ_8K,
> >  };
> >  
> >  static const struct of_device_id mtk_disp_rdma_driver_dt_match[] = {
> > +	{ .compatible = "mediatek,mt2701-disp-rdma",
> > +	  .data = &mt2701_rdma_driver_data},
> >  	{ .compatible = "mediatek,mt8173-disp-rdma",
> >  	  .data = &mt8173_rdma_driver_data},
> >  	{},
> > diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
> > index fa53806..ee0326a 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
> > @@ -32,6 +32,10 @@
> >  #define DISP_REG_CONFIG_DISP_RDMA1_MOUT_EN	0x0c8
> >  #define DISP_REG_CONFIG_MMSYS_CG_CON0		0x100
> >  
> > +#define DISP_REG_CONFIG_DISP_OVL_MOUT_EN	0x030
> > +#define DISP_REG_CONFIG_OUT_SEL			0x04c
> > +#define DISP_REG_CONFIG_DSI_SEL			0x050
> > +
> >  #define DISP_REG_MUTEX_EN(n)	(0x20 + 0x20 * (n))
> >  #define DISP_REG_MUTEX(n)	(0x24 + 0x20 * (n))
> >  #define DISP_REG_MUTEX_RST(n)	(0x28 + 0x20 * (n))
> > @@ -54,6 +58,13 @@
> >  #define MT8173_MUTEX_MOD_DISP_PWM1		BIT(24)
> >  #define MT8173_MUTEX_MOD_DISP_OD		BIT(25)
> >  
> > +#define MT2701_MUTEX_MOD_DISP_OVL		BIT(3)
> > +#define MT2701_MUTEX_MOD_DISP_WDMA		BIT(6)
> > +#define MT2701_MUTEX_MOD_DISP_COLOR		BIT(7)
> > +#define MT2701_MUTEX_MOD_DISP_BLS		BIT(9)
> > +#define MT2701_MUTEX_MOD_DISP_RDMA0		BIT(10)
> > +#define MT2701_MUTEX_MOD_DISP_RDMA1		BIT(12)
> > +
> >  #define MUTEX_SOF_SINGLE_MODE		0
> >  #define MUTEX_SOF_DSI0			1
> >  #define MUTEX_SOF_DSI1			2
> > @@ -69,6 +80,10 @@
> >  #define DPI0_SEL_IN_RDMA1		0x1
> >  #define COLOR1_SEL_IN_OVL1		0x1
> >  
> > +#define OVL_MOUT_EN_RDMA		0x1
> > +#define BLS_TO_DSI_RDMA1_TO_DPI1	0x8
> > +#define DSI_SEL_IN_BLS			0x0
> > +
> >  struct mtk_disp_mutex {
> >  	int id;
> >  	bool claimed;
> > @@ -82,6 +97,15 @@ struct mtk_ddp {
> >  	const unsigned int		*mutex_mod;
> >  };
> >  
> > +static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = {
> > +	[DDP_COMPONENT_BLS] = MT2701_MUTEX_MOD_DISP_BLS,
> > +	[DDP_COMPONENT_COLOR0] = MT2701_MUTEX_MOD_DISP_COLOR,
> > +	[DDP_COMPONENT_OVL0] = MT2701_MUTEX_MOD_DISP_OVL,
> > +	[DDP_COMPONENT_RDMA0] = MT2701_MUTEX_MOD_DISP_RDMA0,
> > +	[DDP_COMPONENT_RDMA1] = MT2701_MUTEX_MOD_DISP_RDMA1,
> > +	[DDP_COMPONENT_WDMA0] = MT2701_MUTEX_MOD_DISP_WDMA,
> > +};
> > +
> >  static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = {
> >  	[DDP_COMPONENT_AAL] = MT8173_MUTEX_MOD_DISP_AAL,
> >  	[DDP_COMPONENT_COLOR0] = MT8173_MUTEX_MOD_DISP_COLOR0,
> > @@ -109,6 +133,9 @@ static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur,
> >  	if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_COLOR0) {
> >  		*addr = DISP_REG_CONFIG_DISP_OVL0_MOUT_EN;
> >  		value = OVL0_MOUT_EN_COLOR0;
> > +	} else if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_RDMA0) {
> > +		*addr = DISP_REG_CONFIG_DISP_OVL_MOUT_EN;
> > +		value = OVL_MOUT_EN_RDMA;
> >  	} else if (cur == DDP_COMPONENT_OD && next == DDP_COMPONENT_RDMA0) {
> >  		*addr = DISP_REG_CONFIG_DISP_OD_MOUT_EN;
> >  		value = OD_MOUT_EN_RDMA0;
> > @@ -146,6 +173,9 @@ static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur,
> >  	} else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) {
> >  		*addr = DISP_REG_CONFIG_DISP_COLOR1_SEL_IN;
> >  		value = COLOR1_SEL_IN_OVL1;
> > +	} else if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0) {
> > +		*addr = DISP_REG_CONFIG_DSI_SEL;
> > +		value = DSI_SEL_IN_BLS;
> >  	} else {
> >  		value = 0;
> >  	}
> > @@ -153,6 +183,14 @@ static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur,
> >  	return value;
> >  }
> >  
> > +static void mtk_ddp_sout_sel(void __iomem *config_regs,
> > +			    enum mtk_ddp_comp_id cur, enum mtk_ddp_comp_id next)
> > +{
> > +	if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0)
> > +		writel_relaxed(BLS_TO_DSI_RDMA1_TO_DPI1,
> > +			       config_regs + DISP_REG_CONFIG_OUT_SEL);
> > +}
> 
> I think all the connection related modification should be an independent
> patch because it is common code. Like the shadow register patch
> (https://patchwork.kernel.org/patch/9231531/) , even MT8173 do not have
> that feature, we still split it out of this patch because it's not
> MT2701-only feature. I think these connection may happen in some MTK
> soc., so the connection related modification should not be placed in a
> MT2701 patch.
OK, will split it out to a common code patch.

Regards,
yt.shen
> 
> > +
> >  void mtk_ddp_add_comp_to_path(void __iomem *config_regs,
> >  			      enum mtk_ddp_comp_id cur,
> >  			      enum mtk_ddp_comp_id next)
> > @@ -165,6 +203,8 @@ void mtk_ddp_add_comp_to_path(void __iomem *config_regs,
> >  		writel_relaxed(reg, config_regs + addr);
> >  	}
> >  
> > +	mtk_ddp_sout_sel(config_regs, cur, next);
> > +
> >  	value = mtk_ddp_sel_in(cur, next, &addr);
> >  	if (value) {
> >  		reg = readl_relaxed(config_regs + addr) | value;
> > @@ -362,6 +402,7 @@ static int mtk_ddp_remove(struct platform_device *pdev)
> >  }
> >  
> >  static const struct of_device_id ddp_driver_dt_match[] = {
> > +	{ .compatible = "mediatek,mt2701-disp-mutex", .data = mt2701_mutex_mod},
> >  	{ .compatible = "mediatek,mt8173-disp-mutex", .data = mt8173_mutex_mod},
> >  	{},
> >  };
> > diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
> > index 4b4e449..465819b 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
> > @@ -112,6 +112,7 @@ struct mtk_ddp_comp_match {
> >  
> >  static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
> >  	[DDP_COMPONENT_AAL]	= { MTK_DISP_AAL,	0, NULL },
> > +	[DDP_COMPONENT_BLS]	= { MTK_DISP_PWM,	0, NULL },
> >  	[DDP_COMPONENT_COLOR0]	= { MTK_DISP_COLOR,	0, &ddp_color },
> >  	[DDP_COMPONENT_COLOR1]	= { MTK_DISP_COLOR,	1, &ddp_color },
> >  	[DDP_COMPONENT_DPI0]	= { MTK_DPI,		0, NULL },
> > @@ -130,11 +131,17 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
> >  	[DDP_COMPONENT_WDMA1]	= { MTK_DISP_WDMA,	1, NULL },
> >  };
> >  
> > +static const struct mtk_ddp_comp_driver_data mt2701_color_driver_data = {
> > +	.color_offset = 0x0f00,
> > +};
> > +
> >  static const struct mtk_ddp_comp_driver_data mt8173_color_driver_data = {
> >  	.color_offset = 0x0c00,
> >  };
> >  
> >  static const struct of_device_id mtk_disp_color_driver_dt_match[] = {
> > +	{ .compatible = "mediatek,mt2701-disp-color",
> > +	  .data = &mt2701_color_driver_data},
> >  	{ .compatible = "mediatek,mt8173-disp-color",
> >  	  .data = &mt8173_color_driver_data},
> >  	{},
> > diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
> > index 53065c7..0850aa4 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
> > +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
> > @@ -40,6 +40,7 @@ enum mtk_ddp_comp_type {
> >  
> >  enum mtk_ddp_comp_id {
> >  	DDP_COMPONENT_AAL,
> > +	DDP_COMPONENT_BLS,
> >  	DDP_COMPONENT_COLOR0,
> >  	DDP_COMPONENT_COLOR1,
> >  	DDP_COMPONENT_DPI0,
> > diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
> > index 80b4f54..13cf160 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
> > @@ -109,6 +109,19 @@ static const struct drm_mode_config_funcs mtk_drm_mode_config_funcs = {
> >  	.atomic_commit = mtk_atomic_commit,
> >  };
> >  
> > +static const enum mtk_ddp_comp_id mt2701_mtk_ddp_main[] = {
> > +	DDP_COMPONENT_OVL0,
> > +	DDP_COMPONENT_RDMA0,
> > +	DDP_COMPONENT_COLOR0,
> > +	DDP_COMPONENT_BLS,
> > +	DDP_COMPONENT_DSI0,
> > +};
> > +
> > +static const enum mtk_ddp_comp_id mt2701_mtk_ddp_ext[] = {
> > +	DDP_COMPONENT_RDMA1,
> > +	DDP_COMPONENT_DPI0,
> > +};
> > +
> >  static const enum mtk_ddp_comp_id mt8173_mtk_ddp_main[] = {
> >  	DDP_COMPONENT_OVL0,
> >  	DDP_COMPONENT_COLOR0,
> > @@ -128,6 +141,14 @@ static const enum mtk_ddp_comp_id mt8173_mtk_ddp_ext[] = {
> >  	DDP_COMPONENT_DPI0,
> >  };
> >  
> > +static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = {
> > +	.main_path = mt2701_mtk_ddp_main,
> > +	.main_len = ARRAY_SIZE(mt2701_mtk_ddp_main),
> > +	.ext_path = mt2701_mtk_ddp_ext,
> > +	.ext_len = ARRAY_SIZE(mt2701_mtk_ddp_ext),
> > +	.shadow_register = true,
> > +};
> > +
> >  static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = {
> >  	.main_path = mt8173_mtk_ddp_main,
> >  	.main_len = ARRAY_SIZE(mt8173_mtk_ddp_main),
> > @@ -331,16 +352,24 @@ static const struct component_master_ops mtk_drm_ops = {
> >  };
> >  
> >  static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
> > +	{ .compatible = "mediatek,mt2701-disp-ovl",   .data = (void *)MTK_DISP_OVL },
> >  	{ .compatible = "mediatek,mt8173-disp-ovl",   .data = (void *)MTK_DISP_OVL },
> > +	{ .compatible = "mediatek,mt2701-disp-rdma",  .data = (void *)MTK_DISP_RDMA },
> >  	{ .compatible = "mediatek,mt8173-disp-rdma",  .data = (void *)MTK_DISP_RDMA },
> > +	{ .compatible = "mediatek,mt2701-disp-wdma",  .data = (void *)MTK_DISP_WDMA },
> >  	{ .compatible = "mediatek,mt8173-disp-wdma",  .data = (void *)MTK_DISP_WDMA },
> > +	{ .compatible = "mediatek,mt2701-disp-color", .data = (void *)MTK_DISP_COLOR },
> >  	{ .compatible = "mediatek,mt8173-disp-color", .data = (void *)MTK_DISP_COLOR },
> >  	{ .compatible = "mediatek,mt8173-disp-aal",   .data = (void *)MTK_DISP_AAL},
> >  	{ .compatible = "mediatek,mt8173-disp-gamma", .data = (void *)MTK_DISP_GAMMA, },
> >  	{ .compatible = "mediatek,mt8173-disp-ufoe",  .data = (void *)MTK_DISP_UFOE },
> > +	{ .compatible = "mediatek,mt2701-dsi",	      .data = (void *)MTK_DSI },
> >  	{ .compatible = "mediatek,mt8173-dsi",        .data = (void *)MTK_DSI },
> > +	{ .compatible = "mediatek,mt2701-dpi",	      .data = (void *)MTK_DPI },
> >  	{ .compatible = "mediatek,mt8173-dpi",        .data = (void *)MTK_DPI },
> > +	{ .compatible = "mediatek,mt2701-disp-mutex", .data = (void *)MTK_DISP_MUTEX },
> >  	{ .compatible = "mediatek,mt8173-disp-mutex", .data = (void *)MTK_DISP_MUTEX },
> > +	{ .compatible = "mediatek,mt2701-disp-pwm",   .data = (void *)MTK_DISP_PWM },
> >  	{ .compatible = "mediatek,mt8173-disp-pwm",   .data = (void *)MTK_DISP_PWM },
> >  	{ .compatible = "mediatek,mt8173-disp-od",    .data = (void *)MTK_DISP_OD },
> >  	{ }
> > @@ -514,6 +543,8 @@ static SIMPLE_DEV_PM_OPS(mtk_drm_pm_ops, mtk_drm_sys_suspend,
> >  			 mtk_drm_sys_resume);
> >  
> >  static const struct of_device_id mtk_drm_of_ids[] = {
> > +	{ .compatible = "mediatek,mt2701-mmsys",
> > +	  .data = &mt2701_mmsys_driver_data},
> >  	{ .compatible = "mediatek,mt8173-mmsys",
> >  	  .data = &mt8173_mmsys_driver_data},
> >  	{ }
> 
> 




From yt.shen at mediatek.com  Tue Jul 19 04:12:38 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Tue, 19 Jul 2016 19:12:38 +0800
Subject: [PATCH v4 3/8] drm/mediatek: add shadow register support
In-Reply-To: <1468830992.2994.6.camel@pengutronix.de>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
 <1468577274-6178-4-git-send-email-yt.shen@mediatek.com>
 <1468823575.30644.33.camel@mtksdaap41>
 <1468830992.2994.6.camel@pengutronix.de>
Message-ID: <1468926758.24098.37.camel@mtksdaap41>

Hi Philipp, CK,

Thanks for the review.

On Mon, 2016-07-18 at 10:36 +0200, Philipp Zabel wrote:
> Hi CK, YT,
> 
> Am Montag, den 18.07.2016, 14:32 +0800 schrieb CK Hu:
> > Hi, YT:
> > 
> > One comment inline.
> > 
> > 
> > On Fri, 2016-07-15 at 18:07 +0800, YT Shen wrote:
> > > We need to acquire mutex before using the resources,
> > > and need to release it after finished.
> > > So we don't need to write registers in the blanking period.
> > > 
> > > Signed-off-by: YT Shen <yt.shen at mediatek.com>
> > > ---
> > >  drivers/gpu/drm/mediatek/mtk_drm_crtc.c |   75 +++++++++++++++++++------------
> > >  drivers/gpu/drm/mediatek/mtk_drm_ddp.c  |   22 +++++++++
> > >  drivers/gpu/drm/mediatek/mtk_drm_ddp.h  |    2 +
> > >  drivers/gpu/drm/mediatek/mtk_drm_drv.h  |    1 +
> > >  4 files changed, 71 insertions(+), 29 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> > > index 24aa3ba..80d9641 100644
> > > --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> > > +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> > > @@ -315,6 +315,42 @@ static void mtk_crtc_ddp_hw_fini(struct mtk_drm_crtc *mtk_crtc)
> > >  	pm_runtime_put(drm->dev);
> > >  }
> > >  
> > > +static void mtk_crtc_ddp_config(struct drm_crtc *crtc)
> > > +{
> > > +	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
> > > +	struct mtk_crtc_state *state = to_mtk_crtc_state(mtk_crtc->base.state);
> > > +	struct mtk_ddp_comp *ovl = mtk_crtc->ddp_comp[0];
> > > +	unsigned int i;
> > > +
> > > +	/*
> > > +	 * TODO: instead of updating the registers here, we should prepare
> > > +	 * working registers in atomic_commit and let the hardware command
> > > +	 * queue update module registers on vblank.
> > > +	 */
> > > +	if (state->pending_config) {
> > > +		mtk_ddp_comp_config(ovl, state->pending_width,
> > > +				    state->pending_height,
> > > +				    state->pending_vrefresh);
> > > +
> > > +		state->pending_config = false;
> > > +	}
> > > +
> > > +	if (mtk_crtc->pending_planes) {
> > > +		for (i = 0; i < OVL_LAYER_NR; i++) {
> > > +			struct drm_plane *plane = &mtk_crtc->planes[i].base;
> > > +			struct mtk_plane_state *plane_state;
> > > +
> > > +			plane_state = to_mtk_plane_state(plane->state);
> > > +
> > > +			if (plane_state->pending.config) {
> > > +				mtk_ddp_comp_layer_config(ovl, i, plane_state);
> > > +				plane_state->pending.config = false;
> > > +			}
> > > +		}
> > > +		mtk_crtc->pending_planes = false;
> > > +	}
> > > +}
> > > +
> > >  static void mtk_drm_crtc_enable(struct drm_crtc *crtc)
> > >  {
> > >  	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
> > > @@ -391,6 +427,7 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
> > >  				      struct drm_crtc_state *old_crtc_state)
> > >  {
> > >  	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
> > > +	struct mtk_drm_private *priv = crtc->dev->dev_private;
> > >  	unsigned int pending_planes = 0;
> > >  	int i;
> > >  
> > > @@ -409,6 +446,12 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
> > >  	}
> > >  	if (pending_planes)
> > >  		mtk_crtc->pending_planes = true;
> > > +
> > > +	if (priv->data->shadow_register) {
> > > +		mtk_disp_mutex_acquire(mtk_crtc->mutex);
> > > +		mtk_crtc_ddp_config(crtc);
> > > +		mtk_disp_mutex_release(mtk_crtc->mutex);
> > > +	}
> > >  }
> > >  
> > >  static const struct drm_crtc_funcs mtk_crtc_funcs = {
> > > @@ -453,36 +496,10 @@ err_cleanup_crtc:
> > >  void mtk_crtc_ddp_irq(struct drm_crtc *crtc, struct mtk_ddp_comp *ovl)
> > >  {
> > >  	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
> > > -	struct mtk_crtc_state *state = to_mtk_crtc_state(mtk_crtc->base.state);
> > > -	unsigned int i;
> > > +	struct mtk_drm_private *priv = crtc->dev->dev_private;
> > >  
> > > -	/*
> > > -	 * TODO: instead of updating the registers here, we should prepare
> > > -	 * working registers in atomic_commit and let the hardware command
> > > -	 * queue update module registers on vblank.
> > > -	 */
> > > -	if (state->pending_config) {
> > > -		mtk_ddp_comp_config(ovl, state->pending_width,
> > > -				    state->pending_height,
> > > -				    state->pending_vrefresh);
> > > -
> > > -		state->pending_config = false;
> > > -	}
> > > -
> > > -	if (mtk_crtc->pending_planes) {
> > > -		for (i = 0; i < OVL_LAYER_NR; i++) {
> > > -			struct drm_plane *plane = &mtk_crtc->planes[i].base;
> > > -			struct mtk_plane_state *plane_state;
> > > -
> > > -			plane_state = to_mtk_plane_state(plane->state);
> > > -
> > > -			if (plane_state->pending.config) {
> > > -				mtk_ddp_comp_layer_config(ovl, i, plane_state);
> > > -				plane_state->pending.config = false;
> > > -			}
> > > -		}
> > > -		mtk_crtc->pending_planes = false;
> > > -	}
> > > +	if (!priv->data->shadow_register)
> > > +		mtk_crtc_ddp_config(crtc);
> > >  
> > >  	mtk_drm_finish_page_flip(mtk_crtc);
> > >  }
> > > diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
> > > index 8030769..fa53806 100644
> > > --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
> > > +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
> > > @@ -12,6 +12,7 @@
> > >   */
> > >  
> > >  #include <linux/clk.h>
> > > +#include <linux/iopoll.h>
> > >  #include <linux/module.h>
> > >  #include <linux/of_device.h>
> > >  #include <linux/platform_device.h>
> > > @@ -32,6 +33,7 @@
> > >  #define DISP_REG_CONFIG_MMSYS_CG_CON0		0x100
> > >  
> > >  #define DISP_REG_MUTEX_EN(n)	(0x20 + 0x20 * (n))
> > > +#define DISP_REG_MUTEX(n)	(0x24 + 0x20 * (n))
> > >  #define DISP_REG_MUTEX_RST(n)	(0x28 + 0x20 * (n))
> > >  #define DISP_REG_MUTEX_MOD(n)	(0x2c + 0x20 * (n))
> > >  #define DISP_REG_MUTEX_SOF(n)	(0x30 + 0x20 * (n))
> > > @@ -300,6 +302,26 @@ void mtk_disp_mutex_disable(struct mtk_disp_mutex *mutex)
> > >  	writel(0, ddp->regs + DISP_REG_MUTEX_EN(mutex->id));
> > >  }
> > >  
> > > +void mtk_disp_mutex_acquire(struct mtk_disp_mutex *mutex)
> > > +{
> > > +	struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
> > > +					   mutex[mutex->id]);
> > > +	u32 tmp;
> > > +
> > > +	writel(1, ddp->regs + DISP_REG_MUTEX_EN(mutex->id));
> > > +	writel(1, ddp->regs + DISP_REG_MUTEX(mutex->id));
> > > +	readl_poll_timeout_atomic(ddp->regs + DISP_REG_MUTEX(mutex->id), tmp,
> > > +				  tmp & 0x2, 1, 10000);
> 
> Please add a descriptive #define for the 0x2 bit of the DISP_REG_MUTEX
> registers.
OK, will do.

> 
> > Nothing to do with timeout? I think it should print error message here
> > or reset HW to recover it.
I will print error messages here for future debugging.

> 
> I assume that if mtk_disp_mutex_acquire is called while the hardware has
> the mutex (during the shadow register update), this should wait until
> the update is complete, since it can't back out from trying to acquire
> the lock. Is that the case?
The acquire/release is handshake interface between software and hardware
to guarantee hardware receives a complete setting.  If software wants to
modify registers, it needs set a request and wait acknowledge.  And
after everything is done, software needs to notify hardware.  As far as
I know, this timeout means hardware is wrong, eg: no output signals.

> 
> regards
> Philipp
> 




From georgi.djakov at linaro.org  Tue Jul 19 09:27:31 2016
From: georgi.djakov at linaro.org (Georgi Djakov)
Date: Tue, 19 Jul 2016 19:27:31 +0300
Subject: [PATCH 2/3] mmc: mmc: do not use CMD13 to get status after speed
 mode switch
In-Reply-To: <CAPDyKFo0438H8odWks6HeD6E64+oyXYMHESv=pxqQyJe_9oaWA@mail.gmail.com>
References: <1463647662-27426-1-git-send-email-chaotian.jing@mediatek.com>
 <1463647662-27426-3-git-send-email-chaotian.jing@mediatek.com>
 <CAOCOHw67NAinC6dEX0KsDn02kuXyNwznm3-bhptSVvQH0V1dqQ@mail.gmail.com>
 <CAPDyKFroGBShATJcQ=b2H=k85F+z9=hixpp3Go-j79ZvvLGAwQ@mail.gmail.com>
 <578CDBD8.2050806@linaro.org>
 <CAPDyKFo0438H8odWks6HeD6E64+oyXYMHESv=pxqQyJe_9oaWA@mail.gmail.com>
Message-ID: <578E54F3.3000908@linaro.org>

On 07/19/2016 12:31 PM, Ulf Hansson wrote:
> On 18 July 2016 at 15:38, Georgi Djakov <georgi.djakov at linaro.org> wrote:
>> On 07/18/2016 03:50 PM, Ulf Hansson wrote:
>>> On 16 July 2016 at 00:10, Bjorn Andersson <bjorn.andersson at linaro.org> wrote:
>>>> On Thu, May 19, 2016 at 1:47 AM, Chaotian Jing
>>>> <chaotian.jing at mediatek.com> wrote:
>>>>> Per JEDEC spec, it is not recommended to use CMD13 to get card status
>>>>> after speed mode switch. below are two reason about this:
>>>>> 1. CMD13 cannot be guaranteed due to the asynchronous operation.
>>>>> Therefore it is not recommended to use CMD13 to check busy completion
>>>>> of the timing change indication.
>>>>> 2. After switch to HS200, CMD13 will get response of 0x800, and even the
>>>>> busy signal gets de-asserted, the response of CMD13 is aslo 0x800.
>>>>>
>>>>> Signed-off-by: Chaotian Jing <chaotian.jing at mediatek.com>
>>>>> ---
>>>>>  drivers/mmc/core/mmc.c | 112 ++++++++++++++++++++-----------------------------
>>>>>  1 file changed, 45 insertions(+), 67 deletions(-)
>>>>>
>>>>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>>>> [..]
>>>>> @@ -1274,20 +1254,18 @@ static int mmc_select_hs200(struct mmc_card *card)
>>>>>                 err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>>>>>                                    EXT_CSD_HS_TIMING, val,
>>>>>                                    card->ext_csd.generic_cmd6_time,
>>>>> -                                  true, send_status, true);
>>>>> +                                  true, false, true);
>>>>>                 if (err)
>>>>>                         goto err;
>>>>>                 old_timing = host->ios.timing;
>>>>>                 mmc_set_timing(host, MMC_TIMING_MMC_HS200);
>>>>> -               if (!send_status) {
>>>>> -                       err = mmc_switch_status(card);
>>>>> -                       /*
>>>>> -                        * mmc_select_timing() assumes timing has not changed if
>>>>> -                        * it is a switch error.
>>>>> -                        */
>>>>> -                       if (err == -EBADMSG)
>>>>> -                               mmc_set_timing(host, old_timing);
>>>>> -               }
>>>>> +               err = mmc_switch_status(card);
>>>>> +               /*
>>>>> +                * mmc_select_timing() assumes timing has not changed if
>>>>> +                * it is a switch error.
>>>>> +                */
>>>>> +               if (err == -EBADMSG)
>>>>> +                       mmc_set_timing(host, old_timing);
>>>>
>>>> Sorry for not spotting this earlier, but with the move of the call of
>>>> mmc_switch_status() to after mmc_set_timing() we get following error
>>>> with sdhci-msm:
>>>
>>> Thanks for reporting!
>>>
>>>>
>>>> mmc0: mmc_select_hs200 failed, error -110
>>>> mmc0: error -110 whilst initialising MMC card
>>>> mmc0: Reset 0x1 never completed.
>>>> sdhci: =========== REGISTER DUMP (mmc0)===========
>>>> sdhci: Sys addr: 0x00000000 | Version: 0x00002e02
>>>> sdhci: Blk size: 0x00004000 | Blk cnt: 0x00000000
>>>> sdhci: Argument: 0x00000000 | Trn mode: 0x00000000
>>>> sdhci: Present: 0x01f80000 | Host ctl: 0x00000000
>>>> sdhci: Power: 0x00000000 | Blk gap: 0x00000000
>>>> sdhci: Wake-up: 0x00000000 | Clock: 0x00000003
>>>> sdhci: Timeout: 0x00000000 | Int stat: 0x00000000
>>>> sdhci: Int enab: 0x00000000 | Sig enab: 0x00000000
>>>> sdhci: AC12 err: 0x00000000 | Slot int: 0x00000000
>>>> sdhci: Caps: 0x322dc8b2 | Caps_1: 0x00008007
>>>> sdhci: Cmd: 0x00000000 | Max curr: 0x00000000
>>>> sdhci: Host ctl2: 0x00000000
>>>> sdhci: ADMA Err: 0x00000000 | ADMA Ptr: 0x0000000000000000
>>>> sdhci: ===========================================
>>>>
>>>> But I if I understand the commit correctly this is the intention of
>>>> the patch (not the error, but the move).
>>>
>>> I tried dropping this change from my next branch, but there are some
>>> more changes on top that prevents a "clean" drop. It's certainly
>>> doable, but perhaps we can try to narrow down the problem to see if
>>> this could/should be fixed in the sdhci msm driver instead!?
>>
>> Yes, i am working on it. Seems that if we just ignore the -ETIMEDOUT
>> returned by mmc_switch_status() everything works as before. Currently
>> i am expecting more information about this controller specifics, in
>> order to understand if this could be fixed with a change in the driver
>> only.
> 
> Thanks for looking into this!
> 

Here is a partial fix, as it resolves the issue for the eMMC only.
https://patchwork.kernel.org/patch/9237679/
More investigation ongoing.

Thanks,
Georgi

>>
>>>
>>> I also noticed that below submitted change, which *isn't* applied for
>>> next, might be related.
>>> https://patchwork.kernel.org/patch/9197881/
>>>
>>
>> It is not related to this issue, but it is good to have when this is
>> resolved, otherwise we will see the dumpregs output (pr_err now),
>> when controller is initialized without a card in the SD slot.
> 
> Okay, thanks for clarifying. Although, I need an ack from Adrian
> before I apply it.
> 
>>
>> Thanks,
>> Georgi
> 
> Kind regards
> Uffe
> 



From tiffany.lin at mediatek.com  Tue Jul 19 09:44:14 2016
From: tiffany.lin at mediatek.com (tiffany lin)
Date: Wed, 20 Jul 2016 00:44:14 +0800
Subject: [PATCH] vcodec: mediatek: Add g/s_selection support for V4L2
 Encoder
In-Reply-To: <f2c031e2-82ca-90f4-0900-4dc961a90f58@xs4all.nl>
References: <1464594768-1993-1-git-send-email-tiffany.lin@mediatek.com>
 <4ca82842-968d-a5e2-587d-752c71713607@xs4all.nl>
 <1468477674.32454.36.camel@mtksdaap41>
 <bb96276a-8e6c-a535-6fd3-fe4327238f65@xs4all.nl>
 <1468844895.12740.15.camel@mtksdaap41>
 <f2c031e2-82ca-90f4-0900-4dc961a90f58@xs4all.nl>
Message-ID: <1468946654.30095.4.camel@mtksdaap41>

Hi Hans,

On Mon, 2016-07-18 at 14:44 +0200, Hans Verkuil wrote:
> On 07/18/2016 02:28 PM, tiffany lin wrote:
> > Understood now.
> > 
> > Now I am trying to figure out how to make this function right.
> > Our encoder only support crop range from (0, 0) to (width, height), so
> > if s->r.top and s->r.left not 0, I will return -EINVAL.
> > 
> > 
> > Another thing is that in v4l2-compliance test, it has testLegacyCrop.
> > It looks like we still need to support 
> >  V4L2_SEL_TGT_COMPOSE_DEFAULT:
> >  V4L2_SEL_TGT_COMPOSE_BOUNDS:
> >  V4L2_SEL_TGT_COMPOSE:
> > to pass v4l2 compliance test, Or it will fail in 
> > fail: v4l2-test-formats.cpp(1318): !doioctl(node, VIDIOC_G_SELECTION,
> > &sel)
> > fail: v4l2-test-formats.cpp(1336): testLegacyCrop(node)
> > test Cropping: FAIL
> 
> Against which kernel are you testing? In the current media_tree master
> there is a bug in drivers/media/v4l2-core/v4l2-ioctl.c, v4l_cropcap():
> 
> This code:
> 
> if (WARN_ON(!ops->vidioc_cropcap && !ops->vidioc_cropcap))
> 
> should be:
> 
> if (WARN_ON(!ops->vidioc_cropcap && !ops->vidioc_g_selection))
> 
> The fix is waiting for a pull from Linus.
> 
> Also update to the latest v4l2-compliance: I've made some changes that
> might affect this. And I added additional checks to verify if all the
> colorspace-related format fields are properly propagated from the
> output format to the capture format.
> 

Sorry, I miss this part.
After update to latest version include this fix, it can pass crop test
without supporting COMPOSE in output queue.
Appreciated for your help

best regards,
Tiffany



> Regards,
> 
> 	Hans
> 
> > 
> > I don't understand the following testing code.
> > 
> >         /*
> >          * If either CROPCAP or G_CROP works, then G_SELECTION should
> >          * work as well.
> >          * If neither CROPCAP nor G_CROP work, then G_SELECTION
> > shouldn't
> >          * work either.
> >          */
> >         if (!doioctl(node, VIDIOC_CROPCAP, &cap)) {
> >                 fail_on_test(doioctl(node, VIDIOC_G_SELECTION, &sel));
> > 
> >                 // Checks for invalid types
> >                 if (cap.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
> >                         cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
> >                 else
> >                         cap.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
> >                 fail_on_test(doioctl(node, VIDIOC_CROPCAP, &cap) !=
> > EINVAL);
> >                 cap.type = 0xff;
> >                 fail_on_test(doioctl(node, VIDIOC_CROPCAP, &cap) !=
> > EINVAL);
> >         } else {
> >                 fail_on_test(!doioctl(node, VIDIOC_G_SELECTION, &sel));
> > -> fail here
> >         }
> > 
> > When test OUTPUT queue, it fail because v4l_cropcap will fail when
> > s.target = V4L2_SEL_TGT_COMPOSE_BOUNDS.
> > If VIDIOC_CROPCAP ioctl fail, VIDIOC_G_SELECTION should fail.
> > But VIDIOC_G_SELECTION target on CROP not COMPOSE and it success.
> > 
> > 
> > best regards,
> > Tiffany
> > 
> > 
> > 
> >> Regards,
> >>
> >> 	Hans
> >>
> >>>
> >>>
> >>> static int v4l_g_crop(const struct v4l2_ioctl_ops *ops,
> >>> 				struct file *file, void *fh, void *arg)
> >>> {
> >>> 	struct v4l2_crop *p = arg;
> >>> 	struct v4l2_selection s = {
> >>> 		.type = p->type,
> >>> 	};
> >>> 	int ret;
> >>>
> >>> 	if (ops->vidioc_g_crop)
> >>> 		return ops->vidioc_g_crop(file, fh, p);
> >>> 	/* simulate capture crop using selection api */
> >>>
> >>> 	/* crop means compose for output devices */
> >>> 	if (V4L2_TYPE_IS_OUTPUT(p->type))
> >>> 		s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE;
> >>> 	else
> >>> 		s.target = V4L2_SEL_TGT_CROP_ACTIVE;
> >>>
> >>> 	ret = ops->vidioc_g_selection(file, fh, &s);
> >>>
> >>> 	/* copying results to old structure on success */
> >>> 	if (!ret)
> >>> 		p->c = s.r;
> >>> 	return ret;
> >>> }
> >>>
> >>> static int v4l_s_crop(const struct v4l2_ioctl_ops *ops,
> >>> 				struct file *file, void *fh, void *arg)
> >>> {
> >>> 	struct v4l2_crop *p = arg;
> >>> 	struct v4l2_selection s = {
> >>> 		.type = p->type,
> >>> 		.r = p->c,
> >>> 	};
> >>>
> >>> 	if (ops->vidioc_s_crop)
> >>> 		return ops->vidioc_s_crop(file, fh, p);
> >>> 	/* simulate capture crop using selection api */
> >>>
> >>> 	/* crop means compose for output devices */
> >>> 	if (V4L2_TYPE_IS_OUTPUT(p->type))
> >>> 		s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE;
> >>> 	else
> >>> 		s.target = V4L2_SEL_TGT_CROP_ACTIVE;
> >>>
> >>> 	return ops->vidioc_s_selection(file, fh, &s);
> >>> }
> >>>
> >>>
> >>> best regards,
> >>> Tiffany
> >>>
> >>>
> >>>
> >>>
> >>>> Regards,
> >>>>
> >>>> 	Hans
> >>>>
> >>>>> +
> >>>>> +	return 0;
> >>>>> +}
> >>>>> +
> >>>>>  static int vidioc_venc_qbuf(struct file *file, void *priv,
> >>>>>  			    struct v4l2_buffer *buf)
> >>>>>  {
> >>>>> @@ -688,6 +759,9 @@ const struct v4l2_ioctl_ops mtk_venc_ioctl_ops = {
> >>>>>  
> >>>>>  	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,
> >>>>>  	.vidioc_prepare_buf		= v4l2_m2m_ioctl_prepare_buf,
> >>>>> +
> >>>>> +	.vidioc_g_selection		= vidioc_venc_g_selection,
> >>>>> +	.vidioc_s_selection		= vidioc_venc_s_selection,
> >>>>>  };
> >>>>>  
> >>>>>  static int vb2ops_venc_queue_setup(struct vb2_queue *vq,
> >>>>>
> >>>
> >>>
> >>> --
> >>> 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
> >>>
> > 
> > 




From yong.wu at mediatek.com  Tue Jul 19 20:01:59 2016
From: yong.wu at mediatek.com (Yong Wu)
Date: Wed, 20 Jul 2016 11:01:59 +0800
Subject: [PATCH 1/3] memory: mediatek: Add a new interface
 mtk_smi_larb_is_ready
Message-ID: <1468983721-3627-1-git-send-email-yong.wu@mediatek.com>

Currently the iommu consumer always call iommu_present to get whether
the iommu is ready. But in MTK IOMMU, this function can't indicate
this. The IOMMU call bus_set_iommu->mtk_iommu_add_device->
mtk_iommu_attach_device to parse the iommu data, then it's able to
transfer "struct mtk_smi_iommu" to SMI-LARB, and the iommu uses the
larbs as compoents, the iommu will finish its probe until all the larbs
probe done.

If the iommu consumer(like DRM) begin to probe after the time of
calling bus_set_iommu and before the time of SMI probe finish, it
will hang like this:

[    7.832359] Call trace:
[    7.834778] [<ffffffc000764424>] mtk_smi_larb_get+0x24/0xa8
[    7.840300] [<ffffffc0005a1390>] mtk_drm_crtc_enable+0x6c/0x450

Because the larb->mmu is NULL at that time.

In order to avoid this issue, we add a new interface
(mtk_smi_larb_is_ready) for checking whether the IOMMU and SMI have
finished their probe. If it return false, the iommu consumer should
probe-defer for the IOMMU and SMI.

Signed-off-by: Yong Wu <yong.wu at mediatek.com>
---
Adding this interface is for avoid adjust the sequence of power
domain probe[1]. This patch-set is based on next-20160719. And
patch[1/3] base on [2], patch[3/3] base on [3], both are in the
pull tree.

[1]:http://lists.infradead.org/pipermail/linux-mediatek/2016-July/006189.html
[2]:https://patchwork.kernel.org/patch/9164067/
[3]:http://www.spinics.net/lists/arm-kernel/msg517840.html
---
 drivers/memory/mtk-smi.c   | 8 ++++++++
 include/soc/mediatek/smi.h | 8 ++++++++
 2 files changed, 16 insertions(+)

diff --git a/drivers/memory/mtk-smi.c b/drivers/memory/mtk-smi.c
index 4afbc41..3e58cbb7 100644
--- a/drivers/memory/mtk-smi.c
+++ b/drivers/memory/mtk-smi.c
@@ -141,6 +141,14 @@ void mtk_smi_larb_put(struct device *larbdev)
 }
 EXPORT_SYMBOL_GPL(mtk_smi_larb_put);
 
+bool mtk_smi_larb_is_ready(struct device *larbdev)
+{
+	struct mtk_smi_larb *larb = dev_get_drvdata(larbdev);
+
+	return larb && larb->mmu;
+}
+EXPORT_SYMBOL_GPL(mtk_smi_larb_is_ready);
+
 static int
 mtk_smi_larb_bind(struct device *dev, struct device *master, void *data)
 {
diff --git a/include/soc/mediatek/smi.h b/include/soc/mediatek/smi.h
index 8893c5e..f0690e0 100644
--- a/include/soc/mediatek/smi.h
+++ b/include/soc/mediatek/smi.h
@@ -33,6 +33,9 @@ struct mtk_smi_iommu {
 	struct mtk_smi_larb_iommu larb_imu[MTK_LARB_NR_MAX];
 };
 
+/* Whether SMI-larb has probe done. */
+bool mtk_smi_larb_is_ready(struct device *larbdev);
+
 /*
  * mtk_smi_larb_get: Enable the power domain and clocks for this local arbiter.
  *                   It also initialize some basic setting(like iommu).
@@ -46,6 +49,11 @@ void mtk_smi_larb_put(struct device *larbdev);
 
 #else
 
+static inline bool mtk_smi_larb_is_ready(struct device *larbdev)
+{
+	return false;
+}
+
 static inline int mtk_smi_larb_get(struct device *larbdev)
 {
 	return 0;
-- 
1.8.1.1.dirty



From yong.wu at mediatek.com  Tue Jul 19 20:02:00 2016
From: yong.wu at mediatek.com (Yong Wu)
Date: Wed, 20 Jul 2016 11:02:00 +0800
Subject: [PATCH 2/3] drm/mediatek: Add probe-defer for MTK IOMMU and SMI
In-Reply-To: <1468983721-3627-1-git-send-email-yong.wu@mediatek.com>
References: <1468983721-3627-1-git-send-email-yong.wu@mediatek.com>
Message-ID: <1468983721-3627-2-git-send-email-yong.wu@mediatek.com>

If DRM begin to probe before SMI probe done. It will hang:

[    7.832359] Call trace:
[    7.834778] [<ffffffc000764424>] mtk_smi_larb_get+0x24/0xa8
[    7.840300] [<ffffffc0005a1390>] mtk_drm_crtc_enable+0x6c/0x450

Use the new interface(mtk_smi_larb_is_ready) to wait for IOMMU and
SMI probe done.

Signed-off-by: Yong Wu <yong.wu at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
index 3970fcf..3ef3124 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
@@ -21,6 +21,7 @@
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <drm/drmP.h>
+#include <soc/mediatek/smi.h>
 #include "mtk_drm_drv.h"
 #include "mtk_drm_plane.h"
 #include "mtk_drm_ddp_comp.h"
@@ -201,6 +202,10 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
 	}
 	of_node_put(larb_node);
 
+	/* Wait until MTK IOMMU and SMI probe done.*/
+	if (!mtk_smi_larb_is_ready(&larb_pdev->dev))
+		return -EPROBE_DEFER;
+
 	comp->larb_dev = &larb_pdev->dev;
 
 	return 0;
-- 
1.8.1.1.dirty



From yong.wu at mediatek.com  Tue Jul 19 20:02:01 2016
From: yong.wu at mediatek.com (Yong Wu)
Date: Wed, 20 Jul 2016 11:02:01 +0800
Subject: [PATCH 3/3] vcodec: mediatek: Add probe-defer for MTK IOMMU and SMI
In-Reply-To: <1468983721-3627-1-git-send-email-yong.wu@mediatek.com>
References: <1468983721-3627-1-git-send-email-yong.wu@mediatek.com>
Message-ID: <1468983721-3627-3-git-send-email-yong.wu@mediatek.com>

Mediatek V4l2 depend on the IOMMU and SMI. we should add probe-defer
to wait for the IOMMU and SMI is ready.

Signed-off-by: Yong Wu <yong.wu at mediatek.com>
---
 drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
index 4c977b2..9e6203e 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
@@ -66,6 +66,11 @@ int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev)
 	pdev = mtkdev->plat_dev;
 	pm->dev = &pdev->dev;
 
+	/* Wait until MTK IOMMU and SMI probe done.*/
+	if (!mtk_smi_larb_is_ready(pm->larbvenc) ||
+	    !mtk_smi_larb_is_ready(pm->larbvenclt))
+		return -EPROBE_DEFER;
+
 	pm->vencpll_d2 = devm_clk_get(&pdev->dev, "venc_sel_src");
 	if (IS_ERR(pm->vencpll_d2)) {
 		mtk_v4l2_err("devm_clk_get vencpll_d2 fail");
-- 
1.8.1.1.dirty



From bibby.hsieh at mediatek.com  Tue Jul 19 21:03:01 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Wed, 20 Jul 2016 12:03:01 +0800
Subject: [PATCH 0/4] MT8173 HDMI 4K support
Message-ID: <1468987385-37353-1-git-send-email-bibby.hsieh@mediatek.com>

This is MT8173 HDMI 4K support PATCH, based on 4.7-rc1.

In order to support HDMI 4K on MT8173,
we have to make some modifications.
1) Make sure that mtk_hdmi_send_infoframe is sent successfully.
2) Enhance the HDMI driving current to improve performance.
3) Make sure that pixel clock is 297MHz when resolution is 4K.  
4) Adjust VENCPLL clock.

Bibby Hsieh (1):
  drm/mediatek: adjust VENCPLL clock for 4K HDMI output

Junzhi Zhao (3):
  drm/mediatek: do mtk_hdmi_send_infoframe after HDMI clock enable
  drm/mediatek: enhance the HDMI driving current
  drm/mediatek: fix the wrong pixel clock when resolution is 4K

 drivers/gpu/drm/mediatek/mtk_dpi.c             |  184 +++++++++++++++++-------
 drivers/gpu/drm/mediatek/mtk_drm_drv.c         |    9 ++
 drivers/gpu/drm/mediatek/mtk_drm_drv.h         |    1 +
 drivers/gpu/drm/mediatek/mtk_hdmi.c            |   19 ++-
 drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c |   89 ++++++++----
 5 files changed, 216 insertions(+), 86 deletions(-)

-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Tue Jul 19 21:03:05 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Wed, 20 Jul 2016 12:03:05 +0800
Subject: [PATCH 4/4] drm/mediatek: adjust VENCPLL clock for 4K HDMI output
In-Reply-To: <1468987385-37353-1-git-send-email-bibby.hsieh@mediatek.com>
References: <1468987385-37353-1-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1468987385-37353-5-git-send-email-bibby.hsieh@mediatek.com>

if MT8173 display module can support 4K HDMI output,
we have to adjust VENCPLL clock from default 660MHz
to 800MHz.

Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_drm_drv.c |    9 +++++++++
 drivers/gpu/drm/mediatek/mtk_drm_drv.h |    1 +
 2 files changed, 10 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index b1223d5..f159189 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -23,6 +23,7 @@
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <linux/pm_runtime.h>
+#include <linux/clk.h>
 
 #include "mtk_drm_crtc.h"
 #include "mtk_drm_ddp.h"
@@ -363,6 +364,14 @@ static int mtk_drm_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	private->vencpll_clk = devm_clk_get(dev, "vencpll");
+	if (IS_ERR(private->vencpll_clk)) {
+		ret = PTR_ERR(private->vencpll_clk);
+		dev_err(dev, "Failed to get vencpll clock: %d\n", ret);
+		return ret;
+	}
+	clk_set_rate(private->vencpll_clk, 800000000);
+
 	/* Iterate over sibling DISP function blocks */
 	for_each_child_of_node(dev->of_node->parent, node) {
 		const struct of_device_id *of_id;
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
index aa93894..273ad02 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
@@ -40,6 +40,7 @@ struct mtk_drm_private {
 	void __iomem *config_regs;
 	struct device_node *comp_node[DDP_COMPONENT_ID_MAX];
 	struct mtk_ddp_comp *ddp_comp[DDP_COMPONENT_ID_MAX];
+	struct clk *vencpll_clk;
 
 	struct {
 		struct drm_atomic_state *state;
-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Tue Jul 19 21:03:03 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Wed, 20 Jul 2016 12:03:03 +0800
Subject: [PATCH 2/4] drm/mediatek: enhance the HDMI driving current
In-Reply-To: <1468987385-37353-1-git-send-email-bibby.hsieh@mediatek.com>
References: <1468987385-37353-1-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1468987385-37353-3-git-send-email-bibby.hsieh@mediatek.com>

From: Junzhi Zhao <junzhi.zhao at mediatek.com>

In order to improve 4K resolution performance,
we have to enhance the HDMI driving currend
when clock rate is greater than 165MHz.

Signed-off-by: Junzhi Zhao <junzhi.zhao at mediatek.com>
Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c |   89 +++++++++++++++++-------
 1 file changed, 63 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
index 8a24754..a871c14 100644
--- a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
+++ b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
@@ -298,32 +298,69 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
 			  (0x1 << PLL_BR_SHIFT),
 			  RG_HDMITX_PLL_BP | RG_HDMITX_PLL_BC |
 			  RG_HDMITX_PLL_BR);
-	mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON3, RG_HDMITX_PRD_IMP_EN);
-	mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON4,
-			  (0x3 << PRD_IBIAS_CLK_SHIFT) |
-			  (0x3 << PRD_IBIAS_D2_SHIFT) |
-			  (0x3 << PRD_IBIAS_D1_SHIFT) |
-			  (0x3 << PRD_IBIAS_D0_SHIFT),
-			  RG_HDMITX_PRD_IBIAS_CLK |
-			  RG_HDMITX_PRD_IBIAS_D2 |
-			  RG_HDMITX_PRD_IBIAS_D1 |
-			  RG_HDMITX_PRD_IBIAS_D0);
-	mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON3,
-			  (0x0 << DRV_IMP_EN_SHIFT), RG_HDMITX_DRV_IMP_EN);
-	mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6,
-			  (hdmi_phy->drv_imp_clk << DRV_IMP_CLK_SHIFT) |
-			  (hdmi_phy->drv_imp_d2 << DRV_IMP_D2_SHIFT) |
-			  (hdmi_phy->drv_imp_d1 << DRV_IMP_D1_SHIFT) |
-			  (hdmi_phy->drv_imp_d0 << DRV_IMP_D0_SHIFT),
-			  RG_HDMITX_DRV_IMP_CLK | RG_HDMITX_DRV_IMP_D2 |
-			  RG_HDMITX_DRV_IMP_D1 | RG_HDMITX_DRV_IMP_D0);
-	mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON5,
-			  (hdmi_phy->ibias << DRV_IBIAS_CLK_SHIFT) |
-			  (hdmi_phy->ibias << DRV_IBIAS_D2_SHIFT) |
-			  (hdmi_phy->ibias << DRV_IBIAS_D1_SHIFT) |
-			  (hdmi_phy->ibias << DRV_IBIAS_D0_SHIFT),
-			  RG_HDMITX_DRV_IBIAS_CLK | RG_HDMITX_DRV_IBIAS_D2 |
-			  RG_HDMITX_DRV_IBIAS_D1 | RG_HDMITX_DRV_IBIAS_D0);
+	if (rate < 165000000) {
+		mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON3,
+					RG_HDMITX_PRD_IMP_EN);
+		mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON4,
+				  (0x3 << PRD_IBIAS_CLK_SHIFT) |
+				  (0x3 << PRD_IBIAS_D2_SHIFT) |
+				  (0x3 << PRD_IBIAS_D1_SHIFT) |
+				  (0x3 << PRD_IBIAS_D0_SHIFT),
+				  RG_HDMITX_PRD_IBIAS_CLK |
+				  RG_HDMITX_PRD_IBIAS_D2 |
+				  RG_HDMITX_PRD_IBIAS_D1 |
+				  RG_HDMITX_PRD_IBIAS_D0);
+		mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON3,
+				  (0x0 << DRV_IMP_EN_SHIFT),
+				  RG_HDMITX_DRV_IMP_EN);
+		mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6,
+				  (hdmi_phy->drv_imp_clk << DRV_IMP_CLK_SHIFT) |
+				  (hdmi_phy->drv_imp_d2 << DRV_IMP_D2_SHIFT) |
+				  (hdmi_phy->drv_imp_d1 << DRV_IMP_D1_SHIFT) |
+				  (hdmi_phy->drv_imp_d0 << DRV_IMP_D0_SHIFT),
+				  RG_HDMITX_DRV_IMP_CLK | RG_HDMITX_DRV_IMP_D2 |
+				  RG_HDMITX_DRV_IMP_D1 | RG_HDMITX_DRV_IMP_D0);
+		mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON5,
+				  (hdmi_phy->ibias << DRV_IBIAS_CLK_SHIFT) |
+				  (hdmi_phy->ibias << DRV_IBIAS_D2_SHIFT) |
+				  (hdmi_phy->ibias << DRV_IBIAS_D1_SHIFT) |
+				  (hdmi_phy->ibias << DRV_IBIAS_D0_SHIFT),
+				  RG_HDMITX_DRV_IBIAS_CLK |
+				  RG_HDMITX_DRV_IBIAS_D2 |
+				  RG_HDMITX_DRV_IBIAS_D1 |
+				  RG_HDMITX_DRV_IBIAS_D0);
+	} else {
+		mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON3,
+				      RG_HDMITX_PRD_IMP_EN);
+		mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON4,
+				  (0x6 << PRD_IBIAS_CLK_SHIFT) |
+				  (0x6 << PRD_IBIAS_D2_SHIFT) |
+				  (0x6 << PRD_IBIAS_D1_SHIFT) |
+				  (0x6 << PRD_IBIAS_D0_SHIFT),
+				  RG_HDMITX_PRD_IBIAS_CLK |
+				  RG_HDMITX_PRD_IBIAS_D2 |
+				  RG_HDMITX_PRD_IBIAS_D1 |
+				  RG_HDMITX_PRD_IBIAS_D0);
+		mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON3,
+				  (0xf << DRV_IMP_EN_SHIFT),
+				  RG_HDMITX_DRV_IMP_EN);
+		mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6,
+				  (hdmi_phy->drv_imp_clk << DRV_IMP_CLK_SHIFT) |
+				  (hdmi_phy->drv_imp_d2 << DRV_IMP_D2_SHIFT) |
+				  (hdmi_phy->drv_imp_d1 << DRV_IMP_D1_SHIFT) |
+				  (hdmi_phy->drv_imp_d0 << DRV_IMP_D0_SHIFT),
+				  RG_HDMITX_DRV_IMP_CLK | RG_HDMITX_DRV_IMP_D2 |
+				  RG_HDMITX_DRV_IMP_D1 | RG_HDMITX_DRV_IMP_D0);
+		mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON5,
+				  (hdmi_phy->ibias_up << DRV_IBIAS_CLK_SHIFT) |
+				  (hdmi_phy->ibias_up << DRV_IBIAS_D2_SHIFT) |
+				  (hdmi_phy->ibias_up << DRV_IBIAS_D1_SHIFT) |
+				  (hdmi_phy->ibias_up << DRV_IBIAS_D0_SHIFT),
+				  RG_HDMITX_DRV_IBIAS_CLK |
+				  RG_HDMITX_DRV_IBIAS_D2 |
+				  RG_HDMITX_DRV_IBIAS_D1 |
+				  RG_HDMITX_DRV_IBIAS_D0);
+	}
 	return 0;
 }
 
-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Tue Jul 19 21:03:04 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Wed, 20 Jul 2016 12:03:04 +0800
Subject: [PATCH 3/4] drm/mediatek: fix the wrong pixel clock when resolution
 is 4K
In-Reply-To: <1468987385-37353-1-git-send-email-bibby.hsieh@mediatek.com>
References: <1468987385-37353-1-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1468987385-37353-4-git-send-email-bibby.hsieh@mediatek.com>

From: Junzhi Zhao <junzhi.zhao at mediatek.com>

Pixel clock should be 297MHz when resolution is 4K.

Signed-off-by: Junzhi Zhao <junzhi.zhao at mediatek.com>
Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_dpi.c |  184 +++++++++++++++++++++++++-----------
 1 file changed, 131 insertions(+), 53 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index d05ca79..c0f04d2 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -60,14 +60,35 @@ enum mtk_dpi_out_color_format {
 	MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL
 };
 
+enum mtk_dpi_clk_id {
+	MTK_DPI_CLK_DPI_ENGINE,
+	MTK_DPI_CLK_DPI_PIXEL,
+	MTK_DPI_CLK_TVD_PLL,
+	MTK_DPI_CLK_TVDPLL_MUX,
+	MTK_DPI_CLK_TVDPLL_D2,
+	MTK_DPI_CLK_TVDPLL_D4,
+	MTK_DPI_CLK_TVDPLL_D8,
+	MTK_DPI_CLK_TVDPLL_D16,
+	MTK_DPI_CLK_COUNT,
+};
+
+static const char * const mtk_dpi_clk_names[MTK_DPI_CLK_COUNT] = {
+	[MTK_DPI_CLK_DPI_ENGINE] = "engine",
+	[MTK_DPI_CLK_DPI_PIXEL] = "pixel",
+	[MTK_DPI_CLK_TVD_PLL] = "pll",
+	[MTK_DPI_CLK_TVDPLL_MUX] = "tvdpll_mux",
+	[MTK_DPI_CLK_TVDPLL_D2] = "tvdpll_d2",
+	[MTK_DPI_CLK_TVDPLL_D4] = "tvdpll_d4",
+	[MTK_DPI_CLK_TVDPLL_D8] = "tvdpll_d8",
+	[MTK_DPI_CLK_TVDPLL_D16] = "tvdpll_d16",
+};
+
 struct mtk_dpi {
 	struct mtk_ddp_comp ddp_comp;
 	struct drm_encoder encoder;
 	void __iomem *regs;
 	struct device *dev;
-	struct clk *engine_clk;
-	struct clk *pixel_clk;
-	struct clk *tvd_clk;
+	struct clk *clk[MTK_DPI_CLK_COUNT];
 	int irq;
 	struct drm_display_mode mode;
 	enum mtk_dpi_out_color_format color_format;
@@ -76,6 +97,7 @@ struct mtk_dpi {
 	enum mtk_dpi_out_channel_swap channel_swap;
 	bool power_sta;
 	u8 power_ctl;
+	void *data;
 };
 
 static inline struct mtk_dpi *mtk_dpi_from_encoder(struct drm_encoder *e)
@@ -114,6 +136,11 @@ struct mtk_dpi_yc_limit {
 	u16 c_bottom;
 };
 
+struct mtk_dpi_conf {
+	int (*parse_clk_from_dt)(struct mtk_dpi *dpi, struct device_node *np);
+	int (*clk_config)(struct mtk_dpi *dpi, struct drm_display_mode *mode);
+};
+
 static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask)
 {
 	u32 tmp = readl(dpi->regs + offset) & ~mask;
@@ -377,8 +404,8 @@ static void mtk_dpi_power_off(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl)
 		return;
 
 	mtk_dpi_disable(dpi);
-	clk_disable_unprepare(dpi->pixel_clk);
-	clk_disable_unprepare(dpi->engine_clk);
+	clk_disable_unprepare(dpi->clk[MTK_DPI_CLK_DPI_PIXEL]);
+	clk_disable_unprepare(dpi->clk[MTK_DPI_CLK_DPI_ENGINE]);
 	dpi->power_sta = false;
 }
 
@@ -395,13 +422,13 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl)
 	if (dpi->power_sta)
 		return 0;
 
-	ret = clk_prepare_enable(dpi->engine_clk);
+	ret = clk_prepare_enable(dpi->clk[MTK_DPI_CLK_DPI_ENGINE]);
 	if (ret) {
 		dev_err(dpi->dev, "Failed to enable engine clock: %d\n", ret);
 		goto err_eng;
 	}
 
-	ret = clk_prepare_enable(dpi->pixel_clk);
+	ret = clk_prepare_enable(dpi->clk[MTK_DPI_CLK_DPI_PIXEL]);
 	if (ret) {
 		dev_err(dpi->dev, "Failed to enable pixel clock: %d\n", ret);
 		goto err_pixel;
@@ -412,7 +439,7 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl)
 	return 0;
 
 err_pixel:
-	clk_disable_unprepare(dpi->engine_clk);
+	clk_disable_unprepare(dpi->clk[MTK_DPI_CLK_DPI_ENGINE]);
 err_eng:
 	dpi->power_ctl &= ~pctl;
 	return ret;
@@ -428,34 +455,16 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
 	struct mtk_dpi_sync_param vsync_leven = { 0 };
 	struct mtk_dpi_sync_param vsync_rodd = { 0 };
 	struct mtk_dpi_sync_param vsync_reven = { 0 };
-	unsigned long pix_rate;
-	unsigned long pll_rate;
-	unsigned int factor;
+	struct mtk_dpi_conf *conf;
+	int ret;
 
 	if (!dpi) {
 		dev_err(dpi->dev, "invalid argument\n");
 		return -EINVAL;
 	}
 
-	pix_rate = 1000UL * mode->clock;
-	if (mode->clock <= 74000)
-		factor = 8 * 3;
-	else
-		factor = 4 * 3;
-	pll_rate = pix_rate * factor;
-
-	dev_dbg(dpi->dev, "Want PLL %lu Hz, pixel clock %lu Hz\n",
-		pll_rate, pix_rate);
-
-	clk_set_rate(dpi->tvd_clk, pll_rate);
-	pll_rate = clk_get_rate(dpi->tvd_clk);
-
-	pix_rate = pll_rate / factor;
-	clk_set_rate(dpi->pixel_clk, pix_rate);
-	pix_rate = clk_get_rate(dpi->pixel_clk);
-
-	dev_dbg(dpi->dev, "Got  PLL %lu Hz, pixel clock %lu Hz\n",
-		pll_rate, pix_rate);
+	conf = (struct mtk_dpi_conf *)dpi->data;
+	ret = conf->clk_config(dpi, mode);
 
 	limit.c_bottom = 0x0010;
 	limit.c_top = 0x0FE0;
@@ -656,20 +665,109 @@ static const struct component_ops mtk_dpi_component_ops = {
 	.unbind = mtk_dpi_unbind,
 };
 
+static int mt8173_parse_clk_from_dt(struct mtk_dpi *dpi, struct device_node *np)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mtk_dpi_clk_names); i++) {
+		dpi->clk[i] = of_clk_get_by_name(np,
+						  mtk_dpi_clk_names[i]);
+		if (IS_ERR(dpi->clk[i]))
+			return PTR_ERR(dpi->clk[i]);
+	}
+	return 0;
+}
+
+static int mt8173_clk_config(struct mtk_dpi *dpi, struct drm_display_mode *mode)
+{
+	unsigned long pix_rate;
+	unsigned long pll_rate;
+	unsigned int factor;
+	struct clk *parent;
+	int ret;
+
+	if (mode->clock <= 27000) {
+		factor = 16 * 3;
+		parent = dpi->clk[MTK_DPI_CLK_TVDPLL_D16];
+	} else if (mode->clock <= 74250) {
+		factor = 8 * 3;
+		parent = dpi->clk[MTK_DPI_CLK_TVDPLL_D8];
+	} else if (mode->clock <= 167000) {
+		factor = 4 * 3;
+		parent = dpi->clk[MTK_DPI_CLK_TVDPLL_D4];
+	} else {
+		factor = 2 * 3;
+		parent = dpi->clk[MTK_DPI_CLK_TVDPLL_D2];
+	}
+
+	pix_rate = 1000UL * mode->clock;
+	pll_rate = pix_rate * factor;
+
+	dev_dbg(dpi->dev, "Want PLL %lu Hz, pixel clock %lu Hz\n",
+		pll_rate, pix_rate);
+
+	ret = clk_prepare_enable(dpi->clk[MTK_DPI_CLK_TVDPLL_MUX]);
+	if (ret) {
+		dev_err(dpi->dev, "tvdpll_mux enable fail\n");
+		return ret;
+	}
+
+	ret = clk_set_parent(dpi->clk[MTK_DPI_CLK_TVDPLL_MUX], parent);
+	if (ret) {
+		dev_err(dpi->dev, "tvdpll_mux set parent fail\n");
+		return ret;
+	}
+	clk_disable_unprepare(dpi->clk[MTK_DPI_CLK_TVDPLL_MUX]);
+
+	ret = clk_set_rate(dpi->clk[MTK_DPI_CLK_TVD_PLL], pll_rate);
+	if (ret) {
+		dev_err(dpi->dev, "dpi pll_rate set rate fail\n");
+		return ret;
+	}
+	pll_rate = clk_get_rate(dpi->clk[MTK_DPI_CLK_TVD_PLL]);
+	pix_rate = clk_get_rate(dpi->clk[MTK_DPI_CLK_DPI_PIXEL]);
+
+	dev_dbg(dpi->dev, "Got  PLL %lu Hz, pixel clock %lu Hz\n",
+		pll_rate, pix_rate);
+
+	return 0;
+}
+
+static const struct mtk_dpi_conf mt8173_conf = {
+	.parse_clk_from_dt = mt8173_parse_clk_from_dt,
+	.clk_config = mt8173_clk_config,
+};
+
+static const struct of_device_id mtk_dpi_of_ids[] = {
+	{ .compatible = "mediatek,mt8173-dpi",
+		.data = &mt8173_conf,
+	},
+	{}
+};
+
 static int mtk_dpi_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct mtk_dpi *dpi;
 	struct resource *mem;
+	struct device_node *np = dev->of_node;
 	struct device_node *ep, *bridge_node = NULL;
 	int comp_id;
+	const struct of_device_id *match;
+	struct mtk_dpi_conf *conf;
 	int ret;
 
+	match = of_match_node(mtk_dpi_of_ids, dev->of_node);
+	if (!match)
+		return -ENODEV;
+
 	dpi = devm_kzalloc(dev, sizeof(*dpi), GFP_KERNEL);
 	if (!dpi)
 		return -ENOMEM;
 
 	dpi->dev = dev;
+	dpi->data = (void *)match->data;
+	conf = (struct mtk_dpi_conf *)match->data;
 
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	dpi->regs = devm_ioremap_resource(dev, mem);
@@ -679,24 +777,9 @@ static int mtk_dpi_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	dpi->engine_clk = devm_clk_get(dev, "engine");
-	if (IS_ERR(dpi->engine_clk)) {
-		ret = PTR_ERR(dpi->engine_clk);
-		dev_err(dev, "Failed to get engine clock: %d\n", ret);
-		return ret;
-	}
-
-	dpi->pixel_clk = devm_clk_get(dev, "pixel");
-	if (IS_ERR(dpi->pixel_clk)) {
-		ret = PTR_ERR(dpi->pixel_clk);
-		dev_err(dev, "Failed to get pixel clock: %d\n", ret);
-		return ret;
-	}
-
-	dpi->tvd_clk = devm_clk_get(dev, "pll");
-	if (IS_ERR(dpi->tvd_clk)) {
-		ret = PTR_ERR(dpi->tvd_clk);
-		dev_err(dev, "Failed to get tvdpll clock: %d\n", ret);
+	ret = conf->parse_clk_from_dt(dpi, np);
+	if (ret) {
+		dev_err(dev, "parse tvd div clk failed!");
 		return ret;
 	}
 
@@ -754,11 +837,6 @@ static int mtk_dpi_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static const struct of_device_id mtk_dpi_of_ids[] = {
-	{ .compatible = "mediatek,mt8173-dpi", },
-	{}
-};
-
 struct platform_driver mtk_dpi_driver = {
 	.probe = mtk_dpi_probe,
 	.remove = mtk_dpi_remove,
-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Tue Jul 19 21:03:02 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Wed, 20 Jul 2016 12:03:02 +0800
Subject: [PATCH 1/4] drm/mediatek: do mtk_hdmi_send_infoframe after HDMI clock
 enable
In-Reply-To: <1468987385-37353-1-git-send-email-bibby.hsieh@mediatek.com>
References: <1468987385-37353-1-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1468987385-37353-2-git-send-email-bibby.hsieh@mediatek.com>

From: Junzhi Zhao <junzhi.zhao at mediatek.com>

The mtk_hdmi_send_infoframe have to
be run after PLL and PIXEL clock of HDMI enable.
Make sure that HDMI inforframes can be sent
successfully.

Signed-off-by: Junzhi Zhao <junzhi.zhao at mediatek.com>
Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_hdmi.c |   19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
index ba812ef..d8609f5 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
@@ -1133,12 +1133,6 @@ static int mtk_hdmi_output_set_display_mode(struct mtk_hdmi *hdmi,
 	phy_power_on(hdmi->phy);
 	mtk_hdmi_aud_output_config(hdmi, mode);
 
-	mtk_hdmi_setup_audio_infoframe(hdmi);
-	mtk_hdmi_setup_avi_infoframe(hdmi, mode);
-	mtk_hdmi_setup_spd_infoframe(hdmi, "mediatek", "On-chip HDMI");
-	if (mode->flags & DRM_MODE_FLAG_3D_MASK)
-		mtk_hdmi_setup_vendor_specific_infoframe(hdmi, mode);
-
 	mtk_hdmi_hw_vid_black(hdmi, false);
 	mtk_hdmi_hw_aud_unmute(hdmi);
 	mtk_hdmi_hw_send_av_unmute(hdmi);
@@ -1401,14 +1395,25 @@ static void mtk_hdmi_bridge_pre_enable(struct drm_bridge *bridge)
 	hdmi->powered = true;
 }
 
+static void mtk_hdmi_send_infoframe(struct mtk_hdmi *hdmi,
+				    struct drm_display_mode *mode)
+{
+	mtk_hdmi_setup_audio_infoframe(hdmi);
+	mtk_hdmi_setup_avi_infoframe(hdmi, mode);
+	mtk_hdmi_setup_spd_infoframe(hdmi, "mediatek", "On-chip HDMI");
+	if (mode->flags & DRM_MODE_FLAG_3D_MASK)
+		mtk_hdmi_setup_vendor_specific_infoframe(hdmi, mode);
+}
+
 static void mtk_hdmi_bridge_enable(struct drm_bridge *bridge)
 {
 	struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
 
+	phy_power_on(hdmi->phy);
 	mtk_hdmi_output_set_display_mode(hdmi, &hdmi->mode);
 	clk_prepare_enable(hdmi->clk[MTK_HDMI_CLK_HDMI_PLL]);
 	clk_prepare_enable(hdmi->clk[MTK_HDMI_CLK_HDMI_PIXEL]);
-	phy_power_on(hdmi->phy);
+	mtk_hdmi_send_infoframe(hdmi, &hdmi->mode);
 
 	hdmi->enabled = true;
 }
-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Tue Jul 19 21:06:11 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Wed, 20 Jul 2016 12:06:11 +0800
Subject: [PATCH] arm64: dts: mt8173: add tvdpll and vencpll clocks for 4K
 support
Message-ID: <1468987571-39104-1-git-send-email-bibby.hsieh@mediatek.com>

From: Junzhi Zhao <junzhi.zhao at mediatek.com>

When the resolution is set to 4k*2k, the hdmi
pixel clock will be 250MHz, however, the correct
pixel clock should be 297MHz. Fix this error by
adding the correct tvdpll clocks.
If MT8173 can support 4K, the vencpll clock should
be 800MHz. Add the vencpll clocks to support 4K.

Signed-off-by: Junzhi Zhao <junzhi.zhao at mediatek.com>
Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
---
 arch/arm64/boot/dts/mediatek/mt8173.dtsi |   18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
index 78529e4..e79bacf 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -690,6 +690,8 @@
 			compatible = "mediatek,mt8173-mmsys", "syscon";
 			reg = <0 0x14000000 0 0x1000>;
 			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+			clocks = <&topckgen CLK_TOP_VENCPLL>;
+			clock-names = "vencpll";
 			#clock-cells = <1>;
 		};
 
@@ -857,10 +859,22 @@
 			reg = <0 0x1401d000 0 0x1000>;
 			interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_LOW>;
 			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
-			clocks = <&mmsys CLK_MM_DPI_PIXEL>,
+			clocks = <&topckgen CLK_TOP_TVDPLL_D2>,
+				 <&topckgen CLK_TOP_TVDPLL_D4>,
+				 <&topckgen CLK_TOP_TVDPLL_D8>,
+				 <&topckgen CLK_TOP_TVDPLL_D16>,
+				 <&topckgen CLK_TOP_DPI0_SEL>,
+				 <&mmsys CLK_MM_DPI_PIXEL>,
 				 <&mmsys CLK_MM_DPI_ENGINE>,
 				 <&apmixedsys CLK_APMIXED_TVDPLL>;
-			clock-names = "pixel", "engine", "pll";
+			clock-names = "tvdpll_d2",
+				      "tvdpll_d4",
+				      "tvdpll_d8",
+				      "tvdpll_d16",
+				      "tvdpll_mux",
+				      "pixel",
+				      "engine",
+				      "pll";
 			status = "disabled";
 		};
 
-- 
1.7.9.5



From ck.hu at mediatek.com  Tue Jul 19 22:59:06 2016
From: ck.hu at mediatek.com (CK Hu)
Date: Wed, 20 Jul 2016 13:59:06 +0800
Subject: [PATCH v4 6/8] drm/mediatek: add dsi transfer function
In-Reply-To: <1468577274-6178-7-git-send-email-yt.shen@mediatek.com>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
 <1468577274-6178-7-git-send-email-yt.shen@mediatek.com>
Message-ID: <1468994346.11841.31.camel@mtksdaap41>

Hi, YT:

Some comments inline.

On Fri, 2016-07-15 at 18:07 +0800, YT Shen wrote:
> From: shaoming chen <shaoming.chen at mediatek.com>
> 
> add dsi read/write commands for transfer function
> 
> Signed-off-by: shaoming chen <shaoming.chen at mediatek.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_dsi.c |  322 ++++++++++++++++++++++++++++++++++++
>  1 file changed, 322 insertions(+)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
> index de5ad7f..1f99894 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dsi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
> @@ -24,6 +24,7 @@
>  #include <linux/of_graph.h>
>  #include <linux/phy/phy.h>
>  #include <linux/platform_device.h>
> +#include <video/mipi_display.h>
>  #include <video/videomode.h>
>  
>  #include "mtk_drm_ddp_comp.h"
> @@ -80,8 +81,16 @@
>  #define DSI_HBP_WC		0x54
>  #define DSI_HFP_WC		0x58
>  
> +#define DSI_CMDQ_SIZE		0x60
> +#define CMDQ_SIZE		0x3f
> +
>  #define DSI_HSTX_CKL_WC		0x64
>  
> +#define DSI_RX_DATA0		0x74
> +#define DSI_RX_DATA1		0x78
> +#define DSI_RX_DATA2		0x7c
> +#define DSI_RX_DATA3		0x80
> +
>  #define DSI_RACK		0x84
>  #define RACK			BIT(0)
>  
> @@ -117,8 +126,25 @@
>  #define CLK_HS_POST			(0xff << 8)
>  #define CLK_HS_EXIT			(0xff << 16)
>  
> +#define DSI_CMDQ0		0x180
> +
>  #define NS_TO_CYCLE(n, c)    ((n) / (c) + (((n) % (c)) ? 1 : 0))
>  
> +#define MTK_DSI_HOST_IS_READ(type) \
> +	((type == MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM) || \
> +	(type == MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM) || \
> +	(type == MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM) || \
> +	(type == MIPI_DSI_DCS_READ))
> +
> +#define MTK_DSI_HOST_IS_WRITE(type) \
> +	((type == MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM) || \
> +	(type == MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM) || \
> +	(type == MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM) || \
> +	(type == MIPI_DSI_DCS_SHORT_WRITE) || \
> +	(type == MIPI_DSI_DCS_SHORT_WRITE_PARAM) || \
> +	(type == MIPI_DSI_GENERIC_LONG_WRITE) || \
> +	(type == MIPI_DSI_DCS_LONG_WRITE))
> +
>  struct phy;
>  
>  struct mtk_dsi {
> @@ -148,6 +174,38 @@ struct mtk_dsi {
>  	int irq_num, irq_data;
>  };
>  
> +struct dsi_cmd_t0 {
> +	u8 config;
> +	u8 type;
> +	u8 data0;
> +	u8 data1;
> +};
> +
> +struct dsi_cmd_t2 {
> +	u8 config;
> +	u8 type;
> +	u16 wc16;
> +	u8 *pdata;
> +};
> +
> +struct dsi_rx_data {
> +	u8 byte0;
> +	u8 byte1;
> +	u8 byte2;
> +	u8 byte3;
> +};
> +
> +struct dsi_tx_cmdq {
> +	u8 byte0;
> +	u8 byte1;
> +	u8 byte2;
> +	u8 byte3;
> +};
> +
> +struct dsi_tx_cmdq_regs {
> +	struct dsi_tx_cmdq data[128];
> +};
> +
>  enum {
>  	DSI_INT_SLEEPOUT_DONE_FLAG	= BIT(6),
>  	DSI_INT_VM_CMD_DONE_FLAG	= BIT(5),
> @@ -858,9 +916,273 @@ static int mtk_dsi_host_detach(struct mipi_dsi_host *host,
>  	return 0;
>  }
>  
> +static void mtk_dsi_set_cmdq(void __iomem *reg, u32 mask, u32 data)
> +{
> +	u32 temp = readl(reg);
> +
> +	writel((temp & ~mask) | (data & mask), reg);
> +}
> +
> +static void mtk_dsi_wait_for_idle(struct mtk_dsi *dsi)
> +{
> +	u32 timeout_ms = 500000; /* total 1s ~ 2s timeout */
> +
> +	while (timeout_ms--) {
> +		if (!(readl(dsi->regs + DSI_INTSTA) & DSI_BUSY))
> +			break;
> +
> +		usleep_range(2, 4);
> +	}
> +
> +	if (timeout_ms == 0) {
> +		dev_info(dsi->dev, "polling dsi wait not busy timeout!\n");
> +
> +		mtk_dsi_enable(dsi);
> +		mtk_dsi_reset_engine(dsi);
> +	}
> +}
> +
> +static ssize_t mtk_dsi_host_read_cmd(struct mtk_dsi *dsi,
> +				     const struct mipi_dsi_msg *msg)
> +{
> +	u8 max_try_count = 5;
> +	u32 recv_data_cnt, tmp_val;
> +	u32 recv_data0, recv_data1, recv_data2, recv_data3;
> +	struct dsi_rx_data read_data0, read_data1, read_data2, read_data3;
> +	struct dsi_cmd_t0 t0;
> +	s32 ret;
> +
> +	u8 *buffer = msg->rx_buf;
> +	u8 buffer_size = msg->rx_len;
> +	u8 packet_type;
> +
> +	if (readl(dsi->regs + DSI_MODE_CTRL) & 0x03) {
> +		dev_info(dsi->dev, "dsi engine is not command mode\n");
> +		return -1;
> +	}
> +
> +	if (!buffer) {
> +		dev_info(dsi->dev, "dsi receive buffer size may be NULL\n");
> +		return -1;
> +	}
> +
> +	do {
> +		if (max_try_count == 0) {
> +			dev_info(dsi->dev, "dsi engine read counter has been maxinum\n");
> +			return -1;
> +		}
> +
> +		max_try_count--;
> +		recv_data_cnt = 0;
> +
> +		mtk_dsi_wait_for_idle(dsi);
> +
> +		t0.config = 0x04;
> +		t0.data0 = *((u8 *)(msg->tx_buf));
> +
> +		if (buffer_size < 0x3)

It's better to use '3' instead of '0x3'.

> +			t0.type = MIPI_DSI_DCS_READ;
> +		else
> +			t0.type = MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM;
> +
> +		t0.data1 = 0;
> +
> +		tmp_val = (t0.data1 << 24) | (t0.data0 << 16) | (t0.type << 8) |
> +			t0.config;

Why need 'struct dsi_cmd_t0 t0'? I think code is more simple when get
rid of this structure. The code looks like:

tmp_val = (data1 << 24) | (data0 << 16) | (type << 8) | config;

> +
> +		writel(tmp_val, dsi->regs + DSI_CMDQ0);
> +		mtk_dsi_mask(dsi, DSI_CMDQ_SIZE, CMDQ_SIZE, 1);
> +
> +		mtk_dsi_mask(dsi, DSI_RACK, RACK, RACK);
> +		mtk_dsi_mask(dsi, DSI_INTSTA, LPRX_RD_RDY_INT_FLAG,
> +			     ~LPRX_RD_RDY_INT_FLAG);
> +		mtk_dsi_mask(dsi, DSI_INTSTA, CMD_DONE_INT_FLAG,
> +			     ~CMD_DONE_INT_FLAG);

I think interrupt status should be cleared in irq handler. So you need
not to clear it here.

> +		mtk_dsi_mask(dsi, DSI_INTEN, DSI_INT_LPRX_RD_RDY_FLAG,
> +			     DSI_INT_LPRX_RD_RDY_FLAG);
> +		mtk_dsi_mask(dsi, DSI_INTEN, DSI_INT_CMD_DONE_FLAG,
> +			     DSI_INT_CMD_DONE_FLAG);

Why enable cmd_done interrupt? You just need interrupt of LPRX_RD_RDY.

> +
> +		mtk_dsi_start(dsi);
> +
> +		dev_info(dsi->dev, "Start polling DSI read ready!!!\n");
> +
> +		 /* 2s timeout*/
> +		ret = mtk_dsi_wait_for_irq_timeout(dsi,
> +						   DSI_INT_LPRX_RD_RDY_FLAG,
> +						   2000);
> +		if (ret) {
> +			dev_info(dsi->dev, "Polling DSI read ready timeout!!!\n");
> +
> +			mtk_dsi_enable(dsi);
> +			mtk_dsi_reset_engine(dsi);
> +
> +			return ret;
> +		}
> +
> +		dev_info(dsi->dev, "End polling DSI read ready!!!\n");
> +
> +		mtk_dsi_mask(dsi, DSI_RACK, RACK, RACK);
> +		mtk_dsi_mask(dsi, DSI_INTSTA, LPRX_RD_RDY_INT_FLAG,
> +			     ~LPRX_RD_RDY_INT_FLAG);
> +
> +		recv_data0 = readl(dsi->regs + DSI_RX_DATA0);
> +		recv_data1 = readl(dsi->regs + DSI_RX_DATA1);
> +		recv_data2 = readl(dsi->regs + DSI_RX_DATA2);
> +		recv_data3 = readl(dsi->regs + DSI_RX_DATA3);
> +
> +		read_data0 = *((struct dsi_rx_data *)(&recv_data0));
> +		read_data1 = *((struct dsi_rx_data *)(&recv_data1));
> +		read_data2 = *((struct dsi_rx_data *)(&recv_data2));
> +		read_data3 = *((struct dsi_rx_data *)(&recv_data3));

You only use read_data0. read_data1, read_data2, and read_data3 are just
for debug. Remove the debug only modification if they are not necessary.
Or move them to another patch to make this patch clear.

> +
> +		ret = readl(dsi->regs + DSI_CMDQ_SIZE);
> +		dev_info(dsi->dev, "DSI_CMDQ_SIZE : 0x%x\n", ret & CMDQ_SIZE);
> +
> +		ret = readl(dsi->regs + DSI_CMDQ0);
> +		dev_info(dsi->dev, "DSI_CMDQ_DATA0 : 0x%x\n",
> +			 ret & 0xff);
> +		dev_info(dsi->dev, "DSI_CMDQ_DATA1 : 0x%x\n",
> +			 (ret >> 8) & 0xff);
> +		dev_info(dsi->dev, "DSI_CMDQ_DATA2 : 0x%x\n",
> +			 (ret >> 16) & 0xff);
> +		dev_info(dsi->dev, "DSI_CMDQ_DATA3 : 0x%x\n",
> +			 (ret >> 24) & 0xff);
> +
> +		dev_info(dsi->dev, "DSI_RX_DATA0: 0x%x\n", recv_data0);
> +		dev_info(dsi->dev, "DSI_RX_DATA1: 0x%x\n", recv_data1);
> +		dev_info(dsi->dev, "DSI_RX_DATA2: 0x%x\n", recv_data2);
> +		dev_info(dsi->dev, "DSI_RX_DATA3: 0x%x\n", recv_data3);
> +
> +		dev_info(dsi->dev, "read_data0: %x,%x,%x,%x\n",
> +			 read_data0.byte0, read_data0.byte1, read_data0.byte2,
> +			 read_data0.byte3);
> +		dev_info(dsi->dev, "read_data1: %x,%x,%x,%x\n",
> +			 read_data1.byte0, read_data1.byte1, read_data1.byte2,
> +			 read_data1.byte3);
> +		dev_info(dsi->dev, "read_data2: %x,%x,%x,%x\n",
> +			 read_data2.byte0, read_data2.byte1, read_data2.byte2,
> +			 read_data2.byte3);
> +		dev_info(dsi->dev, "read_data3: %x,%x,%x,%x\n",
> +			 read_data3.byte0, read_data3.byte1, read_data3.byte2,
> +			 read_data3.byte3);
> +
> +		packet_type = read_data0.byte0;
> +		dev_info(dsi->dev, "DSI read packet_type is 0x%x\n",
> +			 packet_type);
> +
> +		if (packet_type == 0x1a || packet_type == 0x1c) {
> +			void *read_tmp = (void *)&recv_data1;
> +
> +			recv_data_cnt = read_data0.byte1 +
> +					read_data0.byte2 * 16;
> +			if (recv_data_cnt > 10)
> +				recv_data_cnt = 10;

Why do you drop data over size of 10? Isn't it an error?

> +
> +			if (recv_data_cnt > buffer_size)
> +				recv_data_cnt = buffer_size;

Isn't it an error while you drop data over the buffer size?

> +
> +			memcpy(buffer, read_tmp, recv_data_cnt);
> +		} else {
> +			/* short  packet */
> +			recv_data_cnt = 2;
> +			if (recv_data_cnt > buffer_size)
> +				recv_data_cnt = buffer_size;

Isn't it an error while you drop data over the buffer size?

> +
> +			memcpy(buffer, &read_data0.byte1, 2);

If buffer_size is 1, why do you still copy 2 bytes?

> +		}
> +	} while (packet_type != 0x1c && packet_type != 0x21 &&
> +		packet_type != 0x22 && packet_type != 0x1a);

Could you give these magic number a descriptive name?

> +
> +	dev_info(dsi->dev, "dsi get %d byte data from the panel address(0x%x)\n",
> +		 recv_data_cnt, *((u8 *)(msg->tx_buf)));
> +
> +	return recv_data_cnt;
> +}
> +
> +static ssize_t mtk_dsi_host_write_cmd(struct mtk_dsi *dsi,
> +				      const struct mipi_dsi_msg *msg)
> +{
> +	u32 i;
> +	u32 goto_addr, mask_para, set_para, reg_val;
> +	void __iomem *cmdq_reg;
> +	struct dsi_cmd_t0 t0;
> +	struct dsi_cmd_t2 t2;
> +	const char *tx_buf = msg->tx_buf;
> +	struct dsi_tx_cmdq_regs *dsi_cmd_reg;
> +
> +	dsi_cmd_reg = (struct dsi_tx_cmdq_regs *)(dsi->regs + DSI_CMDQ0);
> +
> +	mtk_dsi_wait_for_idle(dsi);
> +
> +	if (msg->tx_len > 2) {
> +		t2.config = 2;
> +		t2.type = msg->type;
> +		t2.wc16 = msg->tx_len;
> +
> +		reg_val = (t2.wc16 << 16) | (t2.type << 8) | t2.config;

Why need 'struct dsi_cmd_t2 t2'? I think code is more simple when get
rid of this structure. The code looks like:

reg_val = (wc16 << 16) | (type << 8) | config;

> +
> +		writel(reg_val, &dsi_cmd_reg->data[0]);
> +
> +		goto_addr = (u32)(&dsi_cmd_reg->data[1].byte0);
> +		mask_para = (0xff << ((goto_addr & 0x3) * 8));
> +		set_para = (tx_buf[0] << ((goto_addr & 0x3) * 8));
> +		cmdq_reg = (void __iomem *)(goto_addr & (~0x3));
> +		mtk_dsi_set_cmdq(cmdq_reg, mask_para, set_para);

I think you can merge this setting into 'for loop' and the loop look
like this:

for (i = 0; i < msg->tx_len; i++) {
	goto_addr = (u32)(&dsi_cmd_reg->data[1].byte0) + i;
	mask_para = (0xff << ((goto_addr & 0x3) * 8));
	set_para = (tx_buf[i] << ((goto_addr & 0x3) * 8));
	cmdq_reg = (void __iomem *)(goto_addr & (~0x3));
	mtk_dsi_set_cmdq(cmdq_reg, mask_para, set_para);
}

> +
> +		for (i = 1; i < msg->tx_len; i++) {
> +			goto_addr = (u32)(&dsi_cmd_reg->data[1].byte1) + i - 1;
> +			mask_para = (0xff << ((goto_addr & 0x3) * 8));
> +			set_para = (tx_buf[i] << ((goto_addr & 0x3) * 8));
> +			cmdq_reg = (void __iomem *)(goto_addr & (~0x3));
> +			mtk_dsi_set_cmdq(cmdq_reg, mask_para, set_para);
> +		}
> +
> +		mtk_dsi_mask(dsi, DSI_CMDQ_SIZE, CMDQ_SIZE,
> +			     2 + (msg->tx_len - 1) / 4);

I think it is better to change formula of DSI_CMDQ_SIZE to '1 +
(msg->tx_len + 3) / 4'. The '1' means the first cmd which describe the
size of tx_buf, and the rest means the other cmds for body of tx_buf.

> +	} else {
> +		t0.config = 0;
> +		t0.data0 = tx_buf[0];
> +		if (msg->tx_len == 2) {
> +			t0.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM;
> +			t0.data1 = tx_buf[1];
> +		} else {
> +			t0.type = MIPI_DSI_DCS_SHORT_WRITE;
> +			t0.data1 = 0;
> +		}
> +
> +		reg_val = (t0.data1 << 24) | (t0.data0 << 16) | (t0.type << 8) |
> +			   t0.config;
> +
> +		writel(reg_val, &dsi_cmd_reg->data[0]);
> +		mtk_dsi_mask(dsi, DSI_CMDQ_SIZE, CMDQ_SIZE, 1);
> +	}
> +
> +	mtk_dsi_start(dsi);
> +	mtk_dsi_wait_for_idle(dsi);
> +
> +	return 0;
> +}
> +
> +static ssize_t mtk_dsi_host_transfer(struct mipi_dsi_host *host,
> +				     const struct mipi_dsi_msg *msg)
> +{
> +	struct mtk_dsi *dsi = host_to_dsi(host);
> +	u8 type = msg->type;
> +	ssize_t ret = 0;
> +
> +	if (MTK_DSI_HOST_IS_READ(type))
> +		ret = mtk_dsi_host_read_cmd(dsi, msg);
> +	else if (MTK_DSI_HOST_IS_WRITE(type))
> +		ret = mtk_dsi_host_write_cmd(dsi, msg);
> +
> +	return ret;
> +}
> +
>  static const struct mipi_dsi_host_ops mtk_dsi_ops = {
>  	.attach = mtk_dsi_host_attach,
>  	.detach = mtk_dsi_host_detach,
> +	.transfer = mtk_dsi_host_transfer,
>  };
>  
>  static int mtk_dsi_bind(struct device *dev, struct device *master, void *data)


Regards,
CK



From zhiyong.tao at mediatek.com  Tue Jul 19 23:02:38 2016
From: zhiyong.tao at mediatek.com (zhiyong tao)
Date: Wed, 20 Jul 2016 14:02:38 +0800
Subject: [PATCH v4 2/3] iio: adc: mt2701: Add Mediatek auxadc driver for
 mt2701.
In-Reply-To: <82fa5ffa-52be-e1ec-83dd-dd92b3f3ef5d@kernel.org>
References: <1468219197-9572-1-git-send-email-zhiyong.tao@mediatek.com>
 <1468219197-9572-3-git-send-email-zhiyong.tao@mediatek.com>
 <82fa5ffa-52be-e1ec-83dd-dd92b3f3ef5d@kernel.org>
Message-ID: <1468994558.419.30.camel@mhfsdcap03>

On Mon, 2016-07-18 at 18:12 +0100, Jonathan Cameron wrote:
> On 11/07/16 07:39, Zhiyong Tao wrote:
> > Add Mediatek auxadc driver based on iio.
> > It will register a device in iio and support iio.
> > So thermal can read auxadc channel to sample data by iio device.
> > It is tested successfully on mt2701 platform.
> > Mt8173 and mt6577 platforms are not tested.
> > But the expectation is compatible.
> > 
> > Signed-off-by: Zhiyong Tao <zhiyong.tao at mediatek.com>
> Looks good to me.  Couple of really minor points / questions inline...
> 
> Just one thing to confirm... (you probably already answered this!)
> What are the units of the voltage channels?
> 
> Jonathan

The units of the voltage channels are mv. 

> > ---
> >  drivers/iio/adc/Kconfig         |   13 ++
> >  drivers/iio/adc/Makefile        |    1 +
> >  drivers/iio/adc/mt6577_auxadc.c |  294 +++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 308 insertions(+)
> >  create mode 100644 drivers/iio/adc/mt6577_auxadc.c
> > 
> > diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> > index 25378c5..14929fc 100644
> > --- a/drivers/iio/adc/Kconfig
> > +++ b/drivers/iio/adc/Kconfig
> > @@ -305,6 +305,19 @@ config MCP3422
> >  	  This driver can also be built as a module. If so, the module will be
> >  	  called mcp3422.
> >  
> > +config MEDIATEK_MT6577_AUXADC
> > +        tristate "MediaTek AUXADC driver"
> > +        depends on ARCH_MEDIATEK || COMPILE_TEST
> > +        depends on HAS_IOMEM
> > +        help
> > +          Say yes here to enable support for MediaTek mt65xx AUXADC.
> > +
> > +          The driver supports immediate mode operation to read from one of sixteen
> > +          channels (external or internal).
> > +
> > +          This driver can also be built as a module. If so, the module will be
> > +          called mt6577_auxadc.
> > +
> >  config MEN_Z188_ADC
> >  	tristate "MEN 16z188 ADC IP Core support"
> >  	depends on MCB
> > diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> > index 38638d4..8306347 100644
> > --- a/drivers/iio/adc/Makefile
> > +++ b/drivers/iio/adc/Makefile
> > @@ -30,6 +30,7 @@ obj-$(CONFIG_MAX1027) += max1027.o
> >  obj-$(CONFIG_MAX1363) += max1363.o
> >  obj-$(CONFIG_MCP320X) += mcp320x.o
> >  obj-$(CONFIG_MCP3422) += mcp3422.o
> > +obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
> >  obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
> >  obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
> >  obj-$(CONFIG_NAU7802) += nau7802.o
> > diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c
> > new file mode 100644
> > index 0000000..c7cc901
> > --- /dev/null
> > +++ b/drivers/iio/adc/mt6577_auxadc.c
> > @@ -0,0 +1,294 @@
> > +/*
> > + * Copyright (c) 2016 MediaTek Inc.
> > + * Author: Zhiyong Tao <zhiyong.tao at mediatek.com>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + *
> > + * 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.
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/delay.h>
> > +#include <linux/err.h>
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/of_device.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/iopoll.h>
> > +#include <linux/io.h>
> > +#include <linux/iio/iio.h>
> > +
> > +/* Register definitions */
> > +#define MT6577_AUXADC_CON0                    0x00
> > +#define MT6577_AUXADC_CON1                    0x04
> > +#define MT6577_AUXADC_CON2                    0x10
> > +#define MT6577_AUXADC_STA                     BIT(0)
> > +
> > +#define MT6577_AUXADC_DAT0                    0x14
> > +#define MT6577_AUXADC_RDY0                    BIT(12)
> > +
> > +#define MT6577_AUXADC_MISC                    0x94
> > +#define MT6577_AUXADC_PDN_EN                  BIT(14)
> > +
> > +#define MT6577_AUXADC_DAT_MASK                0xfff
> > +#define MT6577_AUXADC_SLEEP_US                1000
> > +#define MT6577_AUXADC_TIMEOUT_US              10000
> > +#define MT6577_AUXADC_POWER_READY_MS          1
> > +#define MT6577_AUXADC_SAMPLE_READY_US         25
> > +
> > +struct mt6577_auxadc_device {
> > +	void __iomem *reg_base;
> > +	struct clk *adc_clk;
> > +	struct mutex lock;
> > +};
> > +
> > +#define MT6577_AUXADC_CHANNEL(idx) {				    \
> > +		.type = IIO_VOLTAGE,				    \
> > +		.indexed = 1,					    \
> > +		.channel = (idx),				    \
> > +		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
> > +}
> > +
> > +static const struct iio_chan_spec mt6577_auxadc_iio_channels[] = {
> > +	MT6577_AUXADC_CHANNEL(0),
> > +	MT6577_AUXADC_CHANNEL(1),
> > +	MT6577_AUXADC_CHANNEL(2),
> > +	MT6577_AUXADC_CHANNEL(3),
> > +	MT6577_AUXADC_CHANNEL(4),
> > +	MT6577_AUXADC_CHANNEL(5),
> > +	MT6577_AUXADC_CHANNEL(6),
> > +	MT6577_AUXADC_CHANNEL(7),
> > +	MT6577_AUXADC_CHANNEL(8),
> > +	MT6577_AUXADC_CHANNEL(9),
> > +	MT6577_AUXADC_CHANNEL(10),
> > +	MT6577_AUXADC_CHANNEL(11),
> > +	MT6577_AUXADC_CHANNEL(12),
> > +	MT6577_AUXADC_CHANNEL(13),
> > +	MT6577_AUXADC_CHANNEL(14),
> > +	MT6577_AUXADC_CHANNEL(15),
> > +};
> > +
> > +static int mt6577_auxadc_read(struct iio_dev *indio_dev,
> > +			      struct iio_chan_spec const *chan)
> > +{
> > +	u32 rawdata, val;
> > +	void __iomem *reg_channel;
> > +	int ret;
> > +	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
> > +
> > +	reg_channel = adc_dev->reg_base + MT6577_AUXADC_DAT0 +
> > +		      chan->channel * 0x04;
> > +
> > +	mutex_lock(&adc_dev->lock);
> > +
> > +	val = readl(adc_dev->reg_base + MT6577_AUXADC_CON1);
> > +	val &= ~(1 << chan->channel);
> > +	writel(val, adc_dev->reg_base + MT6577_AUXADC_CON1);
> > +
> > +	/* read channel and make sure old ready bit == 0 */
> > +	ret = readl_poll_timeout(reg_channel, val,
> > +				 ((val & MT6577_AUXADC_RDY0) == 0),
> > +				 MT6577_AUXADC_SLEEP_US,
> > +				 MT6577_AUXADC_TIMEOUT_US);
> > +	if (ret < 0) {
> > +		dev_err(indio_dev->dev.parent,
> > +			"wait for channel[%d] ready bit clear time out\n",
> > +			chan->channel);
> > +
> > +		mutex_unlock(&adc_dev->lock);
> > +
> > +		return -ETIMEDOUT;
> > +	}
> > +
> > +	/* set bit to trigger sample */
> > +	val = readl(adc_dev->reg_base + MT6577_AUXADC_CON1);
> > +	val |= 1 << chan->channel;
> > +	writel(val, adc_dev->reg_base + MT6577_AUXADC_CON1);
> > +
> > +	/* we must delay here for hardware sample channel data */
> > +	udelay(MT6577_AUXADC_SAMPLE_READY_US);
> > +
> > +	/* check MTK_AUXADC_CON2 if auxadc is idle */
> > +	ret = readl_poll_timeout(adc_dev->reg_base + MT6577_AUXADC_CON2, val,
> > +				 ((val & MT6577_AUXADC_STA) == 0),
> > +				 MT6577_AUXADC_SLEEP_US,
> > +				 MT6577_AUXADC_TIMEOUT_US);
> > +	if (ret < 0) {
> > +		dev_err(indio_dev->dev.parent,
> > +			"wait for auxadc idle time out\n");
> > +
> > +		mutex_unlock(&adc_dev->lock);
> > +
> > +		return -ETIMEDOUT;
> > +	}
> > +
> > +	/* read channel and make sure ready bit == 1 */
> > +	ret = readl_poll_timeout(reg_channel, val,
> > +				 ((val & MT6577_AUXADC_RDY0) != 0),
> > +				 MT6577_AUXADC_SLEEP_US,
> > +				 MT6577_AUXADC_TIMEOUT_US);
> > +	if (ret < 0) {
> > +		dev_err(indio_dev->dev.parent,
> > +			"wait for channel[%d] data ready time out\n",
> > +			chan->channel);
> > +
> > +		mutex_unlock(&adc_dev->lock);
> > +
> > +		return -ETIMEDOUT;
> > +	}
> > +
> > +	/* read data */
> > +	rawdata = readl(reg_channel) & MT6577_AUXADC_DAT_MASK;
> > +
> > +	mutex_unlock(&adc_dev->lock);
> > +
> > +	return rawdata;
> > +}
> > +
> > +static int mt6577_auxadc_read_raw(struct iio_dev *indio_dev,
> > +				  struct iio_chan_spec const *chan,
> > +				  int *val,
> > +				  int *val2,
> > +				  long info)
> > +{
> > +	switch (info) {
> > +	case IIO_CHAN_INFO_PROCESSED:
> > +		*val = mt6577_auxadc_read(indio_dev, chan);
> > +		if (*val < 0) {
> > +			dev_err(indio_dev->dev.parent,
> > +				"failed to sample data on channel[%d]\n",
> > +				chan->channel);
> > +			return *val;
> > +		}
> > +		return IIO_VAL_INT;
> > +
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +}
> > +
> > +static const struct iio_info mt6577_auxadc_info = {
> > +	.driver_module = THIS_MODULE,
> > +	.read_raw = &mt6577_auxadc_read_raw,
> > +};
> > +
> > +static int mt6577_auxadc_probe(struct platform_device *pdev)
> > +{
> > +	struct mt6577_auxadc_device *adc_dev;
> > +	unsigned long adc_clk_rate;
> > +	struct resource *res;
> > +	struct iio_dev *indio_dev;
> > +	int ret;
> > +	u32 val;
> > +
> > +	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
> > +	if (!indio_dev)
> > +		return -ENOMEM;
> > +
> > +	adc_dev = iio_priv(indio_dev);
> > +	indio_dev->dev.parent = &pdev->dev;
> > +	indio_dev->name = dev_name(&pdev->dev);
> > +	indio_dev->info = &mt6577_auxadc_info;
> > +	indio_dev->modes = INDIO_DIRECT_MODE;
> > +	indio_dev->channels = mt6577_auxadc_iio_channels;
> > +	indio_dev->num_channels = ARRAY_SIZE(mt6577_auxadc_iio_channels);
> > +
> > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +	adc_dev->reg_base = devm_ioremap_resource(&pdev->dev, res);
> > +	if (IS_ERR(adc_dev->reg_base)) {
> > +		dev_err(&pdev->dev, "failed to get auxadc base address.\n");
> > +		return PTR_ERR(adc_dev->reg_base);
> > +	}
> > +
> > +	adc_dev->adc_clk = devm_clk_get(&pdev->dev, "main");
> > +	if (IS_ERR(adc_dev->adc_clk)) {
> > +		dev_err(&pdev->dev, "failed to get auxadc clock\n");
> > +		return PTR_ERR(adc_dev->adc_clk);
> > +	}
> > +
> > +	ret = clk_prepare_enable(adc_dev->adc_clk);
> > +	if (ret) {
> > +		dev_err(&pdev->dev, "failed to enable auxadc clock\n");
> > +		return ret;
> > +	}
> > +
> > +	adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
> > +	if (!adc_clk_rate) {
> > +		dev_err(&pdev->dev, "null clock rate!\n");
> > +		goto err_disable_clk;
> > +	}
> > +
> > +	mutex_init(&adc_dev->lock);
> > +
> > +	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
> > +	val |= MT6577_AUXADC_PDN_EN;
> > +	writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
> > +	mdelay(MT6577_AUXADC_POWER_READY_MS);
> > +
> > +	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
> > +	if ((val & MT6577_AUXADC_PDN_EN) == 0) {
> That's a high level of paranoia... Any reason to believe this might fail?

Someone reviews the code and gives a suggestion to power off chenck.
If auxadc clk is off in the case, we can not write MT6577_AUXADC_PDN_EN
in MT6577_AUXADC_MISC. So it may cause to enable auxadc power failed.

> > +		dev_err(&pdev->dev, "failed to enable auxadc power!\n");
> > +		goto err_disable_clk;
> > +	}
> > +
> > +	platform_set_drvdata(pdev, indio_dev);
> > +
> > +	ret = iio_device_register(indio_dev);
> > +	if (ret < 0) {
> I'd have slightly preferred that this error unwind block was also
> moved to on a goto.  Makes it easier to review as the error block then
> matches remove (with expected differences!)  Really small point however.

I will update this in next version.

> 
> > +		dev_err(&pdev->dev, "failed to register iio device!\n");
> > +		val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
> > +		val &= ~MT6577_AUXADC_PDN_EN;
> > +		writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
> > +		goto err_disable_clk;
> > +	}
> > +
> > +	return 0;
> > +
> > +err_disable_clk:
> > +	clk_disable_unprepare(adc_dev->adc_clk);
> > +	return -EINVAL;
> > +}
> > +
> > +static int mt6577_auxadc_remove(struct platform_device *pdev)
> > +{
> > +	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
> > +	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
> > +	u32 val;
> > +
> > +	iio_device_unregister(indio_dev);
> > +
> > +	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
> > +	val &= ~MT6577_AUXADC_PDN_EN;
> > +	writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
> > +
> > +	clk_disable_unprepare(adc_dev->adc_clk);
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct of_device_id mt6577_auxadc_of_match[] = {
> > +	{ .compatible = "mediatek,mt2701-auxadc", },
> > +	{ .compatible = "mediatek,mt8173-auxadc", },
> > +	{ }
> > +};
> > +MODULE_DEVICE_TABLE(of, mt6577_auxadc_of_match);
> > +
> > +static struct platform_driver mt6577_auxadc_driver = {
> > +	.driver = {
> > +		.name   = "mt6577-auxadc",
> > +		.of_match_table = mt6577_auxadc_of_match,
> > +	},
> > +	.probe	= mt6577_auxadc_probe,
> > +	.remove	= mt6577_auxadc_remove,
> > +};
> > +module_platform_driver(mt6577_auxadc_driver);
> > +
> > +MODULE_AUTHOR("Zhiyong Tao <zhiyong.tao at mediatek.com>");
> > +MODULE_DESCRIPTION("MTK AUXADC Device Driver");
> > +MODULE_LICENSE("GPL v2");
> > 
> 




From zhiyong.tao at mediatek.com  Tue Jul 19 23:24:31 2016
From: zhiyong.tao at mediatek.com (zhiyong tao)
Date: Wed, 20 Jul 2016 14:24:31 +0800
Subject: [PATCH v4 2/3] iio: adc: mt2701: Add Mediatek auxadc driver for
 mt2701.
In-Reply-To: <1468994558.419.30.camel@mhfsdcap03>
References: <1468219197-9572-1-git-send-email-zhiyong.tao@mediatek.com>
 <1468219197-9572-3-git-send-email-zhiyong.tao@mediatek.com>
 <82fa5ffa-52be-e1ec-83dd-dd92b3f3ef5d@kernel.org>
 <1468994558.419.30.camel@mhfsdcap03>
Message-ID: <1468995871.419.37.camel@mhfsdcap03>

On Wed, 2016-07-20 at 14:02 +0800, zhiyong tao wrote:
> On Mon, 2016-07-18 at 18:12 +0100, Jonathan Cameron wrote:
> > On 11/07/16 07:39, Zhiyong Tao wrote:
> > > Add Mediatek auxadc driver based on iio.
> > > It will register a device in iio and support iio.
> > > So thermal can read auxadc channel to sample data by iio device.
> > > It is tested successfully on mt2701 platform.
> > > Mt8173 and mt6577 platforms are not tested.
> > > But the expectation is compatible.
> > > 
> > > Signed-off-by: Zhiyong Tao <zhiyong.tao at mediatek.com>
> > Looks good to me.  Couple of really minor points / questions inline...
> > 
> > Just one thing to confirm... (you probably already answered this!)
> > What are the units of the voltage channels?
> > 
> > Jonathan
> 
> The units of the voltage channels are mv. 
> 
> > > ---
> > >  drivers/iio/adc/Kconfig         |   13 ++
> > >  drivers/iio/adc/Makefile        |    1 +
> > >  drivers/iio/adc/mt6577_auxadc.c |  294 +++++++++++++++++++++++++++++++++++++++
> > >  3 files changed, 308 insertions(+)
> > >  create mode 100644 drivers/iio/adc/mt6577_auxadc.c
> > > 
> > > diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> > > index 25378c5..14929fc 100644
> > > --- a/drivers/iio/adc/Kconfig
> > > +++ b/drivers/iio/adc/Kconfig
> > > @@ -305,6 +305,19 @@ config MCP3422
> > >  	  This driver can also be built as a module. If so, the module will be
> > >  	  called mcp3422.
> > >  
> > > +config MEDIATEK_MT6577_AUXADC
> > > +        tristate "MediaTek AUXADC driver"
> > > +        depends on ARCH_MEDIATEK || COMPILE_TEST
> > > +        depends on HAS_IOMEM
> > > +        help
> > > +          Say yes here to enable support for MediaTek mt65xx AUXADC.
> > > +
> > > +          The driver supports immediate mode operation to read from one of sixteen
> > > +          channels (external or internal).
> > > +
> > > +          This driver can also be built as a module. If so, the module will be
> > > +          called mt6577_auxadc.
> > > +
> > >  config MEN_Z188_ADC
> > >  	tristate "MEN 16z188 ADC IP Core support"
> > >  	depends on MCB
> > > diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> > > index 38638d4..8306347 100644
> > > --- a/drivers/iio/adc/Makefile
> > > +++ b/drivers/iio/adc/Makefile
> > > @@ -30,6 +30,7 @@ obj-$(CONFIG_MAX1027) += max1027.o
> > >  obj-$(CONFIG_MAX1363) += max1363.o
> > >  obj-$(CONFIG_MCP320X) += mcp320x.o
> > >  obj-$(CONFIG_MCP3422) += mcp3422.o
> > > +obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
> > >  obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
> > >  obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
> > >  obj-$(CONFIG_NAU7802) += nau7802.o
> > > diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c
> > > new file mode 100644
> > > index 0000000..c7cc901
> > > --- /dev/null
> > > +++ b/drivers/iio/adc/mt6577_auxadc.c
> > > @@ -0,0 +1,294 @@
> > > +/*
> > > + * Copyright (c) 2016 MediaTek Inc.
> > > + * Author: Zhiyong Tao <zhiyong.tao at mediatek.com>
> > > + *
> > > + * This program is free software; you can redistribute it and/or modify
> > > + * it under the terms of the GNU General Public License version 2 as
> > > + * published by the Free Software Foundation.
> > > + *
> > > + * 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.
> > > + */
> > > +
> > > +#include <linux/clk.h>
> > > +#include <linux/delay.h>
> > > +#include <linux/err.h>
> > > +#include <linux/kernel.h>
> > > +#include <linux/module.h>
> > > +#include <linux/of.h>
> > > +#include <linux/of_device.h>
> > > +#include <linux/platform_device.h>
> > > +#include <linux/iopoll.h>
> > > +#include <linux/io.h>
> > > +#include <linux/iio/iio.h>
> > > +
> > > +/* Register definitions */
> > > +#define MT6577_AUXADC_CON0                    0x00
> > > +#define MT6577_AUXADC_CON1                    0x04
> > > +#define MT6577_AUXADC_CON2                    0x10
> > > +#define MT6577_AUXADC_STA                     BIT(0)
> > > +
> > > +#define MT6577_AUXADC_DAT0                    0x14
> > > +#define MT6577_AUXADC_RDY0                    BIT(12)
> > > +
> > > +#define MT6577_AUXADC_MISC                    0x94
> > > +#define MT6577_AUXADC_PDN_EN                  BIT(14)
> > > +
> > > +#define MT6577_AUXADC_DAT_MASK                0xfff
> > > +#define MT6577_AUXADC_SLEEP_US                1000
> > > +#define MT6577_AUXADC_TIMEOUT_US              10000
> > > +#define MT6577_AUXADC_POWER_READY_MS          1
> > > +#define MT6577_AUXADC_SAMPLE_READY_US         25
> > > +
> > > +struct mt6577_auxadc_device {
> > > +	void __iomem *reg_base;
> > > +	struct clk *adc_clk;
> > > +	struct mutex lock;
> > > +};
> > > +
> > > +#define MT6577_AUXADC_CHANNEL(idx) {				    \
> > > +		.type = IIO_VOLTAGE,				    \
> > > +		.indexed = 1,					    \
> > > +		.channel = (idx),				    \
> > > +		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
> > > +}
> > > +
> > > +static const struct iio_chan_spec mt6577_auxadc_iio_channels[] = {
> > > +	MT6577_AUXADC_CHANNEL(0),
> > > +	MT6577_AUXADC_CHANNEL(1),
> > > +	MT6577_AUXADC_CHANNEL(2),
> > > +	MT6577_AUXADC_CHANNEL(3),
> > > +	MT6577_AUXADC_CHANNEL(4),
> > > +	MT6577_AUXADC_CHANNEL(5),
> > > +	MT6577_AUXADC_CHANNEL(6),
> > > +	MT6577_AUXADC_CHANNEL(7),
> > > +	MT6577_AUXADC_CHANNEL(8),
> > > +	MT6577_AUXADC_CHANNEL(9),
> > > +	MT6577_AUXADC_CHANNEL(10),
> > > +	MT6577_AUXADC_CHANNEL(11),
> > > +	MT6577_AUXADC_CHANNEL(12),
> > > +	MT6577_AUXADC_CHANNEL(13),
> > > +	MT6577_AUXADC_CHANNEL(14),
> > > +	MT6577_AUXADC_CHANNEL(15),
> > > +};
> > > +
> > > +static int mt6577_auxadc_read(struct iio_dev *indio_dev,
> > > +			      struct iio_chan_spec const *chan)
> > > +{
> > > +	u32 rawdata, val;
> > > +	void __iomem *reg_channel;
> > > +	int ret;
> > > +	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
> > > +
> > > +	reg_channel = adc_dev->reg_base + MT6577_AUXADC_DAT0 +
> > > +		      chan->channel * 0x04;
> > > +
> > > +	mutex_lock(&adc_dev->lock);
> > > +
> > > +	val = readl(adc_dev->reg_base + MT6577_AUXADC_CON1);
> > > +	val &= ~(1 << chan->channel);
> > > +	writel(val, adc_dev->reg_base + MT6577_AUXADC_CON1);
> > > +
> > > +	/* read channel and make sure old ready bit == 0 */
> > > +	ret = readl_poll_timeout(reg_channel, val,
> > > +				 ((val & MT6577_AUXADC_RDY0) == 0),
> > > +				 MT6577_AUXADC_SLEEP_US,
> > > +				 MT6577_AUXADC_TIMEOUT_US);
> > > +	if (ret < 0) {
> > > +		dev_err(indio_dev->dev.parent,
> > > +			"wait for channel[%d] ready bit clear time out\n",
> > > +			chan->channel);
> > > +
> > > +		mutex_unlock(&adc_dev->lock);
> > > +
> > > +		return -ETIMEDOUT;
> > > +	}
> > > +
> > > +	/* set bit to trigger sample */
> > > +	val = readl(adc_dev->reg_base + MT6577_AUXADC_CON1);
> > > +	val |= 1 << chan->channel;
> > > +	writel(val, adc_dev->reg_base + MT6577_AUXADC_CON1);
> > > +
> > > +	/* we must delay here for hardware sample channel data */
> > > +	udelay(MT6577_AUXADC_SAMPLE_READY_US);
> > > +
> > > +	/* check MTK_AUXADC_CON2 if auxadc is idle */
> > > +	ret = readl_poll_timeout(adc_dev->reg_base + MT6577_AUXADC_CON2, val,
> > > +				 ((val & MT6577_AUXADC_STA) == 0),
> > > +				 MT6577_AUXADC_SLEEP_US,
> > > +				 MT6577_AUXADC_TIMEOUT_US);
> > > +	if (ret < 0) {
> > > +		dev_err(indio_dev->dev.parent,
> > > +			"wait for auxadc idle time out\n");
> > > +
> > > +		mutex_unlock(&adc_dev->lock);
> > > +
> > > +		return -ETIMEDOUT;
> > > +	}
> > > +
> > > +	/* read channel and make sure ready bit == 1 */
> > > +	ret = readl_poll_timeout(reg_channel, val,
> > > +				 ((val & MT6577_AUXADC_RDY0) != 0),
> > > +				 MT6577_AUXADC_SLEEP_US,
> > > +				 MT6577_AUXADC_TIMEOUT_US);
> > > +	if (ret < 0) {
> > > +		dev_err(indio_dev->dev.parent,
> > > +			"wait for channel[%d] data ready time out\n",
> > > +			chan->channel);
> > > +
> > > +		mutex_unlock(&adc_dev->lock);
> > > +
> > > +		return -ETIMEDOUT;
> > > +	}
> > > +
> > > +	/* read data */
> > > +	rawdata = readl(reg_channel) & MT6577_AUXADC_DAT_MASK;
> > > +
> > > +	mutex_unlock(&adc_dev->lock);
> > > +
> > > +	return rawdata;
> > > +}
> > > +
> > > +static int mt6577_auxadc_read_raw(struct iio_dev *indio_dev,
> > > +				  struct iio_chan_spec const *chan,
> > > +				  int *val,
> > > +				  int *val2,
> > > +				  long info)
> > > +{
> > > +	switch (info) {
> > > +	case IIO_CHAN_INFO_PROCESSED:
> > > +		*val = mt6577_auxadc_read(indio_dev, chan);
> > > +		if (*val < 0) {
> > > +			dev_err(indio_dev->dev.parent,
> > > +				"failed to sample data on channel[%d]\n",
> > > +				chan->channel);
> > > +			return *val;
> > > +		}
> > > +		return IIO_VAL_INT;
> > > +
> > > +	default:
> > > +		return -EINVAL;
> > > +	}
> > > +}
> > > +
> > > +static const struct iio_info mt6577_auxadc_info = {
> > > +	.driver_module = THIS_MODULE,
> > > +	.read_raw = &mt6577_auxadc_read_raw,
> > > +};
> > > +
> > > +static int mt6577_auxadc_probe(struct platform_device *pdev)
> > > +{
> > > +	struct mt6577_auxadc_device *adc_dev;
> > > +	unsigned long adc_clk_rate;
> > > +	struct resource *res;
> > > +	struct iio_dev *indio_dev;
> > > +	int ret;
> > > +	u32 val;
> > > +
> > > +	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
> > > +	if (!indio_dev)
> > > +		return -ENOMEM;
> > > +
> > > +	adc_dev = iio_priv(indio_dev);
> > > +	indio_dev->dev.parent = &pdev->dev;
> > > +	indio_dev->name = dev_name(&pdev->dev);
> > > +	indio_dev->info = &mt6577_auxadc_info;
> > > +	indio_dev->modes = INDIO_DIRECT_MODE;
> > > +	indio_dev->channels = mt6577_auxadc_iio_channels;
> > > +	indio_dev->num_channels = ARRAY_SIZE(mt6577_auxadc_iio_channels);
> > > +
> > > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > > +	adc_dev->reg_base = devm_ioremap_resource(&pdev->dev, res);
> > > +	if (IS_ERR(adc_dev->reg_base)) {
> > > +		dev_err(&pdev->dev, "failed to get auxadc base address.\n");
> > > +		return PTR_ERR(adc_dev->reg_base);
> > > +	}
> > > +
> > > +	adc_dev->adc_clk = devm_clk_get(&pdev->dev, "main");
> > > +	if (IS_ERR(adc_dev->adc_clk)) {
> > > +		dev_err(&pdev->dev, "failed to get auxadc clock\n");
> > > +		return PTR_ERR(adc_dev->adc_clk);
> > > +	}
> > > +
> > > +	ret = clk_prepare_enable(adc_dev->adc_clk);
> > > +	if (ret) {
> > > +		dev_err(&pdev->dev, "failed to enable auxadc clock\n");
> > > +		return ret;
> > > +	}
> > > +
> > > +	adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
> > > +	if (!adc_clk_rate) {
> > > +		dev_err(&pdev->dev, "null clock rate!\n");
> > > +		goto err_disable_clk;
> > > +	}
> > > +
> > > +	mutex_init(&adc_dev->lock);
> > > +
> > > +	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
> > > +	val |= MT6577_AUXADC_PDN_EN;
> > > +	writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
> > > +	mdelay(MT6577_AUXADC_POWER_READY_MS);
> > > +
> > > +	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
> > > +	if ((val & MT6577_AUXADC_PDN_EN) == 0) {
> > That's a high level of paranoia... Any reason to believe this might fail?
> 
> Someone reviews the code and gives a suggestion to power off chenck.
> If auxadc clk is off in the case, we can not write MT6577_AUXADC_PDN_EN
> in MT6577_AUXADC_MISC. So it may cause to enable auxadc power failed.
> 

sorry, I have searched the previous versions.
I found that I  misunderstand the intention.
The power on failed checked will be removed in the next version.

> > > +		dev_err(&pdev->dev, "failed to enable auxadc power!\n");
> > > +		goto err_disable_clk;
> > > +	}
> > > +
> > > +	platform_set_drvdata(pdev, indio_dev);
> > > +
> > > +	ret = iio_device_register(indio_dev);
> > > +	if (ret < 0) {
> > I'd have slightly preferred that this error unwind block was also
> > moved to on a goto.  Makes it easier to review as the error block then
> > matches remove (with expected differences!)  Really small point however.
> 
> I will update this in next version.
> 
> > 
> > > +		dev_err(&pdev->dev, "failed to register iio device!\n");
> > > +		val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
> > > +		val &= ~MT6577_AUXADC_PDN_EN;
> > > +		writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
> > > +		goto err_disable_clk;
> > > +	}
> > > +
> > > +	return 0;
> > > +
> > > +err_disable_clk:
> > > +	clk_disable_unprepare(adc_dev->adc_clk);
> > > +	return -EINVAL;
> > > +}
> > > +
> > > +static int mt6577_auxadc_remove(struct platform_device *pdev)
> > > +{
> > > +	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
> > > +	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
> > > +	u32 val;
> > > +
> > > +	iio_device_unregister(indio_dev);
> > > +
> > > +	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
> > > +	val &= ~MT6577_AUXADC_PDN_EN;
> > > +	writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
> > > +
> > > +	clk_disable_unprepare(adc_dev->adc_clk);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static const struct of_device_id mt6577_auxadc_of_match[] = {
> > > +	{ .compatible = "mediatek,mt2701-auxadc", },
> > > +	{ .compatible = "mediatek,mt8173-auxadc", },
> > > +	{ }
> > > +};
> > > +MODULE_DEVICE_TABLE(of, mt6577_auxadc_of_match);
> > > +
> > > +static struct platform_driver mt6577_auxadc_driver = {
> > > +	.driver = {
> > > +		.name   = "mt6577-auxadc",
> > > +		.of_match_table = mt6577_auxadc_of_match,
> > > +	},
> > > +	.probe	= mt6577_auxadc_probe,
> > > +	.remove	= mt6577_auxadc_remove,
> > > +};
> > > +module_platform_driver(mt6577_auxadc_driver);
> > > +
> > > +MODULE_AUTHOR("Zhiyong Tao <zhiyong.tao at mediatek.com>");
> > > +MODULE_DESCRIPTION("MTK AUXADC Device Driver");
> > > +MODULE_LICENSE("GPL v2");
> > > 
> > 
> 




From ck.hu at mediatek.com  Tue Jul 19 23:27:56 2016
From: ck.hu at mediatek.com (CK Hu)
Date: Wed, 20 Jul 2016 14:27:56 +0800
Subject: [PATCH v4 7/8] drm/mediatek: add mipi panel support
In-Reply-To: <1468577274-6178-8-git-send-email-yt.shen@mediatek.com>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
 <1468577274-6178-8-git-send-email-yt.shen@mediatek.com>
Message-ID: <1468996076.11841.43.camel@mtksdaap41>

Hi, YT:

Some comments inline.

On Fri, 2016-07-15 at 18:07 +0800, YT Shen wrote:
> From: shaoming chen <shaoming.chen at mediatek.com>
> 
> add dsi and mipi tx driver for mipi panel support
> 
> Signed-off-by: shaoming chen <shaoming.chen at mediatek.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_dsi.c     |  169 ++++++++++++++++++++++----------
>  drivers/gpu/drm/mediatek/mtk_mipi_tx.c |   82 +++++++++++-----
>  2 files changed, 173 insertions(+), 78 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
> index 1f99894..4eae63c 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dsi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
> @@ -29,9 +29,6 @@
>  
>  #include "mtk_drm_ddp_comp.h"
>  
> -#define DSI_VIDEO_FIFO_DEPTH	(1920 / 4)
> -#define DSI_HOST_FIFO_DEPTH	64
> -

I think this should be moved to a 'cleaning up and refine' patch.

>  #define DSI_START		0x00
>  
>  #define DSI_INTEN		0x08
> @@ -55,7 +52,7 @@
>  #define MIX_MODE			BIT(17)
>  
>  #define DSI_TXRX_CTRL		0x18
> -#define VC_NUM				(2 << 0)
> +#define VC_NUM				BIT(1)

I think this should be moved to a 'cleaning up and refine' patch.

>  #define LANE_NUM			(0xf << 2)
>  #define DIS_EOT				BIT(6)
>  #define NULL_EN				BIT(7)
> @@ -94,6 +91,8 @@
>  #define DSI_RACK		0x84
>  #define RACK			BIT(0)
>  
> +#define DSI_MEM_CONTI		0x90
> +
>  #define DSI_PHY_LCCON		0x104
>  #define LC_HS_TX_EN			BIT(0)
>  #define LC_ULPM_EN			BIT(1)
> @@ -126,6 +125,10 @@
>  #define CLK_HS_POST			(0xff << 8)
>  #define CLK_HS_EXIT			(0xff << 16)
>  
> +#define DSI_VM_CMD_CON		0x130
> +#define VM_CMD_EN		BIT(0)
> +#define TS_VFP_EN		BIT(5)

The bitwise definition should add one more tab to align other bitwise
definition in this file.

> +
>  #define DSI_CMDQ0		0x180
>  
>  #define NS_TO_CYCLE(n, c)    ((n) / (c) + (((n) % (c)) ? 1 : 0))
> @@ -239,11 +242,11 @@ static void mtk_dsi_mask(struct mtk_dsi *dsi, u32 offset, u32 mask, u32 data)
>  	writel((temp & ~mask) | (data & mask), dsi->regs + offset);
>  }
>  
> -static void dsi_phy_timconfig(struct mtk_dsi *dsi)
> +static void mtk_dsi_phy_timconfig(struct mtk_dsi *dsi)

I think this should be moved to a 'cleaning up and refine' patch.

>  {
>  	u32 timcon0, timcon1, timcon2, timcon3;
> -	unsigned int ui, cycle_time;
> -	unsigned int lpx;
> +	u32 ui, cycle_time;
> +	u32 lpx;

I think this should be moved to a 'cleaning up and refine' patch.

>  
>  	ui = 1000 / dsi->data_rate + 0x01;
>  	cycle_time = 8000 / dsi->data_rate + 0x01;
> @@ -273,7 +276,7 @@ static void mtk_dsi_disable(struct mtk_dsi *dsi)
>  	mtk_dsi_mask(dsi, DSI_CON_CTRL, DSI_EN, 0);
>  }
>  
> -static void mtk_dsi_reset(struct mtk_dsi *dsi)
> +static void mtk_dsi_reset_engine(struct mtk_dsi *dsi)
>  {
>  	mtk_dsi_mask(dsi, DSI_CON_CTRL, DSI_RESET, DSI_RESET);
>  	mtk_dsi_mask(dsi, DSI_CON_CTRL, DSI_RESET, 0);
> @@ -293,7 +296,9 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi)
>  	 * mipi_ratio is mipi clk coefficient for balance the pixel clk in mipi.
>  	 * we set mipi_ratio is 1.05.
>  	 */
> -	dsi->data_rate = dsi->vm.pixelclock * 3 * 21 / (1 * 1000 * 10);
> +	dsi->data_rate = dsi->vm.pixelclock * 12 * 21;
> +	dsi->data_rate /= (dsi->lanes * 1000 * 10);
> +	dev_info(dev, "set mipitx's data rate: %dMHz\n", dsi->data_rate);
>  
>  	ret = clk_set_rate(dsi->hs_clk, dsi->data_rate * 1000000);
>  	if (ret < 0) {
> @@ -315,10 +320,6 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi)
>  		goto err_disable_engine_clk;
>  	}
>  
> -	mtk_dsi_enable(dsi);
> -	mtk_dsi_reset(dsi);
> -	dsi_phy_timconfig(dsi);
> -
>  	return 0;
>  
>  err_disable_engine_clk:
> @@ -330,33 +331,33 @@ err_refcount:
>  	return ret;
>  }
>  
> -static void dsi_clk_ulp_mode_enter(struct mtk_dsi *dsi)
> +static void mtk_dsi_clk_ulp_mode_enter(struct mtk_dsi *dsi)

I think this should be moved to a 'cleaning up and refine' patch.

>  {
>  	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, 0);
> -	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_ULPM_EN, 0);
> +	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_ULPM_EN, LC_ULPM_EN);
>  }
>  
> -static void dsi_clk_ulp_mode_leave(struct mtk_dsi *dsi)
> +static void mtk_dsi_clk_ulp_mode_leave(struct mtk_dsi *dsi)

I think this should be moved to a 'cleaning up and refine' patch.

>  {
>  	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_ULPM_EN, 0);
>  	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_WAKEUP_EN, LC_WAKEUP_EN);
>  	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_WAKEUP_EN, 0);
>  }
>  
> -static void dsi_lane0_ulp_mode_enter(struct mtk_dsi *dsi)
> +static void mtk_dsi_lane0_ulp_mode_enter(struct mtk_dsi *dsi)

I think this should be moved to a 'cleaning up and refine' patch.

>  {
>  	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_HS_TX_EN, 0);
> -	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_ULPM_EN, 0);
> +	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_ULPM_EN, LD0_ULPM_EN);
>  }
>  
> -static void dsi_lane0_ulp_mode_leave(struct mtk_dsi *dsi)
> +static void mtk_dsi_lane0_ulp_mode_leave(struct mtk_dsi *dsi)
>  {
>  	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_ULPM_EN, 0);
>  	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_WAKEUP_EN, LD0_WAKEUP_EN);
>  	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_WAKEUP_EN, 0);
>  }
>  
> -static bool dsi_clk_hs_state(struct mtk_dsi *dsi)
> +static bool mtk_dsi_clk_hs_state(struct mtk_dsi *dsi)

I think this should be moved to a 'cleaning up and refine' patch.

>  {
>  	u32 tmp_reg1;
>  
> @@ -364,15 +365,15 @@ static bool dsi_clk_hs_state(struct mtk_dsi *dsi)
>  	return ((tmp_reg1 & LC_HS_TX_EN) == 1) ? true : false;
>  }
>  
> -static void dsi_clk_hs_mode(struct mtk_dsi *dsi, bool enter)
> +static void mtk_dsi_clk_hs_mode(struct mtk_dsi *dsi, bool enter)

I think this should be moved to a 'cleaning up and refine' patch.

>  {
> -	if (enter && !dsi_clk_hs_state(dsi))
> +	if (enter && !mtk_dsi_clk_hs_state(dsi))
>  		mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, LC_HS_TX_EN);
> -	else if (!enter && dsi_clk_hs_state(dsi))
> +	else if (!enter && mtk_dsi_clk_hs_state(dsi))
>  		mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, 0);
>  }
>  
> -static void dsi_set_mode(struct mtk_dsi *dsi)
> +static void mtk_dsi_set_mode(struct mtk_dsi *dsi)

I think this should be moved to a 'cleaning up and refine' patch.

>  {
>  	u32 vid_mode = CMD_MODE;
>  
> @@ -382,12 +383,22 @@ static void dsi_set_mode(struct mtk_dsi *dsi)
>  		if ((dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) &&
>  		    !(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE))
>  			vid_mode = BURST_MODE;
> +		else
> +			vid_mode = SYNC_EVENT_MODE;
>  	}
>  
>  	writel(vid_mode, dsi->regs + DSI_MODE_CTRL);
>  }
>  
> -static void dsi_ps_control_vact(struct mtk_dsi *dsi)
> +static void mtk_dsi_set_vm_cmd(struct mtk_dsi *dsi)
> +{
> +	writel(0x3c, dsi->regs + DSI_MEM_CONTI);
> +
> +	mtk_dsi_mask(dsi, DSI_VM_CMD_CON, VM_CMD_EN, VM_CMD_EN);
> +	mtk_dsi_mask(dsi, DSI_VM_CMD_CON, TS_VFP_EN, TS_VFP_EN);
> +}
> +
> +static void mtk_dsi_ps_control_vact(struct mtk_dsi *dsi)
>  {
>  	struct videomode *vm = &dsi->vm;
>  	u32 dsi_buf_bpp, ps_wc;
> @@ -421,7 +432,7 @@ static void dsi_ps_control_vact(struct mtk_dsi *dsi)
>  	writel(ps_wc, dsi->regs + DSI_HSTX_CKL_WC);
>  }
>  
> -static void dsi_rxtx_control(struct mtk_dsi *dsi)
> +static void mtk_dsi_rxtx_control(struct mtk_dsi *dsi)

I think this should be moved to a 'cleaning up and refine' patch.

>  {
>  	u32 tmp_reg;
>  
> @@ -443,12 +454,15 @@ static void dsi_rxtx_control(struct mtk_dsi *dsi)
>  		break;
>  	}
>  
> +	tmp_reg |= (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) << 6;
> +	tmp_reg |= (dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET) >> 3;
> +
>  	writel(tmp_reg, dsi->regs + DSI_TXRX_CTRL);
>  }
>  
> -static void dsi_ps_control(struct mtk_dsi *dsi)
> +static void mtk_dsi_ps_control(struct mtk_dsi *dsi)

I think this should be moved to a 'cleaning up and refine' patch.

>  {
> -	unsigned int dsi_tmp_buf_bpp;
> +	u32 dsi_tmp_buf_bpp;
>  	u32 tmp_reg;
>  
>  	switch (dsi->format) {
> @@ -478,12 +492,12 @@ static void dsi_ps_control(struct mtk_dsi *dsi)
>  	writel(tmp_reg, dsi->regs + DSI_PSCTRL);
>  }
>  
> -static void dsi_config_vdo_timing(struct mtk_dsi *dsi)
> +static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi)

I think this should be moved to a 'cleaning up and refine' patch.

>  {
> -	unsigned int horizontal_sync_active_byte;
> -	unsigned int horizontal_backporch_byte;
> -	unsigned int horizontal_frontporch_byte;
> -	unsigned int dsi_tmp_buf_bpp;
> +	u32 horizontal_sync_active_byte;
> +	u32 horizontal_backporch_byte;
> +	u32 horizontal_frontporch_byte;
> +	u32 dsi_tmp_buf_bpp;

I think this should be moved to a 'cleaning up and refine' patch.

>  
>  	struct videomode *vm = &dsi->vm;
>  
> @@ -512,7 +526,7 @@ static void dsi_config_vdo_timing(struct mtk_dsi *dsi)
>  	writel(horizontal_backporch_byte, dsi->regs + DSI_HBP_WC);
>  	writel(horizontal_frontporch_byte, dsi->regs + DSI_HFP_WC);
>  
> -	dsi_ps_control(dsi);
> +	mtk_dsi_ps_control(dsi);
>  }
>  
>  static void mtk_dsi_start(struct mtk_dsi *dsi)
> @@ -521,6 +535,19 @@ static void mtk_dsi_start(struct mtk_dsi *dsi)
>  	writel(1, dsi->regs + DSI_START);
>  }
>  
> +static void mtk_dsi_stop(struct mtk_dsi *dsi)
> +{
> +	writel(0, dsi->regs + DSI_START);
> +}
> +
> +static void mtk_dsi_set_cmd_mode(struct mtk_dsi *dsi)
> +{
> +	u32 tmp_reg1;
> +
> +	tmp_reg1 = CMD_MODE;
> +	writel(tmp_reg1, dsi->regs + DSI_MODE_CTRL);
> +}
> +
>  static void mtk_dsi_set_interrupt_enable(struct mtk_dsi *dsi)
>  {
>  	u32 inten = DSI_INT_ALL_BITS;
> @@ -609,6 +636,21 @@ static s32 mtk_dsi_wait_for_irq_timeout(struct mtk_dsi *dsi, u32 irq_bit,
>  	return -1;
>  }
>  
> +static void mtk_dsi_switch_to_cmd_mode(struct mtk_dsi *dsi)
> +{
> +	s32 ret = 0;
> +
> +	mtk_dsi_set_cmd_mode(dsi);
> +
> +	ret = mtk_dsi_wait_for_irq_timeout(dsi, DSI_INT_VM_DONE_FLAG, 500);
> +	if (ret != 0) {
> +		dev_info(dsi->dev, "dsi wait engine idle timeout\n");
> +
> +		mtk_dsi_enable(dsi);
> +		mtk_dsi_reset_engine(dsi);
> +	}
> +}
> +
>  static void mtk_dsi_poweroff(struct mtk_dsi *dsi)
>  {
>  	if (WARN_ON(dsi->refcount == 0))
> @@ -617,8 +659,19 @@ static void mtk_dsi_poweroff(struct mtk_dsi *dsi)
>  	if (--dsi->refcount != 0)
>  		return;
>  
> -	dsi_lane0_ulp_mode_enter(dsi);
> -	dsi_clk_ulp_mode_enter(dsi);
> +	mtk_dsi_switch_to_cmd_mode(dsi);
> +
> +	if (dsi->panel) {
> +		if (drm_panel_unprepare(dsi->panel)) {
> +			DRM_ERROR("failed to unprepare the panel\n");
> +			return;
> +		}
> +	}
> +
> +	mtk_dsi_reset_engine(dsi);
> +
> +	mtk_dsi_lane0_ulp_mode_enter(dsi);
> +	mtk_dsi_clk_ulp_mode_enter(dsi);
>  
>  	mtk_dsi_disable(dsi);
>  
> @@ -635,32 +688,40 @@ static void mtk_output_dsi_enable(struct mtk_dsi *dsi)
>  	if (dsi->enabled)
>  		return;
>  
> -	if (dsi->panel) {
> -		if (drm_panel_prepare(dsi->panel)) {
> -			DRM_ERROR("failed to setup the panel\n");
> -			return;
> -		}
> -	}
> -
>  	ret = mtk_dsi_poweron(dsi);
>  	if (ret < 0) {
>  		DRM_ERROR("failed to power on dsi\n");
>  		return;
>  	}
>  
> -	dsi_rxtx_control(dsi);
> +	usleep_range(20000, 21000);
>  
> -	dsi_clk_ulp_mode_leave(dsi);
> -	dsi_lane0_ulp_mode_leave(dsi);
> -	dsi_clk_hs_mode(dsi, 0);
> -	dsi_set_mode(dsi);
> -
> -	dsi_ps_control_vact(dsi);
> -	dsi_config_vdo_timing(dsi);
> +	mtk_dsi_rxtx_control(dsi);
> +	mtk_dsi_phy_timconfig(dsi);
> +	mtk_dsi_ps_control_vact(dsi);
> +	mtk_dsi_set_vm_cmd(dsi);
> +	mtk_dsi_config_vdo_timing(dsi);
>  	mtk_dsi_set_interrupt_enable(dsi);
>  
> -	dsi_set_mode(dsi);
> -	dsi_clk_hs_mode(dsi, 1);
> +	mtk_dsi_enable(dsi);
> +	mtk_dsi_clk_ulp_mode_leave(dsi);
> +	mtk_dsi_lane0_ulp_mode_leave(dsi);
> +	mtk_dsi_clk_hs_mode(dsi, 0);
> +
> +	if (dsi->panel) {
> +		if (drm_panel_prepare(dsi->panel)) {
> +			DRM_ERROR("failed to prepare the panel\n");
> +			return;
> +		}
> +
> +		if (drm_panel_enable(dsi->panel)) {
> +			DRM_ERROR("failed to enable the panel\n");
> +			return;
> +		}
> +	}
> +
> +	mtk_dsi_set_mode(dsi);
> +	mtk_dsi_clk_hs_mode(dsi, 1);
>  
>  	mtk_dsi_start(dsi);
>  
> @@ -679,6 +740,7 @@ static void mtk_output_dsi_disable(struct mtk_dsi *dsi)
>  		}
>  	}
>  
> +	mtk_dsi_stop(dsi);
>  	mtk_dsi_poweroff(dsi);
>  
>  	dsi->enabled = false;
> @@ -1351,6 +1413,7 @@ static int mtk_dsi_remove(struct platform_device *pdev)
>  }
>  
>  static const struct of_device_id mtk_dsi_of_match[] = {
> +	{ .compatible = "mediatek,mt2701-dsi" },

This is not related to 'mipi panel support'. So move this modification
to another patch.

>  	{ .compatible = "mediatek,mt8173-dsi" },
>  	{ },
>  };
> diff --git a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
> index cf8f38d..3bffc40 100644
> --- a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
> +++ b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
> @@ -16,6 +16,7 @@
>  #include <linux/delay.h>
>  #include <linux/io.h>
>  #include <linux/module.h>
> +#include <linux/of_device.h>
>  #include <linux/platform_device.h>
>  #include <linux/phy/phy.h>
>  
> @@ -87,6 +88,9 @@
>  
>  #define MIPITX_DSI_PLL_CON2	0x58
>  
> +#define MIPITX_DSI_PLL_TOP	0x64
> +#define RG_DSI_MPPLL_PRESERVE		(0xff << 8)
> +
>  #define MIPITX_DSI_PLL_PWR	0x68
>  #define RG_DSI_MPPLL_SDM_PWR_ON		BIT(0)
>  #define RG_DSI_MPPLL_SDM_ISO_EN		BIT(1)
> @@ -123,10 +127,32 @@
>  #define SW_LNT2_HSTX_PRE_OE		BIT(24)
>  #define SW_LNT2_HSTX_OE			BIT(25)
>  
> +struct mtk_mipitx_data {
> +	const u32 data;
> +};
> +
> +static const struct mtk_mipitx_data mt2701_mipitx_data = {
> +	.data = (3 << 8)
> +};
> +
> +static const struct mtk_mipitx_data mt8173_mipitx_data = {
> +	.data = (0 << 8)
> +};
> +
> +static const struct of_device_id mtk_mipi_tx_match[] = {
> +	{ .compatible = "mediatek,mt2701-mipi-tx",
> +	  .data = &mt2701_mipitx_data },
> +	{ .compatible = "mediatek,mt8173-mipi-tx",
> +	  .data = &mt8173_mipitx_data },
> +	{},
> +};

This looks more like 'mt2701 support' rather than 'mipi panel support'.
So move this modification to another patch.

> +
>  struct mtk_mipi_tx {
>  	struct device *dev;
>  	void __iomem *regs;
> -	unsigned int data_rate;
> +	u32 data_rate;
> +	const struct mtk_mipitx_data *driver_data;
> +
>  	struct clk_hw pll_hw;
>  	struct clk *pll;
>  };
> @@ -163,12 +189,14 @@ static void mtk_mipi_tx_update_bits(struct mtk_mipi_tx *mipi_tx, u32 offset,
>  static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw)
>  {
>  	struct mtk_mipi_tx *mipi_tx = mtk_mipi_tx_from_clk_hw(hw);
> -	unsigned int txdiv, txdiv0, txdiv1;
> +	u8 txdiv, txdiv0, txdiv1;
>  	u64 pcw;
>  
>  	dev_dbg(mipi_tx->dev, "prepare: %u Hz\n", mipi_tx->data_rate);
>  
> -	if (mipi_tx->data_rate >= 500000000) {
> +	if (mipi_tx->data_rate > 1250000000) {
> +		return -EINVAL;
> +	} else if (mipi_tx->data_rate >= 500000000) {
>  		txdiv = 1;
>  		txdiv0 = 0;
>  		txdiv1 = 0;
> @@ -192,6 +220,10 @@ static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw)
>  		return -EINVAL;
>  	}
>  
> +	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_TOP_CON,
> +				RG_DSI_LNT_IMP_CAL_CODE | RG_DSI_LNT_HS_BIAS_EN,
> +				(8 << 4) | RG_DSI_LNT_HS_BIAS_EN);
> +
>  	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_BG_CON,
>  				RG_DSI_VOUT_MSK |
>  				RG_DSI_BG_CKEN | RG_DSI_BG_CORE_EN,
> @@ -201,24 +233,18 @@ static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw)
>  
>  	usleep_range(30, 100);
>  
> -	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_TOP_CON,
> -				RG_DSI_LNT_IMP_CAL_CODE | RG_DSI_LNT_HS_BIAS_EN,
> -				(8 << 4) | RG_DSI_LNT_HS_BIAS_EN);
> -
> -	mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_CON,
> -			     RG_DSI_CKG_LDOOUT_EN | RG_DSI_LDOCORE_EN);
> +	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_CON,
> +				RG_DSI_CKG_LDOOUT_EN | RG_DSI_LDOCORE_EN,
> +				RG_DSI_CKG_LDOOUT_EN | RG_DSI_LDOCORE_EN);
>  
>  	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_PWR,
>  				RG_DSI_MPPLL_SDM_PWR_ON |
>  				RG_DSI_MPPLL_SDM_ISO_EN,
>  				RG_DSI_MPPLL_SDM_PWR_ON);
>  
> -	mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON0,
> -			       RG_DSI_MPPLL_PLL_EN);
> -
>  	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_CON0,
> -				RG_DSI_MPPLL_TXDIV0 | RG_DSI_MPPLL_TXDIV1 |
> -				RG_DSI_MPPLL_PREDIV,
> +				RG_DSI_MPPLL_PREDIV | RG_DSI_MPPLL_TXDIV0 |
> +				RG_DSI_MPPLL_TXDIV1 | RG_DSI_MPPLL_POSDIV,
>  				(txdiv0 << 3) | (txdiv1 << 5));
>  
>  	/*
> @@ -233,15 +259,21 @@ static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw)
>  		      26000000);
>  	writel(pcw, mipi_tx->regs + MIPITX_DSI_PLL_CON2);
>  
> -	mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_PLL_CON1,
> -			     RG_DSI_MPPLL_SDM_FRA_EN);
> +	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_CON1,
> +				RG_DSI_MPPLL_SDM_FRA_EN,
> +				RG_DSI_MPPLL_SDM_FRA_EN);
>  
> -	mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_PLL_CON0, RG_DSI_MPPLL_PLL_EN);
> +	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_CON0,
> +				RG_DSI_MPPLL_PLL_EN, RG_DSI_MPPLL_PLL_EN);
>  
>  	usleep_range(20, 100);
>  
>  	mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON1,
> -			       RG_DSI_MPPLL_SDM_SSC_EN);
> +					RG_DSI_MPPLL_SDM_SSC_EN);
> +
> +	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_TOP,
> +				RG_DSI_MPPLL_PRESERVE,
> +				mipi_tx->driver_data->data);
>  
>  	return 0;
>  }
> @@ -255,6 +287,10 @@ static void mtk_mipi_tx_pll_unprepare(struct clk_hw *hw)
>  	mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON0,
>  			       RG_DSI_MPPLL_PLL_EN);
>  
> +	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_TOP,
> +				RG_DSI_MPPLL_PRESERVE,
> +				mipi_tx->driver_data->data);
> +
>  	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_PWR,
>  				RG_DSI_MPPLL_SDM_ISO_EN |
>  				RG_DSI_MPPLL_SDM_PWR_ON,
> @@ -310,7 +346,7 @@ static const struct clk_ops mtk_mipi_tx_pll_ops = {
>  static int mtk_mipi_tx_power_on_signal(struct phy *phy)
>  {
>  	struct mtk_mipi_tx *mipi_tx = phy_get_drvdata(phy);
> -	unsigned int reg;
> +	u32 reg;

I think this should be moved to a 'cleaning up and refine' patch.

>  
>  	for (reg = MIPITX_DSI_CLOCK_LANE;
>  	     reg <= MIPITX_DSI_DATA_LANE3; reg += 4)
> @@ -341,7 +377,7 @@ static int mtk_mipi_tx_power_on(struct phy *phy)
>  static void mtk_mipi_tx_power_off_signal(struct phy *phy)
>  {
>  	struct mtk_mipi_tx *mipi_tx = phy_get_drvdata(phy);
> -	unsigned int reg;
> +	u32 reg;

I think this should be moved to a 'cleaning up and refine' patch.

>  
>  	mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_TOP_CON,
>  			     RG_DSI_PAD_TIE_LOW_EN);
> @@ -391,6 +427,7 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev)
>  	if (!mipi_tx)
>  		return -ENOMEM;
>  
> +	mipi_tx->driver_data = of_device_get_match_data(dev);
>  	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	mipi_tx->regs = devm_ioremap_resource(dev, mem);
>  	if (IS_ERR(mipi_tx->regs)) {
> @@ -448,11 +485,6 @@ static int mtk_mipi_tx_remove(struct platform_device *pdev)
>  	return 0;
>  }
>  
> -static const struct of_device_id mtk_mipi_tx_match[] = {
> -	{ .compatible = "mediatek,mt8173-mipi-tx", },
> -	{},
> -};
> -
>  struct platform_driver mtk_mipi_tx_driver = {
>  	.probe = mtk_mipi_tx_probe,
>  	.remove = mtk_mipi_tx_remove,

Regards,
CK



From ck.hu at mediatek.com  Tue Jul 19 23:53:19 2016
From: ck.hu at mediatek.com (CK Hu)
Date: Wed, 20 Jul 2016 14:53:19 +0800
Subject: [PATCH v4 4/8] drm/mediatek: add support for Mediatek SoC MT2701
In-Reply-To: <1468577274-6178-5-git-send-email-yt.shen@mediatek.com>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
 <1468577274-6178-5-git-send-email-yt.shen@mediatek.com>
Message-ID: <1468997599.11841.49.camel@mtksdaap41>

Hi, YT:

Some comments inline.

On Fri, 2016-07-15 at 18:07 +0800, YT Shen wrote:
> This patch add support for the Mediatek MT2701 DISP subsystem.
> There is only one OVL engine in MT2701.
> 
> Signed-off-by: YT Shen <yt.shen at mediatek.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_disp_ovl.c     |    6 ++++
>  drivers/gpu/drm/mediatek/mtk_disp_rdma.c    |    6 ++++
>  drivers/gpu/drm/mediatek/mtk_drm_ddp.c      |   41 +++++++++++++++++++++++++++
>  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |    7 +++++
>  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |    1 +
>  drivers/gpu/drm/mediatek/mtk_drm_drv.c      |   31 ++++++++++++++++++++
>  6 files changed, 92 insertions(+)
> 

[snip...]

>  
>  static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
> +	{ .compatible = "mediatek,mt2701-disp-ovl",   .data = (void *)MTK_DISP_OVL },
>  	{ .compatible = "mediatek,mt8173-disp-ovl",   .data = (void *)MTK_DISP_OVL },
> +	{ .compatible = "mediatek,mt2701-disp-rdma",  .data = (void *)MTK_DISP_RDMA },
>  	{ .compatible = "mediatek,mt8173-disp-rdma",  .data = (void *)MTK_DISP_RDMA },
> +	{ .compatible = "mediatek,mt2701-disp-wdma",  .data = (void *)MTK_DISP_WDMA },

Is WDMA different from MT8173 to MT2701. If they are the same, you need
not to add compatible of 'mediatek,mt2701-disp-wdma' because use
'mediatek,mt8173-disp-wdma' is enough.

>  	{ .compatible = "mediatek,mt8173-disp-wdma",  .data = (void *)MTK_DISP_WDMA },
> +	{ .compatible = "mediatek,mt2701-disp-color", .data = (void *)MTK_DISP_COLOR },
>  	{ .compatible = "mediatek,mt8173-disp-color", .data = (void *)MTK_DISP_COLOR },
>  	{ .compatible = "mediatek,mt8173-disp-aal",   .data = (void *)MTK_DISP_AAL},
>  	{ .compatible = "mediatek,mt8173-disp-gamma", .data = (void *)MTK_DISP_GAMMA, },
>  	{ .compatible = "mediatek,mt8173-disp-ufoe",  .data = (void *)MTK_DISP_UFOE },
> +	{ .compatible = "mediatek,mt2701-dsi",	      .data = (void *)MTK_DSI },
>  	{ .compatible = "mediatek,mt8173-dsi",        .data = (void *)MTK_DSI },
> +	{ .compatible = "mediatek,mt2701-dpi",	      .data = (void *)MTK_DPI },

Is DPI different from MT8173 to MT2701. If they are the same, you need
not to add compatible of 'mediatek,mt2701-dpi' because use
'mediatek,mt8173-dpi' is enough.

>  	{ .compatible = "mediatek,mt8173-dpi",        .data = (void *)MTK_DPI },
> +	{ .compatible = "mediatek,mt2701-disp-mutex", .data = (void *)MTK_DISP_MUTEX },
>  	{ .compatible = "mediatek,mt8173-disp-mutex", .data = (void *)MTK_DISP_MUTEX },
> +	{ .compatible = "mediatek,mt2701-disp-pwm",   .data = (void *)MTK_DISP_PWM },

Is pwm different from MT8173 to MT2701. If they are the same, you need
not to add compatible of 'mediatek,mt2701-disp-pwm' because use
'mediatek,mt8173-disp-pwm' is enough.

>  	{ .compatible = "mediatek,mt8173-disp-pwm",   .data = (void *)MTK_DISP_PWM },
>  	{ .compatible = "mediatek,mt8173-disp-od",    .data = (void *)MTK_DISP_OD },
>  	{ }
> @@ -514,6 +543,8 @@ static SIMPLE_DEV_PM_OPS(mtk_drm_pm_ops, mtk_drm_sys_suspend,
>  			 mtk_drm_sys_resume);
>  
>  static const struct of_device_id mtk_drm_of_ids[] = {
> +	{ .compatible = "mediatek,mt2701-mmsys",
> +	  .data = &mt2701_mmsys_driver_data},
>  	{ .compatible = "mediatek,mt8173-mmsys",
>  	  .data = &mt8173_mmsys_driver_data},
>  	{ }

Regards,
CK



From ck.hu at mediatek.com  Wed Jul 20 00:15:02 2016
From: ck.hu at mediatek.com (CK Hu)
Date: Wed, 20 Jul 2016 15:15:02 +0800
Subject: [PATCH 2/4] drm/mediatek: enhance the HDMI driving current
In-Reply-To: <1468987385-37353-3-git-send-email-bibby.hsieh@mediatek.com>
References: <1468987385-37353-1-git-send-email-bibby.hsieh@mediatek.com>
 <1468987385-37353-3-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1468998902.11841.54.camel@mtksdaap41>

Hi, Bibby:

One comment inline.

On Wed, 2016-07-20 at 12:03 +0800, Bibby Hsieh wrote:
> From: Junzhi Zhao <junzhi.zhao at mediatek.com>
> 
> In order to improve 4K resolution performance,
> we have to enhance the HDMI driving currend
> when clock rate is greater than 165MHz.
> 
> Signed-off-by: Junzhi Zhao <junzhi.zhao at mediatek.com>
> Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c |   89 +++++++++++++++++-------
>  1 file changed, 63 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
> index 8a24754..a871c14 100644
> --- a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
> +++ b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
> @@ -298,32 +298,69 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
>  			  (0x1 << PLL_BR_SHIFT),
>  			  RG_HDMITX_PLL_BP | RG_HDMITX_PLL_BC |
>  			  RG_HDMITX_PLL_BR);
> -	mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON3, RG_HDMITX_PRD_IMP_EN);
> -	mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON4,
> -			  (0x3 << PRD_IBIAS_CLK_SHIFT) |
> -			  (0x3 << PRD_IBIAS_D2_SHIFT) |
> -			  (0x3 << PRD_IBIAS_D1_SHIFT) |
> -			  (0x3 << PRD_IBIAS_D0_SHIFT),
> -			  RG_HDMITX_PRD_IBIAS_CLK |
> -			  RG_HDMITX_PRD_IBIAS_D2 |
> -			  RG_HDMITX_PRD_IBIAS_D1 |
> -			  RG_HDMITX_PRD_IBIAS_D0);
> -	mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON3,
> -			  (0x0 << DRV_IMP_EN_SHIFT), RG_HDMITX_DRV_IMP_EN);
> -	mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6,
> -			  (hdmi_phy->drv_imp_clk << DRV_IMP_CLK_SHIFT) |
> -			  (hdmi_phy->drv_imp_d2 << DRV_IMP_D2_SHIFT) |
> -			  (hdmi_phy->drv_imp_d1 << DRV_IMP_D1_SHIFT) |
> -			  (hdmi_phy->drv_imp_d0 << DRV_IMP_D0_SHIFT),
> -			  RG_HDMITX_DRV_IMP_CLK | RG_HDMITX_DRV_IMP_D2 |
> -			  RG_HDMITX_DRV_IMP_D1 | RG_HDMITX_DRV_IMP_D0);
> -	mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON5,
> -			  (hdmi_phy->ibias << DRV_IBIAS_CLK_SHIFT) |
> -			  (hdmi_phy->ibias << DRV_IBIAS_D2_SHIFT) |
> -			  (hdmi_phy->ibias << DRV_IBIAS_D1_SHIFT) |
> -			  (hdmi_phy->ibias << DRV_IBIAS_D0_SHIFT),
> -			  RG_HDMITX_DRV_IBIAS_CLK | RG_HDMITX_DRV_IBIAS_D2 |
> -			  RG_HDMITX_DRV_IBIAS_D1 | RG_HDMITX_DRV_IBIAS_D0);
> +	if (rate < 165000000) {
> +		mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON3,
> +					RG_HDMITX_PRD_IMP_EN);
> +		mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON4,
> +				  (0x3 << PRD_IBIAS_CLK_SHIFT) |
> +				  (0x3 << PRD_IBIAS_D2_SHIFT) |
> +				  (0x3 << PRD_IBIAS_D1_SHIFT) |
> +				  (0x3 << PRD_IBIAS_D0_SHIFT),
> +				  RG_HDMITX_PRD_IBIAS_CLK |
> +				  RG_HDMITX_PRD_IBIAS_D2 |
> +				  RG_HDMITX_PRD_IBIAS_D1 |
> +				  RG_HDMITX_PRD_IBIAS_D0);
> +		mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON3,
> +				  (0x0 << DRV_IMP_EN_SHIFT),
> +				  RG_HDMITX_DRV_IMP_EN);
> +		mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6,
> +				  (hdmi_phy->drv_imp_clk << DRV_IMP_CLK_SHIFT) |
> +				  (hdmi_phy->drv_imp_d2 << DRV_IMP_D2_SHIFT) |
> +				  (hdmi_phy->drv_imp_d1 << DRV_IMP_D1_SHIFT) |
> +				  (hdmi_phy->drv_imp_d0 << DRV_IMP_D0_SHIFT),
> +				  RG_HDMITX_DRV_IMP_CLK | RG_HDMITX_DRV_IMP_D2 |
> +				  RG_HDMITX_DRV_IMP_D1 | RG_HDMITX_DRV_IMP_D0);
> +		mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON5,
> +				  (hdmi_phy->ibias << DRV_IBIAS_CLK_SHIFT) |
> +				  (hdmi_phy->ibias << DRV_IBIAS_D2_SHIFT) |
> +				  (hdmi_phy->ibias << DRV_IBIAS_D1_SHIFT) |
> +				  (hdmi_phy->ibias << DRV_IBIAS_D0_SHIFT),
> +				  RG_HDMITX_DRV_IBIAS_CLK |
> +				  RG_HDMITX_DRV_IBIAS_D2 |
> +				  RG_HDMITX_DRV_IBIAS_D1 |
> +				  RG_HDMITX_DRV_IBIAS_D0);
> +	} else {
> +		mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON3,
> +				      RG_HDMITX_PRD_IMP_EN);
> +		mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON4,
> +				  (0x6 << PRD_IBIAS_CLK_SHIFT) |
> +				  (0x6 << PRD_IBIAS_D2_SHIFT) |
> +				  (0x6 << PRD_IBIAS_D1_SHIFT) |
> +				  (0x6 << PRD_IBIAS_D0_SHIFT),
> +				  RG_HDMITX_PRD_IBIAS_CLK |
> +				  RG_HDMITX_PRD_IBIAS_D2 |
> +				  RG_HDMITX_PRD_IBIAS_D1 |
> +				  RG_HDMITX_PRD_IBIAS_D0);
> +		mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON3,
> +				  (0xf << DRV_IMP_EN_SHIFT),
> +				  RG_HDMITX_DRV_IMP_EN);
> +		mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6,
> +				  (hdmi_phy->drv_imp_clk << DRV_IMP_CLK_SHIFT) |
> +				  (hdmi_phy->drv_imp_d2 << DRV_IMP_D2_SHIFT) |
> +				  (hdmi_phy->drv_imp_d1 << DRV_IMP_D1_SHIFT) |
> +				  (hdmi_phy->drv_imp_d0 << DRV_IMP_D0_SHIFT),
> +				  RG_HDMITX_DRV_IMP_CLK | RG_HDMITX_DRV_IMP_D2 |
> +				  RG_HDMITX_DRV_IMP_D1 | RG_HDMITX_DRV_IMP_D0);
> +		mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON5,
> +				  (hdmi_phy->ibias_up << DRV_IBIAS_CLK_SHIFT) |
> +				  (hdmi_phy->ibias_up << DRV_IBIAS_D2_SHIFT) |
> +				  (hdmi_phy->ibias_up << DRV_IBIAS_D1_SHIFT) |
> +				  (hdmi_phy->ibias_up << DRV_IBIAS_D0_SHIFT),
> +				  RG_HDMITX_DRV_IBIAS_CLK |
> +				  RG_HDMITX_DRV_IBIAS_D2 |
> +				  RG_HDMITX_DRV_IBIAS_D1 |
> +				  RG_HDMITX_DRV_IBIAS_D0);
> +	}

'if' part and 'else' part looks almost the same. Use variable for
difference and merge these two part. For example:

if (rate < 165000000)
	prd_ibias = 0x3;
else
	prd_ibias = 0x6;

mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON4,
		  (prd_ibias << PRD_IBIAS_CLK_SHIFT) |
		  (prd_ibias << PRD_IBIAS_D2_SHIFT) |
		  (prd_ibias << PRD_IBIAS_D1_SHIFT) |
		  (prd_ibias << PRD_IBIAS_D0_SHIFT),
		  RG_HDMITX_PRD_IBIAS_CLK |
		  RG_HDMITX_PRD_IBIAS_D2 |
		  RG_HDMITX_PRD_IBIAS_D1 |
		  RG_HDMITX_PRD_IBIAS_D0);

>  	return 0;
>  }
>  

Regards,
CK



From ck.hu at mediatek.com  Wed Jul 20 00:57:23 2016
From: ck.hu at mediatek.com (CK Hu)
Date: Wed, 20 Jul 2016 15:57:23 +0800
Subject: [PATCH 3/4] drm/mediatek: fix the wrong pixel clock when
 resolution is 4K
In-Reply-To: <1468987385-37353-4-git-send-email-bibby.hsieh@mediatek.com>
References: <1468987385-37353-1-git-send-email-bibby.hsieh@mediatek.com>
 <1468987385-37353-4-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1469001443.11841.59.camel@mtksdaap41>

Hi, Bibby:

Some comments inline.

On Wed, 2016-07-20 at 12:03 +0800, Bibby Hsieh wrote:
> From: Junzhi Zhao <junzhi.zhao at mediatek.com>
> 
> Pixel clock should be 297MHz when resolution is 4K.
> 
> Signed-off-by: Junzhi Zhao <junzhi.zhao at mediatek.com>
> Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_dpi.c |  184 +++++++++++++++++++++++++-----------
>  1 file changed, 131 insertions(+), 53 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
> index d05ca79..c0f04d2 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dpi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
> @@ -60,14 +60,35 @@ enum mtk_dpi_out_color_format {
>  	MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL
>  };
>  
> +enum mtk_dpi_clk_id {
> +	MTK_DPI_CLK_DPI_ENGINE,
> +	MTK_DPI_CLK_DPI_PIXEL,
> +	MTK_DPI_CLK_TVD_PLL,
> +	MTK_DPI_CLK_TVDPLL_MUX,
> +	MTK_DPI_CLK_TVDPLL_D2,
> +	MTK_DPI_CLK_TVDPLL_D4,
> +	MTK_DPI_CLK_TVDPLL_D8,
> +	MTK_DPI_CLK_TVDPLL_D16,
> +	MTK_DPI_CLK_COUNT,
> +};
> +
> +static const char * const mtk_dpi_clk_names[MTK_DPI_CLK_COUNT] = {
> +	[MTK_DPI_CLK_DPI_ENGINE] = "engine",
> +	[MTK_DPI_CLK_DPI_PIXEL] = "pixel",
> +	[MTK_DPI_CLK_TVD_PLL] = "pll",
> +	[MTK_DPI_CLK_TVDPLL_MUX] = "tvdpll_mux",
> +	[MTK_DPI_CLK_TVDPLL_D2] = "tvdpll_d2",
> +	[MTK_DPI_CLK_TVDPLL_D4] = "tvdpll_d4",
> +	[MTK_DPI_CLK_TVDPLL_D8] = "tvdpll_d8",
> +	[MTK_DPI_CLK_TVDPLL_D16] = "tvdpll_d16",
> +};
> +
>  struct mtk_dpi {
>  	struct mtk_ddp_comp ddp_comp;
>  	struct drm_encoder encoder;
>  	void __iomem *regs;
>  	struct device *dev;
> -	struct clk *engine_clk;
> -	struct clk *pixel_clk;
> -	struct clk *tvd_clk;
> +	struct clk *clk[MTK_DPI_CLK_COUNT];
>  	int irq;
>  	struct drm_display_mode mode;
>  	enum mtk_dpi_out_color_format color_format;
> @@ -76,6 +97,7 @@ struct mtk_dpi {
>  	enum mtk_dpi_out_channel_swap channel_swap;
>  	bool power_sta;
>  	u8 power_ctl;
> +	void *data;
>  };
>  
>  static inline struct mtk_dpi *mtk_dpi_from_encoder(struct drm_encoder *e)
> @@ -114,6 +136,11 @@ struct mtk_dpi_yc_limit {
>  	u16 c_bottom;
>  };
>  
> +struct mtk_dpi_conf {
> +	int (*parse_clk_from_dt)(struct mtk_dpi *dpi, struct device_node *np);
> +	int (*clk_config)(struct mtk_dpi *dpi, struct drm_display_mode *mode);
> +};
> +
>  static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask)
>  {
>  	u32 tmp = readl(dpi->regs + offset) & ~mask;
> @@ -377,8 +404,8 @@ static void mtk_dpi_power_off(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl)
>  		return;
>  
>  	mtk_dpi_disable(dpi);
> -	clk_disable_unprepare(dpi->pixel_clk);
> -	clk_disable_unprepare(dpi->engine_clk);
> +	clk_disable_unprepare(dpi->clk[MTK_DPI_CLK_DPI_PIXEL]);
> +	clk_disable_unprepare(dpi->clk[MTK_DPI_CLK_DPI_ENGINE]);
>  	dpi->power_sta = false;
>  }
>  
> @@ -395,13 +422,13 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl)
>  	if (dpi->power_sta)
>  		return 0;
>  
> -	ret = clk_prepare_enable(dpi->engine_clk);
> +	ret = clk_prepare_enable(dpi->clk[MTK_DPI_CLK_DPI_ENGINE]);
>  	if (ret) {
>  		dev_err(dpi->dev, "Failed to enable engine clock: %d\n", ret);
>  		goto err_eng;
>  	}
>  
> -	ret = clk_prepare_enable(dpi->pixel_clk);
> +	ret = clk_prepare_enable(dpi->clk[MTK_DPI_CLK_DPI_PIXEL]);
>  	if (ret) {
>  		dev_err(dpi->dev, "Failed to enable pixel clock: %d\n", ret);
>  		goto err_pixel;
> @@ -412,7 +439,7 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl)
>  	return 0;
>  
>  err_pixel:
> -	clk_disable_unprepare(dpi->engine_clk);
> +	clk_disable_unprepare(dpi->clk[MTK_DPI_CLK_DPI_ENGINE]);
>  err_eng:
>  	dpi->power_ctl &= ~pctl;
>  	return ret;
> @@ -428,34 +455,16 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
>  	struct mtk_dpi_sync_param vsync_leven = { 0 };
>  	struct mtk_dpi_sync_param vsync_rodd = { 0 };
>  	struct mtk_dpi_sync_param vsync_reven = { 0 };
> -	unsigned long pix_rate;
> -	unsigned long pll_rate;
> -	unsigned int factor;
> +	struct mtk_dpi_conf *conf;
> +	int ret;
>  
>  	if (!dpi) {
>  		dev_err(dpi->dev, "invalid argument\n");
>  		return -EINVAL;
>  	}
>  
> -	pix_rate = 1000UL * mode->clock;
> -	if (mode->clock <= 74000)
> -		factor = 8 * 3;
> -	else
> -		factor = 4 * 3;
> -	pll_rate = pix_rate * factor;
> -
> -	dev_dbg(dpi->dev, "Want PLL %lu Hz, pixel clock %lu Hz\n",
> -		pll_rate, pix_rate);
> -
> -	clk_set_rate(dpi->tvd_clk, pll_rate);
> -	pll_rate = clk_get_rate(dpi->tvd_clk);
> -
> -	pix_rate = pll_rate / factor;
> -	clk_set_rate(dpi->pixel_clk, pix_rate);
> -	pix_rate = clk_get_rate(dpi->pixel_clk);
> -
> -	dev_dbg(dpi->dev, "Got  PLL %lu Hz, pixel clock %lu Hz\n",
> -		pll_rate, pix_rate);
> +	conf = (struct mtk_dpi_conf *)dpi->data;
> +	ret = conf->clk_config(dpi, mode);

Nothing to do with return error?

>  
>  	limit.c_bottom = 0x0010;
>  	limit.c_top = 0x0FE0;
> @@ -656,20 +665,109 @@ static const struct component_ops mtk_dpi_component_ops = {
>  	.unbind = mtk_dpi_unbind,
>  };
>  
> +static int mt8173_parse_clk_from_dt(struct mtk_dpi *dpi, struct device_node *np)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(mtk_dpi_clk_names); i++) {
> +		dpi->clk[i] = of_clk_get_by_name(np,
> +						  mtk_dpi_clk_names[i]);
> +		if (IS_ERR(dpi->clk[i]))
> +			return PTR_ERR(dpi->clk[i]);
> +	}
> +	return 0;
> +}

I think parsing device tree is a pure SW behavior. Would this vary for
different MTK soc?

> +
> +static int mt8173_clk_config(struct mtk_dpi *dpi, struct drm_display_mode *mode)
> +{
> +	unsigned long pix_rate;
> +	unsigned long pll_rate;
> +	unsigned int factor;
> +	struct clk *parent;
> +	int ret;
> +
> +	if (mode->clock <= 27000) {
> +		factor = 16 * 3;
> +		parent = dpi->clk[MTK_DPI_CLK_TVDPLL_D16];
> +	} else if (mode->clock <= 74250) {
> +		factor = 8 * 3;
> +		parent = dpi->clk[MTK_DPI_CLK_TVDPLL_D8];
> +	} else if (mode->clock <= 167000) {
> +		factor = 4 * 3;
> +		parent = dpi->clk[MTK_DPI_CLK_TVDPLL_D4];
> +	} else {
> +		factor = 2 * 3;
> +		parent = dpi->clk[MTK_DPI_CLK_TVDPLL_D2];
> +	}
> +
> +	pix_rate = 1000UL * mode->clock;
> +	pll_rate = pix_rate * factor;
> +
> +	dev_dbg(dpi->dev, "Want PLL %lu Hz, pixel clock %lu Hz\n",
> +		pll_rate, pix_rate);
> +
> +	ret = clk_prepare_enable(dpi->clk[MTK_DPI_CLK_TVDPLL_MUX]);
> +	if (ret) {
> +		dev_err(dpi->dev, "tvdpll_mux enable fail\n");
> +		return ret;
> +	}
> +
> +	ret = clk_set_parent(dpi->clk[MTK_DPI_CLK_TVDPLL_MUX], parent);
> +	if (ret) {
> +		dev_err(dpi->dev, "tvdpll_mux set parent fail\n");

Before return, you may undo something.

> +		return ret;
> +	}
> +	clk_disable_unprepare(dpi->clk[MTK_DPI_CLK_TVDPLL_MUX]);
> +
> +	ret = clk_set_rate(dpi->clk[MTK_DPI_CLK_TVD_PLL], pll_rate);
> +	if (ret) {
> +		dev_err(dpi->dev, "dpi pll_rate set rate fail\n");
> +		return ret;
> +	}
> +	pll_rate = clk_get_rate(dpi->clk[MTK_DPI_CLK_TVD_PLL]);
> +	pix_rate = clk_get_rate(dpi->clk[MTK_DPI_CLK_DPI_PIXEL]);
> +
> +	dev_dbg(dpi->dev, "Got  PLL %lu Hz, pixel clock %lu Hz\n",
> +		pll_rate, pix_rate);
> +
> +	return 0;
> +}
> +
> +static const struct mtk_dpi_conf mt8173_conf = {
> +	.parse_clk_from_dt = mt8173_parse_clk_from_dt,
> +	.clk_config = mt8173_clk_config,
> +};
> +
> +static const struct of_device_id mtk_dpi_of_ids[] = {
> +	{ .compatible = "mediatek,mt8173-dpi",
> +		.data = &mt8173_conf,
> +	},
> +	{}
> +};
> +
>  static int mtk_dpi_probe(struct platform_device *pdev)
>  {
>  	struct device *dev = &pdev->dev;
>  	struct mtk_dpi *dpi;
>  	struct resource *mem;
> +	struct device_node *np = dev->of_node;
>  	struct device_node *ep, *bridge_node = NULL;
>  	int comp_id;
> +	const struct of_device_id *match;
> +	struct mtk_dpi_conf *conf;
>  	int ret;
>  
> +	match = of_match_node(mtk_dpi_of_ids, dev->of_node);
> +	if (!match)
> +		return -ENODEV;
> +
>  	dpi = devm_kzalloc(dev, sizeof(*dpi), GFP_KERNEL);
>  	if (!dpi)
>  		return -ENOMEM;
>  
>  	dpi->dev = dev;
> +	dpi->data = (void *)match->data;
> +	conf = (struct mtk_dpi_conf *)match->data;
>  
>  	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	dpi->regs = devm_ioremap_resource(dev, mem);
> @@ -679,24 +777,9 @@ static int mtk_dpi_probe(struct platform_device *pdev)
>  		return ret;
>  	}
>  
> -	dpi->engine_clk = devm_clk_get(dev, "engine");
> -	if (IS_ERR(dpi->engine_clk)) {
> -		ret = PTR_ERR(dpi->engine_clk);
> -		dev_err(dev, "Failed to get engine clock: %d\n", ret);
> -		return ret;
> -	}
> -
> -	dpi->pixel_clk = devm_clk_get(dev, "pixel");
> -	if (IS_ERR(dpi->pixel_clk)) {
> -		ret = PTR_ERR(dpi->pixel_clk);
> -		dev_err(dev, "Failed to get pixel clock: %d\n", ret);
> -		return ret;
> -	}
> -
> -	dpi->tvd_clk = devm_clk_get(dev, "pll");
> -	if (IS_ERR(dpi->tvd_clk)) {
> -		ret = PTR_ERR(dpi->tvd_clk);
> -		dev_err(dev, "Failed to get tvdpll clock: %d\n", ret);
> +	ret = conf->parse_clk_from_dt(dpi, np);
> +	if (ret) {
> +		dev_err(dev, "parse tvd div clk failed!");
>  		return ret;
>  	}
>  
> @@ -754,11 +837,6 @@ static int mtk_dpi_remove(struct platform_device *pdev)
>  	return 0;
>  }
>  
> -static const struct of_device_id mtk_dpi_of_ids[] = {
> -	{ .compatible = "mediatek,mt8173-dpi", },
> -	{}
> -};
> -
>  struct platform_driver mtk_dpi_driver = {
>  	.probe = mtk_dpi_probe,
>  	.remove = mtk_dpi_remove,

Regards,
CK



From p.zabel at pengutronix.de  Wed Jul 20 02:41:58 2016
From: p.zabel at pengutronix.de (Philipp Zabel)
Date: Wed, 20 Jul 2016 11:41:58 +0200
Subject: [PATCH 3/4] drm/mediatek: fix the wrong pixel clock when
 resolution is 4K
In-Reply-To: <1468987385-37353-4-git-send-email-bibby.hsieh@mediatek.com>
References: <1468987385-37353-1-git-send-email-bibby.hsieh@mediatek.com>
 <1468987385-37353-4-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1469007718.5809.32.camel@pengutronix.de>

Am Mittwoch, den 20.07.2016, 12:03 +0800 schrieb Bibby Hsieh:
> From: Junzhi Zhao <junzhi.zhao at mediatek.com>
> 
> Pixel clock should be 297MHz when resolution is 4K.
> 
> Signed-off-by: Junzhi Zhao <junzhi.zhao at mediatek.com>
> Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_dpi.c |  184 +++++++++++++++++++++++++-----------
>  1 file changed, 131 insertions(+), 53 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
> index d05ca79..c0f04d2 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dpi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
> @@ -60,14 +60,35 @@ enum mtk_dpi_out_color_format {
>  	MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL
>  };
>  
> +enum mtk_dpi_clk_id {
> +	MTK_DPI_CLK_DPI_ENGINE,
> +	MTK_DPI_CLK_DPI_PIXEL,
> +	MTK_DPI_CLK_TVD_PLL,
> +	MTK_DPI_CLK_TVDPLL_MUX,
> +	MTK_DPI_CLK_TVDPLL_D2,
> +	MTK_DPI_CLK_TVDPLL_D4,
> +	MTK_DPI_CLK_TVDPLL_D8,
> +	MTK_DPI_CLK_TVDPLL_D16,
> +	MTK_DPI_CLK_COUNT,
> +};

I think this is going in the wrong direction. If the pixel clock output
isn't correct after a clk_set_rate(dpi->pixel_clk, rate), the clock
drivers should be fixed, not worked around in the dpi driver.

The TVDPLL_* mux and dividers are not direct inputs to the DPI module:

   tvdpll ("pll")
     |               ..|\
     v               ..| | mm_sel ----> mm_dpi_engine ("engine")
   tvdpll_594m(1/3)  ..|/
     |
     |`-> tvdpll_d2 -->|\
     |`-> tvdpll_d4 -->| | dpi0_sel --> mm_dpi_pixel ("pixel")
     |`-> tvdpll_d8 -->| |
     `--> tvdpll_d16 ->|/

Currently the code first sets the "pll" to the desired multiple of the
pixel clock manually (*3*4, *3*8) and than calls clk_set_rate on the
"pixel" clock which gets propagated by the clock framework up to
dpi0_sel. Since dpi0_sel doesn't have the CLK_SET_RATE_PARENT flag set,
it should just choose the tvdpll_d* input divider. I'd like not to give
the dpi driver direct access to all the intermediate clocks.

regards
Philipp


From p.zabel at pengutronix.de  Wed Jul 20 02:55:05 2016
From: p.zabel at pengutronix.de (Philipp Zabel)
Date: Wed, 20 Jul 2016 11:55:05 +0200
Subject: [PATCH 4/4] drm/mediatek: adjust VENCPLL clock for 4K HDMI output
In-Reply-To: <1468987385-37353-5-git-send-email-bibby.hsieh@mediatek.com>
References: <1468987385-37353-1-git-send-email-bibby.hsieh@mediatek.com>
 <1468987385-37353-5-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1469008505.5809.41.camel@pengutronix.de>

Hi Bibby,

Am Mittwoch, den 20.07.2016, 12:03 +0800 schrieb Bibby Hsieh:
> if MT8173 display module can support 4K HDMI output,
> we have to adjust VENCPLL clock from default 660MHz
> to 800MHz.

Is vencpll(_d2) the active source for the mm_sel mux? If so, it seems to
me that mm_sel or rather one of its children should be set to 800 MHz,
and the clock framework should propagate it up to vencpll. I suppose the
requirement is that the input clocks to all the display units (ovl,
rdma, and so on) need to be sufficiently above the pixel clock.

Also, this reads as if we want to keep the clock at 660 MHz if 4K is not
supported at all (for example because of a bridge connected at the
outside).
Actually, would it be desirable to switch vencpll to 660 MHz even on 4K
capable devices as long as only lower pixel clocks are active?

regards
Philipp

> Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_drm_drv.c |    9 +++++++++
>  drivers/gpu/drm/mediatek/mtk_drm_drv.h |    1 +
>  2 files changed, 10 insertions(+)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
> index b1223d5..f159189 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
> @@ -23,6 +23,7 @@
>  #include <linux/of_address.h>
>  #include <linux/of_platform.h>
>  #include <linux/pm_runtime.h>
> +#include <linux/clk.h>
>  
>  #include "mtk_drm_crtc.h"
>  #include "mtk_drm_ddp.h"
> @@ -363,6 +364,14 @@ static int mtk_drm_probe(struct platform_device *pdev)
>  		return ret;
>  	}
>  
> +	private->vencpll_clk = devm_clk_get(dev, "vencpll");
> +	if (IS_ERR(private->vencpll_clk)) {
> +		ret = PTR_ERR(private->vencpll_clk);
> +		dev_err(dev, "Failed to get vencpll clock: %d\n", ret);
> +		return ret;
> +	}
> +	clk_set_rate(private->vencpll_clk, 800000000);
> +
>  	/* Iterate over sibling DISP function blocks */
>  	for_each_child_of_node(dev->of_node->parent, node) {
>  		const struct of_device_id *of_id;
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
> index aa93894..273ad02 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
> @@ -40,6 +40,7 @@ struct mtk_drm_private {
>  	void __iomem *config_regs;
>  	struct device_node *comp_node[DDP_COMPONENT_ID_MAX];
>  	struct mtk_ddp_comp *ddp_comp[DDP_COMPONENT_ID_MAX];
> +	struct clk *vencpll_clk;
>  
>  	struct {
>  		struct drm_atomic_state *state;



From minghsiu.tsai at mediatek.com  Wed Jul 20 05:14:42 2016
From: minghsiu.tsai at mediatek.com (Minghsiu Tsai)
Date: Wed, 20 Jul 2016 20:14:42 +0800
Subject: [PATCH 2/4] dt-bindings: Add a binding for Mediatek MDP
In-Reply-To: <20160716230113.GA31551@rob-hp-laptop>
References: <1468498681-19955-1-git-send-email-minghsiu.tsai@mediatek.com>
 <1468498681-19955-3-git-send-email-minghsiu.tsai@mediatek.com>
 <20160716230113.GA31551@rob-hp-laptop>
Message-ID: <1469016882.12306.3.camel@mtksdaap41>

On Sat, 2016-07-16 at 18:01 -0500, Rob Herring wrote:
> On Thu, Jul 14, 2016 at 08:17:59PM +0800, Minghsiu Tsai wrote:
> > Add a DT binding documentation of MDP for the MT8173 SoC
> > from Mediatek
> > 
> > Signed-off-by: Minghsiu Tsai <minghsiu.tsai at mediatek.com>
> > ---
> >  .../devicetree/bindings/media/mediatek-mdp.txt     |   92 ++++++++++++++++++++
> >  1 file changed, 92 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/media/mediatek-mdp.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/media/mediatek-mdp.txt b/Documentation/devicetree/bindings/media/mediatek-mdp.txt
> > new file mode 100644
> > index 0000000..ef570c3
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/media/mediatek-mdp.txt
> > @@ -0,0 +1,92 @@
> > +* Mediatek Media Data Path
> > +
> > +Media Data Path is used for scaling and color space conversion.
> > +
> > +Required properties:
> > +  - compatible : should contain them as below:
> > +        "mediatek,mt8173-mdp"
> > +        "mediatek,mt8173-mdp-rdma"
> > +        "mediatek,mt8173-mdp-rsz"
> > +        "mediatek,mt8173-mdp-wdma"
> > +        "mediatek,mt8173-mdp-wrot"
> > +  - clocks : device clocks
> > +  - power-domains : a phandle to the power domain.
> > +  - mediatek,larb : should contain the larbes of current platform
> > +  - iommus : Mediatek IOMMU H/W has designed the fixed associations with
> > +        the multimedia H/W. and there is only one multimedia iommu domain.
> > +        "iommus = <&iommu portid>" the "portid" is from
> > +        dt-bindings\iommu\mt8173-iommu-port.h, it means that this portid will
> > +        enable iommu. The portid default is disable iommu if "<&iommu portid>"
> > +        don't be added.
> > +  - mediatek,vpu : the node of video processor unit
> 
> These properties don't apply to all the nodes. I think you need a 
> section for each IP block.


I will add description for those IP block, thanks.




From honghui.zhang at mediatek.com  Wed Jul 20 05:49:21 2016
From: honghui.zhang at mediatek.com (honghui.zhang at mediatek.com)
Date: Wed, 20 Jul 2016 20:49:21 +0800
Subject: [RFC PATCH] iommu: create direct_mapping after device attached
Message-ID: <1469018961-16367-1-git-send-email-honghui.zhang@mediatek.com>

From: Honghui Zhang <honghui.zhang at mediatek.com>

For mtk iommu, the domain_finalize was called in device attatch, the mtk
iommu iopgt ops was allocated and initialized in domain_finalize, the
iommu_group_create_direct_mappings would call the map interface to
implement the map. If it's earlier than device attach, there would be NULL
dereference. Move the iommu_group_create_direct_mappings call after device
attached.

Signed-off-by: Honghui Zhang <honghui.zhang at mediatek.com>
---
 drivers/iommu/iommu.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 3000051..24c671c 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -427,14 +427,19 @@ rename:
 
 	dev->iommu_group = group;
 
-	iommu_group_create_direct_mappings(group, dev);
-
 	mutex_lock(&group->mutex);
 	list_add_tail(&device->list, &group->devices);
 	if (group->domain)
 		__iommu_attach_device(group->domain, dev);
 	mutex_unlock(&group->mutex);
 
+	/*
+	 * For some iommu driver like mtk iommu, the map callback was assigned
+	 * after device attached. The direct_mappings would call iommu map and
+	 * dereference NULL if it's called earlier than attach_device.
+	 */
+	iommu_group_create_direct_mappings(group, dev);
+
 	/* Notify any listeners about change to group. */
 	blocking_notifier_call_chain(&group->notifier,
 				     IOMMU_GROUP_NOTIFY_ADD_DEVICE, dev);
-- 
1.8.1.1.dirty



From joro at 8bytes.org  Wed Jul 20 07:01:27 2016
From: joro at 8bytes.org (Joerg Roedel)
Date: Wed, 20 Jul 2016 16:01:27 +0200
Subject: [RFC PATCH] iommu: create direct_mapping after device attached
In-Reply-To: <1469018961-16367-1-git-send-email-honghui.zhang@mediatek.com>
References: <1469018961-16367-1-git-send-email-honghui.zhang@mediatek.com>
Message-ID: <20160720140127.GA3030@8bytes.org>

On Wed, Jul 20, 2016 at 08:49:21PM +0800, honghui.zhang at mediatek.com wrote:
> From: Honghui Zhang <honghui.zhang at mediatek.com>
> 
> For mtk iommu, the domain_finalize was called in device attatch, the mtk
> iommu iopgt ops was allocated and initialized in domain_finalize, the
> iommu_group_create_direct_mappings would call the map interface to
> implement the map. If it's earlier than device attach, there would be NULL
> dereference. Move the iommu_group_create_direct_mappings call after device
> attached.

No, this would open a race window where the device is attached, but
doesn't have its unity-mappings in place. You should re-organize the mtk
driver instead, so that it works in this order too.



	Joerg



From bibby.hsieh at mediatek.com  Wed Jul 20 20:21:28 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Thu, 21 Jul 2016 11:21:28 +0800
Subject: [PATCH v3 2/2] drm/mediatek: set mt8173 dithering function
In-Reply-To: <1468809237.30644.28.camel@mtksdaap41>
References: <1467877029-45236-1-git-send-email-bibby.hsieh@mediatek.com>
 <1467877029-45236-3-git-send-email-bibby.hsieh@mediatek.com>
 <1468809237.30644.28.camel@mtksdaap41>
Message-ID: <1469071288.26205.9.camel@mtksdaap41>

Hi, CK

I'm appreciate your comments.


On Mon, 2016-07-18 at 10:33 +0800, CK Hu wrote:
> Hi, Bibby:
> 
> Some comments inline.
> 
> On Thu, 2016-07-07 at 15:37 +0800, Bibby Hsieh wrote:
> > Some panels only accept bpc (bit per color) 6-bit.
> > But, the default bpc in mt8173 display data path is 8-bit.
> > If we didn't enable dithering function to convert bpc,
> > display cannot show the smooth grayscale image.
> > 
> > In mt8173, the dithering function in OD (OverDrive) and
> > GAMMA module, we have to config them with
> > connector->display_mode.bpc when CRTC initial.
> > 
> > 1. Clear the default value at *_DITHER_5 and *_DITHER_7 register.
> > 2. Calculate the LSB_ERR_SHIFT bits and ADD_LSHIFT bits two values.
> > i.e. Input bpc of OD is 10 bits, we assume the bpc of panel is 6-bit,
> > so, we need to set 4-bit to LSB_ERR_SHIFT and ADD_LSHIFT bits respectively.
> > 3. Then, set the OD or GAMMA to dithering mode depends on path-1 or path-2.
> > 
> > Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> > ---
> >  drivers/gpu/drm/mediatek/mtk_disp_ovl.c     |    3 +-
> >  drivers/gpu/drm/mediatek/mtk_disp_rdma.c    |    3 +-
> >  drivers/gpu/drm/mediatek/mtk_drm_crtc.c     |   21 ++++++--
> >  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |   77 +++++++++++++++++++++++----
> >  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |    6 +--
> >  5 files changed, 92 insertions(+), 18 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> > index 8f62671f..019b7ca 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> > @@ -103,7 +103,8 @@ static void mtk_ovl_stop(struct mtk_ddp_comp *comp)
> >  }
> >  
> >  static void mtk_ovl_config(struct mtk_ddp_comp *comp, unsigned int w,
> > -			   unsigned int h, unsigned int vrefresh)
> > +			   unsigned int h, unsigned int vrefresh,
> > +			   unsigned int bpc)
> >  {
> >  	if (w != 0 && h != 0)
> >  		writel_relaxed(h << 16 | w, comp->regs + DISP_REG_OVL_ROI_SIZE);
> > diff --git a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
> > index 5fb80cb..0df05f9 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
> > @@ -106,7 +106,8 @@ static void mtk_rdma_stop(struct mtk_ddp_comp *comp)
> >  }
> >  
> >  static void mtk_rdma_config(struct mtk_ddp_comp *comp, unsigned int width,
> > -			    unsigned int height, unsigned int vrefresh)
> > +			    unsigned int height, unsigned int vrefresh,
> > +			    unsigned int bpc)
> >  {
> >  	unsigned int threshold;
> >  	unsigned int reg;
> > diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> > index ee219bb..18c9d0d 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> > @@ -222,7 +222,9 @@ static void mtk_crtc_ddp_clk_disable(struct mtk_drm_crtc *mtk_crtc)
> >  static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
> >  {
> >  	struct drm_crtc *crtc = &mtk_crtc->base;
> > -	unsigned int width, height, vrefresh;
> > +	struct drm_connector *connector;
> > +	struct drm_encoder *encoder;
> > +	unsigned int width, height, vrefresh, bpc = 0;
> >  	int ret;
> >  	int i;
> >  
> > @@ -234,6 +236,19 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
> >  	height = crtc->state->adjusted_mode.vdisplay;
> >  	vrefresh = crtc->state->adjusted_mode.vrefresh;
> >  
> > +	drm_for_each_encoder(encoder, crtc->dev) {
> > +		if (encoder->crtc != crtc)
> > +			continue;
> > +
> > +		drm_for_each_connector(connector, crtc->dev) {
> > +			if (connector->encoder != encoder)
> > +				continue;
> > +			if (connector->display_info.bpc >= 3 &&
> 
> I think you should left this HW constrain in mtk_od_config() and
> mtk_gamma_config(). Here just calculate the expected bpc.
> 
Ok, I will do that.
> > +			    (bpc == 0 || bpc > connector->display_info.bpc))
> 
> I think bpc should be initialized as HW default bpc and you can remove
> this condiction 'bpc == 0' because we should set bpc to HW default bpc
> while all connnector bpc is greater than HW default bpc.
> 
Ok, will do.
> > +				bpc = connector->display_info.bpc;
> > +		}
> > +	}
> > +
> >  	ret = pm_runtime_get_sync(crtc->dev->dev);
> >  	if (ret < 0) {
> >  		DRM_ERROR("Failed to enable power domain: %d\n", ret);
> > @@ -266,7 +281,7 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
> >  	for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
> >  		struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[i];
> >  
> > -		mtk_ddp_comp_config(comp, width, height, vrefresh);
> > +		mtk_ddp_comp_config(comp, width, height, vrefresh, bpc);
> >  		mtk_ddp_comp_start(comp);
> >  	}
> >  
> > @@ -469,7 +484,7 @@ void mtk_crtc_ddp_irq(struct drm_crtc *crtc, struct mtk_ddp_comp *ovl)
> >  	if (state->pending_config) {
> >  		mtk_ddp_comp_config(ovl, state->pending_width,
> >  				    state->pending_height,
> > -				    state->pending_vrefresh);
> > +				    state->pending_vrefresh, 0);
> 
> Why set bpc as 0 here? Maybe you have a assumption that OVL don't care
> the bpc parameter. If one day OVL care it and we do not review here, the
> bugs happen.
> 
Pass 0 means don't care, I will modify mtk_od_config() and
mtk_gamma_config() to filter this condition.
> >  
> >  		state->pending_config = false;
> >  	}
> > diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
> > index 56c5894..c10faac 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
> > @@ -30,7 +30,26 @@
> >  #define DISP_OD_INTEN				0x0008
> >  #define DISP_OD_INTSTA				0x000c
> >  #define DISP_OD_CFG				0x0020
> > +#define OD_RELAYMODE				BIT(0)
> > +#define OD_DITHERING				BIT(2)
> >  #define DISP_OD_SIZE				0x0030
> > +#define DISP_OD_DITHER_5			0x0114
> > +#define DISP_OD_DITHER_7			0x011c
> > +#define DISP_OD_DITHER_15			0x013c
> > +#define DITHER_LSB_ERR_SHIFT_R(x)		(((x) & 0x7) << 28)
> > +#define DITHER_OVFLW_BIT_R(x)			(((x) & 0x7) << 24)
> > +#define DITHER_ADD_LSHIFT_R(x)			(((x) & 0x7) << 20)
> > +#define DITHER_ADD_RSHIFT_R(x)			(((x) & 0x7) << 16)
> > +#define DITHER_NEW_BIT_MODE			BIT(0)
> > +#define DISP_OD_DITHER_16			0x140
> > +#define DITHER_LSB_ERR_SHIFT_B(x)		(((x) & 0x7) << 28)
> > +#define DITHER_OVFLW_BIT_B(x)			(((x) & 0x7) << 24)
> > +#define DITHER_ADD_LSHIFT_B(x)			(((x) & 0x7) << 20)
> > +#define DITHER_ADD_RSHIFT_B(x)			(((x) & 0x7) << 16)
> > +#define DITHER_LSB_ERR_SHIFT_G(x)		(((x) & 0x7) << 12)
> > +#define DITHER_OVFLW_BIT_G(x)			(((x) & 0x7) << 8)
> > +#define DITHER_ADD_LSHIFT_G(x)			(((x) & 0x7) << 4)
> > +#define DITHER_ADD_RSHIFT_G(x)			(((x) & 0x7) << 0)
> >  
> >  #define DISP_REG_UFO_START			0x0000
> >  
> > @@ -44,25 +63,28 @@
> >  
> >  #define DISP_GAMMA_EN				0x000
> >  #define DISP_GAMMA_CFG				0x020
> > +#define GAMMA_EN				BIT(0)
> > +#define GAMMA_LUT_EN				BIT(1)
> > +#define GAMMA_DITHERING				BIT(2)
> >  #define DISP_GAMMA_SIZE				0x030
> >  #define DISP_GAMMA_LUT				0x700
> > +#define DISP_GAMMA_DITHER_5			0x0114
> > +#define DISP_GAMMA_DITHER_7			0x011c
> > +#define DISP_GAMMA_DITHER_15			0x013c
> > +#define DISP_GAMMA_DITHER_16			0x0140
> >  
> >  #define LUT_10BIT_MASK				0x3ff
> >  
> >  #define AAL_EN			BIT(0)
> >  
> > -#define GAMMA_EN		BIT(0)
> > -#define GAMMA_LUT_EN		BIT(1)
> > -
> > -#define	OD_RELAY_MODE		BIT(0)
> > -
> >  #define	UFO_BYPASS		BIT(2)
> >  
> >  #define	COLOR_BYPASS_ALL	BIT(7)
> >  #define	COLOR_SEQ_SEL		BIT(13)
> >  
> >  static void mtk_color_config(struct mtk_ddp_comp *comp, unsigned int w,
> > -			     unsigned int h, unsigned int vrefresh)
> > +			     unsigned int h, unsigned int vrefresh,
> > +			     unsigned int bpc)
> >  {
> >  	writel(w, comp->regs + DISP_COLOR_WIDTH);
> >  	writel(h, comp->regs + DISP_COLOR_HEIGHT);
> > @@ -76,14 +98,33 @@ static void mtk_color_start(struct mtk_ddp_comp *comp)
> >  }
> >  
> >  static void mtk_od_config(struct mtk_ddp_comp *comp, unsigned int w,
> > -			  unsigned int h, unsigned int vrefresh)
> > +			  unsigned int h, unsigned int vrefresh,
> > +			  unsigned int bpc)
> >  {
> >  	writel(w << 16 | h, comp->regs + DISP_OD_SIZE);
> > +	if (bpc >= 3 && bpc < 10) {
> 
> Use symbol to replace magic number can improve the readability. For
> example.
> 
> #define DITHER_MIN_BITS 3
> #define DITHER_MAX_BITS 8
> 
Ok, I will use definition instead of magic number.
> > +		writel(0, comp->regs + DISP_OD_DITHER_5);
> > +		writel(0, comp->regs + DISP_OD_DITHER_7);
> > +		writel(DITHER_LSB_ERR_SHIFT_R(10 - bpc) |
> > +		       DITHER_ADD_LSHIFT_R(10 - bpc) |
> > +		       DITHER_NEW_BIT_MODE,
> > +		       comp->regs + DISP_OD_DITHER_15);
> > +		writel(DITHER_LSB_ERR_SHIFT_B(10 - bpc) |
> > +		       DITHER_ADD_LSHIFT_B(10 - bpc) |
> > +		       DITHER_LSB_ERR_SHIFT_G(10 - bpc) |
> > +		       DITHER_ADD_LSHIFT_G(10 - bpc),
> > +		       comp->regs + DISP_OD_DITHER_16);
> > +		writel(OD_DITHERING,
> > +		       comp->regs + DISP_OD_CFG);
> > +	} else {
> > +		writel(OD_RELAYMODE,
> > +		       comp->regs + DISP_OD_CFG);
> > +	}
> > +
> >  }
> >  
> >  static void mtk_od_start(struct mtk_ddp_comp *comp)
> >  {
> > -	writel(OD_RELAY_MODE, comp->regs + DISP_OD_CFG);
> >  	writel(1, comp->regs + DISP_OD_EN);
> >  }
> >  
> > @@ -93,7 +134,8 @@ static void mtk_ufoe_start(struct mtk_ddp_comp *comp)
> >  }
> >  
> >  static void mtk_aal_config(struct mtk_ddp_comp *comp, unsigned int w,
> > -			   unsigned int h, unsigned int vrefresh)
> > +			   unsigned int h, unsigned int vrefresh,
> > +			   unsigned int bpc)
> >  {
> >  	writel(h << 16 | w, comp->regs + DISP_AAL_SIZE);
> >  }
> > @@ -109,9 +151,24 @@ static void mtk_aal_stop(struct mtk_ddp_comp *comp)
> >  }
> >  
> >  static void mtk_gamma_config(struct mtk_ddp_comp *comp, unsigned int w,
> > -			     unsigned int h, unsigned int vrefresh)
> > +			     unsigned int h, unsigned int vrefresh,
> > +			     unsigned int bpc)
> >  {
> >  	writel(h << 16 | w, comp->regs + DISP_GAMMA_SIZE);
> > +	if (bpc >= 3 && bpc < 10) {
> > +		writel(0, comp->regs + DISP_GAMMA_DITHER_5);
> > +		writel(0, comp->regs + DISP_GAMMA_DITHER_7);
> > +		writel(DITHER_LSB_ERR_SHIFT_R(10 - bpc) |
> > +		       DITHER_ADD_LSHIFT_R(10 - bpc) |
> > +		       DITHER_NEW_BIT_MODE,
> > +		       comp->regs + DISP_GAMMA_DITHER_15);
> > +		writel(DITHER_LSB_ERR_SHIFT_B(10 - bpc) |
> > +		       DITHER_ADD_LSHIFT_B(10 - bpc) |
> > +		       DITHER_LSB_ERR_SHIFT_G(10 - bpc) |
> > +		       DITHER_ADD_LSHIFT_G(10 - bpc),
> > +		       comp->regs + DISP_GAMMA_DITHER_16);
> > +		writel(GAMMA_DITHERING, comp->regs + DISP_GAMMA_CFG);
> > +	}
> 
> This part is the same as mtk_od_config(), so it's better to have a
> function 'mtk_dither_config()' and both mtk_od_config() and
> mtk_gamma_config() call this function.
> 
Ok, will do.
> >  }
> >  
> >  static void mtk_gamma_start(struct mtk_ddp_comp *comp)
> > diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
> > index 07e17fe..c7c2e92 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
> > +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
> > @@ -65,7 +65,7 @@ struct mtk_ddp_comp;
> >  
> >  struct mtk_ddp_comp_funcs {
> >  	void (*config)(struct mtk_ddp_comp *comp, unsigned int w,
> > -		       unsigned int h, unsigned int vrefresh);
> > +		       unsigned int h, unsigned int vrefresh, unsigned int bpc);
> >  	void (*start)(struct mtk_ddp_comp *comp);
> >  	void (*stop)(struct mtk_ddp_comp *comp);
> >  	void (*enable_vblank)(struct mtk_ddp_comp *comp, struct drm_crtc *crtc);
> > @@ -89,10 +89,10 @@ struct mtk_ddp_comp {
> >  
> >  static inline void mtk_ddp_comp_config(struct mtk_ddp_comp *comp,
> >  				       unsigned int w, unsigned int h,
> > -				       unsigned int vrefresh)
> > +				       unsigned int vrefresh, unsigned int bpc)
> >  {
> >  	if (comp->funcs && comp->funcs->config)
> > -		comp->funcs->config(comp, w, h, vrefresh);
> > +		comp->funcs->config(comp, w, h, vrefresh, bpc);
> >  }
> >  
> >  static inline void mtk_ddp_comp_start(struct mtk_ddp_comp *comp)
> 
> 




From bibby.hsieh at mediatek.com  Wed Jul 20 20:23:00 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Thu, 21 Jul 2016 11:23:00 +0800
Subject: [PATCH v3 1/2] drm/mediatek: Add gamma correction
In-Reply-To: <1468573908.25670.10.camel@mtksdaap41>
References: <1467877029-45236-1-git-send-email-bibby.hsieh@mediatek.com>
 <1467877029-45236-2-git-send-email-bibby.hsieh@mediatek.com>
 <1468573908.25670.10.camel@mtksdaap41>
Message-ID: <1469071380.26205.10.camel@mtksdaap41>

Hi, CK

I'm appreciate your comments.

On Fri, 2016-07-15 at 17:11 +0800, CK Hu wrote:
> Hi, Bibby:
> 
> Some comments inline.
> 
> On Thu, 2016-07-07 at 15:37 +0800, Bibby Hsieh wrote:
> > Apply gamma function to correct brightness values.
> > It applies arbitrary mapping curve to compensate the
> > incorrect transfer function of the panel.
> > 
> > Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> > ---
> >  drivers/gpu/drm/mediatek/mtk_drm_crtc.c     |    8 +++
> >  drivers/gpu/drm/mediatek/mtk_drm_crtc.h     |    1 +
> >  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |   89 ++++++++++++++++++++++++++-
> >  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |   10 +++
> >  4 files changed, 106 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> > index 24aa3ba..ee219bb 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> > @@ -409,6 +409,10 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
> >  	}
> >  	if (pending_planes)
> >  		mtk_crtc->pending_planes = true;
> > +	if (crtc->state->color_mgmt_changed)
> > +		for (i = 0; i < mtk_crtc->ddp_comp_nr; i++)
> > +			mtk_ddp_gamma_set(mtk_crtc->ddp_comp[i], crtc->state);
> > +
> >  }
> >  
> >  static const struct drm_crtc_funcs mtk_crtc_funcs = {
> > @@ -418,6 +422,7 @@ static const struct drm_crtc_funcs mtk_crtc_funcs = {
> >  	.reset			= mtk_drm_crtc_reset,
> >  	.atomic_duplicate_state	= mtk_drm_crtc_duplicate_state,
> >  	.atomic_destroy_state	= mtk_drm_crtc_destroy_state,
> > +	.gamma_set		= drm_atomic_helper_legacy_gamma_set,
> >  };
> >  
> >  static const struct drm_crtc_helper_funcs mtk_crtc_helper_funcs = {
> > @@ -569,6 +574,9 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
> >  	if (ret < 0)
> >  		goto unprepare;
> >  
> > +	drm_mode_crtc_set_gamma_size(&mtk_crtc->base, MTK_LUT_SIZE);
> > +	drm_helper_crtc_enable_color_mgmt(&mtk_crtc->base, MTK_LUT_SIZE,
> > +					  MTK_LUT_SIZE);
> >  	priv->crtc[pipe] = &mtk_crtc->base;
> >  	priv->num_pipes++;
> >  
> > diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.h b/drivers/gpu/drm/mediatek/mtk_drm_crtc.h
> > index 81e5566..d332564 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.h
> > +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.h
> > @@ -19,6 +19,7 @@
> >  #include "mtk_drm_plane.h"
> >  
> >  #define OVL_LAYER_NR	4
> > +#define MTK_LUT_SIZE	512
> >  
> >  int mtk_drm_crtc_enable_vblank(struct drm_device *drm, unsigned int pipe);
> >  void mtk_drm_crtc_disable_vblank(struct drm_device *drm, unsigned int pipe);
> > diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
> > index 3970fcf..56c5894 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
> > @@ -24,6 +24,7 @@
> >  #include "mtk_drm_drv.h"
> >  #include "mtk_drm_plane.h"
> >  #include "mtk_drm_ddp_comp.h"
> > +#include "mtk_drm_crtc.h"
> >  
> >  #define DISP_OD_EN				0x0000
> >  #define DISP_OD_INTEN				0x0008
> > @@ -38,6 +39,21 @@
> >  #define DISP_COLOR_WIDTH			0x0c50
> >  #define DISP_COLOR_HEIGHT			0x0c54
> >  
> > +#define DISP_AAL_EN				0x000
> > +#define DISP_AAL_SIZE				0x030
> > +
> > +#define DISP_GAMMA_EN				0x000
> > +#define DISP_GAMMA_CFG				0x020
> > +#define DISP_GAMMA_SIZE				0x030
> > +#define DISP_GAMMA_LUT				0x700
> 
> It's better that the digits of register address of OD, COLOR, AAL, and
> GAMMA are the same. Maybe you can align all to 4 digits.
> 
Ok, will fix.
> > +
> > +#define LUT_10BIT_MASK				0x3ff
> > +
> > +#define AAL_EN			BIT(0)
> > +
> > +#define GAMMA_EN		BIT(0)
> > +#define GAMMA_LUT_EN		BIT(1)
> > +
> >  #define	OD_RELAY_MODE		BIT(0)
> >  
> >  #define	UFO_BYPASS		BIT(2)
> > @@ -76,6 +92,61 @@ static void mtk_ufoe_start(struct mtk_ddp_comp *comp)
> >  	writel(UFO_BYPASS, comp->regs + DISP_REG_UFO_START);
> >  }
> >  
> > +static void mtk_aal_config(struct mtk_ddp_comp *comp, unsigned int w,
> > +			   unsigned int h, unsigned int vrefresh)
> > +{
> > +	writel(h << 16 | w, comp->regs + DISP_AAL_SIZE);
> > +}
> > +
> > +static void mtk_aal_start(struct mtk_ddp_comp *comp)
> > +{
> > +	writel(AAL_EN, comp->regs  + DISP_AAL_EN);
> > +}
> > +
> > +static void mtk_aal_stop(struct mtk_ddp_comp *comp)
> > +{
> > +	writel_relaxed(0x0, comp->regs  + DISP_AAL_EN);
> > +}
> 
> I think AAL is somewhat different from GAMMA and this patch include 3
> modifications:
> 
> 1. AAL basic config
> 2. GAMMA basic config
> 3. Add gamma function of AAL and GAMMA
> 
> So you should split this patch into 3 patches.
> 
Ok, I will split that.
> > +
> > +static void mtk_gamma_config(struct mtk_ddp_comp *comp, unsigned int w,
> > +			     unsigned int h, unsigned int vrefresh)
> > +{
> > +	writel(h << 16 | w, comp->regs + DISP_GAMMA_SIZE);
> > +}
> > +
> > +static void mtk_gamma_start(struct mtk_ddp_comp *comp)
> > +{
> > +	writel(GAMMA_EN, comp->regs  + DISP_GAMMA_EN);
> > +}
> > +
> > +static void mtk_gamma_stop(struct mtk_ddp_comp *comp)
> > +{
> > +	writel_relaxed(0x0, comp->regs  + DISP_GAMMA_EN);
> > +}
> > +
> > +static void mtk_gamma_set(struct mtk_ddp_comp *comp,
> > +			  struct drm_crtc_state *state)
> > +{
> > +	unsigned int i, reg;
> > +	struct drm_color_lut *lut;
> > +	void __iomem *lut_base;
> > +	u32 word;
> > +
> > +	if (state->gamma_lut) {
> > +		reg = readl(comp->regs + DISP_GAMMA_CFG);
> > +		reg = reg | GAMMA_LUT_EN;
> > +		writel(reg, comp->regs + DISP_GAMMA_CFG);
> > +		lut_base = comp->regs + DISP_GAMMA_LUT;
> > +		lut = (struct drm_color_lut *)state->gamma_lut->data;
> > +		for (i = 0; i < MTK_LUT_SIZE; i++) {
> > +			word = (((lut[i].red >> 6) & LUT_10BIT_MASK) << 20) +
> > +			      (((lut[i].green >> 6) & LUT_10BIT_MASK) << 10) +
> > +			      ((lut[i].blue >> 6) & LUT_10BIT_MASK);
> > +			writel(word, (lut_base + i * 4));
> > +		}
> > +	}
> > +}
> > +
> >  static const struct mtk_ddp_comp_funcs ddp_color = {
> >  	.config = mtk_color_config,
> >  	.start = mtk_color_start,
> > @@ -90,6 +161,20 @@ static const struct mtk_ddp_comp_funcs ddp_ufoe = {
> >  	.start = mtk_ufoe_start,
> >  };
> >  
> > +static const struct mtk_ddp_comp_funcs ddp_aal = {
> > +	.gamma_set = mtk_gamma_set,
> > +	.config = mtk_aal_config,
> > +	.start = mtk_aal_start,
> > +	.stop = mtk_aal_stop,
> > +};
> > +
> > +static const struct mtk_ddp_comp_funcs ddp_gamma = {
> > +	.gamma_set = mtk_gamma_set,
> > +	.config = mtk_gamma_config,
> > +	.start = mtk_gamma_start,
> > +	.stop = mtk_gamma_stop,
> > +};
> > +
> >  static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = {
> >  	[MTK_DISP_OVL] = "ovl",
> >  	[MTK_DISP_RDMA] = "rdma",
> > @@ -112,13 +197,13 @@ struct mtk_ddp_comp_match {
> >  };
> >  
> >  static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
> > -	[DDP_COMPONENT_AAL]	= { MTK_DISP_AAL,	0, NULL },
> > +	[DDP_COMPONENT_AAL]	= { MTK_DISP_AAL,	0, &ddp_aal },
> >  	[DDP_COMPONENT_COLOR0]	= { MTK_DISP_COLOR,	0, &ddp_color },
> >  	[DDP_COMPONENT_COLOR1]	= { MTK_DISP_COLOR,	1, &ddp_color },
> >  	[DDP_COMPONENT_DPI0]	= { MTK_DPI,		0, NULL },
> >  	[DDP_COMPONENT_DSI0]	= { MTK_DSI,		0, NULL },
> >  	[DDP_COMPONENT_DSI1]	= { MTK_DSI,		1, NULL },
> > -	[DDP_COMPONENT_GAMMA]	= { MTK_DISP_GAMMA,	0, NULL },
> > +	[DDP_COMPONENT_GAMMA]	= { MTK_DISP_GAMMA,	0, &ddp_gamma },
> >  	[DDP_COMPONENT_OD]	= { MTK_DISP_OD,	0, &ddp_od },
> >  	[DDP_COMPONENT_OVL0]	= { MTK_DISP_OVL,	0, NULL },
> >  	[DDP_COMPONENT_OVL1]	= { MTK_DISP_OVL,	1, NULL },
> > diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
> > index 6b13ba9..07e17fe 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
> > +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
> > @@ -20,6 +20,7 @@ struct device;
> >  struct device_node;
> >  struct drm_crtc;
> >  struct drm_device;
> > +struct drm_crtc_state;
> >  struct mtk_plane_state;
> >  
> >  enum mtk_ddp_comp_type {
> > @@ -73,6 +74,8 @@ struct mtk_ddp_comp_funcs {
> >  	void (*layer_off)(struct mtk_ddp_comp *comp, unsigned int idx);
> >  	void (*layer_config)(struct mtk_ddp_comp *comp, unsigned int idx,
> >  			     struct mtk_plane_state *state);
> > +	void (*gamma_set)(struct mtk_ddp_comp *comp,
> > +			  struct drm_crtc_state *state);
> >  };
> >  
> >  struct mtk_ddp_comp {
> > @@ -139,6 +142,13 @@ static inline void mtk_ddp_comp_layer_config(struct mtk_ddp_comp *comp,
> >  		comp->funcs->layer_config(comp, idx, state);
> >  }
> >  
> > +static inline void mtk_ddp_gamma_set(struct mtk_ddp_comp *comp,
> > +				     struct drm_crtc_state *state)
> > +{
> > +	if (comp->funcs && comp->funcs->gamma_set)
> > +		comp->funcs->gamma_set(comp, state);
> > +}
> > +
> >  int mtk_ddp_comp_get_id(struct device_node *node,
> >  			enum mtk_ddp_comp_type comp_type);
> >  int mtk_ddp_comp_init(struct device *dev, struct device_node *comp_node,
> 
> 




From ck.hu at mediatek.com  Wed Jul 20 20:58:12 2016
From: ck.hu at mediatek.com (CK Hu)
Date: Thu, 21 Jul 2016 11:58:12 +0800
Subject: [PATCH v3 2/2] drm/mediatek: set mt8173 dithering function
In-Reply-To: <1469071288.26205.9.camel@mtksdaap41>
References: <1467877029-45236-1-git-send-email-bibby.hsieh@mediatek.com>
 <1467877029-45236-3-git-send-email-bibby.hsieh@mediatek.com>
 <1468809237.30644.28.camel@mtksdaap41>
 <1469071288.26205.9.camel@mtksdaap41>
Message-ID: <1469073492.11841.63.camel@mtksdaap41>

Hi, Bibby:

On Thu, 2016-07-21 at 11:21 +0800, Bibby Hsieh wrote:
> Hi, CK
> 
> I'm appreciate your comments.
> 
> 

[snip...]

> > >  
> > > @@ -469,7 +484,7 @@ void mtk_crtc_ddp_irq(struct drm_crtc *crtc, struct mtk_ddp_comp *ovl)
> > >  	if (state->pending_config) {
> > >  		mtk_ddp_comp_config(ovl, state->pending_width,
> > >  				    state->pending_height,
> > > -				    state->pending_vrefresh);
> > > +				    state->pending_vrefresh, 0);
> > 
> > Why set bpc as 0 here? Maybe you have a assumption that OVL don't care
> > the bpc parameter. If one day OVL care it and we do not review here, the
> > bugs happen.
> > 
> Pass 0 means don't care, I will modify mtk_od_config() and
> mtk_gamma_config() to filter this condition.

Using 0 as 'don't care' looks tricky. Please add comments to describe
this.

> > >  
> > >  		state->pending_config = false;
> > >  	}

Regards,
CK




From zhiyong.tao at mediatek.com  Thu Jul 21 00:17:29 2016
From: zhiyong.tao at mediatek.com (Zhiyong Tao)
Date: Thu, 21 Jul 2016 15:17:29 +0800
Subject: [PATCH v5 3/3] arm: dts: mt2701: Add auxadc node.
In-Reply-To: <1469085449-22679-1-git-send-email-zhiyong.tao@mediatek.com>
References: <1469085449-22679-1-git-send-email-zhiyong.tao@mediatek.com>
Message-ID: <1469085449-22679-4-git-send-email-zhiyong.tao@mediatek.com>

The commit adds auxadc nodes to the Mediatek MT2701 dtsi file.

Signed-off-by: Zhiyong Tao <zhiyong.tao at mediatek.com>
---
 arch/arm/boot/dts/mt2701.dtsi |    9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
index 42d5a37..c0a2644 100644
--- a/arch/arm/boot/dts/mt2701.dtsi
+++ b/arch/arm/boot/dts/mt2701.dtsi
@@ -187,6 +187,15 @@
 		      <0 0x10216000 0 0x2000>;
 	};
 
+	auxadc: adc at 11001000 {
+		compatible = "mediatek,mt2701-auxadc";
+		reg = <0 0x11001000 0 0x1000>;
+		clocks = <&pericfg CLK_PERI_AUXADC>;
+		clock-names = "main";
+		#io-channel-cells = <1>;
+		status = "disabled";
+	};
+
 	uart0: serial at 11002000 {
 		compatible = "mediatek,mt2701-uart",
 			     "mediatek,mt6577-uart";
-- 
1.7.9.5



From zhiyong.tao at mediatek.com  Thu Jul 21 00:17:26 2016
From: zhiyong.tao at mediatek.com (Zhiyong Tao)
Date: Thu, 21 Jul 2016 15:17:26 +0800
Subject: [PATCH v5 0/3] AUXADC: Mediatek auxadc driver 
Message-ID: <1469085449-22679-1-git-send-email-zhiyong.tao@mediatek.com>

This series includes three patches:
1.Change the device tree binding documentation.
2.Add auxadc driver based on linux iio.
3.Add auxadc nodes in the mediatek MT2701 dtsi file.

Changes in patch v5:
1).Add 'Acked-by' information in commit message.
1).Change auxadc compatible in binding document.
2).Remove power on failed check.
3).Moved power off error unwind block to 'err_power_off'.

Changes in patch v4:
1).Change the file name 'mt65xx_auxdc.txt' to 'mt6577_auxdc.txt'.
2).Remove 'break' after 'return' in 'mt6577_auxadc_read_raw'.
3).Use 'mt2701' instead of 'auxadc' in dts commit message.
4).Change 'auxadc@' to 'adc@' in mt2701.dtsi.

Changes in patch v3:
1).Add '#' before 'io-channel-cells' and change 'auxadc@' to 'adc@' in auxadc binding document.
2).Fix CONFIG_MEDIATEK_MT65XX_AUXADC sequence as alphabetical order.
3).Change the prefix 'MT65XX' to 'MT6577' to match auxadc driver name.
4).Remove the delays stored in 'mt6577_auxadc_device' and use the defined delay directly.
5).Use '-ETIMEDOUT' instead of '-EINVAL'.
6).Return value directly in 'mt6577_auxadc_read_raw'.
7).Add power off and unprepare clock if 'iio_device_register' failed.
8).Change 'Registers' to 'Register'.

Changes in patch v2:
1).Change the file name mt65xx_auxadc.c to mt6577_auxadc.c.
2).Add 'depends on ARCH_MEDIATEK || COMPILE_TEST and HAS_IOMEM' for MEDIATEK_MT65XX_AUXADC config.
3).Add check case for return value of 'readl_poll_timeout'.
4).Remove returning 1 and 0 for SCALE and OFFSET. use channel type 'IIO_CHAN_INFO_PROCESSED' instead of 'IIO_CHAN_INFO_RAW'.
5).Remove 'IIO_CHAN_INFO_OFFSET' and 'IIO_CHAN_INFO_SCALE' in 'MT65XX_AUXADC_CHANNEL' channel type.
6).Add check case when auxadc power on failure. if auxadc power on failure, clk_disable_unprepare should be executed.
7).Put 'platform_set_drvdata' before 'iio_device_register'.
8).Fix coding style and spelling error.

Zhiyong Tao (3):
  dt-bindings: auxadc: Add binding document for Mediatek auxadc.
  iio: adc: mt2701: Add Mediatek auxadc driver for mt2701.
  arm: dts: mt2701: Add auxadc node.

 .../auxadc.txt => iio/adc/mt6577_auxadc.txt}       |   18 +-
 arch/arm/boot/dts/mt2701.dtsi                      |    9 +
 drivers/iio/adc/Kconfig                            |   13 +
 drivers/iio/adc/Makefile                           |    1 +
 drivers/iio/adc/mt6577_auxadc.c                    |  289 ++++++++++++++++++++
 5 files changed, 325 insertions(+), 5 deletions(-)
 rename Documentation/devicetree/bindings/{soc/mediatek/auxadc.txt => iio/adc/mt6577_auxadc.txt} (46%)
 create mode 100644 drivers/iio/adc/mt6577_auxadc.c



From zhiyong.tao at mediatek.com  Thu Jul 21 00:17:27 2016
From: zhiyong.tao at mediatek.com (Zhiyong Tao)
Date: Thu, 21 Jul 2016 15:17:27 +0800
Subject: [PATCH v5 1/3] dt-bindings: auxadc: Add binding document for Mediatek
 auxadc.
In-Reply-To: <1469085449-22679-1-git-send-email-zhiyong.tao@mediatek.com>
References: <1469085449-22679-1-git-send-email-zhiyong.tao@mediatek.com>
Message-ID: <1469085449-22679-2-git-send-email-zhiyong.tao@mediatek.com>

The commit adds the device tree binding documentation for the mediatek
auxadc found on Mediatek MT2701.
Thermal gets auxadc sample data by iio device.
So the commit changes auxadc device tree binding documentation from
/soc/mediatek/auxadc.txt to /iio/adc/mt6577_auxadc.txt.

Acked-by: Rob Herring <robh at kernel.org>
Signed-off-by: Zhiyong Tao <zhiyong.tao at mediatek.com>
---
 .../auxadc.txt => iio/adc/mt6577_auxadc.txt}       |   18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)
 rename Documentation/devicetree/bindings/{soc/mediatek/auxadc.txt => iio/adc/mt6577_auxadc.txt} (46%)

diff --git a/Documentation/devicetree/bindings/soc/mediatek/auxadc.txt b/Documentation/devicetree/bindings/iio/adc/mt6577_auxadc.txt
similarity index 46%
rename from Documentation/devicetree/bindings/soc/mediatek/auxadc.txt
rename to Documentation/devicetree/bindings/iio/adc/mt6577_auxadc.txt
index bdb7829..68c45cb 100644
--- a/Documentation/devicetree/bindings/soc/mediatek/auxadc.txt
+++ b/Documentation/devicetree/bindings/iio/adc/mt6577_auxadc.txt
@@ -1,4 +1,4 @@
-MediaTek AUXADC
+* Mediatek AUXADC - Analog to Digital Converter on Mediatek mobile soc (mt65xx/mt81xx/mt27xx)
 ===============
 
 The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found
@@ -10,12 +10,20 @@ Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
 for the Thermal Controller which holds a phandle to the AUXADC.
 
 Required properties:
-- compatible: Must be "mediatek,mt8173-auxadc"
-- reg: Address range of the AUXADC unit
+  - compatible: Should be one of:
+    - "mediatek,mt2701-auxadc": For MT2701 family of SoCs
+    - "mediatek,mt8173-auxadc": For MT8173 family of SoCs
+  - reg: Address range of the AUXADC unit.
+  - clocks: Should contain a clock specifier for each entry in clock-names
+  - clock-names: Should contain "main".
+  - #io-channel-cells: Should be 1, see ../iio-bindings.txt
 
 Example:
 
-auxadc: auxadc at 11001000 {
-	compatible = "mediatek,mt8173-auxadc";
+auxadc: adc at 11001000 {
+	compatible = "mediatek,mt2701-auxadc";
 	reg = <0 0x11001000 0 0x1000>;
+	clocks = <&pericfg CLK_PERI_AUXADC>;
+	clock-names = "main";
+	#io-channel-cells = <1>;
 };
-- 
1.7.9.5



From zhiyong.tao at mediatek.com  Thu Jul 21 00:17:28 2016
From: zhiyong.tao at mediatek.com (Zhiyong Tao)
Date: Thu, 21 Jul 2016 15:17:28 +0800
Subject: [PATCH v5 2/3] iio: adc: mt2701: Add Mediatek auxadc driver for
 mt2701.
In-Reply-To: <1469085449-22679-1-git-send-email-zhiyong.tao@mediatek.com>
References: <1469085449-22679-1-git-send-email-zhiyong.tao@mediatek.com>
Message-ID: <1469085449-22679-3-git-send-email-zhiyong.tao@mediatek.com>

Add Mediatek auxadc driver based on iio.
It will register a device in iio and support iio.
So thermal can read auxadc channel to sample data by iio device.
It is tested successfully on mt2701 platform.
Mt8173 and mt6577 platforms are not tested.
But the expectation is compatible.

Signed-off-by: Zhiyong Tao <zhiyong.tao at mediatek.com>
---
 drivers/iio/adc/Kconfig         |   13 ++
 drivers/iio/adc/Makefile        |    1 +
 drivers/iio/adc/mt6577_auxadc.c |  289 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 303 insertions(+)
 create mode 100644 drivers/iio/adc/mt6577_auxadc.c

diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 25378c5..14929fc 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -305,6 +305,19 @@ config MCP3422
 	  This driver can also be built as a module. If so, the module will be
 	  called mcp3422.
 
+config MEDIATEK_MT6577_AUXADC
+        tristate "MediaTek AUXADC driver"
+        depends on ARCH_MEDIATEK || COMPILE_TEST
+        depends on HAS_IOMEM
+        help
+          Say yes here to enable support for MediaTek mt65xx AUXADC.
+
+          The driver supports immediate mode operation to read from one of sixteen
+          channels (external or internal).
+
+          This driver can also be built as a module. If so, the module will be
+          called mt6577_auxadc.
+
 config MEN_Z188_ADC
 	tristate "MEN 16z188 ADC IP Core support"
 	depends on MCB
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 38638d4..8306347 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_MAX1027) += max1027.o
 obj-$(CONFIG_MAX1363) += max1363.o
 obj-$(CONFIG_MCP320X) += mcp320x.o
 obj-$(CONFIG_MCP3422) += mcp3422.o
+obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
 obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
 obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
 obj-$(CONFIG_NAU7802) += nau7802.o
diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c
new file mode 100644
index 0000000..6240236
--- /dev/null
+++ b/drivers/iio/adc/mt6577_auxadc.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Zhiyong Tao <zhiyong.tao at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/iopoll.h>
+#include <linux/io.h>
+#include <linux/iio/iio.h>
+
+/* Register definitions */
+#define MT6577_AUXADC_CON0                    0x00
+#define MT6577_AUXADC_CON1                    0x04
+#define MT6577_AUXADC_CON2                    0x10
+#define MT6577_AUXADC_STA                     BIT(0)
+
+#define MT6577_AUXADC_DAT0                    0x14
+#define MT6577_AUXADC_RDY0                    BIT(12)
+
+#define MT6577_AUXADC_MISC                    0x94
+#define MT6577_AUXADC_PDN_EN                  BIT(14)
+
+#define MT6577_AUXADC_DAT_MASK                0xfff
+#define MT6577_AUXADC_SLEEP_US                1000
+#define MT6577_AUXADC_TIMEOUT_US              10000
+#define MT6577_AUXADC_POWER_READY_MS          1
+#define MT6577_AUXADC_SAMPLE_READY_US         25
+
+struct mt6577_auxadc_device {
+	void __iomem *reg_base;
+	struct clk *adc_clk;
+	struct mutex lock;
+};
+
+#define MT6577_AUXADC_CHANNEL(idx) {				    \
+		.type = IIO_VOLTAGE,				    \
+		.indexed = 1,					    \
+		.channel = (idx),				    \
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
+}
+
+static const struct iio_chan_spec mt6577_auxadc_iio_channels[] = {
+	MT6577_AUXADC_CHANNEL(0),
+	MT6577_AUXADC_CHANNEL(1),
+	MT6577_AUXADC_CHANNEL(2),
+	MT6577_AUXADC_CHANNEL(3),
+	MT6577_AUXADC_CHANNEL(4),
+	MT6577_AUXADC_CHANNEL(5),
+	MT6577_AUXADC_CHANNEL(6),
+	MT6577_AUXADC_CHANNEL(7),
+	MT6577_AUXADC_CHANNEL(8),
+	MT6577_AUXADC_CHANNEL(9),
+	MT6577_AUXADC_CHANNEL(10),
+	MT6577_AUXADC_CHANNEL(11),
+	MT6577_AUXADC_CHANNEL(12),
+	MT6577_AUXADC_CHANNEL(13),
+	MT6577_AUXADC_CHANNEL(14),
+	MT6577_AUXADC_CHANNEL(15),
+};
+
+static int mt6577_auxadc_read(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan)
+{
+	u32 rawdata, val;
+	void __iomem *reg_channel;
+	int ret;
+	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
+
+	reg_channel = adc_dev->reg_base + MT6577_AUXADC_DAT0 +
+		      chan->channel * 0x04;
+
+	mutex_lock(&adc_dev->lock);
+
+	val = readl(adc_dev->reg_base + MT6577_AUXADC_CON1);
+	val &= ~(1 << chan->channel);
+	writel(val, adc_dev->reg_base + MT6577_AUXADC_CON1);
+
+	/* read channel and make sure old ready bit == 0 */
+	ret = readl_poll_timeout(reg_channel, val,
+				 ((val & MT6577_AUXADC_RDY0) == 0),
+				 MT6577_AUXADC_SLEEP_US,
+				 MT6577_AUXADC_TIMEOUT_US);
+	if (ret < 0) {
+		dev_err(indio_dev->dev.parent,
+			"wait for channel[%d] ready bit clear time out\n",
+			chan->channel);
+
+		mutex_unlock(&adc_dev->lock);
+
+		return -ETIMEDOUT;
+	}
+
+	/* set bit to trigger sample */
+	val = readl(adc_dev->reg_base + MT6577_AUXADC_CON1);
+	val |= 1 << chan->channel;
+	writel(val, adc_dev->reg_base + MT6577_AUXADC_CON1);
+
+	/* we must delay here for hardware sample channel data */
+	udelay(MT6577_AUXADC_SAMPLE_READY_US);
+
+	/* check MTK_AUXADC_CON2 if auxadc is idle */
+	ret = readl_poll_timeout(adc_dev->reg_base + MT6577_AUXADC_CON2, val,
+				 ((val & MT6577_AUXADC_STA) == 0),
+				 MT6577_AUXADC_SLEEP_US,
+				 MT6577_AUXADC_TIMEOUT_US);
+	if (ret < 0) {
+		dev_err(indio_dev->dev.parent,
+			"wait for auxadc idle time out\n");
+
+		mutex_unlock(&adc_dev->lock);
+
+		return -ETIMEDOUT;
+	}
+
+	/* read channel and make sure ready bit == 1 */
+	ret = readl_poll_timeout(reg_channel, val,
+				 ((val & MT6577_AUXADC_RDY0) != 0),
+				 MT6577_AUXADC_SLEEP_US,
+				 MT6577_AUXADC_TIMEOUT_US);
+	if (ret < 0) {
+		dev_err(indio_dev->dev.parent,
+			"wait for channel[%d] data ready time out\n",
+			chan->channel);
+
+		mutex_unlock(&adc_dev->lock);
+
+		return -ETIMEDOUT;
+	}
+
+	/* read data */
+	rawdata = readl(reg_channel) & MT6577_AUXADC_DAT_MASK;
+
+	mutex_unlock(&adc_dev->lock);
+
+	return rawdata;
+}
+
+static int mt6577_auxadc_read_raw(struct iio_dev *indio_dev,
+				  struct iio_chan_spec const *chan,
+				  int *val,
+				  int *val2,
+				  long info)
+{
+	switch (info) {
+	case IIO_CHAN_INFO_PROCESSED:
+		*val = mt6577_auxadc_read(indio_dev, chan);
+		if (*val < 0) {
+			dev_err(indio_dev->dev.parent,
+				"failed to sample data on channel[%d]\n",
+				chan->channel);
+			return *val;
+		}
+		return IIO_VAL_INT;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info mt6577_auxadc_info = {
+	.driver_module = THIS_MODULE,
+	.read_raw = &mt6577_auxadc_read_raw,
+};
+
+static int mt6577_auxadc_probe(struct platform_device *pdev)
+{
+	struct mt6577_auxadc_device *adc_dev;
+	unsigned long adc_clk_rate;
+	struct resource *res;
+	struct iio_dev *indio_dev;
+	int ret;
+	u32 val;
+
+	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	adc_dev = iio_priv(indio_dev);
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->name = dev_name(&pdev->dev);
+	indio_dev->info = &mt6577_auxadc_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = mt6577_auxadc_iio_channels;
+	indio_dev->num_channels = ARRAY_SIZE(mt6577_auxadc_iio_channels);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	adc_dev->reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(adc_dev->reg_base)) {
+		dev_err(&pdev->dev, "failed to get auxadc base address.\n");
+		return PTR_ERR(adc_dev->reg_base);
+	}
+
+	adc_dev->adc_clk = devm_clk_get(&pdev->dev, "main");
+	if (IS_ERR(adc_dev->adc_clk)) {
+		dev_err(&pdev->dev, "failed to get auxadc clock\n");
+		return PTR_ERR(adc_dev->adc_clk);
+	}
+
+	ret = clk_prepare_enable(adc_dev->adc_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable auxadc clock\n");
+		return ret;
+	}
+
+	adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
+	if (!adc_clk_rate) {
+		dev_err(&pdev->dev, "null clock rate!\n");
+		goto err_disable_clk;
+	}
+
+	mutex_init(&adc_dev->lock);
+
+	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
+	val |= MT6577_AUXADC_PDN_EN;
+	writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
+	mdelay(MT6577_AUXADC_POWER_READY_MS);
+
+	platform_set_drvdata(pdev, indio_dev);
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to register iio device!\n");
+		goto err_power_off;
+	}
+
+	return 0;
+
+err_power_off:
+	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
+	val &= ~MT6577_AUXADC_PDN_EN;
+	writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
+err_disable_clk:
+	clk_disable_unprepare(adc_dev->adc_clk);
+	return -EINVAL;
+}
+
+static int mt6577_auxadc_remove(struct platform_device *pdev)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
+	u32 val;
+
+	iio_device_unregister(indio_dev);
+
+	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
+	val &= ~MT6577_AUXADC_PDN_EN;
+	writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
+
+	clk_disable_unprepare(adc_dev->adc_clk);
+
+	return 0;
+}
+
+static const struct of_device_id mt6577_auxadc_of_match[] = {
+	{ .compatible = "mediatek,mt2701-auxadc", },
+	{ .compatible = "mediatek,mt8173-auxadc", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, mt6577_auxadc_of_match);
+
+static struct platform_driver mt6577_auxadc_driver = {
+	.driver = {
+		.name   = "mt6577-auxadc",
+		.of_match_table = mt6577_auxadc_of_match,
+	},
+	.probe	= mt6577_auxadc_probe,
+	.remove	= mt6577_auxadc_remove,
+};
+module_platform_driver(mt6577_auxadc_driver);
+
+MODULE_AUTHOR("Zhiyong Tao <zhiyong.tao at mediatek.com>");
+MODULE_DESCRIPTION("MTK AUXADC Device Driver");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5



From pmeerw at pmeerw.net  Thu Jul 21 01:05:05 2016
From: pmeerw at pmeerw.net (Peter Meerwald-Stadler)
Date: Thu, 21 Jul 2016 10:05:05 +0200 (CEST)
Subject: [PATCH v5 2/3] iio: adc: mt2701: Add Mediatek auxadc driver for
 mt2701.
In-Reply-To: <1469085449-22679-3-git-send-email-zhiyong.tao@mediatek.com>
References: <1469085449-22679-1-git-send-email-zhiyong.tao@mediatek.com>
 <1469085449-22679-3-git-send-email-zhiyong.tao@mediatek.com>
Message-ID: <alpine.DEB.2.02.1607210956290.30580@pmeerw.net>

On Thu, 21 Jul 2016, Zhiyong Tao wrote:

> Add Mediatek auxadc driver based on iio.
> It will register a device in iio and support iio.
> So thermal can read auxadc channel to sample data by iio device.
> It is tested successfully on mt2701 platform.
> Mt8173 and mt6577 platforms are not tested.
> But the expectation is compatible.

minor comments below, consider if you do another respin
 
> Signed-off-by: Zhiyong Tao <zhiyong.tao at mediatek.com>
> ---
>  drivers/iio/adc/Kconfig         |   13 ++
>  drivers/iio/adc/Makefile        |    1 +
>  drivers/iio/adc/mt6577_auxadc.c |  289 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 303 insertions(+)
>  create mode 100644 drivers/iio/adc/mt6577_auxadc.c
> 
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 25378c5..14929fc 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -305,6 +305,19 @@ config MCP3422
>  	  This driver can also be built as a module. If so, the module will be
>  	  called mcp3422.
>  
> +config MEDIATEK_MT6577_AUXADC
> +        tristate "MediaTek AUXADC driver"
> +        depends on ARCH_MEDIATEK || COMPILE_TEST
> +        depends on HAS_IOMEM
> +        help
> +          Say yes here to enable support for MediaTek mt65xx AUXADC.
> +
> +          The driver supports immediate mode operation to read from one of sixteen
> +          channels (external or internal).
> +
> +          This driver can also be built as a module. If so, the module will be
> +          called mt6577_auxadc.
> +
>  config MEN_Z188_ADC
>  	tristate "MEN 16z188 ADC IP Core support"
>  	depends on MCB
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index 38638d4..8306347 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -30,6 +30,7 @@ obj-$(CONFIG_MAX1027) += max1027.o
>  obj-$(CONFIG_MAX1363) += max1363.o
>  obj-$(CONFIG_MCP320X) += mcp320x.o
>  obj-$(CONFIG_MCP3422) += mcp3422.o
> +obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
>  obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
>  obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
>  obj-$(CONFIG_NAU7802) += nau7802.o
> diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c
> new file mode 100644
> index 0000000..6240236
> --- /dev/null
> +++ b/drivers/iio/adc/mt6577_auxadc.c
> @@ -0,0 +1,289 @@
> +/*
> + * Copyright (c) 2016 MediaTek Inc.
> + * Author: Zhiyong Tao <zhiyong.tao at mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/iopoll.h>
> +#include <linux/io.h>
> +#include <linux/iio/iio.h>
> +
> +/* Register definitions */
> +#define MT6577_AUXADC_CON0                    0x00
> +#define MT6577_AUXADC_CON1                    0x04
> +#define MT6577_AUXADC_CON2                    0x10
> +#define MT6577_AUXADC_STA                     BIT(0)
> +
> +#define MT6577_AUXADC_DAT0                    0x14
> +#define MT6577_AUXADC_RDY0                    BIT(12)
> +
> +#define MT6577_AUXADC_MISC                    0x94
> +#define MT6577_AUXADC_PDN_EN                  BIT(14)
> +
> +#define MT6577_AUXADC_DAT_MASK                0xfff
> +#define MT6577_AUXADC_SLEEP_US                1000
> +#define MT6577_AUXADC_TIMEOUT_US              10000
> +#define MT6577_AUXADC_POWER_READY_MS          1
> +#define MT6577_AUXADC_SAMPLE_READY_US         25
> +
> +struct mt6577_auxadc_device {
> +	void __iomem *reg_base;
> +	struct clk *adc_clk;
> +	struct mutex lock;
> +};
> +
> +#define MT6577_AUXADC_CHANNEL(idx) {				    \
> +		.type = IIO_VOLTAGE,				    \
> +		.indexed = 1,					    \
> +		.channel = (idx),				    \
> +		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
> +}
> +
> +static const struct iio_chan_spec mt6577_auxadc_iio_channels[] = {
> +	MT6577_AUXADC_CHANNEL(0),
> +	MT6577_AUXADC_CHANNEL(1),
> +	MT6577_AUXADC_CHANNEL(2),
> +	MT6577_AUXADC_CHANNEL(3),
> +	MT6577_AUXADC_CHANNEL(4),
> +	MT6577_AUXADC_CHANNEL(5),
> +	MT6577_AUXADC_CHANNEL(6),
> +	MT6577_AUXADC_CHANNEL(7),
> +	MT6577_AUXADC_CHANNEL(8),
> +	MT6577_AUXADC_CHANNEL(9),
> +	MT6577_AUXADC_CHANNEL(10),
> +	MT6577_AUXADC_CHANNEL(11),
> +	MT6577_AUXADC_CHANNEL(12),
> +	MT6577_AUXADC_CHANNEL(13),
> +	MT6577_AUXADC_CHANNEL(14),
> +	MT6577_AUXADC_CHANNEL(15),
> +};
> +
> +static int mt6577_auxadc_read(struct iio_dev *indio_dev,
> +			      struct iio_chan_spec const *chan)
> +{
> +	u32 rawdata, val;

could drop rawdata variable and use val instead

> +	void __iomem *reg_channel;
> +	int ret;
> +	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
> +
> +	reg_channel = adc_dev->reg_base + MT6577_AUXADC_DAT0 +
> +		      chan->channel * 0x04;
> +
> +	mutex_lock(&adc_dev->lock);
> +
> +	val = readl(adc_dev->reg_base + MT6577_AUXADC_CON1);
> +	val &= ~(1 << chan->channel);
> +	writel(val, adc_dev->reg_base + MT6577_AUXADC_CON1);
> +
> +	/* read channel and make sure old ready bit == 0 */
> +	ret = readl_poll_timeout(reg_channel, val,
> +				 ((val & MT6577_AUXADC_RDY0) == 0),
> +				 MT6577_AUXADC_SLEEP_US,
> +				 MT6577_AUXADC_TIMEOUT_US);
> +	if (ret < 0) {
> +		dev_err(indio_dev->dev.parent,
> +			"wait for channel[%d] ready bit clear time out\n",
> +			chan->channel);
> +
> +		mutex_unlock(&adc_dev->lock);
> +
> +		return -ETIMEDOUT;
> +	}
> +
> +	/* set bit to trigger sample */
> +	val = readl(adc_dev->reg_base + MT6577_AUXADC_CON1);
> +	val |= 1 << chan->channel;
> +	writel(val, adc_dev->reg_base + MT6577_AUXADC_CON1);
> +
> +	/* we must delay here for hardware sample channel data */
> +	udelay(MT6577_AUXADC_SAMPLE_READY_US);
> +
> +	/* check MTK_AUXADC_CON2 if auxadc is idle */
> +	ret = readl_poll_timeout(adc_dev->reg_base + MT6577_AUXADC_CON2, val,
> +				 ((val & MT6577_AUXADC_STA) == 0),
> +				 MT6577_AUXADC_SLEEP_US,
> +				 MT6577_AUXADC_TIMEOUT_US);
> +	if (ret < 0) {
> +		dev_err(indio_dev->dev.parent,
> +			"wait for auxadc idle time out\n");
> +
> +		mutex_unlock(&adc_dev->lock);
> +
> +		return -ETIMEDOUT;
> +	}
> +
> +	/* read channel and make sure ready bit == 1 */
> +	ret = readl_poll_timeout(reg_channel, val,
> +				 ((val & MT6577_AUXADC_RDY0) != 0),
> +				 MT6577_AUXADC_SLEEP_US,
> +				 MT6577_AUXADC_TIMEOUT_US);
> +	if (ret < 0) {
> +		dev_err(indio_dev->dev.parent,
> +			"wait for channel[%d] data ready time out\n",
> +			chan->channel);
> +
> +		mutex_unlock(&adc_dev->lock);
> +
> +		return -ETIMEDOUT;
> +	}
> +
> +	/* read data */
> +	rawdata = readl(reg_channel) & MT6577_AUXADC_DAT_MASK;
> +
> +	mutex_unlock(&adc_dev->lock);
> +
> +	return rawdata;
> +}
> +
> +static int mt6577_auxadc_read_raw(struct iio_dev *indio_dev,
> +				  struct iio_chan_spec const *chan,
> +				  int *val,
> +				  int *val2,
> +				  long info)
> +{
> +	switch (info) {
> +	case IIO_CHAN_INFO_PROCESSED:
> +		*val = mt6577_auxadc_read(indio_dev, chan);
> +		if (*val < 0) {
> +			dev_err(indio_dev->dev.parent,
> +				"failed to sample data on channel[%d]\n",
> +				chan->channel);
> +			return *val;
> +		}
> +		return IIO_VAL_INT;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static const struct iio_info mt6577_auxadc_info = {
> +	.driver_module = THIS_MODULE,
> +	.read_raw = &mt6577_auxadc_read_raw,
> +};
> +
> +static int mt6577_auxadc_probe(struct platform_device *pdev)
> +{
> +	struct mt6577_auxadc_device *adc_dev;
> +	unsigned long adc_clk_rate;
> +	struct resource *res;
> +	struct iio_dev *indio_dev;
> +	int ret;
> +	u32 val;
> +
> +	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
> +	if (!indio_dev)
> +		return -ENOMEM;
> +
> +	adc_dev = iio_priv(indio_dev);
> +	indio_dev->dev.parent = &pdev->dev;
> +	indio_dev->name = dev_name(&pdev->dev);
> +	indio_dev->info = &mt6577_auxadc_info;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->channels = mt6577_auxadc_iio_channels;
> +	indio_dev->num_channels = ARRAY_SIZE(mt6577_auxadc_iio_channels);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	adc_dev->reg_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(adc_dev->reg_base)) {
> +		dev_err(&pdev->dev, "failed to get auxadc base address.\n");

this is the only error msg ending with a '.'

> +		return PTR_ERR(adc_dev->reg_base);
> +	}
> +
> +	adc_dev->adc_clk = devm_clk_get(&pdev->dev, "main");
> +	if (IS_ERR(adc_dev->adc_clk)) {
> +		dev_err(&pdev->dev, "failed to get auxadc clock\n");
> +		return PTR_ERR(adc_dev->adc_clk);
> +	}
> +
> +	ret = clk_prepare_enable(adc_dev->adc_clk);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to enable auxadc clock\n");
> +		return ret;
> +	}
> +
> +	adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
> +	if (!adc_clk_rate) {
> +		dev_err(&pdev->dev, "null clock rate!\n");
> +		goto err_disable_clk;
> +	}
> +
> +	mutex_init(&adc_dev->lock);
> +
> +	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
> +	val |= MT6577_AUXADC_PDN_EN;
> +	writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
> +	mdelay(MT6577_AUXADC_POWER_READY_MS);
> +
> +	platform_set_drvdata(pdev, indio_dev);
> +
> +	ret = iio_device_register(indio_dev);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "failed to register iio device!\n");
> +		goto err_power_off;
> +	}
> +
> +	return 0;
> +
> +err_power_off:
> +	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
> +	val &= ~MT6577_AUXADC_PDN_EN;
> +	writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
> +err_disable_clk:
> +	clk_disable_unprepare(adc_dev->adc_clk);
> +	return -EINVAL;

not happy with inventing error codes; IMHO you should return the ret given 
e.g. by iio_device_register()

> +}
> +
> +static int mt6577_auxadc_remove(struct platform_device *pdev)
> +{
> +	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
> +	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
> +	u32 val;
> +
> +	iio_device_unregister(indio_dev);
> +
> +	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
> +	val &= ~MT6577_AUXADC_PDN_EN;
> +	writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);

maybe the read/modify/write code sequence could be put into a function to 
save some lines

something like 
mt6577_auxadc_mod_reg(reg, or_mask, and_mask) {
val = readl(reg)
val |= or_mask;
val &= ~and_mask;
writel(val, reg)
}

> +
> +	clk_disable_unprepare(adc_dev->adc_clk);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mt6577_auxadc_of_match[] = {
> +	{ .compatible = "mediatek,mt2701-auxadc", },
> +	{ .compatible = "mediatek,mt8173-auxadc", },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, mt6577_auxadc_of_match);
> +
> +static struct platform_driver mt6577_auxadc_driver = {
> +	.driver = {
> +		.name   = "mt6577-auxadc",
> +		.of_match_table = mt6577_auxadc_of_match,
> +	},
> +	.probe	= mt6577_auxadc_probe,
> +	.remove	= mt6577_auxadc_remove,
> +};
> +module_platform_driver(mt6577_auxadc_driver);
> +
> +MODULE_AUTHOR("Zhiyong Tao <zhiyong.tao at mediatek.com>");
> +MODULE_DESCRIPTION("MTK AUXADC Device Driver");
> +MODULE_LICENSE("GPL v2");
> 

-- 

Peter Meerwald-Stadler
+43-664-2444418 (mobile)


From tiffany.lin at mediatek.com  Thu Jul 21 02:12:08 2016
From: tiffany.lin at mediatek.com (tiffany lin)
Date: Thu, 21 Jul 2016 17:12:08 +0800
Subject: [PATCH v3 0/9] Add MT8173 Video Decoder Driver
In-Reply-To: <e2952cc2-3abd-894e-9481-b91a45cf7891@xs4all.nl>
References: <1464611363-14936-1-git-send-email-tiffany.lin@mediatek.com>
 <577D0576.2050706@xs4all.nl> <1467886612.21382.18.camel@mtksdaap41>
 <e2952cc2-3abd-894e-9481-b91a45cf7891@xs4all.nl>
Message-ID: <1469092328.30095.11.camel@mtksdaap41>

Hi Hans,

On Fri, 2016-07-08 at 13:44 +0200, Hans Verkuil wrote:
> On 07/07/2016 12:16 PM, tiffany lin wrote:
> > Hi Hans,
> > 
> > 
> > On Wed, 2016-07-06 at 15:19 +0200, Hans Verkuil wrote:
> >> Hi Tiffany,
> >>
> >> I plan to review this patch series on Friday, but one obvious question is
> >> what the reason for these failures is:
> >>
> >>> 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_QUERYCTRL/MENU: OK
> >>>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-controls.cpp(357): g_ctrl returned an error (11)
> >>>                 test VIDIOC_G/S_CTRL: FAIL
> >>>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-controls.cpp(579): g_ext_ctrls returned an error (11)
> >>>                 test VIDIOC_G/S/TRY_EXT_CTRLS: FAIL
> > These fails are because VIDIOC_G_CTRL and VIDIOC_G_EXT_CTRLS return
> > V4L2_CID_MIN_BUFFERS_FOR_CAPTURE only when dirver in MTK_STATE_HEADER
> > state, or it will return EAGAIN.
> > This could help user space get correct value, not default value that may
> > changed base on media content.
> 
> OK, I really don't like this. I also looked what the s5p-mfc-dec driver does (the only other
> driver currently implementing this), and that returns -EINVAL.
> 
> My proposal would be to change this. If this information isn't known yet, why not
> just return 0 as the value? The doc would have to be updated and (preferably) also
> the s5p-mfc-dec driver. I've added Samsung devs to the Cc list, let me know what you
> think.
> 
We are ok with just return 0 as the value when header not parsed yet
We will update decoder with this solution.


> > 
> >>>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-controls.cpp(721): subscribe event for control 'User Controls' failed
> >>>                 test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: FAIL
> > Driver do not support subscribe event for control 'User Controls' for
> > now.
> > Do we need to support this?
> 
> I don't see why this would fail. It's OK to subscribe to such controls, although
> you'll never get an event.
> 
After upgrade to latest v4l-utils,this test pass.

> >>>                 test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
> >>>                 Standard Controls: 2 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)
> >>>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-formats.cpp(405): expected EINVAL, but got 11 when getting format for buftype 9
> >>>                 test VIDIOC_G_FMT: FAIL
> > This is because vidioc_vdec_g_fmt only succeed when context is in
> > MTK_STATE_HEADER state, or user space cannot get correct format data
> > using this function.
> 
> Comparing this to s5p-mfc-dec I see that -EINVAL is returned in that case.
> 
> I am not opposed to using EAGAIN in s5p-mfc-dec as well. Marek, Kamil, what is
> your opinion?
> 
> > 
> >>>                 test VIDIOC_TRY_FMT: OK (Not Supported)
> >>>                 test VIDIOC_S_FMT: OK (Not Supported)
> >>>                 test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
> >>>
> >>>         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
> >>>                 fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-buffers.cpp(500): q.has_expbuf(node)
> > Our OUTPUT and CAPTURE queue support both VB2_DMABUF and VB2_MMAP, user
> > space can select which to use in runtime.
> > So our driver default support v4l2_m2m_ioctl_expbuf functionality.
> > In v4l2-compliance test, it will check v4l2_m2m_ioctl_expbuf only valid
> > when node->valid_memorytype is V4L2_MEMORY_MMAP.
> > So when go through node->valid_memorytype is V4L2_MEMORY_DMABUF, it
> > fail.
> 
> valid_memorytype should have both MMAP and DMABUF flags.
> 
> But v4l-utils-1.6.0 is way too old to be certain it isn't some v4l2-compliance bug
> that has since been fixed.
After upgrade to latest v4l-utils, I still see this issue.

test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
fail: v4l2-test-buffers.cpp(571): q.has_expbuf(node)

best regards,
Tiffany

> 
> Regards,
> 
> 	Hans
> 
> > 
> > 
> > best regards,
> > Tiffany
> > 
> > 
> > 
> >>>                 test VIDIOC_EXPBUF: FAIL
> >>>
> >>>
> >>> Total: 38, Succeeded: 33, Failed: 5, Warnings: 0
> >>
> >> If it is due to a bug in v4l2-compliance, then let me know and I'll fix it. If not,
> >> then it should be fixed in the driver.
> >>
> >> Frankly, it was the presence of these failures that made me think this patch series
> >> wasn't final. Before a v4l2 driver can be accepted in the kernel, v4l2-compliance must pass.
> >>
> >> Regards,
> >>
> >> 	Hans
> > 
> > 
> > --
> > 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
> > 




From lkp at intel.com  Thu Jul 21 15:08:54 2016
From: lkp at intel.com (kbuild test robot)
Date: Fri, 22 Jul 2016 06:08:54 +0800
Subject: [PATCH v5 3/3] arm: dts: mt2701: Add auxadc node.
In-Reply-To: <1469085449-22679-4-git-send-email-zhiyong.tao@mediatek.com>
Message-ID: <201607220639.0tIT3cRj%fengguang.wu@intel.com>

Hi,

[auto build test ERROR on robh/for-next]
[also build test ERROR on v4.7-rc7 next-20160721]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Zhiyong-Tao/AUXADC-Mediatek-auxadc-driver/20160722-041141
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: arm-at91_dt_defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 5.4.0-6) 5.4.0 20160609
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm 

All errors (new ones prefixed by >>):

>> Error: arch/arm/boot/dts/mt2701.dtsi:145.22-23 syntax error
   FATAL ERROR: Unable to parse input tree

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/octet-stream
Size: 21319 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mediatek/attachments/20160722/d4a5fbee/attachment-0001.obj>

From zhiyong.tao at mediatek.com  Thu Jul 21 21:19:21 2016
From: zhiyong.tao at mediatek.com (zhiyong tao)
Date: Fri, 22 Jul 2016 12:19:21 +0800
Subject: [PATCH v5 3/3] arm: dts: mt2701: Add auxadc node.
In-Reply-To: <201607220639.0tIT3cRj%fengguang.wu@intel.com>
References: <201607220639.0tIT3cRj%fengguang.wu@intel.com>
Message-ID: <1469161161.419.48.camel@mhfsdcap03>

On Fri, 2016-07-22 at 06:08 +0800, kbuild test robot wrote:

sorry, I forget to add this information:
---
This patch dependents on "Add clock support for Mediatek MT2701"[1].
Please accept this patch together with [1].
[1]http://lists.infradead.org/pipermail/linux-mediatek/2016-June/005969.html
---
I will add this information in next version commit message.

> Hi,
> 
> [auto build test ERROR on robh/for-next]
> [also build test ERROR on v4.7-rc7 next-20160721]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
> 
> url:    https://github.com/0day-ci/linux/commits/Zhiyong-Tao/AUXADC-Mediatek-auxadc-driver/20160722-041141
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
> config: arm-at91_dt_defconfig (attached as .config)
> compiler: arm-linux-gnueabi-gcc (Debian 5.4.0-6) 5.4.0 20160609
> reproduce:
>         wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
>         chmod +x ~/bin/make.cross
>         # save the attached .config to linux build tree
>         make.cross ARCH=arm 
> 
> All errors (new ones prefixed by >>):
> 
> >> Error: arch/arm/boot/dts/mt2701.dtsi:145.22-23 syntax error
>    FATAL ERROR: Unable to parse input tree
> 
> ---
> 0-DAY kernel test infrastructure                Open Source Technology Center
> https://lists.01.org/pipermail/kbuild-all                   Intel Corporation




From minghsiu.tsai at mediatek.com  Thu Jul 21 22:35:47 2016
From: minghsiu.tsai at mediatek.com (Minghsiu Tsai)
Date: Fri, 22 Jul 2016 13:35:47 +0800
Subject: [PATCH 3/4] media: Add Mediatek MDP Driver
In-Reply-To: <41900916-26c8-014a-6a7f-de3c34a2592f@xs4all.nl>
References: <1468498681-19955-1-git-send-email-minghsiu.tsai@mediatek.com>
 <1468498681-19955-4-git-send-email-minghsiu.tsai@mediatek.com>
 <41900916-26c8-014a-6a7f-de3c34a2592f@xs4all.nl>
Message-ID: <1469165747.18138.6.camel@mtksdaap41>

On Mon, 2016-07-18 at 14:18 +0200, Hans Verkuil wrote:
> On 07/14/2016 02:18 PM, Minghsiu Tsai wrote:
> > Add MDP driver for MT8173
> > 
> > Signed-off-by: Minghsiu Tsai <minghsiu.tsai at mediatek.com>
> > ---
> >  drivers/media/platform/Kconfig                |   16 +
> >  drivers/media/platform/Makefile               |    2 +
> >  drivers/media/platform/mtk-mdp/Makefile       |    9 +
> >  drivers/media/platform/mtk-mdp/mtk_mdp_comp.c |  159 +++
> >  drivers/media/platform/mtk-mdp/mtk_mdp_comp.h |   72 ++
> >  drivers/media/platform/mtk-mdp/mtk_mdp_core.c |  294 ++++++
> >  drivers/media/platform/mtk-mdp/mtk_mdp_core.h |  233 +++++
> >  drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h  |  126 +++
> >  drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c  | 1304 +++++++++++++++++++++++++
> >  drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h  |   22 +
> >  drivers/media/platform/mtk-mdp/mtk_mdp_regs.c |  153 +++
> >  drivers/media/platform/mtk-mdp/mtk_mdp_regs.h |   31 +
> >  drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c  |  140 +++
> >  drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h  |   41 +
> >  14 files changed, 2602 insertions(+)
> >  create mode 100644 drivers/media/platform/mtk-mdp/Makefile
> >  create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_comp.c
> >  create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_comp.h
> >  create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_core.c
> >  create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_core.h
> >  create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h
> >  create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
> >  create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h
> >  create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_regs.c
> >  create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_regs.h
> >  create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c
> >  create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h
> > 
> > diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
> > index 2c2670c..782b618 100644
> > --- a/drivers/media/platform/Kconfig
> > +++ b/drivers/media/platform/Kconfig
> > @@ -166,6 +166,22 @@ config VIDEO_MEDIATEK_VPU
> >  	    To compile this driver as a module, choose M here: the
> >  	    module will be called mtk-vpu.
> >  
> > +config VIDEO_MEDIATEK_MDP
> > +	tristate "Mediatek MDP driver"
> > +	depends on MTK_IOMMU || COMPILE_TEST
> > +	depends on VIDEO_DEV && VIDEO_V4L2
> > +	depends on ARCH_MEDIATEK || COMPILE_TEST
> > +	select VIDEOBUF2_DMA_CONTIG
> > +	select V4L2_MEM2MEM_DEV
> > +	select VIDEO_MEDIATEK_VPU
> > +	default n
> > +	---help---
> > +	    It is a v4l2 driver and present in Mediatek MT8173 SoCs.
> > +	    The driver supports for scaling and color space conversion.
> > +
> > +	    To compile this driver as a module, choose M here: the
> > +	    module will be called mtk-mdp.
> > +
> >  config VIDEO_MEDIATEK_VCODEC
> >  	tristate "Mediatek Video Codec driver"
> >  	depends on MTK_IOMMU || COMPILE_TEST
> > diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
> > index c6b3b92..9c54f1a 100644
> > --- a/drivers/media/platform/Makefile
> > +++ b/drivers/media/platform/Makefile
> > @@ -62,3 +62,5 @@ ccflags-y += -I$(srctree)/drivers/media/i2c
> >  obj-$(CONFIG_VIDEO_MEDIATEK_VPU)	+= mtk-vpu/
> >  
> >  obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC)	+= mtk-vcodec/
> > +
> > +obj-$(CONFIG_VIDEO_MEDIATEK_MDP)	+= mtk-mdp/
> > diff --git a/drivers/media/platform/mtk-mdp/Makefile b/drivers/media/platform/mtk-mdp/Makefile
> > new file mode 100644
> > index 0000000..f802569
> > --- /dev/null
> > +++ b/drivers/media/platform/mtk-mdp/Makefile
> > @@ -0,0 +1,9 @@
> > +mtk-mdp-y += mtk_mdp_core.o
> > +mtk-mdp-y += mtk_mdp_comp.o
> > +mtk-mdp-y += mtk_mdp_m2m.o
> > +mtk-mdp-y += mtk_mdp_regs.o
> > +mtk-mdp-y += mtk_mdp_vpu.o
> > +
> > +obj-$(CONFIG_VIDEO_MEDIATEK_MDP) += mtk-mdp.o
> > +
> > +ccflags-y += -I$(srctree)/drivers/media/platform/mtk-vpu
> > diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_comp.c b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.c
> > new file mode 100644
> > index 0000000..aa8f9fd
> > --- /dev/null
> > +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.c
> > @@ -0,0 +1,159 @@
> > +/*
> > + * Copyright (c) 2016 MediaTek Inc.
> > + * Author: Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + *
> > + * 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.
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/device.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_platform.h>
> > +#include <soc/mediatek/smi.h>
> > +
> > +#include "mtk_mdp_comp.h"
> > +
> > +
> > +static const char * const mtk_mdp_comp_stem[MTK_MDP_COMP_TYPE_MAX] = {
> > +	"mdp_rdma",
> > +	"mdp_rsz",
> > +	"mdp_wdma",
> > +	"mdp_wrot",
> > +};
> > +
> > +struct mtk_mdp_comp_match {
> > +	enum mtk_mdp_comp_type type;
> > +	int alias_id;
> > +};
> > +
> > +static const struct mtk_mdp_comp_match mtk_mdp_matches[MTK_MDP_COMP_ID_MAX] = {
> > +	{ MTK_MDP_RDMA,	0 },
> > +	{ MTK_MDP_RDMA,	1 },
> > +	{ MTK_MDP_RSZ,	0 },
> > +	{ MTK_MDP_RSZ,	1 },
> > +	{ MTK_MDP_RSZ,	2 },
> > +	{ MTK_MDP_WDMA,	0 },
> > +	{ MTK_MDP_WROT,	0 },
> > +	{ MTK_MDP_WROT,	1 },
> > +};
> > +
> > +int mtk_mdp_comp_get_id(struct device *dev, struct device_node *node,
> > +			enum mtk_mdp_comp_type comp_type)
> > +{
> > +	int id = of_alias_get_id(node, mtk_mdp_comp_stem[comp_type]);
> > +	int i;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(mtk_mdp_matches); i++) {
> > +		if (comp_type == mtk_mdp_matches[i].type &&
> > +		    id == mtk_mdp_matches[i].alias_id)
> > +			return i;
> > +	}
> > +
> > +	dev_err(dev, "Failed to get id. type: %d, id: %d\n", comp_type, id);
> > +
> > +	return -EINVAL;
> > +}
> > +
> > +void mtk_mdp_comp_clock_on(struct device *dev, struct mtk_mdp_comp *comp)
> > +{
> > +	int i, err;
> > +
> > +	if (comp->larb_dev) {
> > +		err = mtk_smi_larb_get(comp->larb_dev);
> > +		if (err)
> > +			dev_err(dev,
> > +				"failed to get larb, err %d. type:%d id:%d\n",
> > +				err, comp->type, comp->id);
> > +	}
> > +
> > +	for (i = 0; i < ARRAY_SIZE(comp->clk); i++) {
> > +		if (!comp->clk[i])
> > +			continue;
> > +		err = clk_prepare_enable(comp->clk[i]);
> > +		if (err)
> > +			dev_err(dev,
> > +			"failed to enable clock, err %d. type:%d id:%d i:%d\n",
> > +				err, comp->type, comp->id, i);
> > +	}
> > +}
> > +
> > +void mtk_mdp_comp_clock_off(struct device *dev, struct mtk_mdp_comp *comp)
> > +{
> > +	int i;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(comp->clk); i++) {
> > +		if (!comp->clk[i])
> > +			continue;
> > +		clk_disable_unprepare(comp->clk[i]);
> > +	}
> > +
> > +	if (comp->larb_dev)
> > +		mtk_smi_larb_put(comp->larb_dev);
> > +}
> > +
> > +int mtk_mdp_comp_init(struct device *dev, struct device_node *node,
> > +		      struct mtk_mdp_comp *comp, enum mtk_mdp_comp_id comp_id)
> > +{
> > +	struct device_node *larb_node;
> > +	struct platform_device *larb_pdev;
> > +	int i;
> > +
> > +	if (comp_id < 0 || comp_id >= MTK_MDP_COMP_ID_MAX) {
> > +		dev_err(dev, "Invalid comp_id %d\n", comp_id);
> > +		return -EINVAL;
> > +	}
> > +
> > +	comp->dev_node = of_node_get(node);
> > +	comp->id = comp_id;
> > +	comp->type = mtk_mdp_matches[comp_id].type;
> > +	comp->regs = of_iomap(node, 0);
> > +
> > +	for (i = 0; i < ARRAY_SIZE(comp->clk); i++) {
> > +		comp->clk[i] = of_clk_get(node, i);
> > +
> > +		/* Only RDMA needs two clocks */
> > +		if (comp->type != MTK_MDP_RDMA)
> > +			break;
> > +	}
> > +
> > +	/* Only DMA capable components need the LARB property */
> > +	comp->larb_dev = NULL;
> > +	if (comp->type != MTK_MDP_RDMA &&
> > +	    comp->type != MTK_MDP_WDMA &&
> > +	    comp->type != MTK_MDP_WROT)
> > +		return 0;
> > +
> > +	larb_node = of_parse_phandle(node, "mediatek,larb", 0);
> > +	if (!larb_node) {
> > +		dev_err(dev,
> > +			"Missing mediadek,larb phandle in %s node\n",
> > +			node->full_name);
> > +		return -EINVAL;
> > +	}
> > +
> > +	larb_pdev = of_find_device_by_node(larb_node);
> > +	if (!larb_pdev) {
> > +		dev_warn(dev, "Waiting for larb device %s\n",
> > +			 larb_node->full_name);
> > +		of_node_put(larb_node);
> > +		return -EPROBE_DEFER;
> > +	}
> > +	of_node_put(larb_node);
> > +
> > +	comp->larb_dev = &larb_pdev->dev;
> > +
> > +	return 0;
> > +}
> > +
> > +void mtk_mdp_comp_deinit(struct device *dev, struct mtk_mdp_comp *comp)
> > +{
> > +	of_node_put(comp->dev_node);
> > +}
> > diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_comp.h b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.h
> > new file mode 100644
> > index 0000000..63b3983
> > --- /dev/null
> > +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.h
> > @@ -0,0 +1,72 @@
> > +/*
> > + * Copyright (c) 2016 MediaTek Inc.
> > + * Author: Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + *
> > + * 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.
> > + */
> > +
> > +#ifndef __MTK_MDP_COMP_H__
> > +#define __MTK_MDP_COMP_H__
> > +
> > +/**
> > + * enum mtk_mdp_comp_type - the MDP component
> > + * @MTK_MDP_RDMA:	Read DMA
> > + * @MTK_MDP_RSZ:	Riszer
> > + * @MTK_MDP_WDMA:	Write DMA
> > + * @MTK_MDP_WROT:	Write DMA with rotation
> > + */
> > +enum mtk_mdp_comp_type {
> > +	MTK_MDP_RDMA,
> > +	MTK_MDP_RSZ,
> > +	MTK_MDP_WDMA,
> > +	MTK_MDP_WROT,
> > +	MTK_MDP_COMP_TYPE_MAX,
> > +};
> > +
> > +enum mtk_mdp_comp_id {
> > +	MTK_MDP_COMP_RDMA0,
> > +	MTK_MDP_COMP_RDMA1,
> > +	MTK_MDP_COMP_RSZ0,
> > +	MTK_MDP_COMP_RSZ1,
> > +	MTK_MDP_COMP_RSZ2,
> > +	MTK_MDP_COMP_WDMA,
> > +	MTK_MDP_COMP_WROT0,
> > +	MTK_MDP_COMP_WROT1,
> > +	MTK_MDP_COMP_ID_MAX,
> > +};
> > +
> > +/**
> > + * struct mtk_mdp_comp - the MDP's function component data
> > + * @dev_node:	component device node
> > + * @clk:	clocks required for component
> > + * @regs:	Mapped address of component registers.
> > + * @larb_dev:	SMI device required for component
> > + * @type:	component type
> > + * @id:		component ID
> > + */
> > +struct mtk_mdp_comp {
> > +	struct device_node	*dev_node;
> > +	struct clk		*clk[2];
> > +	void __iomem		*regs;
> > +	struct device		*larb_dev;
> > +	enum mtk_mdp_comp_type	type;
> > +	enum mtk_mdp_comp_id	id;
> > +};
> > +
> > +int mtk_mdp_comp_init(struct device *dev, struct device_node *node,
> > +		      struct mtk_mdp_comp *comp, enum mtk_mdp_comp_id comp_id);
> > +void mtk_mdp_comp_deinit(struct device *dev, struct mtk_mdp_comp *comp);
> > +int mtk_mdp_comp_get_id(struct device *dev, struct device_node *node,
> > +			enum mtk_mdp_comp_type comp_type);
> > +void mtk_mdp_comp_clock_on(struct device *dev, struct mtk_mdp_comp *comp);
> > +void mtk_mdp_comp_clock_off(struct device *dev, struct mtk_mdp_comp *comp);
> > +
> > +
> > +#endif /* __MTK_MDP_COMP_H__ */
> > diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c
> > new file mode 100644
> > index 0000000..8a81dd9
> > --- /dev/null
> > +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c
> > @@ -0,0 +1,294 @@
> > +/*
> > + * Copyright (c) 2015-2016 MediaTek Inc.
> > + * Author: Houlong Wei <houlong.wei at mediatek.com>
> > + *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + *
> > + * 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.
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/device.h>
> > +#include <linux/errno.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_platform.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/pm_runtime.h>
> > +#include <linux/workqueue.h>
> > +#include <soc/mediatek/smi.h>
> > +
> > +#include "mtk_mdp_core.h"
> > +#include "mtk_mdp_m2m.h"
> > +#include "mtk_vpu.h"
> > +
> > +/* MDP debug log level (0-3). 3 shows all the logs. */
> > +int mtk_mdp_dbg_level;
> > +EXPORT_SYMBOL(mtk_mdp_dbg_level);
> > +
> > +module_param(mtk_mdp_dbg_level, int, S_IRUGO | S_IWUSR);
> > +
> > +static const struct of_device_id mtk_mdp_comp_dt_ids[] = {
> > +	{
> > +		.compatible = "mediatek,mt8173-mdp-rdma",
> > +		.data = (void *)MTK_MDP_RDMA
> > +	}, {
> > +		.compatible = "mediatek,mt8173-mdp-rsz",
> > +		.data = (void *)MTK_MDP_RSZ
> > +	}, {
> > +		.compatible = "mediatek,mt8173-mdp-wdma",
> > +		.data = (void *)MTK_MDP_WDMA
> > +	}, {
> > +		.compatible = "mediatek,mt8173-mdp-wrot",
> > +		.data = (void *)MTK_MDP_WROT
> > +	}
> > +};
> > +
> > +static const struct of_device_id mtk_mdp_of_ids[] = {
> > +	{ .compatible = "mediatek,mt8173-mdp", },
> > +	{ },
> > +};
> > +MODULE_DEVICE_TABLE(of, mtk_mdp_of_ids);
> > +
> > +static void mtk_mdp_clock_on(struct mtk_mdp_dev *mdp)
> > +{
> > +	struct device *dev = &mdp->pdev->dev;
> > +	int i;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(mdp->comp); i++)
> > +		mtk_mdp_comp_clock_on(dev, mdp->comp[i]);
> > +}
> > +
> > +static void mtk_mdp_clock_off(struct mtk_mdp_dev *mdp)
> > +{
> > +	struct device *dev = &mdp->pdev->dev;
> > +	int i;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(mdp->comp); i++)
> > +		mtk_mdp_comp_clock_off(dev, mdp->comp[i]);
> > +}
> > +
> > +static void mtk_mdp_wdt_worker(struct work_struct *work)
> > +{
> > +	struct mtk_mdp_dev *mdp =
> > +			container_of(work, struct mtk_mdp_dev, wdt_work);
> > +	struct mtk_mdp_ctx *ctx;
> > +
> > +	mtk_mdp_err("Watchdog timeout");
> > +
> > +	list_for_each_entry(ctx, &mdp->ctx_list, list) {
> > +		mtk_mdp_dbg(0, "[%d] Change as state error", ctx->id);
> > +		mtk_mdp_ctx_state_lock_set(ctx, MTK_MDP_CTX_ERROR);
> > +	}
> > +}
> > +
> > +static void mtk_mdp_reset_handler(void *priv)
> > +{
> > +	struct mtk_mdp_dev *mdp = priv;
> > +
> > +	queue_work(mdp->wdt_wq, &mdp->wdt_work);
> > +}
> > +
> > +static int mtk_mdp_probe(struct platform_device *pdev)
> > +{
> > +	struct mtk_mdp_dev *mdp;
> > +	struct device *dev = &pdev->dev;
> > +	struct device_node *node;
> > +	int i, ret = 0;
> > +
> > +	mdp = devm_kzalloc(dev, sizeof(*mdp), GFP_KERNEL);
> > +	if (!mdp)
> > +		return -ENOMEM;
> > +
> > +	mdp->id = pdev->id;
> > +	mdp->pdev = pdev;
> > +	INIT_LIST_HEAD(&mdp->ctx_list);
> > +
> > +	mutex_init(&mdp->lock);
> > +	mutex_init(&mdp->vpulock);
> > +
> > +	/* Iterate over sibling MDP function blocks */
> > +	for_each_child_of_node(dev->of_node->parent, node) {
> > +		const struct of_device_id *of_id;
> > +		enum mtk_mdp_comp_type comp_type;
> > +		int comp_id;
> > +		struct mtk_mdp_comp *comp;
> > +
> > +		of_id = of_match_node(mtk_mdp_comp_dt_ids, node);
> > +		if (!of_id)
> > +			continue;
> > +
> > +		if (!of_device_is_available(node)) {
> > +			dev_err(dev, "Skipping disabled component %s\n",
> > +				node->full_name);
> > +			continue;
> > +		}
> > +
> > +		comp_type = (enum mtk_mdp_comp_type)of_id->data;
> > +		comp_id = mtk_mdp_comp_get_id(dev, node, comp_type);
> > +		if (comp_id < 0) {
> > +			dev_warn(dev, "Skipping unknown component %s\n",
> > +				 node->full_name);
> > +			continue;
> > +		}
> > +
> > +		comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL);
> > +		if (!comp) {
> > +			ret = -ENOMEM;
> > +			goto err_comp;
> > +		}
> > +		mdp->comp[comp_id] = comp;
> > +
> > +		ret = mtk_mdp_comp_init(dev, node, comp, comp_id);
> > +		if (ret)
> > +			goto err_comp;
> > +	}
> > +
> > +	mdp->job_wq = create_singlethread_workqueue(MTK_MDP_MODULE_NAME);
> > +	if (!mdp->job_wq) {
> > +		dev_err(&pdev->dev, "unable to alloc job workqueue\n");
> > +		ret = -ENOMEM;
> > +		goto err_alloc_job_wq;
> > +	}
> > +
> > +	mdp->wdt_wq = create_singlethread_workqueue("mdp_wdt_wq");
> > +	if (!mdp->wdt_wq) {
> > +		dev_err(&pdev->dev, "unable to alloc wdt workqueue\n");
> > +		ret = -ENOMEM;
> > +		goto err_alloc_wdt_wq;
> > +	}
> > +	INIT_WORK(&mdp->wdt_work, mtk_mdp_wdt_worker);
> > +
> > +	ret = v4l2_device_register(dev, &mdp->v4l2_dev);
> > +	if (ret) {
> > +		dev_err(&pdev->dev, "Failed to register v4l2 device\n");
> > +		ret = -EINVAL;
> > +		goto err_dev_register;
> > +	}
> > +
> > +	ret = mtk_mdp_register_m2m_device(mdp);
> > +	if (ret) {
> > +		v4l2_err(&mdp->v4l2_dev, "Failed to init mem2mem device\n");
> > +		goto err_m2m_register;
> > +	}
> > +
> > +	mdp->vpu_dev = vpu_get_plat_device(pdev);
> > +	vpu_wdt_reg_handler(mdp->vpu_dev, mtk_mdp_reset_handler, mdp,
> > +			    VPU_RST_MDP);
> > +
> > +	platform_set_drvdata(pdev, mdp);
> > +
> > +	vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32));
> > +
> > +	pm_runtime_enable(dev);
> > +	dev_dbg(dev, "mdp-%d registered successfully\n", mdp->id);
> > +
> > +	return 0;
> > +
> > +err_m2m_register:
> > +	v4l2_device_unregister(&mdp->v4l2_dev);
> > +
> > +err_dev_register:
> > +	destroy_workqueue(mdp->wdt_wq);
> > +
> > +err_alloc_wdt_wq:
> > +	destroy_workqueue(mdp->job_wq);
> > +
> > +err_alloc_job_wq:
> > +
> > +err_comp:
> > +	for (i = 0; i < ARRAY_SIZE(mdp->comp); i++)
> > +		mtk_mdp_comp_deinit(dev, mdp->comp[i]);
> > +
> > +	dev_dbg(dev, "err %d\n", ret);
> > +	return ret;
> > +}
> > +
> > +static int mtk_mdp_remove(struct platform_device *pdev)
> > +{
> > +	struct mtk_mdp_dev *mdp = platform_get_drvdata(pdev);
> > +	int i;
> > +
> > +	pm_runtime_disable(&pdev->dev);
> > +	vb2_dma_contig_clear_max_seg_size(&pdev->dev);
> > +	mtk_mdp_unregister_m2m_device(mdp);
> > +	v4l2_device_unregister(&mdp->v4l2_dev);
> > +
> > +	flush_workqueue(mdp->job_wq);
> > +	destroy_workqueue(mdp->job_wq);
> > +
> > +	for (i = 0; i < ARRAY_SIZE(mdp->comp); i++)
> > +		mtk_mdp_comp_deinit(&pdev->dev, mdp->comp[i]);
> > +
> > +	dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
> > +	return 0;
> > +}
> > +
> > +#if defined(CONFIG_PM_RUNTIME) || defined(CONFIG_PM_SLEEP)
> > +static int mtk_mdp_pm_suspend(struct device *dev)
> > +{
> > +	struct mtk_mdp_dev *mdp = dev_get_drvdata(dev);
> > +
> > +	mtk_mdp_clock_off(mdp);
> > +
> > +	return 0;
> > +}
> > +
> > +static int mtk_mdp_pm_resume(struct device *dev)
> > +{
> > +	struct mtk_mdp_dev *mdp = dev_get_drvdata(dev);
> > +
> > +	mtk_mdp_clock_on(mdp);
> > +
> > +	return 0;
> > +}
> > +#endif /* CONFIG_PM_RUNTIME || CONFIG_PM_SLEEP */
> > +
> > +#ifdef CONFIG_PM_SLEEP
> > +static int mtk_mdp_suspend(struct device *dev)
> > +{
> > +	if (pm_runtime_suspended(dev))
> > +		return 0;
> > +
> > +	return mtk_mdp_pm_suspend(dev);
> > +}
> > +
> > +static int mtk_mdp_resume(struct device *dev)
> > +{
> > +	if (pm_runtime_suspended(dev))
> > +		return 0;
> > +
> > +	return mtk_mdp_pm_resume(dev);
> > +}
> > +#endif /* CONFIG_PM_SLEEP */
> > +
> > +static const struct dev_pm_ops mtk_mdp_pm_ops = {
> > +	SET_SYSTEM_SLEEP_PM_OPS(mtk_mdp_suspend, mtk_mdp_resume)
> > +	SET_RUNTIME_PM_OPS(mtk_mdp_pm_suspend, mtk_mdp_pm_resume, NULL)
> > +};
> > +
> > +static struct platform_driver mtk_mdp_driver = {
> > +	.probe		= mtk_mdp_probe,
> > +	.remove		= mtk_mdp_remove,
> > +	.driver = {
> > +		.name	= MTK_MDP_MODULE_NAME,
> > +		.owner	= THIS_MODULE,
> > +		.pm	= &mtk_mdp_pm_ops,
> > +		.of_match_table = mtk_mdp_of_ids,
> > +	}
> > +};
> > +
> > +module_platform_driver(mtk_mdp_driver);
> > +
> > +MODULE_AUTHOR("Houlong Wei <houlong.wei at mediatek.com>");
> > +MODULE_DESCRIPTION("Mediatek image processor driver");
> > +MODULE_LICENSE("GPL v2");
> > diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.h b/drivers/media/platform/mtk-mdp/mtk_mdp_core.h
> > new file mode 100644
> > index 0000000..9046968
> > --- /dev/null
> > +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.h
> > @@ -0,0 +1,233 @@
> > +/*
> > + * Copyright (c) 2015-2016 MediaTek Inc.
> > + * Author: Houlong Wei <houlong.wei at mediatek.com>
> > + *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + *
> > + * 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.
> > + */
> > +
> > +#ifndef __MTK_MDP_CORE_H__
> > +#define __MTK_MDP_CORE_H__
> > +
> > +#include <linux/videodev2.h>
> > +#include <media/v4l2-ctrls.h>
> > +#include <media/v4l2-device.h>
> > +#include <media/v4l2-mem2mem.h>
> > +#include <media/videobuf2-core.h>
> > +#include <media/videobuf2-dma-contig.h>
> > +
> > +#include "mtk_mdp_vpu.h"
> > +#include "mtk_mdp_comp.h"
> > +
> > +
> > +#define MTK_MDP_MODULE_NAME		"mtk-mdp"
> > +
> > +#define MTK_MDP_SHUTDOWN_TIMEOUT	((100*HZ)/1000) /* 100ms */
> > +#define MTK_MDP_MAX_CTRL_NUM		10
> > +
> > +#define MTK_MDP_FMT_FLAG_OUTPUT		BIT(0)
> > +#define MTK_MDP_FMT_FLAG_CAPTURE	BIT(1)
> > +
> > +#define MTK_MDP_SRC_FMT			BIT(1)
> > +#define MTK_MDP_DST_FMT			BIT(2)
> > +#define MTK_MDP_CTX_ERROR		BIT(5)
> > +
> > +/**
> > + * struct mtk_mdp_fmt - the driver's internal color format data
> > + * @name: format description
> > + * @pixelformat: the fourcc code for this format, 0 if not applicable
> > + * @num_planes: number of physically non-contiguous data planes
> > + * @depth: per plane driver's private 'number of bits per pixel'
> > + * @flags: flags indicating which operation mode format applies to
> > +	   MTK_MDP_FMT_FLAG_OUTPUT is used in OUTPUT stream
> > +	   MTK_MDP_FMT_FLAG_CAPTURE is used in CAPTURE stream
> > + */
> > +struct mtk_mdp_fmt {
> > +	char	*name;
> > +	u32	pixelformat;
> > +	u16	num_planes;
> > +	u8	depth[VIDEO_MAX_PLANES];
> > +	u32	flags;
> > +};
> > +
> > +/**
> > + * struct mtk_mdp_addr - the image processor physical address set
> > + * @addr:	address of planes
> > + */
> > +struct mtk_mdp_addr {
> > +	dma_addr_t addr[MTK_MDP_MAX_NUM_PLANE];
> > +};
> > +
> > +/* struct mtk_mdp_ctrls - the image processor control set
> > + * @rotate: rotation degree
> > + * @hflip: horizontal flip
> > + * @vflip: vertical flip
> > + * @global_alpha: the alpha value of current frame
> > + */
> > +struct mtk_mdp_ctrls {
> > +	struct v4l2_ctrl *rotate;
> > +	struct v4l2_ctrl *hflip;
> > +	struct v4l2_ctrl *vflip;
> > +	struct v4l2_ctrl *global_alpha;
> > +};
> > +
> > +/**
> > + * struct mtk_mdp_frame - source/target frame properties
> > + * @width:	SRC : SRCIMG_WIDTH, DST : OUTPUTDMA_WHOLE_IMG_WIDTH
> > + * @height:	SRC : SRCIMG_HEIGHT, DST : OUTPUTDMA_WHOLE_IMG_HEIGHT
> > + * @crop:	cropped(source)/scaled(destination) size
> > + * @payload:	image size in bytes (w x h x bpp)
> > + * @pitch:	bytes per line of image in memory
> > + * @addr:	image frame buffer physical addresses
> > + * @fmt:	color format pointer
> > + * @alpha:	frame's alpha value
> > + */
> > +struct mtk_mdp_frame {
> > +	u32				width;
> > +	u32				height;
> > +	struct v4l2_rect		crop;
> > +	unsigned long			payload[VIDEO_MAX_PLANES];
> > +	unsigned int			pitch[VIDEO_MAX_PLANES];
> > +	struct mtk_mdp_addr		addr;
> > +	const struct mtk_mdp_fmt	*fmt;
> > +	u8				alpha;
> > +};
> > +
> > +/**
> > + * struct mtk_mdp_variant - image processor variant information
> > + * @pix_max:		maximum limit of image size
> > + * @pix_min:		minimun limit of image size
> > + * @pix_align:		alignement of image
> > + * @h_scale_up_max:	maximum scale-up in horizontal
> > + * @v_scale_up_max:	maximum scale-up in vertical
> > + * @h_scale_down_max:	maximum scale-down in horizontal
> > + * @v_scale_down_max:	maximum scale-down in vertical
> > + */
> > +struct mtk_mdp_variant {
> > +	struct mtk_mdp_pix_limit	*pix_max;
> > +	struct mtk_mdp_pix_limit	*pix_min;
> > +	struct mtk_mdp_pix_align	*pix_align;
> > +	u16				h_scale_up_max;
> > +	u16				v_scale_up_max;
> > +	u16				h_scale_down_max;
> > +	u16				v_scale_down_max;
> > +};
> > +
> > +/**
> > + * struct mtk_mdp_dev - abstraction for image processor entity
> > + * @lock:	the mutex protecting this data structure
> > + * @vpulock:	the mutex protecting the communication with VPU
> > + * @pdev:	pointer to the image processor platform device
> > + * @variant:	the IP variant information
> > + * @id:		image processor device index (0..MTK_MDP_MAX_DEVS)
> > + * @comp:	MDP function components
> > + * @m2m_dev:	v4l2 memory-to-memory device data
> > + * @ctx_list:	list of struct mtk_mdp_ctx
> > + * @vdev:	video device for image processor driver
> > + * @v4l2_dev:	V4L2 device to register video devices for.
> > + * @job_wq:	processor work queue
> > + * @vpu_dev:	VPU platform device
> > + * @ctx_num:	counter of active MTK MDP context
> > + * @id_counter:	An integer id given to the next opened context
> > + * @wdt_wq:	work queue for VPU watchdog
> > + * @wdt_work:	worker for VPU watchdog
> > + */
> > +struct mtk_mdp_dev {
> > +	struct mutex			lock;
> > +	struct mutex			vpulock;
> > +	struct platform_device		*pdev;
> > +	struct mtk_mdp_variant		*variant;
> > +	u16				id;
> > +	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 v4l2_device		v4l2_dev;
> > +	struct workqueue_struct		*job_wq;
> > +	struct platform_device		*vpu_dev;
> > +	int				ctx_num;
> > +	unsigned long			id_counter;
> > +	struct workqueue_struct		*wdt_wq;
> > +	struct work_struct		wdt_work;
> > +};
> > +
> > +/**
> > + * mtk_mdp_ctx - the device context data
> > + * @list:		link to ctx_list of mtk_mdp_dev
> > + * @s_frame:		source frame properties
> > + * @d_frame:		destination frame properties
> > + * @id:			index of the context that this structure describes
> > + * @flags:		additional flags for image conversion
> > + * @state:		flags to keep track of user configuration
> > +			Protected by slock
> > + * @rotation:		rotates the image by specified angle
> > + * @hflip:		mirror the picture horizontally
> > + * @vflip:		mirror the picture vertically
> > + * @mdp_dev:		the image processor device this context applies to
> > + * @m2m_ctx:		memory-to-memory device context
> > + * @fh:			v4l2 file handle
> > + * @ctrl_handler:	v4l2 controls handler
> > + * @ctrls		image processor control set
> > + * @ctrls_rdy:		true if the control handler is initialized
> > + * @vpu:		VPU instance
> > + * @slock:		the mutex protecting mtp_mdp_ctx.state
> > + * @work:		worker for image processing
> > + */
> > +struct mtk_mdp_ctx {
> > +	struct list_head		list;
> > +	struct mtk_mdp_frame		s_frame;
> > +	struct mtk_mdp_frame		d_frame;
> > +	u32				flags;
> > +	u32				state;
> > +	int				id;
> > +	int				rotation;
> > +	u32				hflip:1;
> > +	u32				vflip:1;
> > +	struct mtk_mdp_dev		*mdp_dev;
> > +	struct v4l2_m2m_ctx		*m2m_ctx;
> > +	struct v4l2_fh			fh;
> > +	struct v4l2_ctrl_handler	ctrl_handler;
> > +	struct mtk_mdp_ctrls		ctrls;
> > +	bool				ctrls_rdy;
> > +
> > +	struct mtk_mdp_vpu		vpu;
> > +	struct mutex			slock;
> > +	struct work_struct		work;
> > +};
> > +
> > +extern int mtk_mdp_dbg_level;
> > +
> > +#if defined(DEBUG)
> > +
> > +#define mtk_mdp_dbg(level, fmt, args...)				 \
> > +	do {								 \
> > +		if (mtk_mdp_dbg_level >= level)				 \
> > +			pr_info("[MTK_MDP] level=%d %s(),%d: " fmt "\n", \
> > +				level, __func__, __LINE__, ##args);	 \
> > +	} while (0)
> > +
> > +#define mtk_mdp_err(fmt, args...)					\
> > +	pr_err("[MTK_MDP][ERROR] %s:%d: " fmt "\n", __func__, __LINE__, \
> > +	       ##args)
> > +
> > +
> > +#define mtk_mdp_dbg_enter()  mtk_mdp_dbg(3, "+")
> > +#define mtk_mdp_dbg_leave()  mtk_mdp_dbg(3, "-")
> > +
> > +#else
> > +
> > +#define mtk_mdp_dbg(level, fmt, args...)
> > +#define mtk_mdp_err(fmt, args...)
> > +#define mtk_mdp_dbg_enter()
> > +#define mtk_mdp_dbg_leave()
> > +
> > +#endif
> > +
> > +#endif /* __MTK_MDP_CORE_H__ */
> > diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h b/drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h
> > new file mode 100644
> > index 0000000..78e2cc0
> > --- /dev/null
> > +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h
> > @@ -0,0 +1,126 @@
> > +/*
> > + * Copyright (c) 2015-2016 MediaTek Inc.
> > + * Author: Houlong Wei <houlong.wei at mediatek.com>
> > + *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + *
> > + * 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.
> > + */
> > +
> > +#ifndef __MTK_MDP_IPI_H__
> > +#define __MTK_MDP_IPI_H__
> > +
> > +#define MTK_MDP_MAX_NUM_PLANE		3
> > +
> > +enum mdp_ipi_msgid {
> > +	AP_MDP_INIT		= 0xd000,
> > +	AP_MDP_DEINIT		= 0xd001,
> > +	AP_MDP_PROCESS		= 0xd002,
> > +
> > +	VPU_MDP_INIT_ACK	= 0xe000,
> > +	VPU_MDP_DEINIT_ACK	= 0xe001,
> > +	VPU_MDP_PROCESS_ACK	= 0xe002
> > +};
> > +
> > +#pragma pack(push, 4)
> > +
> > +/**
> > + * struct mdp_ipi_init - for AP_MDP_INIT
> > + * @msg_id   : AP_MDP_INIT
> > + * @ipi_id   : IPI_MDP
> > + * @ap_inst  : AP mtk_mdp_vpu address
> > + */
> > +struct mdp_ipi_init {
> > +	uint32_t msg_id;
> > +	uint32_t ipi_id;
> > +	uint64_t ap_inst;
> > +};
> > +
> > +/**
> > + * struct mdp_ipi_comm - for AP_MDP_PROCESS, AP_MDP_DEINIT
> > + * @msg_id        : AP_MDP_PROCESS, AP_MDP_DEINIT
> > + * @ipi_id        : IPI_MDP
> > + * @ap_inst       : AP mtk_mdp_vpu address
> > + * @vpu_inst_addr : VPU MDP instance address
> > + */
> > +struct mdp_ipi_comm {
> > +	uint32_t msg_id;
> > +	uint32_t ipi_id;
> > +	uint64_t ap_inst;
> > +	uint32_t vpu_inst_addr;
> > +};
> > +
> > +/**
> > + * struct mdp_ipi_comm_ack - for VPU_MDP_DEINIT_ACK, VPU_MDP_PROCESS_ACK
> > + * @msg_id        : VPU_MDP_DEINIT_ACK, VPU_MDP_PROCESS_ACK
> > + * @ipi_id        : IPI_MDP
> > + * @ap_inst       : AP mtk_mdp_vpu address
> > + * @vpu_inst_addr : VPU MDP instance address
> > + * @status        : VPU exeuction result
> > + */
> > +struct mdp_ipi_comm_ack {
> > +	uint32_t msg_id;
> > +	uint32_t ipi_id;
> > +	uint64_t ap_inst;
> > +	uint32_t vpu_inst_addr;
> > +	int32_t status;
> > +};
> > +
> > +/**
> > + * struct mdp_config - configured for source/destination image
> > + * @x        : left
> > + * @y        : top
> > + * @w        : width
> > + * @h        : height
> > + * @w_stride : bytes in horizontal
> > + * @h_stride : bytes in vertical
> > + * @crop_x   : cropped left
> > + * @crop_y   : cropped top
> > + * @crop_w   : cropped width
> > + * @crop_h   : cropped height
> > + * @format   : color format
> > + */
> > +struct mdp_config {
> > +	int32_t x;
> > +	int32_t y;
> > +	int32_t w;
> > +	int32_t h;
> > +	int32_t w_stride;
> > +	int32_t h_stride;
> > +	int32_t crop_x;
> > +	int32_t crop_y;
> > +	int32_t crop_w;
> > +	int32_t crop_h;
> > +	int32_t format;
> > +};
> > +
> > +struct mdp_buffer {
> > +	uint64_t addr_mva[MTK_MDP_MAX_NUM_PLANE];
> > +	int32_t plane_size[MTK_MDP_MAX_NUM_PLANE];
> > +	int32_t plane_num;
> > +};
> > +
> > +struct mdp_config_misc {
> > +	int32_t orientation; /* 0, 90, 180, 270 */
> > +	int32_t hflip; /* 1 will enable the flip */
> > +	int32_t vflip; /* 1 will enable the flip */
> > +	int32_t alpha; /* global alpha */
> > +};
> > +
> > +struct mdp_process_vsi {
> > +	struct mdp_config src_config;
> > +	struct mdp_buffer src_buffer;
> > +	struct mdp_config dst_config;
> > +	struct mdp_buffer dst_buffer;
> > +	struct mdp_config_misc misc;
> > +};
> > +
> > +#pragma pack(pop)
> > +
> > +#endif /* __MTK_MDP_IPI_H__ */
> > diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
> > new file mode 100644
> > index 0000000..e3ea97d
> > --- /dev/null
> > +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
> > @@ -0,0 +1,1304 @@
> > +/*
> > + * Copyright (c) 2015-2016 MediaTek Inc.
> > + * Author: Houlong Wei <houlong.wei at mediatek.com>
> > + *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + *
> > + * 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.
> > + */
> > +
> > +#include <linux/device.h>
> > +#include <linux/errno.h>
> > +#include <linux/kernel.h>
> > +#include <linux/pm_runtime.h>
> > +#include <linux/workqueue.h>
> > +#include <media/v4l2-event.h>
> > +#include <media/v4l2-ioctl.h>
> > +
> > +#include "mtk_mdp_core.h"
> > +#include "mtk_mdp_m2m.h"
> > +#include "mtk_mdp_regs.h"
> > +#include "mtk_vpu.h"
> > +
> > +
> > +/**
> > + *  struct mtk_mdp_pix_limit - image pixel size limits
> > + *  @org_w: source pixel width
> > + *  @org_h: source pixel height
> > + *  @target_rot_dis_w: pixel dst scaled width with the rotator is off
> > + *  @target_rot_dis_h: pixel dst scaled height with the rotator is off
> > + *  @target_rot_en_w: pixel dst scaled width with the rotator is on
> > + *  @target_rot_en_h: pixel dst scaled height with the rotator is on
> > + */
> > +struct mtk_mdp_pix_limit {
> > +	u16 org_w;
> > +	u16 org_h;
> > +	u16 target_rot_dis_w;
> > +	u16 target_rot_dis_h;
> > +	u16 target_rot_en_w;
> > +	u16 target_rot_en_h;
> > +};
> > +
> > +/**
> > + *  struct mtk_mdp_pix_align - alignement of image
> > + *  @org_w: source alignment of width
> > + *  @org_h: source alignment of height
> > + *  @target_w: dst alignment of width
> > + *  @target_h: dst alignment of height
> > + */
> > +struct mtk_mdp_pix_align {
> > +	u16 org_w;
> > +	u16 org_h;
> > +	u16 target_w;
> > +	u16 target_h;
> > +};
> > +
> > +static const struct mtk_mdp_fmt mtk_mdp_formats[] = {
> > +	{
> > +		.name		= "YUV420 MT21. 2p, Y/CbCr",
> > +		.pixelformat	= V4L2_PIX_FMT_MT21,
> > +		.depth		= { 8, 4 },
> > +		.num_planes	= 2,
> > +		.flags		= MTK_MDP_FMT_FLAG_OUTPUT,
> > +	}, {
> > +		.name		= "YUV420 non-contig. 2p, Y/CbCr",
> > +		.pixelformat	= V4L2_PIX_FMT_NV12M,
> > +		.depth		= { 8, 4 },
> > +		.num_planes	= 2,
> > +		.flags		= MTK_MDP_FMT_FLAG_OUTPUT |
> > +				  MTK_MDP_FMT_FLAG_CAPTURE,
> > +	}, {
> > +		.name		= "YUV420 non-contig. 3p, Y/Cb/Cr",
> > +		.pixelformat	= V4L2_PIX_FMT_YUV420M,
> > +		.depth		= { 8, 2, 2 },
> > +		.num_planes	= 3,
> > +		.flags		= MTK_MDP_FMT_FLAG_OUTPUT |
> > +				  MTK_MDP_FMT_FLAG_CAPTURE,
> > +	}
> > +};
> > +
> > +static struct mtk_mdp_pix_limit mtk_mdp_size_max = {
> > +	.target_rot_dis_w	= 4096,
> > +	.target_rot_dis_h	= 4096,
> > +	.target_rot_en_w	= 4096,
> > +	.target_rot_en_h	= 4096,
> > +};
> > +
> > +static struct mtk_mdp_pix_limit mtk_mdp_size_min = {
> > +	.org_w			= 16,
> > +	.org_h			= 16,
> > +	.target_rot_dis_w	= 16,
> > +	.target_rot_dis_h	= 16,
> > +	.target_rot_en_w	= 16,
> > +	.target_rot_en_h	= 16,
> > +};
> > +
> > +static struct mtk_mdp_pix_align mtk_mdp_size_align = {
> > +	.org_w			= 16,
> > +	.org_h			= 16,
> > +	.target_w		= 2,
> > +	.target_h		= 2,
> > +};
> > +
> > +static struct mtk_mdp_variant mtk_mdp_default_variant = {
> > +	.pix_max		= &mtk_mdp_size_max,
> > +	.pix_min		= &mtk_mdp_size_min,
> > +	.pix_align		= &mtk_mdp_size_align,
> > +	.h_scale_up_max		= 32,
> > +	.v_scale_up_max		= 32,
> > +	.h_scale_down_max	= 32,
> > +	.v_scale_down_max	= 128,
> > +};
> > +
> > +static const struct mtk_mdp_fmt *mtk_mdp_find_fmt(u32 pixelformat, u32 type)
> > +{
> > +	u32 i, flag;
> > +
> > +	flag = V4L2_TYPE_IS_OUTPUT(type) ? MTK_MDP_FMT_FLAG_OUTPUT :
> > +					   MTK_MDP_FMT_FLAG_CAPTURE;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(mtk_mdp_formats); ++i) {
> > +		if (!(mtk_mdp_formats[i].flags & flag))
> > +			continue;
> > +		if (mtk_mdp_formats[i].pixelformat == pixelformat)
> > +			return &mtk_mdp_formats[i];
> > +	}
> > +	return NULL;
> > +}
> > +
> > +static const struct mtk_mdp_fmt *mtk_mdp_find_fmt_by_index(u32 index, u32 type)
> > +{
> > +	u32 i, flag, num = 0;
> > +
> > +	flag = V4L2_TYPE_IS_OUTPUT(type) ? MTK_MDP_FMT_FLAG_OUTPUT :
> > +					   MTK_MDP_FMT_FLAG_CAPTURE;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(mtk_mdp_formats); ++i) {
> > +		if (!(mtk_mdp_formats[i].flags & flag))
> > +			continue;
> > +		if (index == num)
> > +			return &mtk_mdp_formats[i];
> > +		num++;
> > +	}
> > +	return NULL;
> > +}
> > +
> > +static void mtk_mdp_bound_align_image(u32 *w, unsigned int wmin,
> > +				      unsigned int wmax, unsigned int align_w,
> > +				      u32 *h, unsigned int hmin,
> > +				      unsigned int hmax, unsigned int align_h)
> > +{
> > +	int org_w, org_h, step_w, step_h;
> > +	int walign, halign;
> > +
> > +	org_w = *w;
> > +	org_h = *h;
> > +	walign = ffs(align_w) - 1;
> > +	halign = ffs(align_h) - 1;
> > +	v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
> > +
> > +	step_w = 1 << walign;
> > +	step_h = 1 << halign;
> > +	if (*w < org_w && (*w + step_w) <= wmax)
> > +		*w += step_w;
> > +	if (*h < org_h && (*h + step_h) <= hmax)
> > +		*h += step_h;
> > +}
> > +
> > +static const struct mtk_mdp_fmt *mtk_mdp_try_fmt_mplane(struct mtk_mdp_ctx *ctx,
> > +							struct v4l2_format *f)
> > +{
> > +	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
> > +	struct mtk_mdp_variant *variant = mdp->variant;
> > +	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
> > +	const struct mtk_mdp_fmt *fmt;
> > +	u32 max_w, max_h, align_w, align_h;
> > +	u32 min_w, min_h, org_w, org_h;
> > +	int i;
> > +
> > +	fmt = mtk_mdp_find_fmt(pix_mp->pixelformat, f->type);
> > +	if (!fmt)
> > +		fmt = mtk_mdp_find_fmt_by_index(0, f->type);
> > +	if (!fmt) {
> > +		dev_dbg(&ctx->mdp_dev->pdev->dev,
> > +			"pixelformat format 0x%X invalid\n",
> > +			pix_mp->pixelformat);
> > +		return NULL;
> > +	}
> > +
> > +	pix_mp->field = V4L2_FIELD_NONE;
> > +	pix_mp->pixelformat = fmt->pixelformat;
> > +	memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
> > +
> > +	max_w = variant->pix_max->target_rot_dis_w;
> > +	max_h = variant->pix_max->target_rot_dis_h;
> > +
> > +	align_w = variant->pix_align->org_w;
> > +	align_h = variant->pix_align->org_h;
> > +
> > +	if (V4L2_TYPE_IS_OUTPUT(f->type)) {
> > +		min_w = variant->pix_min->org_w;
> > +		min_h = variant->pix_min->org_h;
> > +	} else {
> > +		min_w = variant->pix_min->target_rot_dis_w;
> > +		min_h = variant->pix_min->target_rot_dis_h;
> > +	}
> > +
> > +	mtk_mdp_dbg(2, "[%d] type:%d, wxh:%ux%u, align:%ux%u, max:%ux%u",
> > +		    ctx->id, f->type, pix_mp->width, pix_mp->height,
> > +		    align_w, align_h, max_w, max_h);
> > +	/*
> > +	 * To check if image size is modified to adjust parameter against
> > +	 * hardware abilities
> > +	 */
> > +	org_w = pix_mp->width;
> > +	org_h = pix_mp->height;
> > +
> > +	mtk_mdp_bound_align_image(&pix_mp->width, min_w, max_w, align_w,
> > +				  &pix_mp->height, min_h, max_h, align_h);
> > +
> > +	if (org_w != pix_mp->width || org_h != pix_mp->height)
> > +		mtk_mdp_dbg(1, "[%d] size change:%ux%u to %ux%u", ctx->id,
> > +			    org_w, org_h, pix_mp->width, pix_mp->height);
> > +	pix_mp->num_planes = fmt->num_planes;
> > +
> > +	for (i = 0; i < pix_mp->num_planes; ++i) {
> > +		int bpl = (pix_mp->width * fmt->depth[i]) >> 3;
> > +		int sizeimage = bpl * pix_mp->height;
> > +
> > +		pix_mp->plane_fmt[i].bytesperline = bpl;
> > +		if (pix_mp->plane_fmt[i].sizeimage < sizeimage)
> > +			pix_mp->plane_fmt[i].sizeimage = sizeimage;
> > +		memset(pix_mp->plane_fmt[i].reserved, 0,
> > +		       sizeof(pix_mp->plane_fmt[i].reserved));
> > +		mtk_mdp_dbg(2, "[%d] p%d, bpl:%d, sizeimage:%u (%u)", ctx->id,
> > +			    i, bpl, pix_mp->plane_fmt[i].sizeimage, sizeimage);
> > +	}
> > +
> > +	return fmt;
> > +}
> > +
> > +static struct mtk_mdp_frame *mtk_mdp_ctx_get_frame(struct mtk_mdp_ctx *ctx,
> > +					    enum v4l2_buf_type type)
> > +{
> > +	if (V4L2_TYPE_IS_OUTPUT(type))
> > +		return &ctx->s_frame;
> > +	return &ctx->d_frame;
> > +}
> > +
> > +static void mtk_mdp_check_crop_change(u32 new_w, u32 new_h, u32 *w, u32 *h)
> > +{
> > +	if (new_w != *w || new_h != *h) {
> > +		mtk_mdp_dbg(1, "size change:%dx%d to %dx%d",
> > +			    *w, *h, new_w, new_h);
> > +
> > +		*w = new_w;
> > +		*h = new_h;
> > +	}
> > +}
> > +
> > +static int mtk_mdp_try_crop(struct mtk_mdp_ctx *ctx, struct v4l2_crop *cr)
> > +{
> > +	struct mtk_mdp_frame *frame;
> > +	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
> > +	struct mtk_mdp_variant *variant = mdp->variant;
> > +	u32 align_w, align_h, new_w, new_h;
> > +	u32 min_w, min_h, max_w, max_h;
> > +
> > +	if (cr->c.top < 0 || cr->c.left < 0) {
> > +		dev_err(&ctx->mdp_dev->pdev->dev,
> > +			"doesn't support negative values for top & left\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	mtk_mdp_dbg(2, "[%d] type:%d, set wxh:%dx%d", ctx->id, cr->type,
> > +		    cr->c.width, cr->c.height);
> > +
> > +	frame = mtk_mdp_ctx_get_frame(ctx, cr->type);
> > +	max_w = frame->width;
> > +	max_h = frame->height;
> > +	new_w = cr->c.width;
> > +	new_h = cr->c.height;
> > +
> > +	if (V4L2_TYPE_IS_OUTPUT(cr->type)) {
> > +		align_w = 1;
> > +		align_h = 1;
> > +		min_w = 64;
> > +		min_h = 32;
> > +	} else {
> > +		align_w = variant->pix_align->target_w;
> > +		align_h = variant->pix_align->target_h;
> > +		if (ctx->ctrls.rotate->val == 90 ||
> > +		    ctx->ctrls.rotate->val == 270) {
> > +			max_w = frame->height;
> > +			max_h = frame->width;
> > +			min_w = variant->pix_min->target_rot_en_w;
> > +			min_h = variant->pix_min->target_rot_en_h;
> > +			new_w = cr->c.height;
> > +			new_h = cr->c.width;
> > +		} else {
> > +			min_w = variant->pix_min->target_rot_dis_w;
> > +			min_h = variant->pix_min->target_rot_dis_h;
> > +		}
> > +	}
> > +
> > +	mtk_mdp_dbg(2, "[%d] align:%dx%d, min:%dx%d, new:%dx%d", ctx->id,
> > +		    align_w, align_h, min_w, min_h, new_w, new_h);
> > +
> > +	mtk_mdp_bound_align_image(&new_w, min_w, max_w, align_w,
> > +				  &new_h, min_h, max_h, align_h);
> > +
> > +	if (!V4L2_TYPE_IS_OUTPUT(cr->type) &&
> > +		(ctx->ctrls.rotate->val == 90 ||
> > +		ctx->ctrls.rotate->val == 270))
> > +		mtk_mdp_check_crop_change(new_h, new_w,
> > +					  &cr->c.width, &cr->c.height);
> > +	else
> > +		mtk_mdp_check_crop_change(new_w, new_h,
> > +					  &cr->c.width, &cr->c.height);
> > +
> > +	/* adjust left/top if cropping rectangle is out of bounds */
> > +	/* Need to add code to algin left value with 2's multiple */
> > +	if (cr->c.left + new_w > max_w)
> > +		cr->c.left = max_w - new_w;
> > +	if (cr->c.top + new_h > max_h)
> > +		cr->c.top = max_h - new_h;
> > +
> > +	if (cr->c.left & 1)
> > +		cr->c.left -= 1;
> > +
> > +	mtk_mdp_dbg(2, "[%d] crop l,t,w,h:%d,%d,%d,%d, max:%dx%d", ctx->id,
> > +		    cr->c.left, cr->c.top, cr->c.width,
> > +		    cr->c.height, max_w, max_h);
> > +	return 0;
> > +}
> > +
> > +static inline struct mtk_mdp_ctx *fh_to_ctx(struct v4l2_fh *fh)
> > +{
> > +	return container_of(fh, struct mtk_mdp_ctx, fh);
> > +}
> > +
> > +static inline struct mtk_mdp_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl)
> > +{
> > +	return container_of(ctrl->handler, struct mtk_mdp_ctx, ctrl_handler);
> > +}
> > +
> > +void mtk_mdp_ctx_state_lock_set(struct mtk_mdp_ctx *ctx, u32 state)
> > +{
> > +	mutex_lock(&ctx->slock);
> > +	ctx->state |= state;
> > +	mutex_unlock(&ctx->slock);
> > +}
> > +
> > +static void mtk_mdp_ctx_state_lock_clear(struct mtk_mdp_ctx *ctx, u32 state)
> > +{
> > +	mutex_lock(&ctx->slock);
> > +	ctx->state &= ~state;
> > +	mutex_unlock(&ctx->slock);
> > +}
> > +
> > +static bool mtk_mdp_ctx_state_is_set(struct mtk_mdp_ctx *ctx, u32 mask)
> > +{
> > +	bool ret;
> > +
> > +	mutex_lock(&ctx->slock);
> > +	ret = (ctx->state & mask) == mask;
> > +	mutex_unlock(&ctx->slock);
> > +	return ret;
> > +}
> > +
> > +static void mtk_mdp_ctx_lock(struct vb2_queue *vq)
> > +{
> > +	struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vq);
> > +
> > +	mutex_lock(&ctx->mdp_dev->lock);
> > +}
> > +
> > +static void mtk_mdp_ctx_unlock(struct vb2_queue *vq)
> > +{
> > +	struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vq);
> > +
> > +	mutex_unlock(&ctx->mdp_dev->lock);
> > +}
> > +
> > +static void mtk_mdp_set_frame_size(struct mtk_mdp_frame *frame, int width,
> > +				   int height)
> > +{
> > +	frame->width = width;
> > +	frame->height = height;
> > +	frame->crop.width = width;
> > +	frame->crop.height = height;
> > +	frame->crop.left = 0;
> > +	frame->crop.top = 0;
> > +}
> > +
> > +static int mtk_mdp_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
> > +{
> > +	struct mtk_mdp_ctx *ctx = q->drv_priv;
> > +	int ret;
> > +
> > +	ret = pm_runtime_get_sync(&ctx->mdp_dev->pdev->dev);
> > +	if (ret < 0)
> > +		mtk_mdp_dbg(1, "[%d] pm_runtime_get_sync failed:%d",
> > +			    ctx->id, ret);
> > +
> > +	return 0;
> > +}
> > +
> > +static void *mtk_mdp_m2m_buf_remove(struct mtk_mdp_ctx *ctx,
> > +				    enum v4l2_buf_type type)
> > +{
> > +	if (V4L2_TYPE_IS_OUTPUT(type))
> > +		return v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
> > +	else
> > +		return v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
> > +}
> > +
> > +static void mtk_mdp_m2m_stop_streaming(struct vb2_queue *q)
> > +{
> > +	struct mtk_mdp_ctx *ctx = q->drv_priv;
> > +	struct vb2_buffer *vb;
> > +
> > +	vb = mtk_mdp_m2m_buf_remove(ctx, q->type);
> > +	while (vb != NULL) {
> > +		v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_ERROR);
> > +		vb = mtk_mdp_m2m_buf_remove(ctx, q->type);
> > +	}
> > +
> > +	pm_runtime_put(&ctx->mdp_dev->pdev->dev);
> > +}
> > +
> > +static void mtk_mdp_m2m_job_abort(void *priv)
> > +{
> > +}
> > +
> > +/* The color format (num_planes) must be already configured. */
> > +static void mtk_mdp_prepare_addr(struct mtk_mdp_ctx *ctx,
> > +				 struct vb2_buffer *vb,
> > +				 struct mtk_mdp_frame *frame,
> > +				 struct mtk_mdp_addr *addr)
> > +{
> > +	u32 pix_size, planes, i;
> > +
> > +	pix_size = frame->width * frame->height;
> > +	planes = min_t(u32, frame->fmt->num_planes, ARRAY_SIZE(addr->addr));
> > +	for (i = 0; i < planes; i++)
> > +		addr->addr[i] = vb2_dma_contig_plane_dma_addr(vb, i);
> > +
> > +	mtk_mdp_dbg(3, "[%d] planes:%d, size:%d, addr:%p,%p,%p",
> > +		    ctx->id, planes, pix_size, (void *)addr->addr[0],
> > +		    (void *)addr->addr[1], (void *)addr->addr[2]);
> > +}
> > +
> > +static void mtk_mdp_m2m_get_bufs(struct mtk_mdp_ctx *ctx)
> > +{
> > +	struct mtk_mdp_frame *s_frame, *d_frame;
> > +	struct vb2_buffer *src_vb, *dst_vb;
> > +	struct vb2_v4l2_buffer *src_vbuf, *dst_vbuf;
> > +
> > +	s_frame = &ctx->s_frame;
> > +	d_frame = &ctx->d_frame;
> > +
> > +	src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
> > +	mtk_mdp_prepare_addr(ctx, src_vb, s_frame, &s_frame->addr);
> > +
> > +	dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
> > +	mtk_mdp_prepare_addr(ctx, dst_vb, d_frame, &d_frame->addr);
> > +
> > +	src_vbuf = to_vb2_v4l2_buffer(src_vb);
> > +	dst_vbuf = to_vb2_v4l2_buffer(dst_vb);
> > +	dst_vbuf->vb2_buf.timestamp = src_vbuf->vb2_buf.timestamp;
> > +}
> > +
> > +static void mtk_mdp_process_done(void *priv, int vb_state)
> > +{
> > +	struct mtk_mdp_dev *mdp = priv;
> > +	struct mtk_mdp_ctx *ctx;
> > +	struct vb2_buffer *src_vb, *dst_vb;
> > +	struct vb2_v4l2_buffer *src_vbuf = NULL, *dst_vbuf = NULL;
> > +
> > +	ctx = v4l2_m2m_get_curr_priv(mdp->m2m_dev);
> > +	if (!ctx)
> > +		return;
> > +
> > +	src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
> > +	src_vbuf = to_vb2_v4l2_buffer(src_vb);
> > +	dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
> > +	dst_vbuf = to_vb2_v4l2_buffer(dst_vb);
> > +
> > +	dst_vbuf->vb2_buf.timestamp = src_vbuf->vb2_buf.timestamp;
> > +	dst_vbuf->timecode = src_vbuf->timecode;
> > +	dst_vbuf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
> > +	dst_vbuf->flags |= src_vbuf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
> > +
> > +	v4l2_m2m_buf_done(src_vbuf, vb_state);
> > +	v4l2_m2m_buf_done(dst_vbuf, vb_state);
> > +	v4l2_m2m_job_finish(ctx->mdp_dev->m2m_dev, ctx->m2m_ctx);
> > +}
> > +
> > +static void mtk_mdp_m2m_worker(struct work_struct *work)
> > +{
> > +	struct mtk_mdp_ctx *ctx =
> > +				container_of(work, struct mtk_mdp_ctx, work);
> > +	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
> > +	enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
> > +	int ret;
> > +
> > +	if (mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_CTX_ERROR)) {
> > +		dev_err(&mdp->pdev->dev, "ctx is in error state");
> > +		goto worker_end;
> > +	}
> > +
> > +	mtk_mdp_m2m_get_bufs(ctx);
> > +
> > +	mtk_mdp_hw_set_input_addr(ctx, &ctx->s_frame.addr);
> > +	mtk_mdp_hw_set_output_addr(ctx, &ctx->d_frame.addr);
> > +
> > +	mtk_mdp_hw_set_in_size(ctx);
> > +	mtk_mdp_hw_set_in_image_format(ctx);
> > +
> > +	mtk_mdp_hw_set_out_size(ctx);
> > +	mtk_mdp_hw_set_out_image_format(ctx);
> > +
> > +	mtk_mdp_hw_set_rotation(ctx);
> > +	mtk_mdp_hw_set_global_alpha(ctx);
> > +
> > +	ret = mtk_mdp_vpu_process(&ctx->vpu);
> > +	if (ret) {
> > +		dev_err(&mdp->pdev->dev, "processing failed: %d", ret);
> > +		goto worker_end;
> > +	}
> > +
> > +	buf_state = VB2_BUF_STATE_DONE;
> > +
> > +worker_end:
> > +	mtk_mdp_process_done(mdp, buf_state);
> > +}
> > +
> > +static void mtk_mdp_m2m_device_run(void *priv)
> > +{
> > +	struct mtk_mdp_ctx *ctx = priv;
> > +
> > +	queue_work(ctx->mdp_dev->job_wq, &ctx->work);
> > +}
> > +
> > +static int mtk_mdp_m2m_queue_setup(struct vb2_queue *vq,
> > +			unsigned int *num_buffers, unsigned int *num_planes,
> > +			unsigned int sizes[], struct device *alloc_devs[])
> > +{
> > +	struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vq);
> > +	struct mtk_mdp_frame *frame;
> > +	int i;
> > +
> > +	frame = mtk_mdp_ctx_get_frame(ctx, vq->type);
> > +	*num_planes = frame->fmt->num_planes;
> > +	for (i = 0; i < frame->fmt->num_planes; i++)
> > +		sizes[i] = frame->payload[i];
> > +	mtk_mdp_dbg(2, "[%d] type:%d, planes:%d, buffers:%d, size:%u,%u",
> > +		    ctx->id, vq->type, *num_planes, *num_buffers,
> > +		    sizes[0], sizes[1]);
> > +	return 0;
> > +}
> > +
> > +static int mtk_mdp_m2m_buf_prepare(struct vb2_buffer *vb)
> > +{
> > +	struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
> > +	struct mtk_mdp_frame *frame;
> > +	int i;
> > +
> > +	frame = mtk_mdp_ctx_get_frame(ctx, vb->vb2_queue->type);
> > +
> > +	if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
> > +		for (i = 0; i < frame->fmt->num_planes; i++)
> > +			vb2_set_plane_payload(vb, i, frame->payload[i]);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static void mtk_mdp_m2m_buf_queue(struct vb2_buffer *vb)
> > +{
> > +	struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
> > +
> > +	v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb));
> > +}
> > +
> > +static struct vb2_ops mtk_mdp_m2m_qops = {
> > +	.queue_setup	 = mtk_mdp_m2m_queue_setup,
> > +	.buf_prepare	 = mtk_mdp_m2m_buf_prepare,
> > +	.buf_queue	 = mtk_mdp_m2m_buf_queue,
> > +	.wait_prepare	 = mtk_mdp_ctx_unlock,
> > +	.wait_finish	 = mtk_mdp_ctx_lock,
> > +	.stop_streaming	 = mtk_mdp_m2m_stop_streaming,
> > +	.start_streaming = mtk_mdp_m2m_start_streaming,
> > +};
> > +
> > +static int mtk_mdp_m2m_querycap(struct file *file, void *fh,
> > +				struct v4l2_capability *cap)
> > +{
> > +	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
> > +	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
> > +
> > +	strlcpy(cap->driver, MTK_MDP_MODULE_NAME, sizeof(cap->driver));
> > +	strlcpy(cap->card, mdp->pdev->name, sizeof(cap->card));
> > +	strlcpy(cap->bus_info, "platform:mt8173", sizeof(cap->bus_info));
> > +	cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
> > +	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
> 
> Fill in the new device_caps field of struct video_device instead. Once done
> you can drop these two lines as the core will fill them in for you.
> 

I will remove them.

> > +
> > +	return 0;
> > +}
> > +
> > +static int mtk_mdp_enum_fmt_mplane(struct v4l2_fmtdesc *f, u32 type)
> > +{
> > +	const struct mtk_mdp_fmt *fmt;
> > +
> > +	fmt = mtk_mdp_find_fmt_by_index(f->index, type);
> > +	if (!fmt)
> > +		return -EINVAL;
> > +
> > +	strlcpy(f->description, fmt->name, sizeof(f->description));
> 
> Drop this line. The v4l2 core will this in for you. You can probably drop fmt->name
> as well.
> 

I will remove them.

> > +	f->pixelformat = fmt->pixelformat;
> > +
> > +	return 0;
> > +}
> > +
> > +static int mtk_mdp_m2m_enum_fmt_mplane_vid_cap(struct file *file, void *priv,
> > +				       struct v4l2_fmtdesc *f)
> > +{
> > +	return mtk_mdp_enum_fmt_mplane(f, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
> > +}
> > +
> > +static int mtk_mdp_m2m_enum_fmt_mplane_vid_out(struct file *file, void *priv,
> > +				       struct v4l2_fmtdesc *f)
> > +{
> > +	return mtk_mdp_enum_fmt_mplane(f, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
> > +}
> > +
> > +static int mtk_mdp_g_fmt_mplane(struct mtk_mdp_ctx *ctx, struct v4l2_format *f)
> > +{
> > +	struct mtk_mdp_frame *frame;
> > +	struct v4l2_pix_format_mplane *pix_mp;
> > +	int i;
> > +
> > +	mtk_mdp_dbg(2, "[%d] type:%d", ctx->id, f->type);
> > +
> > +	frame = mtk_mdp_ctx_get_frame(ctx, f->type);
> > +	pix_mp = &f->fmt.pix_mp;
> > +
> > +	pix_mp->width = frame->width;
> > +	pix_mp->height = frame->height;
> > +	pix_mp->field = V4L2_FIELD_NONE;
> > +	pix_mp->pixelformat = frame->fmt->pixelformat;
> > +	pix_mp->num_planes = frame->fmt->num_planes;
> > +	mtk_mdp_dbg(2, "[%d] wxh:%dx%d", ctx->id,
> > +		    pix_mp->width, pix_mp->height);
> > +
> > +	for (i = 0; i < pix_mp->num_planes; ++i) {
> > +		pix_mp->plane_fmt[i].bytesperline = (frame->width *
> > +			frame->fmt->depth[i]) / 8;
> > +		pix_mp->plane_fmt[i].sizeimage =
> > +			 pix_mp->plane_fmt[i].bytesperline * frame->height;
> > +
> > +		mtk_mdp_dbg(2, "[%d] p%d, bpl:%d, sizeimage:%d", ctx->id, i,
> > +			    pix_mp->plane_fmt[i].bytesperline,
> > +			    pix_mp->plane_fmt[i].sizeimage);
> > +	}
> 
> Since this is a codec you will need to pass the colorspace-related format
> fields from the video output format to the video capture format.
> 
> I have added tests to v4l2-compliance to check for that. See also the
> vim2m reference driver and this vim2m patch:
> 
> https://patchwork.linuxtv.org/patch/35562/
> 

I will add them as patch 35562 and pull the latest v4l2-compliance to verify.

> > +
> > +	return 0;
> > +}
> > +
> > +static int mtk_mdp_m2m_g_fmt_mplane(struct file *file, void *fh,
> > +				    struct v4l2_format *f)
> > +{
> > +	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
> > +
> > +	return mtk_mdp_g_fmt_mplane(ctx, f);
> > +}
> > +
> > +static int mtk_mdp_m2m_try_fmt_mplane(struct file *file, void *fh,
> > +				      struct v4l2_format *f)
> > +{
> > +	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
> > +
> > +	if (!mtk_mdp_try_fmt_mplane(ctx, f))
> > +		return -EINVAL;
> > +	return 0;
> > +}
> > +
> > +static int mtk_mdp_m2m_s_fmt_mplane(struct file *file, void *fh,
> > +				    struct v4l2_format *f)
> > +{
> > +	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
> > +	struct vb2_queue *vq;
> > +	struct mtk_mdp_frame *frame;
> > +	struct v4l2_pix_format_mplane *pix;
> > +	const struct mtk_mdp_fmt *fmt;
> > +	int i;
> > +
> > +	mtk_mdp_dbg(2, "[%d] type:%d", ctx->id, f->type);
> > +
> > +	frame = mtk_mdp_ctx_get_frame(ctx, f->type);
> > +	fmt = mtk_mdp_try_fmt_mplane(ctx, f);
> > +	if (!fmt) {
> > +		mtk_mdp_err("[%d] try_fmt failed, type:%d", ctx->id, f->type);
> > +		return -EINVAL;
> > +	}
> > +	frame->fmt = fmt;
> > +
> > +	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
> > +	if (vb2_is_streaming(vq)) {
> > +		dev_info(&ctx->mdp_dev->pdev->dev, "queue %d busy", f->type);
> > +		return -EBUSY;
> > +	}
> > +
> > +	pix = &f->fmt.pix_mp;
> > +	for (i = 0; i < frame->fmt->num_planes; i++) {
> > +		frame->payload[i] = pix->plane_fmt[i].sizeimage;
> > +		frame->pitch[i] = pix->plane_fmt[i].bytesperline;
> > +	}
> > +
> > +	mtk_mdp_set_frame_size(frame, pix->width, pix->height);
> > +
> > +	if (V4L2_TYPE_IS_OUTPUT(f->type))
> > +		mtk_mdp_ctx_state_lock_set(ctx, MTK_MDP_SRC_FMT);
> > +	else
> > +		mtk_mdp_ctx_state_lock_set(ctx, MTK_MDP_DST_FMT);
> > +
> > +	mtk_mdp_dbg(2, "[%d] type:%d, frame:%dx%d", ctx->id, f->type,
> > +		    frame->width, frame->height);
> > +
> > +	return 0;
> > +}
> > +
> > +static int mtk_mdp_m2m_reqbufs(struct file *file, void *fh,
> > +			       struct v4l2_requestbuffers *reqbufs)
> > +{
> > +	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
> > +
> > +	if (reqbufs->count == 0) {
> > +		if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
> > +			mtk_mdp_ctx_state_lock_clear(ctx, MTK_MDP_SRC_FMT);
> > +		else
> > +			mtk_mdp_ctx_state_lock_clear(ctx, MTK_MDP_DST_FMT);
> > +	}
> > +
> > +	return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
> > +}
> > +
> > +static int mtk_mdp_m2m_querybuf(struct file *file, void *fh,
> > +				struct v4l2_buffer *buf)
> > +{
> > +	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
> > +
> > +	return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
> > +}
> 
> Can't you use the v4l2_m2m_ioctl_* helpers here? See v4l2-mem2mem.h.
> 

I will modify it.

> > +
> > +static int mtk_mdp_m2m_qbuf(struct file *file, void *fh,
> > +			    struct v4l2_buffer *buf)
> > +{
> > +	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
> > +
> > +	return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
> > +}
> > +
> > +static int mtk_mdp_m2m_dqbuf(struct file *file, void *fh,
> > +			     struct v4l2_buffer *buf)
> > +{
> > +	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
> > +
> > +	return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
> > +}
> > +
> > +static int mtk_mdp_m2m_streamon(struct file *file, void *fh,
> > +				enum v4l2_buf_type type)
> > +{
> > +	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
> > +
> > +	/* The source and target color format need to be set */
> > +	if (V4L2_TYPE_IS_OUTPUT(type)) {
> > +		if (!mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_SRC_FMT))
> > +			return -EINVAL;
> > +	} else if (!mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_DST_FMT)) {
> > +		return -EINVAL;
> > +	}
> > +
> > +	return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
> > +}
> > +
> > +static int mtk_mdp_m2m_streamoff(struct file *file, void *fh,
> > +			    enum v4l2_buf_type type)
> > +{
> > +	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
> > +
> > +	return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
> > +}
> > +
> > +/*
> > + * Return true if rectangle a is enclosed in rectangle b, or false otherwise.
> > + */
> > +static bool mtk_mdp_m2m_is_rectangle_enclosed(struct v4l2_rect *a,
> > +					     struct v4l2_rect *b)
> > +{
> > +	if (a->left < b->left || a->top < b->top)
> > +		return false;
> > +
> > +	if (a->left + a->width > b->left + b->width)
> > +		return false;
> > +
> > +	if (a->top + a->height > b->top + b->height)
> > +		return false;
> > +
> > +	return true;
> > +}
> > +
> > +static int mtk_mdp_m2m_g_selection(struct file *file, void *fh,
> > +				   struct v4l2_selection *s)
> > +{
> > +	struct mtk_mdp_frame *frame;
> > +	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
> > +
> > +	if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
> > +	    (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
> > +		return -EINVAL;
> > +
> > +	frame = mtk_mdp_ctx_get_frame(ctx, s->type);
> > +
> > +	switch (s->target) {
> > +	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
> > +	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
> > +	case V4L2_SEL_TGT_CROP_BOUNDS:
> > +	case V4L2_SEL_TGT_CROP_DEFAULT:
> > +		s->r.left = 0;
> > +		s->r.top = 0;
> > +		s->r.width = frame->width;
> > +		s->r.height = frame->height;
> > +		return 0;
> > +
> > +	case V4L2_SEL_TGT_COMPOSE:
> > +	case V4L2_SEL_TGT_CROP:
> > +		s->r.left = frame->crop.left;
> > +		s->r.top = frame->crop.top;
> > +		s->r.width = frame->crop.width;
> > +		s->r.height = frame->crop.height;
> > +		return 0;
> > +	}
> 
> This is almost certainly wrong. Unless I am mistaken you support cropping of
> the memory buffer for video output, and composing into a memory buffer for video
> capture. That's the standard behavior for codecs.
> 
> The code above reports both composing and cropping for both capture and output,
> and that's not right. Same in s_selection.
> 

MTK MDP supports to crop source and destination buffer.


> > +
> > +	return -EINVAL;
> > +}
> > +
> > +static int mtk_mdp_check_scaler_ratio(struct mtk_mdp_variant *var, int src_w,
> > +				      int src_h, int dst_w, int dst_h, int rot)
> > +{
> > +	int tmp_w, tmp_h;
> > +
> > +	if (rot == 90 || rot == 270) {
> > +		tmp_w = dst_h;
> > +		tmp_h = dst_w;
> > +	} else {
> > +		tmp_w = dst_w;
> > +		tmp_h = dst_h;
> > +	}
> > +
> > +	if ((src_w / tmp_w) > var->h_scale_down_max ||
> > +	    (src_h / tmp_h) > var->v_scale_down_max ||
> > +	    (tmp_w / src_w) > var->h_scale_up_max ||
> > +	    (tmp_h / src_h) > var->v_scale_up_max)
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> > +static int mtk_mdp_m2m_s_selection(struct file *file, void *fh,
> > +				   struct v4l2_selection *s)
> > +{
> > +	struct mtk_mdp_frame *frame;
> > +	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
> > +	struct v4l2_crop cr;
> > +	struct mtk_mdp_variant *variant = ctx->mdp_dev->variant;
> > +	int ret;
> > +
> > +	cr.type = s->type;
> > +	cr.c = s->r;
> > +
> > +	if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
> > +	    (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
> > +		return -EINVAL;
> > +
> > +	ret = mtk_mdp_try_crop(ctx, &cr);
> > +	if (ret)
> > +		return ret;
> > +
> > +	if (s->flags & V4L2_SEL_FLAG_LE &&
> > +	    !mtk_mdp_m2m_is_rectangle_enclosed(&cr.c, &s->r))
> > +		return -ERANGE;
> > +
> > +	if (s->flags & V4L2_SEL_FLAG_GE &&
> > +	    !mtk_mdp_m2m_is_rectangle_enclosed(&s->r, &cr.c))
> > +		return -ERANGE;
> > +
> > +	s->r = cr.c;
> > +
> > +	switch (s->target) {
> > +	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
> > +	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
> > +	case V4L2_SEL_TGT_COMPOSE:
> > +		frame = &ctx->s_frame;
> > +		break;
> > +
> > +	case V4L2_SEL_TGT_CROP_BOUNDS:
> > +	case V4L2_SEL_TGT_CROP:
> > +	case V4L2_SEL_TGT_CROP_DEFAULT:
> > +		frame = &ctx->d_frame;
> > +		break;
> > +
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +
> > +	/* Check to see if scaling ratio is within supported range */
> > +	if (mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_DST_FMT | MTK_MDP_SRC_FMT)) {
> > +		if (V4L2_TYPE_IS_OUTPUT(s->type)) {
> > +			ret = mtk_mdp_check_scaler_ratio(variant, cr.c.width,
> > +				cr.c.height, ctx->d_frame.crop.width,
> > +				ctx->d_frame.crop.height,
> > +				ctx->ctrls.rotate->val);
> > +		} else {
> > +			ret = mtk_mdp_check_scaler_ratio(variant,
> > +				ctx->s_frame.crop.width,
> > +				ctx->s_frame.crop.height, cr.c.width,
> > +				cr.c.height, ctx->ctrls.rotate->val);
> > +		}
> > +
> > +		if (ret) {
> > +			dev_info(&ctx->mdp_dev->pdev->dev,
> > +				"Out of scaler range");
> > +			return -EINVAL;
> > +		}
> > +	}
> > +
> > +	frame->crop = cr.c;
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct v4l2_ioctl_ops mtk_mdp_m2m_ioctl_ops = {
> > +	.vidioc_querycap		= mtk_mdp_m2m_querycap,
> > +	.vidioc_enum_fmt_vid_cap_mplane	= mtk_mdp_m2m_enum_fmt_mplane_vid_cap,
> > +	.vidioc_enum_fmt_vid_out_mplane	= mtk_mdp_m2m_enum_fmt_mplane_vid_out,
> > +	.vidioc_g_fmt_vid_cap_mplane	= mtk_mdp_m2m_g_fmt_mplane,
> > +	.vidioc_g_fmt_vid_out_mplane	= mtk_mdp_m2m_g_fmt_mplane,
> > +	.vidioc_try_fmt_vid_cap_mplane	= mtk_mdp_m2m_try_fmt_mplane,
> > +	.vidioc_try_fmt_vid_out_mplane	= mtk_mdp_m2m_try_fmt_mplane,
> > +	.vidioc_s_fmt_vid_cap_mplane	= mtk_mdp_m2m_s_fmt_mplane,
> > +	.vidioc_s_fmt_vid_out_mplane	= mtk_mdp_m2m_s_fmt_mplane,
> > +	.vidioc_reqbufs			= mtk_mdp_m2m_reqbufs,
> > +	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,
> > +	.vidioc_expbuf			= v4l2_m2m_ioctl_expbuf,
> > +	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
> > +	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
> > +	.vidioc_querybuf		= mtk_mdp_m2m_querybuf,
> > +	.vidioc_qbuf			= mtk_mdp_m2m_qbuf,
> > +	.vidioc_dqbuf			= mtk_mdp_m2m_dqbuf,
> > +	.vidioc_streamon		= mtk_mdp_m2m_streamon,
> > +	.vidioc_streamoff		= mtk_mdp_m2m_streamoff,
> > +	.vidioc_g_selection		= mtk_mdp_m2m_g_selection,
> > +	.vidioc_s_selection		= mtk_mdp_m2m_s_selection
> > +};
> > +
> > +static int mtk_mdp_m2m_queue_init(void *priv, struct vb2_queue *src_vq,
> > +				  struct vb2_queue *dst_vq)
> > +{
> > +	struct mtk_mdp_ctx *ctx = priv;
> > +	int ret;
> > +
> > +	memset(src_vq, 0, sizeof(*src_vq));
> > +	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
> > +	src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
> > +	src_vq->drv_priv = ctx;
> > +	src_vq->ops = &mtk_mdp_m2m_qops;
> > +	src_vq->mem_ops = &vb2_dma_contig_memops;
> > +	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
> > +	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> 
> Shouldn't src_vq->dev be filled in here?
> 

It is failed to allocate dma really. I have fixed it. Thanks

> > +
> > +	ret = vb2_queue_init(src_vq);
> > +	if (ret)
> > +		return ret;
> > +
> > +	memset(dst_vq, 0, sizeof(*dst_vq));
> > +	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
> > +	dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
> > +	dst_vq->drv_priv = ctx;
> > +	dst_vq->ops = &mtk_mdp_m2m_qops;
> > +	dst_vq->mem_ops = &vb2_dma_contig_memops;
> > +	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
> > +	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> 
> and here?
> 
> Otherwise the dma-contig code won't know the right struct device pointer to
> use for the DMA.
> 
> I'm a bit surprised that this works, actually.
> 

The same as src_vq. I have fixed it. Thanks.

> > +
> > +	return vb2_queue_init(dst_vq);
> > +}
> > +
> > +static int mtk_mdp_s_ctrl(struct v4l2_ctrl *ctrl)
> > +{
> > +	struct mtk_mdp_ctx *ctx = ctrl_to_ctx(ctrl);
> > +	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
> > +	struct mtk_mdp_variant *variant = mdp->variant;
> > +	u32 state = MTK_MDP_DST_FMT | MTK_MDP_SRC_FMT;
> > +	int ret = 0;
> > +
> > +	if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
> > +		return 0;
> > +
> > +	switch (ctrl->id) {
> > +	case V4L2_CID_HFLIP:
> > +		ctx->hflip = ctrl->val;
> > +		break;
> > +	case V4L2_CID_VFLIP:
> > +		ctx->vflip = ctrl->val;
> > +		break;
> > +	case V4L2_CID_ROTATE:
> > +		if (mtk_mdp_ctx_state_is_set(ctx, state)) {
> > +			ret = mtk_mdp_check_scaler_ratio(variant,
> > +					ctx->s_frame.crop.width,
> > +					ctx->s_frame.crop.height,
> > +					ctx->d_frame.crop.width,
> > +					ctx->d_frame.crop.height,
> > +					ctx->ctrls.rotate->val);
> > +
> > +			if (ret)
> > +				return -EINVAL;
> > +		}
> > +
> > +		ctx->rotation = ctrl->val;
> > +		break;
> > +	case V4L2_CID_ALPHA_COMPONENT:
> > +		ctx->d_frame.alpha = ctrl->val;
> > +		break;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct v4l2_ctrl_ops mtk_mdp_ctrl_ops = {
> > +	.s_ctrl = mtk_mdp_s_ctrl,
> > +};
> > +
> > +static int mtk_mdp_ctrls_create(struct mtk_mdp_ctx *ctx)
> > +{
> > +	v4l2_ctrl_handler_init(&ctx->ctrl_handler, MTK_MDP_MAX_CTRL_NUM);
> > +
> > +	ctx->ctrls.rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler,
> > +			&mtk_mdp_ctrl_ops, V4L2_CID_ROTATE, 0, 270, 90, 0);
> > +	ctx->ctrls.hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
> > +					     &mtk_mdp_ctrl_ops,
> > +					     V4L2_CID_HFLIP,
> > +					     0, 1, 1, 0);
> > +	ctx->ctrls.vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
> > +					     &mtk_mdp_ctrl_ops,
> > +					     V4L2_CID_VFLIP,
> > +					     0, 1, 1, 0);
> > +	ctx->ctrls.global_alpha = v4l2_ctrl_new_std(&ctx->ctrl_handler,
> > +						    &mtk_mdp_ctrl_ops,
> > +						    V4L2_CID_ALPHA_COMPONENT,
> > +						    0, 255, 1, 0);
> > +	ctx->ctrls_rdy = ctx->ctrl_handler.error == 0;
> > +
> > +	if (ctx->ctrl_handler.error) {
> > +		int err = ctx->ctrl_handler.error;
> > +
> > +		v4l2_ctrl_handler_free(&ctx->ctrl_handler);
> > +		dev_err(&ctx->mdp_dev->pdev->dev,
> > +			"Failed to create control handlers\n");
> > +		return err;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static void mtk_mdp_set_default_params(struct mtk_mdp_ctx *ctx)
> > +{
> > +	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
> > +	struct mtk_mdp_frame *frame;
> > +
> > +	frame = mtk_mdp_ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
> > +	frame->fmt = mtk_mdp_find_fmt_by_index(0,
> > +					V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
> > +	frame->width = mdp->variant->pix_min->org_w;
> > +	frame->height = mdp->variant->pix_min->org_h;
> > +	frame->payload[0] = frame->width * frame->height;
> > +	frame->payload[1] = frame->payload[0] / 2;
> > +
> > +	frame = mtk_mdp_ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
> > +	frame->fmt = mtk_mdp_find_fmt_by_index(0,
> > +					V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
> > +	frame->width = mdp->variant->pix_min->target_rot_dis_w;
> > +	frame->height = mdp->variant->pix_min->target_rot_dis_h;
> > +	frame->payload[0] = frame->width * frame->height;
> > +	frame->payload[1] = frame->payload[0] / 2;
> > +
> > +}
> > +
> > +static int mtk_mdp_m2m_open(struct file *file)
> > +{
> > +	struct mtk_mdp_dev *mdp = video_drvdata(file);
> > +	struct video_device *vfd = video_devdata(file);
> > +	struct mtk_mdp_ctx *ctx = NULL;
> > +	int ret;
> > +
> > +	if (mutex_lock_interruptible(&mdp->lock))
> > +		return -ERESTARTSYS;
> > +
> > +	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> > +	if (!ctx) {
> > +		ret = -ENOMEM;
> > +		goto err_ctx_alloc;
> > +	}
> > +
> > +	mutex_init(&ctx->slock);
> > +	ctx->id = mdp->id_counter++;
> > +	v4l2_fh_init(&ctx->fh, vfd);
> > +	file->private_data = &ctx->fh;
> > +	ret = mtk_mdp_ctrls_create(ctx);
> > +	if (ret)
> > +		goto error_ctrls;
> > +
> > +	/* Use separate control handler per file handle */
> > +	ctx->fh.ctrl_handler = &ctx->ctrl_handler;
> > +	v4l2_fh_add(&ctx->fh);
> > +	INIT_LIST_HEAD(&ctx->list);
> > +
> > +	ctx->mdp_dev = mdp;
> > +	mtk_mdp_set_default_params(ctx);
> > +
> > +	INIT_WORK(&ctx->work, mtk_mdp_m2m_worker);
> > +	ctx->m2m_ctx = v4l2_m2m_ctx_init(mdp->m2m_dev, ctx,
> > +					 mtk_mdp_m2m_queue_init);
> > +	if (IS_ERR(ctx->m2m_ctx)) {
> > +		dev_err(&mdp->pdev->dev, "Failed to initialize m2m context");
> > +		ret = PTR_ERR(ctx->m2m_ctx);
> > +		goto error_m2m_ctx;
> > +	}
> > +	ctx->fh.m2m_ctx = ctx->m2m_ctx;
> > +	if (mdp->ctx_num++ == 0) {
> > +		ret = vpu_load_firmware(mdp->vpu_dev);
> > +		if (ret < 0) {
> > +			dev_err(&mdp->pdev->dev,
> > +				"vpu_load_firmware failed %d\n", ret);
> > +			goto err_load_vpu;
> > +		}
> > +
> > +		ret = mtk_mdp_vpu_register(mdp->pdev);
> > +		if (ret < 0) {
> > +			dev_err(&mdp->pdev->dev,
> > +				"mdp_vpu register failed %d\n", ret);
> > +			goto err_load_vpu;
> > +		}
> > +	}
> > +
> > +	ret = mtk_mdp_vpu_init(&ctx->vpu);
> > +	if (ret < 0) {
> > +		dev_err(&mdp->pdev->dev, "Initialize vpu failed %d\n", ret);
> > +		ret = -EINVAL;
> > +		goto err_load_vpu;
> > +	}
> > +	list_add(&ctx->list, &mdp->ctx_list);
> > +	mutex_unlock(&mdp->lock);
> > +
> > +	mtk_mdp_dbg(0, "%s [%d]", dev_name(&mdp->pdev->dev), ctx->id);
> > +
> > +	return 0;
> > +
> > +err_load_vpu:
> > +	mdp->ctx_num--;
> > +	v4l2_m2m_ctx_release(ctx->m2m_ctx);
> > +error_m2m_ctx:
> > +	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
> > +error_ctrls:
> > +	v4l2_fh_del(&ctx->fh);
> > +	v4l2_fh_exit(&ctx->fh);
> > +err_ctx_alloc:
> > +	kfree(ctx);
> > +	mutex_unlock(&mdp->lock);
> > +
> > +	return ret;
> > +}
> > +
> > +static int mtk_mdp_m2m_release(struct file *file)
> > +{
> > +	struct mtk_mdp_ctx *ctx = fh_to_ctx(file->private_data);
> > +	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
> > +
> > +	flush_workqueue(mdp->job_wq);
> > +	mutex_lock(&mdp->lock);
> > +	v4l2_m2m_ctx_release(ctx->m2m_ctx);
> > +	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
> > +	v4l2_fh_del(&ctx->fh);
> > +	v4l2_fh_exit(&ctx->fh);
> > +	mtk_mdp_vpu_deinit(&ctx->vpu);
> > +	mdp->ctx_num--;
> > +	list_del_init(&ctx->list);
> > +
> > +	mtk_mdp_dbg(0, "%s [%d]", dev_name(&mdp->pdev->dev), ctx->id);
> > +
> > +	mutex_unlock(&mdp->lock);
> > +	kfree(ctx);
> > +
> > +	return 0;
> > +}
> > +
> > +static unsigned int mtk_mdp_m2m_poll(struct file *file,
> > +				     struct poll_table_struct *wait)
> > +{
> > +	struct mtk_mdp_ctx *ctx = fh_to_ctx(file->private_data);
> > +	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
> > +	int ret;
> > +
> > +	if (mutex_lock_interruptible(&mdp->lock))
> > +		return -ERESTARTSYS;
> > +
> > +	ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
> > +	mutex_unlock(&mdp->lock);
> > +
> > +	return ret;
> > +}
> > +
> > +static int mtk_mdp_m2m_mmap(struct file *file, struct vm_area_struct *vma)
> > +{
> > +	struct mtk_mdp_ctx *ctx = fh_to_ctx(file->private_data);
> > +	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
> > +	int ret;
> > +
> > +	if (mutex_lock_interruptible(&mdp->lock))
> > +		return -ERESTARTSYS;
> > +
> > +	ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
> > +	mutex_unlock(&mdp->lock);
> > +
> > +	return ret;
> 
> Can you use the v4l2-mem2mem helpers for mmap and poll?
> 

I will modify them.

> > +}
> > +
> > +static const struct v4l2_file_operations mtk_mdp_m2m_fops = {
> > +	.owner		= THIS_MODULE,
> > +	.open		= mtk_mdp_m2m_open,
> > +	.release	= mtk_mdp_m2m_release,
> > +	.poll		= mtk_mdp_m2m_poll,
> > +	.unlocked_ioctl	= video_ioctl2,
> > +	.mmap		= mtk_mdp_m2m_mmap,
> > +};
> > +
> > +static struct v4l2_m2m_ops mtk_mdp_m2m_ops = {
> > +	.device_run	= mtk_mdp_m2m_device_run,
> > +	.job_abort	= mtk_mdp_m2m_job_abort,
> > +};
> > +
> > +int mtk_mdp_register_m2m_device(struct mtk_mdp_dev *mdp)
> > +{
> > +	struct device *dev = &mdp->pdev->dev;
> > +	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",
> > +		 MTK_MDP_MODULE_NAME);
> > +	video_set_drvdata(&mdp->vdev, mdp);
> > +
> > +	mdp->m2m_dev = v4l2_m2m_init(&mtk_mdp_m2m_ops);
> > +	if (IS_ERR(mdp->m2m_dev)) {
> > +		dev_err(dev, "failed to initialize v4l2-m2m device\n");
> > +		ret = PTR_ERR(mdp->m2m_dev);
> > +		goto err_m2m_init;
> > +	}
> > +
> > +	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);
> > +	return 0;
> > +
> > +err_vdev_register:
> > +	v4l2_m2m_release(mdp->m2m_dev);
> > +err_m2m_init:
> > +	video_device_release(&mdp->vdev);
> > +
> > +	return ret;
> > +}
> > +
> > +void mtk_mdp_unregister_m2m_device(struct mtk_mdp_dev *mdp)
> > +{
> > +	video_device_release(&mdp->vdev);
> > +	v4l2_m2m_release(mdp->m2m_dev);
> > +}
> > diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h
> > new file mode 100644
> > index 0000000..45afd36
> > --- /dev/null
> > +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h
> > @@ -0,0 +1,22 @@
> > +/*
> > + * Copyright (c) 2016 MediaTek Inc.
> > + * Author: Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + *
> > + * 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.
> > + */
> > +
> > +#ifndef __MTK_MDP_M2M_H__
> > +#define __MTK_MDP_M2M_H__
> > +
> > +void mtk_mdp_ctx_state_lock_set(struct mtk_mdp_ctx *ctx, u32 state);
> > +int mtk_mdp_register_m2m_device(struct mtk_mdp_dev *mdp);
> > +void mtk_mdp_unregister_m2m_device(struct mtk_mdp_dev *mdp);
> > +
> > +#endif /* __MTK_MDP_M2M_H__ */
> > diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_regs.c b/drivers/media/platform/mtk-mdp/mtk_mdp_regs.c
> > new file mode 100644
> > index 0000000..063e7b1
> > --- /dev/null
> > +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_regs.c
> > @@ -0,0 +1,153 @@
> > +/*
> > + * Copyright (c) 2015-2016 MediaTek Inc.
> > + * Author: Houlong Wei <houlong.wei at mediatek.com>
> > + *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + *
> > + * 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.
> > + */
> > +
> > +#include <linux/platform_device.h>
> > +
> > +#include "mtk_mdp_core.h"
> > +#include "mtk_mdp_regs.h"
> > +
> > +
> > +#define MDP_COLORFMT_PACK(VIDEO, PLANE, COPLANE, HF, VF, BITS, GROUP, SWAP, ID)\
> > +	(((VIDEO) << 27) | ((PLANE) << 24) | ((COPLANE) << 22) |\
> > +	((HF) << 20) | ((VF) << 18) | ((BITS) << 8) | ((GROUP) << 6) |\
> > +	((SWAP) << 5) | ((ID) << 0))
> > +
> > +enum MDP_COLOR_ENUM {
> > +	MDP_COLOR_UNKNOWN = 0,
> > +	MDP_COLOR_NV12 = MDP_COLORFMT_PACK(0, 2, 1, 1, 1, 8, 1, 0, 12),
> > +	MDP_COLOR_I420 = MDP_COLORFMT_PACK(0, 3, 0, 1, 1, 8, 1, 0, 8),
> > +	/* Mediatek proprietary format */
> > +	MDP_COLOR_420_MT21 = MDP_COLORFMT_PACK(5, 2, 1, 1, 1, 256, 1, 0, 12),
> > +};
> > +
> > +static int32_t mtk_mdp_map_color_format(int v4l2_format)
> > +{
> > +	switch (v4l2_format) {
> > +	case V4L2_PIX_FMT_NV12M:
> > +	case V4L2_PIX_FMT_NV12:
> > +		return MDP_COLOR_NV12;
> > +	case V4L2_PIX_FMT_MT21:
> > +		return MDP_COLOR_420_MT21;
> > +	case V4L2_PIX_FMT_YUV420M:
> > +	case V4L2_PIX_FMT_YUV420:
> > +		return MDP_COLOR_I420;
> > +	}
> > +
> > +	mtk_mdp_err("Unknown format 0x%x", v4l2_format);
> > +
> > +	return MDP_COLOR_UNKNOWN;
> > +}
> > +
> > +void mtk_mdp_hw_set_input_addr(struct mtk_mdp_ctx *ctx,
> > +			       struct mtk_mdp_addr *addr)
> > +{
> > +	struct mdp_buffer *src_buf = &ctx->vpu.vsi->src_buffer;
> > +	int i;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(addr->addr); i++)
> > +		src_buf->addr_mva[i] = (uint64_t)addr->addr[i];
> > +}
> > +
> > +void mtk_mdp_hw_set_output_addr(struct mtk_mdp_ctx *ctx,
> > +				struct mtk_mdp_addr *addr)
> > +{
> > +	struct mdp_buffer *dst_buf = &ctx->vpu.vsi->dst_buffer;
> > +	int i;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(addr->addr); i++)
> > +		dst_buf->addr_mva[i] = (uint64_t)addr->addr[i];
> > +}
> > +
> > +void mtk_mdp_hw_set_in_size(struct mtk_mdp_ctx *ctx)
> > +{
> > +	struct mtk_mdp_frame *frame = &ctx->s_frame;
> > +	struct mdp_config *config = &ctx->vpu.vsi->src_config;
> > +
> > +	/* Set input pixel offset */
> > +	config->crop_x = frame->crop.left;
> > +	config->crop_y = frame->crop.top;
> > +
> > +	/* Set input cropped size */
> > +	config->crop_w = frame->crop.width;
> > +	config->crop_h = frame->crop.height;
> > +
> > +	/* Set input original size */
> > +	config->x = 0;
> > +	config->y = 0;
> > +	config->w = frame->width;
> > +	config->h = frame->height;
> > +}
> > +
> > +void mtk_mdp_hw_set_in_image_format(struct mtk_mdp_ctx *ctx)
> > +{
> > +	unsigned int i;
> > +	struct mtk_mdp_frame *frame = &ctx->s_frame;
> > +	struct mdp_config *config = &ctx->vpu.vsi->src_config;
> > +	struct mdp_buffer *src_buf = &ctx->vpu.vsi->src_buffer;
> > +
> > +	src_buf->plane_num = frame->fmt->num_planes;
> > +	config->format = mtk_mdp_map_color_format(frame->fmt->pixelformat);
> > +	config->w_stride = 0; /* MDP will calculate it by color format. */
> > +	config->h_stride = 0; /* MDP will calculate it by color format. */
> > +
> > +	for (i = 0; i < src_buf->plane_num; i++)
> > +		src_buf->plane_size[i] = frame->payload[i];
> > +}
> > +
> > +void mtk_mdp_hw_set_out_size(struct mtk_mdp_ctx *ctx)
> > +{
> > +	struct mtk_mdp_frame *frame = &ctx->d_frame;
> > +	struct mdp_config *config = &ctx->vpu.vsi->dst_config;
> > +
> > +	config->crop_x = frame->crop.left;
> > +	config->crop_y = frame->crop.top;
> > +	config->crop_w = frame->crop.width;
> > +	config->crop_h = frame->crop.height;
> > +	config->x = 0;
> > +	config->y = 0;
> > +	config->w = frame->width;
> > +	config->h = frame->height;
> > +}
> > +
> > +void mtk_mdp_hw_set_out_image_format(struct mtk_mdp_ctx *ctx)
> > +{
> > +	unsigned int i;
> > +	struct mtk_mdp_frame *frame = &ctx->d_frame;
> > +	struct mdp_config *config = &ctx->vpu.vsi->dst_config;
> > +	struct mdp_buffer *dst_buf = &ctx->vpu.vsi->dst_buffer;
> > +
> > +	dst_buf->plane_num = frame->fmt->num_planes;
> > +	config->format = mtk_mdp_map_color_format(frame->fmt->pixelformat);
> > +	config->w_stride = 0; /* MDP will calculate it by color format. */
> > +	config->h_stride = 0; /* MDP will calculate it by color format. */
> > +	for (i = 0; i < dst_buf->plane_num; i++)
> > +		dst_buf->plane_size[i] = frame->payload[i];
> > +}
> > +
> > +void mtk_mdp_hw_set_rotation(struct mtk_mdp_ctx *ctx)
> > +{
> > +	struct mdp_config_misc *misc = &ctx->vpu.vsi->misc;
> > +
> > +	misc->orientation = ctx->ctrls.rotate->val;
> > +	misc->hflip = ctx->ctrls.hflip->val;
> > +	misc->vflip = ctx->ctrls.vflip->val;
> > +}
> > +
> > +void mtk_mdp_hw_set_global_alpha(struct mtk_mdp_ctx *ctx)
> > +{
> > +	struct mdp_config_misc *misc = &ctx->vpu.vsi->misc;
> > +
> > +	misc->alpha = ctx->ctrls.global_alpha->val;
> > +}
> > diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_regs.h b/drivers/media/platform/mtk-mdp/mtk_mdp_regs.h
> > new file mode 100644
> > index 0000000..42bd057
> > --- /dev/null
> > +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_regs.h
> > @@ -0,0 +1,31 @@
> > +/*
> > + * Copyright (c) 2016 MediaTek Inc.
> > + * Author: Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + *
> > + * 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.
> > + */
> > +
> > +#ifndef __MTK_MDP_REGS_H__
> > +#define __MTK_MDP_REGS_H__
> > +
> > +
> > +void mtk_mdp_hw_set_input_addr(struct mtk_mdp_ctx *ctx,
> > +			       struct mtk_mdp_addr *addr);
> > +void mtk_mdp_hw_set_output_addr(struct mtk_mdp_ctx *ctx,
> > +				struct mtk_mdp_addr *addr);
> > +void mtk_mdp_hw_set_in_size(struct mtk_mdp_ctx *ctx);
> > +void mtk_mdp_hw_set_in_image_format(struct mtk_mdp_ctx *ctx);
> > +void mtk_mdp_hw_set_out_size(struct mtk_mdp_ctx *ctx);
> > +void mtk_mdp_hw_set_out_image_format(struct mtk_mdp_ctx *ctx);
> > +void mtk_mdp_hw_set_rotation(struct mtk_mdp_ctx *ctx);
> > +void mtk_mdp_hw_set_global_alpha(struct mtk_mdp_ctx *ctx);
> > +
> > +
> > +#endif /* __MTK_MDP_REGS_H__ */
> > diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c b/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c
> > new file mode 100644
> > index 0000000..850376a
> > --- /dev/null
> > +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c
> > @@ -0,0 +1,140 @@
> > +/*
> > + * Copyright (c) 2015-2016 MediaTek Inc.
> > + * Author: Houlong Wei <houlong.wei at mediatek.com>
> > + *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + *
> > + * 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.
> > + */
> > +
> > +#include "mtk_mdp_core.h"
> > +#include "mtk_mdp_vpu.h"
> > +#include "mtk_vpu.h"
> > +
> > +
> > +static inline struct mtk_mdp_ctx *vpu_to_ctx(struct mtk_mdp_vpu *vpu)
> > +{
> > +	return container_of(vpu, struct mtk_mdp_ctx, vpu);
> > +}
> > +
> > +static void mtk_mdp_vpu_handle_init_ack(struct mdp_ipi_comm_ack *msg)
> > +{
> > +	struct mtk_mdp_vpu *vpu = (struct mtk_mdp_vpu *)msg->ap_inst;
> > +
> > +	/* mapping VPU address to kernel virtual address */
> > +	vpu->vsi = (struct mdp_process_vsi *)
> > +			vpu_mapping_dm_addr(vpu->pdev, msg->vpu_inst_addr);
> > +	vpu->inst_addr = msg->vpu_inst_addr;
> > +}
> > +
> > +static void mtk_mdp_vpu_ipi_handler(void *data, unsigned int len, void *priv)
> > +{
> > +	unsigned int msg_id = *(unsigned int *)data;
> > +	struct mdp_ipi_comm_ack *msg = (struct mdp_ipi_comm_ack *)data;
> > +	struct mtk_mdp_vpu *vpu = (struct mtk_mdp_vpu *)msg->ap_inst;
> > +	struct mtk_mdp_ctx *ctx;
> > +
> > +	vpu->failure = msg->status;
> > +	if (!vpu->failure) {
> > +		switch (msg_id) {
> > +		case VPU_MDP_INIT_ACK:
> > +			mtk_mdp_vpu_handle_init_ack(data);
> > +			break;
> > +		case VPU_MDP_DEINIT_ACK:
> > +		case VPU_MDP_PROCESS_ACK:
> > +			break;
> > +		default:
> > +			ctx = vpu_to_ctx(vpu);
> > +			dev_err(&ctx->mdp_dev->pdev->dev,
> > +				"handle unknown ipi msg:0x%x\n",
> > +				msg_id);
> > +			break;
> > +		}
> > +	} else {
> > +		ctx = vpu_to_ctx(vpu);
> > +		mtk_mdp_dbg(0, "[%d]:msg 0x%x, failure:%d", ctx->id,
> > +			    msg_id, vpu->failure);
> > +	}
> > +}
> > +
> > +int mtk_mdp_vpu_register(struct platform_device *pdev)
> > +{
> > +	struct mtk_mdp_dev *mdp = platform_get_drvdata(pdev);
> > +	int err;
> > +
> > +	err = vpu_ipi_register(mdp->vpu_dev, IPI_MDP,
> > +			       mtk_mdp_vpu_ipi_handler, "mdp_vpu", NULL);
> > +	if (err)
> > +		dev_err(&mdp->pdev->dev,
> > +			"vpu_ipi_registration fail status=%d\n", err);
> > +
> > +	return err;
> > +}
> > +
> > +static int mtk_mdp_vpu_send_msg(void *msg, int len, struct mtk_mdp_vpu *vpu,
> > +				int id)
> > +{
> > +	struct mtk_mdp_ctx *ctx = vpu_to_ctx(vpu);
> > +	int err;
> > +
> > +	mutex_lock(&ctx->mdp_dev->vpulock);
> > +	err = vpu_ipi_send(vpu->pdev, (enum ipi_id)id, msg, len);
> > +	if (err) {
> > +		mutex_unlock(&ctx->mdp_dev->vpulock);
> > +		dev_err(&ctx->mdp_dev->pdev->dev,
> > +			"vpu_ipi_send fail status %d\n", err);
> > +	}
> > +	mutex_unlock(&ctx->mdp_dev->vpulock);
> > +
> > +	return err;
> > +}
> > +
> > +static int mtk_mdp_vpu_send_ap_ipi(struct mtk_mdp_vpu *vpu, uint32_t msg_id)
> > +{
> > +	int err;
> > +	struct mdp_ipi_comm msg;
> > +
> > +	msg.msg_id = msg_id;
> > +	msg.ipi_id = IPI_MDP;
> > +	msg.vpu_inst_addr = vpu->inst_addr;
> > +	msg.ap_inst = (uint64_t)vpu;
> > +	err = mtk_mdp_vpu_send_msg((void *)&msg, sizeof(msg), vpu, IPI_MDP);
> > +	if (!err && vpu->failure)
> > +		err = -EINVAL;
> > +
> > +	return err;
> > +}
> > +
> > +int mtk_mdp_vpu_init(struct mtk_mdp_vpu *vpu)
> > +{
> > +	int err;
> > +	struct mdp_ipi_init msg;
> > +	struct mtk_mdp_ctx *ctx = vpu_to_ctx(vpu);
> > +
> > +	vpu->pdev = ctx->mdp_dev->vpu_dev;
> > +
> > +	msg.msg_id = AP_MDP_INIT;
> > +	msg.ipi_id = IPI_MDP;
> > +	msg.ap_inst = (uint64_t)vpu;
> > +	err = mtk_mdp_vpu_send_msg((void *)&msg, sizeof(msg), vpu, IPI_MDP);
> > +	if (!err && vpu->failure)
> > +		err = -EINVAL;
> > +
> > +	return err;
> > +}
> > +
> > +int mtk_mdp_vpu_deinit(struct mtk_mdp_vpu *vpu)
> > +{
> > +	return mtk_mdp_vpu_send_ap_ipi(vpu, AP_MDP_DEINIT);
> > +}
> > +
> > +int mtk_mdp_vpu_process(struct mtk_mdp_vpu *vpu)
> > +{
> > +	return mtk_mdp_vpu_send_ap_ipi(vpu, AP_MDP_PROCESS);
> > +}
> > diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h b/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h
> > new file mode 100644
> > index 0000000..df4bdda
> > --- /dev/null
> > +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h
> > @@ -0,0 +1,41 @@
> > +/*
> > + * Copyright (c) 2015-2016 MediaTek Inc.
> > + * Author: Houlong Wei <houlong.wei at mediatek.com>
> > + *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + *
> > + * 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.
> > + */
> > +
> > +#ifndef __MTK_MDP_VPU_H__
> > +#define __MTK_MDP_VPU_H__
> > +
> > +#include "mtk_mdp_ipi.h"
> > +
> > +
> > +/**
> > + * struct mtk_mdp_vpu - VPU instance for MDP
> > + * @pdev	: pointer to the VPU platform device
> > + * @inst_addr	: VPU MDP instance address
> > + * @failure	: VPU execution result status
> > + * @vsi		: VPU shared information
> > + */
> > +struct mtk_mdp_vpu {
> > +	struct platform_device	*pdev;
> > +	uint32_t		inst_addr;
> > +	int32_t			failure;
> > +	struct mdp_process_vsi	*vsi;
> > +};
> > +
> > +int mtk_mdp_vpu_register(struct platform_device *pdev);
> > +int mtk_mdp_vpu_init(struct mtk_mdp_vpu *vpu);
> > +int mtk_mdp_vpu_deinit(struct mtk_mdp_vpu *vpu);
> > +int mtk_mdp_vpu_process(struct mtk_mdp_vpu *vpu);
> > +
> > +#endif /* __MTK_MDP_VPU_H__ */
> > 
> 
> Regards,
> 
> 	Hans





From minghsiu.tsai at mediatek.com  Fri Jul 22 01:33:00 2016
From: minghsiu.tsai at mediatek.com (Minghsiu Tsai)
Date: Fri, 22 Jul 2016 16:33:00 +0800
Subject: [PATCH v2 1/4] VPU: mediatek: Add mdp support
In-Reply-To: <1469176383-35210-1-git-send-email-minghsiu.tsai@mediatek.com>
References: <1469176383-35210-1-git-send-email-minghsiu.tsai@mediatek.com>
Message-ID: <1469176383-35210-2-git-send-email-minghsiu.tsai@mediatek.com>

VPU driver add mdp support

Signed-off-by: Minghsiu Tsai <minghsiu.tsai at mediatek.com>
---
 drivers/media/platform/mtk-vpu/mtk_vpu.h |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.h b/drivers/media/platform/mtk-vpu/mtk_vpu.h
index f457479..291ae46 100644
--- a/drivers/media/platform/mtk-vpu/mtk_vpu.h
+++ b/drivers/media/platform/mtk-vpu/mtk_vpu.h
@@ -53,6 +53,8 @@ typedef void (*ipi_handler_t) (void *data,
 			 handle H264 video encoder job, and vice versa.
  * @IPI_VENC_VP8:	 The interrupt fro vpu is to notify kernel to
 			 handle VP8 video encoder job,, and vice versa.
+ * @IPI_MDP:		 The interrupt from vpu is to notify kernel to
+			 handle MDP (Media Data Path) job, and vice versa.
  * @IPI_MAX:		 The maximum IPI number
  */
 
@@ -63,6 +65,7 @@ enum ipi_id {
 	IPI_VDEC_VP9,
 	IPI_VENC_H264,
 	IPI_VENC_VP8,
+	IPI_MDP,
 	IPI_MAX,
 };
 
@@ -71,11 +74,13 @@ enum ipi_id {
  *
  * @VPU_RST_ENC: encoder reset id
  * @VPU_RST_DEC: decoder reset id
+ * @VPU_RST_MDP: MDP (Media Data Path) reset id
  * @VPU_RST_MAX: maximum reset id
  */
 enum rst_id {
 	VPU_RST_ENC,
 	VPU_RST_DEC,
+	VPU_RST_MDP,
 	VPU_RST_MAX,
 };
 
-- 
1.7.9.5



From minghsiu.tsai at mediatek.com  Fri Jul 22 01:33:01 2016
From: minghsiu.tsai at mediatek.com (Minghsiu Tsai)
Date: Fri, 22 Jul 2016 16:33:01 +0800
Subject: [PATCH v2 2/4] dt-bindings: Add a binding for Mediatek MDP
In-Reply-To: <1469176383-35210-1-git-send-email-minghsiu.tsai@mediatek.com>
References: <1469176383-35210-1-git-send-email-minghsiu.tsai@mediatek.com>
Message-ID: <1469176383-35210-3-git-send-email-minghsiu.tsai@mediatek.com>

Add a DT binding documentation of MDP for the MT8173 SoC
from Mediatek

Signed-off-by: Minghsiu Tsai <minghsiu.tsai at mediatek.com>
---
 .../devicetree/bindings/media/mediatek-mdp.txt     |   96 ++++++++++++++++++++
 1 file changed, 96 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/mediatek-mdp.txt

diff --git a/Documentation/devicetree/bindings/media/mediatek-mdp.txt b/Documentation/devicetree/bindings/media/mediatek-mdp.txt
new file mode 100644
index 0000000..2dad031
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/mediatek-mdp.txt
@@ -0,0 +1,96 @@
+* Mediatek Media Data Path
+
+Media Data Path is used for scaling and color space conversion.
+
+Required properties (all function blocks):
+- compatible: "mediatek,<chip>-mdp"
+        "mediatek,<chip>-mdp-<function>", one of
+        "mediatek,<chip>-mdp-rdma"  - read DMA
+        "mediatek,<chip>-mdp-rsz"   - resizer
+        "mediatek,<chip>-mdp-wdma"  - write DMA
+        "mediatek,<chip>-mdp-wrot"  - write DMA with rotation
+- reg: Physical base address and length of the function block register space
+- clocks: device clocks
+- power-domains: a phandle to the power domain.
+- mediatek,vpu: the node of video processor unit
+
+Required properties (DMA function blocks):
+- compatible: Should be one of
+        "mediatek,<chip>-mdp-rdma"
+        "mediatek,<chip>-mdp-wdma"
+        "mediatek,<chip>-mdp-wrot"
+- iommus: should point to the respective IOMMU block with master port as
+  argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
+  for details.
+- mediatek,larb: must contain the local arbiters in the current Socs.
+
+Example:
+	mdp_rdma0: rdma at 14001000 {
+		compatible = "mediatek,mt8173-mdp-rdma",
+			     "mediatek,mt8173-mdp";
+		reg = <0 0x14001000 0 0x1000>;
+		clocks = <&mmsys CLK_MM_MDP_RDMA0>,
+			 <&mmsys CLK_MM_MUTEX_32K>;
+		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+		iommus = <&iommu M4U_PORT_MDP_RDMA0>;
+		mediatek,larb = <&larb0>;
+		mediatek,vpu = <&vpu>;
+	};
+
+	mdp_rdma1: rdma at 14002000 {
+		compatible = "mediatek,mt8173-mdp-rdma";
+		reg = <0 0x14002000 0 0x1000>;
+		clocks = <&mmsys CLK_MM_MDP_RDMA1>,
+			 <&mmsys CLK_MM_MUTEX_32K>;
+		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+		iommus = <&iommu M4U_PORT_MDP_RDMA1>;
+		mediatek,larb = <&larb4>;
+	};
+
+	mdp_rsz0: rsz at 14003000 {
+		compatible = "mediatek,mt8173-mdp-rsz";
+		reg = <0 0x14003000 0 0x1000>;
+		clocks = <&mmsys CLK_MM_MDP_RSZ0>;
+		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+	};
+
+	mdp_rsz1: rsz at 14004000 {
+		compatible = "mediatek,mt8173-mdp-rsz";
+		reg = <0 0x14004000 0 0x1000>;
+		clocks = <&mmsys CLK_MM_MDP_RSZ1>;
+		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+	};
+
+	mdp_rsz2: rsz at 14005000 {
+		compatible = "mediatek,mt8173-mdp-rsz";
+		reg = <0 0x14005000 0 0x1000>;
+		clocks = <&mmsys CLK_MM_MDP_RSZ2>;
+		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+	};
+
+	mdp_wdma0: wdma at 14006000 {
+		compatible = "mediatek,mt8173-mdp-wdma";
+		reg = <0 0x14006000 0 0x1000>;
+		clocks = <&mmsys CLK_MM_MDP_WDMA>;
+		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+		iommus = <&iommu M4U_PORT_MDP_WDMA>;
+		mediatek,larb = <&larb0>;
+	};
+
+	mdp_wrot0: wrot at 14007000 {
+		compatible = "mediatek,mt8173-mdp-wrot";
+		reg = <0 0x14007000 0 0x1000>;
+		clocks = <&mmsys CLK_MM_MDP_WROT0>;
+		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+		iommus = <&iommu M4U_PORT_MDP_WROT0>;
+		mediatek,larb = <&larb0>;
+	};
+
+	mdp_wrot1: wrot at 14008000 {
+		compatible = "mediatek,mt8173-mdp-wrot";
+		reg = <0 0x14008000 0 0x1000>;
+		clocks = <&mmsys CLK_MM_MDP_WROT1>;
+		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+		iommus = <&iommu M4U_PORT_MDP_WROT1>;
+		mediatek,larb = <&larb4>;
+	};
-- 
1.7.9.5



From minghsiu.tsai at mediatek.com  Fri Jul 22 01:33:03 2016
From: minghsiu.tsai at mediatek.com (Minghsiu Tsai)
Date: Fri, 22 Jul 2016 16:33:03 +0800
Subject: [PATCH v2 4/4] arm64: dts: mediatek: Add MDP for MT8173
In-Reply-To: <1469176383-35210-1-git-send-email-minghsiu.tsai@mediatek.com>
References: <1469176383-35210-1-git-send-email-minghsiu.tsai@mediatek.com>
Message-ID: <1469176383-35210-5-git-send-email-minghsiu.tsai@mediatek.com>

Add MDP node for MT8173

Signed-off-by: Minghsiu Tsai <minghsiu.tsai at mediatek.com>
---
 arch/arm64/boot/dts/mediatek/mt8173.dtsi |   80 ++++++++++++++++++++++++++++++
 1 file changed, 80 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
index a44cfb7..cabbd85 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -26,6 +26,16 @@
 	#address-cells = <2>;
 	#size-cells = <2>;
 
+	aliases {
+		mdp_rdma0 = &mdp_rdma0;
+		mdp_rdma1 = &mdp_rdma1;
+		mdp_rsz0 = &mdp_rsz0;
+		mdp_rsz1 = &mdp_rsz1;
+		mdp_rsz2 = &mdp_rsz2;
+		mdp_wdma0 = &mdp_wdma0;
+		mdp_wrot0 = &mdp_wrot0;
+		mdp_wrot1 = &mdp_wrot1;
+	};
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -678,6 +688,76 @@
 			#clock-cells = <1>;
 		};
 
+		mdp_rdma0: rdma at 14001000 {
+			compatible = "mediatek,mt8173-mdp-rdma",
+				     "mediatek,mt8173-mdp";
+			reg = <0 0x14001000 0 0x1000>;
+			clocks = <&mmsys CLK_MM_MDP_RDMA0>,
+				 <&mmsys CLK_MM_MUTEX_32K>;
+			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+			iommus = <&iommu M4U_PORT_MDP_RDMA0>;
+			mediatek,larb = <&larb0>;
+			mediatek,vpu = <&vpu>;
+		};
+
+		mdp_rdma1: rdma at 14002000 {
+			compatible = "mediatek,mt8173-mdp-rdma";
+			reg = <0 0x14002000 0 0x1000>;
+			clocks = <&mmsys CLK_MM_MDP_RDMA1>,
+				 <&mmsys CLK_MM_MUTEX_32K>;
+			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+			iommus = <&iommu M4U_PORT_MDP_RDMA1>;
+			mediatek,larb = <&larb4>;
+		};
+
+		mdp_rsz0: rsz at 14003000 {
+			compatible = "mediatek,mt8173-mdp-rsz";
+			reg = <0 0x14003000 0 0x1000>;
+			clocks = <&mmsys CLK_MM_MDP_RSZ0>;
+			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+		};
+
+		mdp_rsz1: rsz at 14004000 {
+			compatible = "mediatek,mt8173-mdp-rsz";
+			reg = <0 0x14004000 0 0x1000>;
+			clocks = <&mmsys CLK_MM_MDP_RSZ1>;
+			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+		};
+
+		mdp_rsz2: rsz at 14005000 {
+			compatible = "mediatek,mt8173-mdp-rsz";
+			reg = <0 0x14005000 0 0x1000>;
+			clocks = <&mmsys CLK_MM_MDP_RSZ2>;
+			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+		};
+
+		mdp_wdma0: wdma at 14006000 {
+			compatible = "mediatek,mt8173-mdp-wdma";
+			reg = <0 0x14006000 0 0x1000>;
+			clocks = <&mmsys CLK_MM_MDP_WDMA>;
+			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+			iommus = <&iommu M4U_PORT_MDP_WDMA>;
+			mediatek,larb = <&larb0>;
+		};
+
+		mdp_wrot0: wrot at 14007000 {
+			compatible = "mediatek,mt8173-mdp-wrot";
+			reg = <0 0x14007000 0 0x1000>;
+			clocks = <&mmsys CLK_MM_MDP_WROT0>;
+			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+			iommus = <&iommu M4U_PORT_MDP_WROT0>;
+			mediatek,larb = <&larb0>;
+		};
+
+		mdp_wrot1: wrot at 14008000 {
+			compatible = "mediatek,mt8173-mdp-wrot";
+			reg = <0 0x14008000 0 0x1000>;
+			clocks = <&mmsys CLK_MM_MDP_WROT1>;
+			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+			iommus = <&iommu M4U_PORT_MDP_WROT1>;
+			mediatek,larb = <&larb4>;
+		};
+
 		pwm0: pwm at 1401e000 {
 			compatible = "mediatek,mt8173-disp-pwm",
 				     "mediatek,mt6595-disp-pwm";
-- 
1.7.9.5



From minghsiu.tsai at mediatek.com  Fri Jul 22 01:32:59 2016
From: minghsiu.tsai at mediatek.com (Minghsiu Tsai)
Date: Fri, 22 Jul 2016 16:32:59 +0800
Subject: [PATCH v2 0/4] Add MT8173 MDP Driver 
Message-ID: <1469176383-35210-1-git-send-email-minghsiu.tsai@mediatek.com>

Changes in v2:
- Add section to describe blocks function in dts-bindings
- Remove the assignment of device_caps in querycap()
- Remove format's name assignment
- Copy colorspace-related parameters from OUTPUT to CAPTURE
- Use m2m helper functions
- Fix DMA allocation failure
- Initialize lazily vpu instance in streamon()

==============
 Introduction
==============

The purpose of this series is to add the driver for Media Data Path HW embedded in the Mediatek's MT8173 SoC.
MDP is used for scaling and color space conversion.

It could convert V4L2_PIX_FMT_MT21 to V4L2_PIX_FMT_NV12M or V4L2_PIX_FMT_YUV420M.

NV12M/YUV420M/MT21 -> MDP -> NV12M/YUV420M

This patch series rely on MTK VPU driver in patch series "Add MT8173 Video Encoder Driver and VPU Driver"[1] and "Add MT8173 Video Decoder Driver"[2].
MDP driver rely on VPU driver to load, communicate with VPU.

Internally the driver uses videobuf2 framework and MTK IOMMU and MTK SMI both have been merged in v4.6-rc1.

[1]https://patchwork.kernel.org/patch/9002171/
[2]https://patchwork.kernel.org/patch/9141245/

==================
 Device interface
==================

In principle the driver bases on v4l2 memory-to-memory framework:
it provides a single video node and each opened file handle gets its own private context with separate buffer queues. Each context consist of 2 buffer queues: OUTPUT (for source buffers) and CAPTURE (for destination buffers).
OUTPUT and CAPTURE buffer could be MMAP or DMABUF memory type.

v4l2-compliance test output:
Need the patch "[for,4.7] v4l2-ioctl: fix stupid mistake in cropcap condition"[3] to pass test item Cropping.

[3]https://patchwork.linuxtv.org/patch/34374/

# v4l2-compliance -d /dev/image-proc0
v4l2-compliance SHA   : 42e5b23fcb64fd0012688b537446df565507b2d7

Driver Info:
        Driver name   : mtk-mdp
        Card type     : 14001000.rdma
        Bus info      : platform:mt8173
        Driver version: 4.7.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 (Not Supported)

        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 (4):
  VPU: mediatek: Add mdp support
  dt-bindings: Add a binding for Mediatek MDP
  media: Add Mediatek MDP Driver
  arm64: dts: mediatek: Add MDP for MT8173

 .../devicetree/bindings/media/mediatek-mdp.txt     |   96 ++
 arch/arm64/boot/dts/mediatek/mt8173.dtsi           |   80 ++
 drivers/media/platform/Kconfig                     |   16 +
 drivers/media/platform/Makefile                    |    2 +
 drivers/media/platform/mtk-mdp/Makefile            |    9 +
 drivers/media/platform/mtk-mdp/mtk_mdp_comp.c      |  159 +++
 drivers/media/platform/mtk-mdp/mtk_mdp_comp.h      |   72 ++
 drivers/media/platform/mtk-mdp/mtk_mdp_core.c      |  294 +++++
 drivers/media/platform/mtk-mdp/mtk_mdp_core.h      |  240 ++++
 drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h       |  126 ++
 drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c       | 1263 ++++++++++++++++++++
 drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h       |   22 +
 drivers/media/platform/mtk-mdp/mtk_mdp_regs.c      |  153 +++
 drivers/media/platform/mtk-mdp/mtk_mdp_regs.h      |   31 +
 drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c       |  145 +++
 drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h       |   41 +
 drivers/media/platform/mtk-vpu/mtk_vpu.h           |    5 +
 17 files changed, 2754 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/mediatek-mdp.txt
 create mode 100644 drivers/media/platform/mtk-mdp/Makefile
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_comp.c
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_comp.h
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_core.c
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_core.h
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_regs.c
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_regs.h
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h

--
1.7.9.5



From minghsiu.tsai at mediatek.com  Fri Jul 22 01:33:02 2016
From: minghsiu.tsai at mediatek.com (Minghsiu Tsai)
Date: Fri, 22 Jul 2016 16:33:02 +0800
Subject: [PATCH v2 3/4] media: Add Mediatek MDP Driver
In-Reply-To: <1469176383-35210-1-git-send-email-minghsiu.tsai@mediatek.com>
References: <1469176383-35210-1-git-send-email-minghsiu.tsai@mediatek.com>
Message-ID: <1469176383-35210-4-git-send-email-minghsiu.tsai@mediatek.com>

Add MDP driver for MT8173

Signed-off-by: Minghsiu Tsai <minghsiu.tsai at mediatek.com>
---
 drivers/media/platform/Kconfig                |   16 +
 drivers/media/platform/Makefile               |    2 +
 drivers/media/platform/mtk-mdp/Makefile       |    9 +
 drivers/media/platform/mtk-mdp/mtk_mdp_comp.c |  159 ++++
 drivers/media/platform/mtk-mdp/mtk_mdp_comp.h |   72 ++
 drivers/media/platform/mtk-mdp/mtk_mdp_core.c |  294 ++++++
 drivers/media/platform/mtk-mdp/mtk_mdp_core.h |  240 +++++
 drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h  |  126 +++
 drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c  | 1263 +++++++++++++++++++++++++
 drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h  |   22 +
 drivers/media/platform/mtk-mdp/mtk_mdp_regs.c |  153 +++
 drivers/media/platform/mtk-mdp/mtk_mdp_regs.h |   31 +
 drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c  |  145 +++
 drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h  |   41 +
 14 files changed, 2573 insertions(+)
 create mode 100644 drivers/media/platform/mtk-mdp/Makefile
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_comp.c
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_comp.h
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_core.c
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_core.h
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_regs.c
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_regs.h
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c
 create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h

diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index f25344b..4bb874b 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -166,6 +166,22 @@ config VIDEO_MEDIATEK_VPU
 	    To compile this driver as a module, choose M here: the
 	    module will be called mtk-vpu.
 
+config VIDEO_MEDIATEK_MDP
+	tristate "Mediatek MDP driver"
+	depends on MTK_IOMMU || COMPILE_TEST
+	depends on VIDEO_DEV && VIDEO_V4L2
+	depends on ARCH_MEDIATEK || COMPILE_TEST
+	select VIDEOBUF2_DMA_CONTIG
+	select V4L2_MEM2MEM_DEV
+	select VIDEO_MEDIATEK_VPU
+	default n
+	---help---
+	    It is a v4l2 driver and present in Mediatek MT8173 SoCs.
+	    The driver supports for scaling and color space conversion.
+
+	    To compile this driver as a module, choose M here: the
+	    module will be called mtk-mdp.
+
 config VIDEO_MEDIATEK_VCODEC
 	tristate "Mediatek Video Codec driver"
 	depends on MTK_IOMMU || COMPILE_TEST
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index 21771c1..221aace 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -63,3 +63,5 @@ ccflags-y += -I$(srctree)/drivers/media/i2c
 obj-$(CONFIG_VIDEO_MEDIATEK_VPU)	+= mtk-vpu/
 
 obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC)	+= mtk-vcodec/
+
+obj-$(CONFIG_VIDEO_MEDIATEK_MDP)	+= mtk-mdp/
diff --git a/drivers/media/platform/mtk-mdp/Makefile b/drivers/media/platform/mtk-mdp/Makefile
new file mode 100644
index 0000000..f802569
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp/Makefile
@@ -0,0 +1,9 @@
+mtk-mdp-y += mtk_mdp_core.o
+mtk-mdp-y += mtk_mdp_comp.o
+mtk-mdp-y += mtk_mdp_m2m.o
+mtk-mdp-y += mtk_mdp_regs.o
+mtk-mdp-y += mtk_mdp_vpu.o
+
+obj-$(CONFIG_VIDEO_MEDIATEK_MDP) += mtk-mdp.o
+
+ccflags-y += -I$(srctree)/drivers/media/platform/mtk-vpu
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_comp.c b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.c
new file mode 100644
index 0000000..aa8f9fd
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <soc/mediatek/smi.h>
+
+#include "mtk_mdp_comp.h"
+
+
+static const char * const mtk_mdp_comp_stem[MTK_MDP_COMP_TYPE_MAX] = {
+	"mdp_rdma",
+	"mdp_rsz",
+	"mdp_wdma",
+	"mdp_wrot",
+};
+
+struct mtk_mdp_comp_match {
+	enum mtk_mdp_comp_type type;
+	int alias_id;
+};
+
+static const struct mtk_mdp_comp_match mtk_mdp_matches[MTK_MDP_COMP_ID_MAX] = {
+	{ MTK_MDP_RDMA,	0 },
+	{ MTK_MDP_RDMA,	1 },
+	{ MTK_MDP_RSZ,	0 },
+	{ MTK_MDP_RSZ,	1 },
+	{ MTK_MDP_RSZ,	2 },
+	{ MTK_MDP_WDMA,	0 },
+	{ MTK_MDP_WROT,	0 },
+	{ MTK_MDP_WROT,	1 },
+};
+
+int mtk_mdp_comp_get_id(struct device *dev, struct device_node *node,
+			enum mtk_mdp_comp_type comp_type)
+{
+	int id = of_alias_get_id(node, mtk_mdp_comp_stem[comp_type]);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mtk_mdp_matches); i++) {
+		if (comp_type == mtk_mdp_matches[i].type &&
+		    id == mtk_mdp_matches[i].alias_id)
+			return i;
+	}
+
+	dev_err(dev, "Failed to get id. type: %d, id: %d\n", comp_type, id);
+
+	return -EINVAL;
+}
+
+void mtk_mdp_comp_clock_on(struct device *dev, struct mtk_mdp_comp *comp)
+{
+	int i, err;
+
+	if (comp->larb_dev) {
+		err = mtk_smi_larb_get(comp->larb_dev);
+		if (err)
+			dev_err(dev,
+				"failed to get larb, err %d. type:%d id:%d\n",
+				err, comp->type, comp->id);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(comp->clk); i++) {
+		if (!comp->clk[i])
+			continue;
+		err = clk_prepare_enable(comp->clk[i]);
+		if (err)
+			dev_err(dev,
+			"failed to enable clock, err %d. type:%d id:%d i:%d\n",
+				err, comp->type, comp->id, i);
+	}
+}
+
+void mtk_mdp_comp_clock_off(struct device *dev, struct mtk_mdp_comp *comp)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(comp->clk); i++) {
+		if (!comp->clk[i])
+			continue;
+		clk_disable_unprepare(comp->clk[i]);
+	}
+
+	if (comp->larb_dev)
+		mtk_smi_larb_put(comp->larb_dev);
+}
+
+int mtk_mdp_comp_init(struct device *dev, struct device_node *node,
+		      struct mtk_mdp_comp *comp, enum mtk_mdp_comp_id comp_id)
+{
+	struct device_node *larb_node;
+	struct platform_device *larb_pdev;
+	int i;
+
+	if (comp_id < 0 || comp_id >= MTK_MDP_COMP_ID_MAX) {
+		dev_err(dev, "Invalid comp_id %d\n", comp_id);
+		return -EINVAL;
+	}
+
+	comp->dev_node = of_node_get(node);
+	comp->id = comp_id;
+	comp->type = mtk_mdp_matches[comp_id].type;
+	comp->regs = of_iomap(node, 0);
+
+	for (i = 0; i < ARRAY_SIZE(comp->clk); i++) {
+		comp->clk[i] = of_clk_get(node, i);
+
+		/* Only RDMA needs two clocks */
+		if (comp->type != MTK_MDP_RDMA)
+			break;
+	}
+
+	/* Only DMA capable components need the LARB property */
+	comp->larb_dev = NULL;
+	if (comp->type != MTK_MDP_RDMA &&
+	    comp->type != MTK_MDP_WDMA &&
+	    comp->type != MTK_MDP_WROT)
+		return 0;
+
+	larb_node = of_parse_phandle(node, "mediatek,larb", 0);
+	if (!larb_node) {
+		dev_err(dev,
+			"Missing mediadek,larb phandle in %s node\n",
+			node->full_name);
+		return -EINVAL;
+	}
+
+	larb_pdev = of_find_device_by_node(larb_node);
+	if (!larb_pdev) {
+		dev_warn(dev, "Waiting for larb device %s\n",
+			 larb_node->full_name);
+		of_node_put(larb_node);
+		return -EPROBE_DEFER;
+	}
+	of_node_put(larb_node);
+
+	comp->larb_dev = &larb_pdev->dev;
+
+	return 0;
+}
+
+void mtk_mdp_comp_deinit(struct device *dev, struct mtk_mdp_comp *comp)
+{
+	of_node_put(comp->dev_node);
+}
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_comp.h b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.h
new file mode 100644
index 0000000..63b3983
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __MTK_MDP_COMP_H__
+#define __MTK_MDP_COMP_H__
+
+/**
+ * enum mtk_mdp_comp_type - the MDP component
+ * @MTK_MDP_RDMA:	Read DMA
+ * @MTK_MDP_RSZ:	Riszer
+ * @MTK_MDP_WDMA:	Write DMA
+ * @MTK_MDP_WROT:	Write DMA with rotation
+ */
+enum mtk_mdp_comp_type {
+	MTK_MDP_RDMA,
+	MTK_MDP_RSZ,
+	MTK_MDP_WDMA,
+	MTK_MDP_WROT,
+	MTK_MDP_COMP_TYPE_MAX,
+};
+
+enum mtk_mdp_comp_id {
+	MTK_MDP_COMP_RDMA0,
+	MTK_MDP_COMP_RDMA1,
+	MTK_MDP_COMP_RSZ0,
+	MTK_MDP_COMP_RSZ1,
+	MTK_MDP_COMP_RSZ2,
+	MTK_MDP_COMP_WDMA,
+	MTK_MDP_COMP_WROT0,
+	MTK_MDP_COMP_WROT1,
+	MTK_MDP_COMP_ID_MAX,
+};
+
+/**
+ * struct mtk_mdp_comp - the MDP's function component data
+ * @dev_node:	component device node
+ * @clk:	clocks required for component
+ * @regs:	Mapped address of component registers.
+ * @larb_dev:	SMI device required for component
+ * @type:	component type
+ * @id:		component ID
+ */
+struct mtk_mdp_comp {
+	struct device_node	*dev_node;
+	struct clk		*clk[2];
+	void __iomem		*regs;
+	struct device		*larb_dev;
+	enum mtk_mdp_comp_type	type;
+	enum mtk_mdp_comp_id	id;
+};
+
+int mtk_mdp_comp_init(struct device *dev, struct device_node *node,
+		      struct mtk_mdp_comp *comp, enum mtk_mdp_comp_id comp_id);
+void mtk_mdp_comp_deinit(struct device *dev, struct mtk_mdp_comp *comp);
+int mtk_mdp_comp_get_id(struct device *dev, struct device_node *node,
+			enum mtk_mdp_comp_type comp_type);
+void mtk_mdp_comp_clock_on(struct device *dev, struct mtk_mdp_comp *comp);
+void mtk_mdp_comp_clock_off(struct device *dev, struct mtk_mdp_comp *comp);
+
+
+#endif /* __MTK_MDP_COMP_H__ */
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c
new file mode 100644
index 0000000..8a81dd9
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2015-2016 MediaTek Inc.
+ * Author: Houlong Wei <houlong.wei at mediatek.com>
+ *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/workqueue.h>
+#include <soc/mediatek/smi.h>
+
+#include "mtk_mdp_core.h"
+#include "mtk_mdp_m2m.h"
+#include "mtk_vpu.h"
+
+/* MDP debug log level (0-3). 3 shows all the logs. */
+int mtk_mdp_dbg_level;
+EXPORT_SYMBOL(mtk_mdp_dbg_level);
+
+module_param(mtk_mdp_dbg_level, int, S_IRUGO | S_IWUSR);
+
+static const struct of_device_id mtk_mdp_comp_dt_ids[] = {
+	{
+		.compatible = "mediatek,mt8173-mdp-rdma",
+		.data = (void *)MTK_MDP_RDMA
+	}, {
+		.compatible = "mediatek,mt8173-mdp-rsz",
+		.data = (void *)MTK_MDP_RSZ
+	}, {
+		.compatible = "mediatek,mt8173-mdp-wdma",
+		.data = (void *)MTK_MDP_WDMA
+	}, {
+		.compatible = "mediatek,mt8173-mdp-wrot",
+		.data = (void *)MTK_MDP_WROT
+	}
+};
+
+static const struct of_device_id mtk_mdp_of_ids[] = {
+	{ .compatible = "mediatek,mt8173-mdp", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, mtk_mdp_of_ids);
+
+static void mtk_mdp_clock_on(struct mtk_mdp_dev *mdp)
+{
+	struct device *dev = &mdp->pdev->dev;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mdp->comp); i++)
+		mtk_mdp_comp_clock_on(dev, mdp->comp[i]);
+}
+
+static void mtk_mdp_clock_off(struct mtk_mdp_dev *mdp)
+{
+	struct device *dev = &mdp->pdev->dev;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mdp->comp); i++)
+		mtk_mdp_comp_clock_off(dev, mdp->comp[i]);
+}
+
+static void mtk_mdp_wdt_worker(struct work_struct *work)
+{
+	struct mtk_mdp_dev *mdp =
+			container_of(work, struct mtk_mdp_dev, wdt_work);
+	struct mtk_mdp_ctx *ctx;
+
+	mtk_mdp_err("Watchdog timeout");
+
+	list_for_each_entry(ctx, &mdp->ctx_list, list) {
+		mtk_mdp_dbg(0, "[%d] Change as state error", ctx->id);
+		mtk_mdp_ctx_state_lock_set(ctx, MTK_MDP_CTX_ERROR);
+	}
+}
+
+static void mtk_mdp_reset_handler(void *priv)
+{
+	struct mtk_mdp_dev *mdp = priv;
+
+	queue_work(mdp->wdt_wq, &mdp->wdt_work);
+}
+
+static int mtk_mdp_probe(struct platform_device *pdev)
+{
+	struct mtk_mdp_dev *mdp;
+	struct device *dev = &pdev->dev;
+	struct device_node *node;
+	int i, ret = 0;
+
+	mdp = devm_kzalloc(dev, sizeof(*mdp), GFP_KERNEL);
+	if (!mdp)
+		return -ENOMEM;
+
+	mdp->id = pdev->id;
+	mdp->pdev = pdev;
+	INIT_LIST_HEAD(&mdp->ctx_list);
+
+	mutex_init(&mdp->lock);
+	mutex_init(&mdp->vpulock);
+
+	/* Iterate over sibling MDP function blocks */
+	for_each_child_of_node(dev->of_node->parent, node) {
+		const struct of_device_id *of_id;
+		enum mtk_mdp_comp_type comp_type;
+		int comp_id;
+		struct mtk_mdp_comp *comp;
+
+		of_id = of_match_node(mtk_mdp_comp_dt_ids, node);
+		if (!of_id)
+			continue;
+
+		if (!of_device_is_available(node)) {
+			dev_err(dev, "Skipping disabled component %s\n",
+				node->full_name);
+			continue;
+		}
+
+		comp_type = (enum mtk_mdp_comp_type)of_id->data;
+		comp_id = mtk_mdp_comp_get_id(dev, node, comp_type);
+		if (comp_id < 0) {
+			dev_warn(dev, "Skipping unknown component %s\n",
+				 node->full_name);
+			continue;
+		}
+
+		comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL);
+		if (!comp) {
+			ret = -ENOMEM;
+			goto err_comp;
+		}
+		mdp->comp[comp_id] = comp;
+
+		ret = mtk_mdp_comp_init(dev, node, comp, comp_id);
+		if (ret)
+			goto err_comp;
+	}
+
+	mdp->job_wq = create_singlethread_workqueue(MTK_MDP_MODULE_NAME);
+	if (!mdp->job_wq) {
+		dev_err(&pdev->dev, "unable to alloc job workqueue\n");
+		ret = -ENOMEM;
+		goto err_alloc_job_wq;
+	}
+
+	mdp->wdt_wq = create_singlethread_workqueue("mdp_wdt_wq");
+	if (!mdp->wdt_wq) {
+		dev_err(&pdev->dev, "unable to alloc wdt workqueue\n");
+		ret = -ENOMEM;
+		goto err_alloc_wdt_wq;
+	}
+	INIT_WORK(&mdp->wdt_work, mtk_mdp_wdt_worker);
+
+	ret = v4l2_device_register(dev, &mdp->v4l2_dev);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register v4l2 device\n");
+		ret = -EINVAL;
+		goto err_dev_register;
+	}
+
+	ret = mtk_mdp_register_m2m_device(mdp);
+	if (ret) {
+		v4l2_err(&mdp->v4l2_dev, "Failed to init mem2mem device\n");
+		goto err_m2m_register;
+	}
+
+	mdp->vpu_dev = vpu_get_plat_device(pdev);
+	vpu_wdt_reg_handler(mdp->vpu_dev, mtk_mdp_reset_handler, mdp,
+			    VPU_RST_MDP);
+
+	platform_set_drvdata(pdev, mdp);
+
+	vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32));
+
+	pm_runtime_enable(dev);
+	dev_dbg(dev, "mdp-%d registered successfully\n", mdp->id);
+
+	return 0;
+
+err_m2m_register:
+	v4l2_device_unregister(&mdp->v4l2_dev);
+
+err_dev_register:
+	destroy_workqueue(mdp->wdt_wq);
+
+err_alloc_wdt_wq:
+	destroy_workqueue(mdp->job_wq);
+
+err_alloc_job_wq:
+
+err_comp:
+	for (i = 0; i < ARRAY_SIZE(mdp->comp); i++)
+		mtk_mdp_comp_deinit(dev, mdp->comp[i]);
+
+	dev_dbg(dev, "err %d\n", ret);
+	return ret;
+}
+
+static int mtk_mdp_remove(struct platform_device *pdev)
+{
+	struct mtk_mdp_dev *mdp = platform_get_drvdata(pdev);
+	int i;
+
+	pm_runtime_disable(&pdev->dev);
+	vb2_dma_contig_clear_max_seg_size(&pdev->dev);
+	mtk_mdp_unregister_m2m_device(mdp);
+	v4l2_device_unregister(&mdp->v4l2_dev);
+
+	flush_workqueue(mdp->job_wq);
+	destroy_workqueue(mdp->job_wq);
+
+	for (i = 0; i < ARRAY_SIZE(mdp->comp); i++)
+		mtk_mdp_comp_deinit(&pdev->dev, mdp->comp[i]);
+
+	dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
+	return 0;
+}
+
+#if defined(CONFIG_PM_RUNTIME) || defined(CONFIG_PM_SLEEP)
+static int mtk_mdp_pm_suspend(struct device *dev)
+{
+	struct mtk_mdp_dev *mdp = dev_get_drvdata(dev);
+
+	mtk_mdp_clock_off(mdp);
+
+	return 0;
+}
+
+static int mtk_mdp_pm_resume(struct device *dev)
+{
+	struct mtk_mdp_dev *mdp = dev_get_drvdata(dev);
+
+	mtk_mdp_clock_on(mdp);
+
+	return 0;
+}
+#endif /* CONFIG_PM_RUNTIME || CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM_SLEEP
+static int mtk_mdp_suspend(struct device *dev)
+{
+	if (pm_runtime_suspended(dev))
+		return 0;
+
+	return mtk_mdp_pm_suspend(dev);
+}
+
+static int mtk_mdp_resume(struct device *dev)
+{
+	if (pm_runtime_suspended(dev))
+		return 0;
+
+	return mtk_mdp_pm_resume(dev);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops mtk_mdp_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(mtk_mdp_suspend, mtk_mdp_resume)
+	SET_RUNTIME_PM_OPS(mtk_mdp_pm_suspend, mtk_mdp_pm_resume, NULL)
+};
+
+static struct platform_driver mtk_mdp_driver = {
+	.probe		= mtk_mdp_probe,
+	.remove		= mtk_mdp_remove,
+	.driver = {
+		.name	= MTK_MDP_MODULE_NAME,
+		.owner	= THIS_MODULE,
+		.pm	= &mtk_mdp_pm_ops,
+		.of_match_table = mtk_mdp_of_ids,
+	}
+};
+
+module_platform_driver(mtk_mdp_driver);
+
+MODULE_AUTHOR("Houlong Wei <houlong.wei at mediatek.com>");
+MODULE_DESCRIPTION("Mediatek image processor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.h b/drivers/media/platform/mtk-mdp/mtk_mdp_core.h
new file mode 100644
index 0000000..e48c4fe
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.h
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2015-2016 MediaTek Inc.
+ * Author: Houlong Wei <houlong.wei at mediatek.com>
+ *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __MTK_MDP_CORE_H__
+#define __MTK_MDP_CORE_H__
+
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "mtk_mdp_vpu.h"
+#include "mtk_mdp_comp.h"
+
+
+#define MTK_MDP_MODULE_NAME		"mtk-mdp"
+
+#define MTK_MDP_SHUTDOWN_TIMEOUT	((100*HZ)/1000) /* 100ms */
+#define MTK_MDP_MAX_CTRL_NUM		10
+
+#define MTK_MDP_FMT_FLAG_OUTPUT		BIT(0)
+#define MTK_MDP_FMT_FLAG_CAPTURE	BIT(1)
+
+#define MTK_MDP_VPU_INIT		BIT(0)
+#define MTK_MDP_SRC_FMT			BIT(1)
+#define MTK_MDP_DST_FMT			BIT(2)
+#define MTK_MDP_CTX_ERROR		BIT(5)
+
+/**
+ * struct mtk_mdp_fmt - the driver's internal color format data
+ * @pixelformat: the fourcc code for this format, 0 if not applicable
+ * @num_planes: number of physically non-contiguous data planes
+ * @depth: per plane driver's private 'number of bits per pixel'
+ * @flags: flags indicating which operation mode format applies to
+	   MTK_MDP_FMT_FLAG_OUTPUT is used in OUTPUT stream
+	   MTK_MDP_FMT_FLAG_CAPTURE is used in CAPTURE stream
+ */
+struct mtk_mdp_fmt {
+	u32	pixelformat;
+	u16	num_planes;
+	u8	depth[VIDEO_MAX_PLANES];
+	u32	flags;
+};
+
+/**
+ * struct mtk_mdp_addr - the image processor physical address set
+ * @addr:	address of planes
+ */
+struct mtk_mdp_addr {
+	dma_addr_t addr[MTK_MDP_MAX_NUM_PLANE];
+};
+
+/* struct mtk_mdp_ctrls - the image processor control set
+ * @rotate: rotation degree
+ * @hflip: horizontal flip
+ * @vflip: vertical flip
+ * @global_alpha: the alpha value of current frame
+ */
+struct mtk_mdp_ctrls {
+	struct v4l2_ctrl *rotate;
+	struct v4l2_ctrl *hflip;
+	struct v4l2_ctrl *vflip;
+	struct v4l2_ctrl *global_alpha;
+};
+
+/**
+ * struct mtk_mdp_frame - source/target frame properties
+ * @width:	SRC : SRCIMG_WIDTH, DST : OUTPUTDMA_WHOLE_IMG_WIDTH
+ * @height:	SRC : SRCIMG_HEIGHT, DST : OUTPUTDMA_WHOLE_IMG_HEIGHT
+ * @crop:	cropped(source)/scaled(destination) size
+ * @payload:	image size in bytes (w x h x bpp)
+ * @pitch:	bytes per line of image in memory
+ * @addr:	image frame buffer physical addresses
+ * @fmt:	color format pointer
+ * @alpha:	frame's alpha value
+ */
+struct mtk_mdp_frame {
+	u32				width;
+	u32				height;
+	struct v4l2_rect		crop;
+	unsigned long			payload[VIDEO_MAX_PLANES];
+	unsigned int			pitch[VIDEO_MAX_PLANES];
+	struct mtk_mdp_addr		addr;
+	const struct mtk_mdp_fmt	*fmt;
+	u8				alpha;
+};
+
+/**
+ * struct mtk_mdp_variant - image processor variant information
+ * @pix_max:		maximum limit of image size
+ * @pix_min:		minimun limit of image size
+ * @pix_align:		alignement of image
+ * @h_scale_up_max:	maximum scale-up in horizontal
+ * @v_scale_up_max:	maximum scale-up in vertical
+ * @h_scale_down_max:	maximum scale-down in horizontal
+ * @v_scale_down_max:	maximum scale-down in vertical
+ */
+struct mtk_mdp_variant {
+	struct mtk_mdp_pix_limit	*pix_max;
+	struct mtk_mdp_pix_limit	*pix_min;
+	struct mtk_mdp_pix_align	*pix_align;
+	u16				h_scale_up_max;
+	u16				v_scale_up_max;
+	u16				h_scale_down_max;
+	u16				v_scale_down_max;
+};
+
+/**
+ * struct mtk_mdp_dev - abstraction for image processor entity
+ * @lock:	the mutex protecting this data structure
+ * @vpulock:	the mutex protecting the communication with VPU
+ * @pdev:	pointer to the image processor platform device
+ * @variant:	the IP variant information
+ * @id:		image processor device index (0..MTK_MDP_MAX_DEVS)
+ * @comp:	MDP function components
+ * @m2m_dev:	v4l2 memory-to-memory device data
+ * @ctx_list:	list of struct mtk_mdp_ctx
+ * @vdev:	video device for image processor driver
+ * @v4l2_dev:	V4L2 device to register video devices for.
+ * @job_wq:	processor work queue
+ * @vpu_dev:	VPU platform device
+ * @ctx_num:	counter of active MTK MDP context
+ * @id_counter:	An integer id given to the next opened context
+ * @wdt_wq:	work queue for VPU watchdog
+ * @wdt_work:	worker for VPU watchdog
+ */
+struct mtk_mdp_dev {
+	struct mutex			lock;
+	struct mutex			vpulock;
+	struct platform_device		*pdev;
+	struct mtk_mdp_variant		*variant;
+	u16				id;
+	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 v4l2_device		v4l2_dev;
+	struct workqueue_struct		*job_wq;
+	struct platform_device		*vpu_dev;
+	int				ctx_num;
+	unsigned long			id_counter;
+	struct workqueue_struct		*wdt_wq;
+	struct work_struct		wdt_work;
+};
+
+/**
+ * mtk_mdp_ctx - the device context data
+ * @list:		link to ctx_list of mtk_mdp_dev
+ * @s_frame:		source frame properties
+ * @d_frame:		destination frame properties
+ * @id:			index of the context that this structure describes
+ * @flags:		additional flags for image conversion
+ * @state:		flags to keep track of user configuration
+			Protected by slock
+ * @rotation:		rotates the image by specified angle
+ * @hflip:		mirror the picture horizontally
+ * @vflip:		mirror the picture vertically
+ * @mdp_dev:		the image processor device this context applies to
+ * @m2m_ctx:		memory-to-memory device context
+ * @fh:			v4l2 file handle
+ * @ctrl_handler:	v4l2 controls handler
+ * @ctrls		image processor control set
+ * @ctrls_rdy:		true if the control handler is initialized
+ * @colorspace:		enum v4l2_colorspace; supplemental to pixelformat
+ * @ycbcr_enc:		enum v4l2_ycbcr_encoding, Y'CbCr encoding
+ * @xfer_func:		enum v4l2_xfer_func, colorspace transfer function
+ * @quant:		enum v4l2_quantization, colorspace quantization
+ * @vpu:		VPU instance
+ * @slock:		the mutex protecting mtp_mdp_ctx.state
+ * @work:		worker for image processing
+ */
+struct mtk_mdp_ctx {
+	struct list_head		list;
+	struct mtk_mdp_frame		s_frame;
+	struct mtk_mdp_frame		d_frame;
+	u32				flags;
+	u32				state;
+	int				id;
+	int				rotation;
+	u32				hflip:1;
+	u32				vflip:1;
+	struct mtk_mdp_dev		*mdp_dev;
+	struct v4l2_m2m_ctx		*m2m_ctx;
+	struct v4l2_fh			fh;
+	struct v4l2_ctrl_handler	ctrl_handler;
+	struct mtk_mdp_ctrls		ctrls;
+	bool				ctrls_rdy;
+	enum v4l2_colorspace		colorspace;
+	enum v4l2_ycbcr_encoding	ycbcr_enc;
+	enum v4l2_xfer_func		xfer_func;
+	enum v4l2_quantization		quant;
+
+	struct mtk_mdp_vpu		vpu;
+	struct mutex			slock;
+	struct work_struct		work;
+};
+
+extern int mtk_mdp_dbg_level;
+
+#if defined(DEBUG)
+
+#define mtk_mdp_dbg(level, fmt, args...)				 \
+	do {								 \
+		if (mtk_mdp_dbg_level >= level)				 \
+			pr_info("[MTK_MDP] level=%d %s(),%d: " fmt "\n", \
+				level, __func__, __LINE__, ##args);	 \
+	} while (0)
+
+#define mtk_mdp_err(fmt, args...)					\
+	pr_err("[MTK_MDP][ERROR] %s:%d: " fmt "\n", __func__, __LINE__, \
+	       ##args)
+
+
+#define mtk_mdp_dbg_enter()  mtk_mdp_dbg(3, "+")
+#define mtk_mdp_dbg_leave()  mtk_mdp_dbg(3, "-")
+
+#else
+
+#define mtk_mdp_dbg(level, fmt, args...)
+#define mtk_mdp_err(fmt, args...)
+#define mtk_mdp_dbg_enter()
+#define mtk_mdp_dbg_leave()
+
+#endif
+
+#endif /* __MTK_MDP_CORE_H__ */
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h b/drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h
new file mode 100644
index 0000000..78e2cc0
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2015-2016 MediaTek Inc.
+ * Author: Houlong Wei <houlong.wei at mediatek.com>
+ *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __MTK_MDP_IPI_H__
+#define __MTK_MDP_IPI_H__
+
+#define MTK_MDP_MAX_NUM_PLANE		3
+
+enum mdp_ipi_msgid {
+	AP_MDP_INIT		= 0xd000,
+	AP_MDP_DEINIT		= 0xd001,
+	AP_MDP_PROCESS		= 0xd002,
+
+	VPU_MDP_INIT_ACK	= 0xe000,
+	VPU_MDP_DEINIT_ACK	= 0xe001,
+	VPU_MDP_PROCESS_ACK	= 0xe002
+};
+
+#pragma pack(push, 4)
+
+/**
+ * struct mdp_ipi_init - for AP_MDP_INIT
+ * @msg_id   : AP_MDP_INIT
+ * @ipi_id   : IPI_MDP
+ * @ap_inst  : AP mtk_mdp_vpu address
+ */
+struct mdp_ipi_init {
+	uint32_t msg_id;
+	uint32_t ipi_id;
+	uint64_t ap_inst;
+};
+
+/**
+ * struct mdp_ipi_comm - for AP_MDP_PROCESS, AP_MDP_DEINIT
+ * @msg_id        : AP_MDP_PROCESS, AP_MDP_DEINIT
+ * @ipi_id        : IPI_MDP
+ * @ap_inst       : AP mtk_mdp_vpu address
+ * @vpu_inst_addr : VPU MDP instance address
+ */
+struct mdp_ipi_comm {
+	uint32_t msg_id;
+	uint32_t ipi_id;
+	uint64_t ap_inst;
+	uint32_t vpu_inst_addr;
+};
+
+/**
+ * struct mdp_ipi_comm_ack - for VPU_MDP_DEINIT_ACK, VPU_MDP_PROCESS_ACK
+ * @msg_id        : VPU_MDP_DEINIT_ACK, VPU_MDP_PROCESS_ACK
+ * @ipi_id        : IPI_MDP
+ * @ap_inst       : AP mtk_mdp_vpu address
+ * @vpu_inst_addr : VPU MDP instance address
+ * @status        : VPU exeuction result
+ */
+struct mdp_ipi_comm_ack {
+	uint32_t msg_id;
+	uint32_t ipi_id;
+	uint64_t ap_inst;
+	uint32_t vpu_inst_addr;
+	int32_t status;
+};
+
+/**
+ * struct mdp_config - configured for source/destination image
+ * @x        : left
+ * @y        : top
+ * @w        : width
+ * @h        : height
+ * @w_stride : bytes in horizontal
+ * @h_stride : bytes in vertical
+ * @crop_x   : cropped left
+ * @crop_y   : cropped top
+ * @crop_w   : cropped width
+ * @crop_h   : cropped height
+ * @format   : color format
+ */
+struct mdp_config {
+	int32_t x;
+	int32_t y;
+	int32_t w;
+	int32_t h;
+	int32_t w_stride;
+	int32_t h_stride;
+	int32_t crop_x;
+	int32_t crop_y;
+	int32_t crop_w;
+	int32_t crop_h;
+	int32_t format;
+};
+
+struct mdp_buffer {
+	uint64_t addr_mva[MTK_MDP_MAX_NUM_PLANE];
+	int32_t plane_size[MTK_MDP_MAX_NUM_PLANE];
+	int32_t plane_num;
+};
+
+struct mdp_config_misc {
+	int32_t orientation; /* 0, 90, 180, 270 */
+	int32_t hflip; /* 1 will enable the flip */
+	int32_t vflip; /* 1 will enable the flip */
+	int32_t alpha; /* global alpha */
+};
+
+struct mdp_process_vsi {
+	struct mdp_config src_config;
+	struct mdp_buffer src_buffer;
+	struct mdp_config dst_config;
+	struct mdp_buffer dst_buffer;
+	struct mdp_config_misc misc;
+};
+
+#pragma pack(pop)
+
+#endif /* __MTK_MDP_IPI_H__ */
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
new file mode 100644
index 0000000..c588ecc
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
@@ -0,0 +1,1263 @@
+/*
+ * Copyright (c) 2015-2016 MediaTek Inc.
+ * Author: Houlong Wei <houlong.wei at mediatek.com>
+ *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/pm_runtime.h>
+#include <linux/workqueue.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+
+#include "mtk_mdp_core.h"
+#include "mtk_mdp_m2m.h"
+#include "mtk_mdp_regs.h"
+#include "mtk_vpu.h"
+
+
+/**
+ *  struct mtk_mdp_pix_limit - image pixel size limits
+ *  @org_w: source pixel width
+ *  @org_h: source pixel height
+ *  @target_rot_dis_w: pixel dst scaled width with the rotator is off
+ *  @target_rot_dis_h: pixel dst scaled height with the rotator is off
+ *  @target_rot_en_w: pixel dst scaled width with the rotator is on
+ *  @target_rot_en_h: pixel dst scaled height with the rotator is on
+ */
+struct mtk_mdp_pix_limit {
+	u16 org_w;
+	u16 org_h;
+	u16 target_rot_dis_w;
+	u16 target_rot_dis_h;
+	u16 target_rot_en_w;
+	u16 target_rot_en_h;
+};
+
+/**
+ *  struct mtk_mdp_pix_align - alignement of image
+ *  @org_w: source alignment of width
+ *  @org_h: source alignment of height
+ *  @target_w: dst alignment of width
+ *  @target_h: dst alignment of height
+ */
+struct mtk_mdp_pix_align {
+	u16 org_w;
+	u16 org_h;
+	u16 target_w;
+	u16 target_h;
+};
+
+static const struct mtk_mdp_fmt mtk_mdp_formats[] = {
+	{
+		.pixelformat	= V4L2_PIX_FMT_MT21,
+		.depth		= { 8, 4 },
+		.num_planes	= 2,
+		.flags		= MTK_MDP_FMT_FLAG_OUTPUT,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_NV12M,
+		.depth		= { 8, 4 },
+		.num_planes	= 2,
+		.flags		= MTK_MDP_FMT_FLAG_OUTPUT |
+				  MTK_MDP_FMT_FLAG_CAPTURE,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_YUV420M,
+		.depth		= { 8, 2, 2 },
+		.num_planes	= 3,
+		.flags		= MTK_MDP_FMT_FLAG_OUTPUT |
+				  MTK_MDP_FMT_FLAG_CAPTURE,
+	}
+};
+
+static struct mtk_mdp_pix_limit mtk_mdp_size_max = {
+	.target_rot_dis_w	= 4096,
+	.target_rot_dis_h	= 4096,
+	.target_rot_en_w	= 4096,
+	.target_rot_en_h	= 4096,
+};
+
+static struct mtk_mdp_pix_limit mtk_mdp_size_min = {
+	.org_w			= 16,
+	.org_h			= 16,
+	.target_rot_dis_w	= 16,
+	.target_rot_dis_h	= 16,
+	.target_rot_en_w	= 16,
+	.target_rot_en_h	= 16,
+};
+
+static struct mtk_mdp_pix_align mtk_mdp_size_align = {
+	.org_w			= 16,
+	.org_h			= 16,
+	.target_w		= 2,
+	.target_h		= 2,
+};
+
+static struct mtk_mdp_variant mtk_mdp_default_variant = {
+	.pix_max		= &mtk_mdp_size_max,
+	.pix_min		= &mtk_mdp_size_min,
+	.pix_align		= &mtk_mdp_size_align,
+	.h_scale_up_max		= 32,
+	.v_scale_up_max		= 32,
+	.h_scale_down_max	= 32,
+	.v_scale_down_max	= 128,
+};
+
+static const struct mtk_mdp_fmt *mtk_mdp_find_fmt(u32 pixelformat, u32 type)
+{
+	u32 i, flag;
+
+	flag = V4L2_TYPE_IS_OUTPUT(type) ? MTK_MDP_FMT_FLAG_OUTPUT :
+					   MTK_MDP_FMT_FLAG_CAPTURE;
+
+	for (i = 0; i < ARRAY_SIZE(mtk_mdp_formats); ++i) {
+		if (!(mtk_mdp_formats[i].flags & flag))
+			continue;
+		if (mtk_mdp_formats[i].pixelformat == pixelformat)
+			return &mtk_mdp_formats[i];
+	}
+	return NULL;
+}
+
+static const struct mtk_mdp_fmt *mtk_mdp_find_fmt_by_index(u32 index, u32 type)
+{
+	u32 i, flag, num = 0;
+
+	flag = V4L2_TYPE_IS_OUTPUT(type) ? MTK_MDP_FMT_FLAG_OUTPUT :
+					   MTK_MDP_FMT_FLAG_CAPTURE;
+
+	for (i = 0; i < ARRAY_SIZE(mtk_mdp_formats); ++i) {
+		if (!(mtk_mdp_formats[i].flags & flag))
+			continue;
+		if (index == num)
+			return &mtk_mdp_formats[i];
+		num++;
+	}
+	return NULL;
+}
+
+static void mtk_mdp_bound_align_image(u32 *w, unsigned int wmin,
+				      unsigned int wmax, unsigned int align_w,
+				      u32 *h, unsigned int hmin,
+				      unsigned int hmax, unsigned int align_h)
+{
+	int org_w, org_h, step_w, step_h;
+	int walign, halign;
+
+	org_w = *w;
+	org_h = *h;
+	walign = ffs(align_w) - 1;
+	halign = ffs(align_h) - 1;
+	v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
+
+	step_w = 1 << walign;
+	step_h = 1 << halign;
+	if (*w < org_w && (*w + step_w) <= wmax)
+		*w += step_w;
+	if (*h < org_h && (*h + step_h) <= hmax)
+		*h += step_h;
+}
+
+static const struct mtk_mdp_fmt *mtk_mdp_try_fmt_mplane(struct mtk_mdp_ctx *ctx,
+							struct v4l2_format *f)
+{
+	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
+	struct mtk_mdp_variant *variant = mdp->variant;
+	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+	const struct mtk_mdp_fmt *fmt;
+	u32 max_w, max_h, align_w, align_h;
+	u32 min_w, min_h, org_w, org_h;
+	int i;
+
+	fmt = mtk_mdp_find_fmt(pix_mp->pixelformat, f->type);
+	if (!fmt)
+		fmt = mtk_mdp_find_fmt_by_index(0, f->type);
+	if (!fmt) {
+		dev_dbg(&ctx->mdp_dev->pdev->dev,
+			"pixelformat format 0x%X invalid\n",
+			pix_mp->pixelformat);
+		return NULL;
+	}
+
+	pix_mp->field = V4L2_FIELD_NONE;
+	pix_mp->pixelformat = fmt->pixelformat;
+	if (!V4L2_TYPE_IS_OUTPUT(f->type)) {
+		pix_mp->colorspace = ctx->colorspace;
+		pix_mp->xfer_func = ctx->xfer_func;
+		pix_mp->ycbcr_enc = ctx->ycbcr_enc;
+		pix_mp->quantization = ctx->quant;
+	}
+	memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
+
+	max_w = variant->pix_max->target_rot_dis_w;
+	max_h = variant->pix_max->target_rot_dis_h;
+
+	align_w = variant->pix_align->org_w;
+	align_h = variant->pix_align->org_h;
+
+	if (V4L2_TYPE_IS_OUTPUT(f->type)) {
+		min_w = variant->pix_min->org_w;
+		min_h = variant->pix_min->org_h;
+	} else {
+		min_w = variant->pix_min->target_rot_dis_w;
+		min_h = variant->pix_min->target_rot_dis_h;
+	}
+
+	mtk_mdp_dbg(2, "[%d] type:%d, wxh:%ux%u, align:%ux%u, max:%ux%u",
+		    ctx->id, f->type, pix_mp->width, pix_mp->height,
+		    align_w, align_h, max_w, max_h);
+	/*
+	 * To check if image size is modified to adjust parameter against
+	 * hardware abilities
+	 */
+	org_w = pix_mp->width;
+	org_h = pix_mp->height;
+
+	mtk_mdp_bound_align_image(&pix_mp->width, min_w, max_w, align_w,
+				  &pix_mp->height, min_h, max_h, align_h);
+
+	if (org_w != pix_mp->width || org_h != pix_mp->height)
+		mtk_mdp_dbg(1, "[%d] size change:%ux%u to %ux%u", ctx->id,
+			    org_w, org_h, pix_mp->width, pix_mp->height);
+	pix_mp->num_planes = fmt->num_planes;
+
+	for (i = 0; i < pix_mp->num_planes; ++i) {
+		int bpl = (pix_mp->width * fmt->depth[i]) >> 3;
+		int sizeimage = bpl * pix_mp->height;
+
+		pix_mp->plane_fmt[i].bytesperline = bpl;
+		if (pix_mp->plane_fmt[i].sizeimage < sizeimage)
+			pix_mp->plane_fmt[i].sizeimage = sizeimage;
+		memset(pix_mp->plane_fmt[i].reserved, 0,
+		       sizeof(pix_mp->plane_fmt[i].reserved));
+		mtk_mdp_dbg(2, "[%d] p%d, bpl:%d, sizeimage:%u (%u)", ctx->id,
+			    i, bpl, pix_mp->plane_fmt[i].sizeimage, sizeimage);
+	}
+
+	return fmt;
+}
+
+static struct mtk_mdp_frame *mtk_mdp_ctx_get_frame(struct mtk_mdp_ctx *ctx,
+					    enum v4l2_buf_type type)
+{
+	if (V4L2_TYPE_IS_OUTPUT(type))
+		return &ctx->s_frame;
+	return &ctx->d_frame;
+}
+
+static void mtk_mdp_check_crop_change(u32 new_w, u32 new_h, u32 *w, u32 *h)
+{
+	if (new_w != *w || new_h != *h) {
+		mtk_mdp_dbg(1, "size change:%dx%d to %dx%d",
+			    *w, *h, new_w, new_h);
+
+		*w = new_w;
+		*h = new_h;
+	}
+}
+
+static int mtk_mdp_try_crop(struct mtk_mdp_ctx *ctx, struct v4l2_crop *cr)
+{
+	struct mtk_mdp_frame *frame;
+	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
+	struct mtk_mdp_variant *variant = mdp->variant;
+	u32 align_w, align_h, new_w, new_h;
+	u32 min_w, min_h, max_w, max_h;
+
+	if (cr->c.top < 0 || cr->c.left < 0) {
+		dev_err(&ctx->mdp_dev->pdev->dev,
+			"doesn't support negative values for top & left\n");
+		return -EINVAL;
+	}
+
+	mtk_mdp_dbg(2, "[%d] type:%d, set wxh:%dx%d", ctx->id, cr->type,
+		    cr->c.width, cr->c.height);
+
+	frame = mtk_mdp_ctx_get_frame(ctx, cr->type);
+	max_w = frame->width;
+	max_h = frame->height;
+	new_w = cr->c.width;
+	new_h = cr->c.height;
+
+	if (V4L2_TYPE_IS_OUTPUT(cr->type)) {
+		align_w = 1;
+		align_h = 1;
+		min_w = 64;
+		min_h = 32;
+	} else {
+		align_w = variant->pix_align->target_w;
+		align_h = variant->pix_align->target_h;
+		if (ctx->ctrls.rotate->val == 90 ||
+		    ctx->ctrls.rotate->val == 270) {
+			max_w = frame->height;
+			max_h = frame->width;
+			min_w = variant->pix_min->target_rot_en_w;
+			min_h = variant->pix_min->target_rot_en_h;
+			new_w = cr->c.height;
+			new_h = cr->c.width;
+		} else {
+			min_w = variant->pix_min->target_rot_dis_w;
+			min_h = variant->pix_min->target_rot_dis_h;
+		}
+	}
+
+	mtk_mdp_dbg(2, "[%d] align:%dx%d, min:%dx%d, new:%dx%d", ctx->id,
+		    align_w, align_h, min_w, min_h, new_w, new_h);
+
+	mtk_mdp_bound_align_image(&new_w, min_w, max_w, align_w,
+				  &new_h, min_h, max_h, align_h);
+
+	if (!V4L2_TYPE_IS_OUTPUT(cr->type) &&
+		(ctx->ctrls.rotate->val == 90 ||
+		ctx->ctrls.rotate->val == 270))
+		mtk_mdp_check_crop_change(new_h, new_w,
+					  &cr->c.width, &cr->c.height);
+	else
+		mtk_mdp_check_crop_change(new_w, new_h,
+					  &cr->c.width, &cr->c.height);
+
+	/* adjust left/top if cropping rectangle is out of bounds */
+	/* Need to add code to algin left value with 2's multiple */
+	if (cr->c.left + new_w > max_w)
+		cr->c.left = max_w - new_w;
+	if (cr->c.top + new_h > max_h)
+		cr->c.top = max_h - new_h;
+
+	if (cr->c.left & 1)
+		cr->c.left -= 1;
+
+	mtk_mdp_dbg(2, "[%d] crop l,t,w,h:%d,%d,%d,%d, max:%dx%d", ctx->id,
+		    cr->c.left, cr->c.top, cr->c.width,
+		    cr->c.height, max_w, max_h);
+	return 0;
+}
+
+static inline struct mtk_mdp_ctx *fh_to_ctx(struct v4l2_fh *fh)
+{
+	return container_of(fh, struct mtk_mdp_ctx, fh);
+}
+
+static inline struct mtk_mdp_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl)
+{
+	return container_of(ctrl->handler, struct mtk_mdp_ctx, ctrl_handler);
+}
+
+void mtk_mdp_ctx_state_lock_set(struct mtk_mdp_ctx *ctx, u32 state)
+{
+	mutex_lock(&ctx->slock);
+	ctx->state |= state;
+	mutex_unlock(&ctx->slock);
+}
+
+static void mtk_mdp_ctx_state_lock_clear(struct mtk_mdp_ctx *ctx, u32 state)
+{
+	mutex_lock(&ctx->slock);
+	ctx->state &= ~state;
+	mutex_unlock(&ctx->slock);
+}
+
+static bool mtk_mdp_ctx_state_is_set(struct mtk_mdp_ctx *ctx, u32 mask)
+{
+	bool ret;
+
+	mutex_lock(&ctx->slock);
+	ret = (ctx->state & mask) == mask;
+	mutex_unlock(&ctx->slock);
+	return ret;
+}
+
+static void mtk_mdp_ctx_lock(struct vb2_queue *vq)
+{
+	struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vq);
+
+	mutex_lock(&ctx->mdp_dev->lock);
+}
+
+static void mtk_mdp_ctx_unlock(struct vb2_queue *vq)
+{
+	struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vq);
+
+	mutex_unlock(&ctx->mdp_dev->lock);
+}
+
+static void mtk_mdp_set_frame_size(struct mtk_mdp_frame *frame, int width,
+				   int height)
+{
+	frame->width = width;
+	frame->height = height;
+	frame->crop.width = width;
+	frame->crop.height = height;
+	frame->crop.left = 0;
+	frame->crop.top = 0;
+}
+
+static int mtk_mdp_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct mtk_mdp_ctx *ctx = q->drv_priv;
+	int ret;
+
+	ret = pm_runtime_get_sync(&ctx->mdp_dev->pdev->dev);
+	if (ret < 0)
+		mtk_mdp_dbg(1, "[%d] pm_runtime_get_sync failed:%d",
+			    ctx->id, ret);
+
+	return 0;
+}
+
+static void *mtk_mdp_m2m_buf_remove(struct mtk_mdp_ctx *ctx,
+				    enum v4l2_buf_type type)
+{
+	if (V4L2_TYPE_IS_OUTPUT(type))
+		return v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+	else
+		return v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+}
+
+static void mtk_mdp_m2m_stop_streaming(struct vb2_queue *q)
+{
+	struct mtk_mdp_ctx *ctx = q->drv_priv;
+	struct vb2_buffer *vb;
+
+	vb = mtk_mdp_m2m_buf_remove(ctx, q->type);
+	while (vb != NULL) {
+		v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_ERROR);
+		vb = mtk_mdp_m2m_buf_remove(ctx, q->type);
+	}
+
+	pm_runtime_put(&ctx->mdp_dev->pdev->dev);
+}
+
+static void mtk_mdp_m2m_job_abort(void *priv)
+{
+}
+
+/* The color format (num_planes) must be already configured. */
+static void mtk_mdp_prepare_addr(struct mtk_mdp_ctx *ctx,
+				 struct vb2_buffer *vb,
+				 struct mtk_mdp_frame *frame,
+				 struct mtk_mdp_addr *addr)
+{
+	u32 pix_size, planes, i;
+
+	pix_size = frame->width * frame->height;
+	planes = min_t(u32, frame->fmt->num_planes, ARRAY_SIZE(addr->addr));
+	for (i = 0; i < planes; i++)
+		addr->addr[i] = vb2_dma_contig_plane_dma_addr(vb, i);
+
+	mtk_mdp_dbg(3, "[%d] planes:%d, size:%d, addr:%p,%p,%p",
+		    ctx->id, planes, pix_size, (void *)addr->addr[0],
+		    (void *)addr->addr[1], (void *)addr->addr[2]);
+}
+
+static void mtk_mdp_m2m_get_bufs(struct mtk_mdp_ctx *ctx)
+{
+	struct mtk_mdp_frame *s_frame, *d_frame;
+	struct vb2_buffer *src_vb, *dst_vb;
+	struct vb2_v4l2_buffer *src_vbuf, *dst_vbuf;
+
+	s_frame = &ctx->s_frame;
+	d_frame = &ctx->d_frame;
+
+	src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+	mtk_mdp_prepare_addr(ctx, src_vb, s_frame, &s_frame->addr);
+
+	dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+	mtk_mdp_prepare_addr(ctx, dst_vb, d_frame, &d_frame->addr);
+
+	src_vbuf = to_vb2_v4l2_buffer(src_vb);
+	dst_vbuf = to_vb2_v4l2_buffer(dst_vb);
+	dst_vbuf->vb2_buf.timestamp = src_vbuf->vb2_buf.timestamp;
+}
+
+static void mtk_mdp_process_done(void *priv, int vb_state)
+{
+	struct mtk_mdp_dev *mdp = priv;
+	struct mtk_mdp_ctx *ctx;
+	struct vb2_buffer *src_vb, *dst_vb;
+	struct vb2_v4l2_buffer *src_vbuf = NULL, *dst_vbuf = NULL;
+
+	ctx = v4l2_m2m_get_curr_priv(mdp->m2m_dev);
+	if (!ctx)
+		return;
+
+	src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+	src_vbuf = to_vb2_v4l2_buffer(src_vb);
+	dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+	dst_vbuf = to_vb2_v4l2_buffer(dst_vb);
+
+	dst_vbuf->vb2_buf.timestamp = src_vbuf->vb2_buf.timestamp;
+	dst_vbuf->timecode = src_vbuf->timecode;
+	dst_vbuf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+	dst_vbuf->flags |= src_vbuf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+
+	v4l2_m2m_buf_done(src_vbuf, vb_state);
+	v4l2_m2m_buf_done(dst_vbuf, vb_state);
+	v4l2_m2m_job_finish(ctx->mdp_dev->m2m_dev, ctx->m2m_ctx);
+}
+
+static void mtk_mdp_m2m_worker(struct work_struct *work)
+{
+	struct mtk_mdp_ctx *ctx =
+				container_of(work, struct mtk_mdp_ctx, work);
+	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
+	enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
+	int ret;
+
+	if (mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_CTX_ERROR)) {
+		dev_err(&mdp->pdev->dev, "ctx is in error state");
+		goto worker_end;
+	}
+
+	mtk_mdp_m2m_get_bufs(ctx);
+
+	mtk_mdp_hw_set_input_addr(ctx, &ctx->s_frame.addr);
+	mtk_mdp_hw_set_output_addr(ctx, &ctx->d_frame.addr);
+
+	mtk_mdp_hw_set_in_size(ctx);
+	mtk_mdp_hw_set_in_image_format(ctx);
+
+	mtk_mdp_hw_set_out_size(ctx);
+	mtk_mdp_hw_set_out_image_format(ctx);
+
+	mtk_mdp_hw_set_rotation(ctx);
+	mtk_mdp_hw_set_global_alpha(ctx);
+
+	ret = mtk_mdp_vpu_process(&ctx->vpu);
+	if (ret) {
+		dev_err(&mdp->pdev->dev, "processing failed: %d", ret);
+		goto worker_end;
+	}
+
+	buf_state = VB2_BUF_STATE_DONE;
+
+worker_end:
+	mtk_mdp_process_done(mdp, buf_state);
+}
+
+static void mtk_mdp_m2m_device_run(void *priv)
+{
+	struct mtk_mdp_ctx *ctx = priv;
+
+	queue_work(ctx->mdp_dev->job_wq, &ctx->work);
+}
+
+static int mtk_mdp_m2m_queue_setup(struct vb2_queue *vq,
+			unsigned int *num_buffers, unsigned int *num_planes,
+			unsigned int sizes[], struct device *alloc_devs[])
+{
+	struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vq);
+	struct mtk_mdp_frame *frame;
+	int i;
+
+	frame = mtk_mdp_ctx_get_frame(ctx, vq->type);
+	*num_planes = frame->fmt->num_planes;
+	for (i = 0; i < frame->fmt->num_planes; i++)
+		sizes[i] = frame->payload[i];
+	mtk_mdp_dbg(2, "[%d] type:%d, planes:%d, buffers:%d, size:%u,%u",
+		    ctx->id, vq->type, *num_planes, *num_buffers,
+		    sizes[0], sizes[1]);
+	return 0;
+}
+
+static int mtk_mdp_m2m_buf_prepare(struct vb2_buffer *vb)
+{
+	struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct mtk_mdp_frame *frame;
+	int i;
+
+	frame = mtk_mdp_ctx_get_frame(ctx, vb->vb2_queue->type);
+
+	if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
+		for (i = 0; i < frame->fmt->num_planes; i++)
+			vb2_set_plane_payload(vb, i, frame->payload[i]);
+	}
+
+	return 0;
+}
+
+static void mtk_mdp_m2m_buf_queue(struct vb2_buffer *vb)
+{
+	struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+	v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb));
+}
+
+static struct vb2_ops mtk_mdp_m2m_qops = {
+	.queue_setup	 = mtk_mdp_m2m_queue_setup,
+	.buf_prepare	 = mtk_mdp_m2m_buf_prepare,
+	.buf_queue	 = mtk_mdp_m2m_buf_queue,
+	.wait_prepare	 = mtk_mdp_ctx_unlock,
+	.wait_finish	 = mtk_mdp_ctx_lock,
+	.stop_streaming	 = mtk_mdp_m2m_stop_streaming,
+	.start_streaming = mtk_mdp_m2m_start_streaming,
+};
+
+static int mtk_mdp_m2m_querycap(struct file *file, void *fh,
+				struct v4l2_capability *cap)
+{
+	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
+	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
+
+	strlcpy(cap->driver, MTK_MDP_MODULE_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, mdp->pdev->name, sizeof(cap->card));
+	strlcpy(cap->bus_info, "platform:mt8173", sizeof(cap->bus_info));
+
+	return 0;
+}
+
+static int mtk_mdp_enum_fmt_mplane(struct v4l2_fmtdesc *f, u32 type)
+{
+	const struct mtk_mdp_fmt *fmt;
+
+	fmt = mtk_mdp_find_fmt_by_index(f->index, type);
+	if (!fmt)
+		return -EINVAL;
+
+	f->pixelformat = fmt->pixelformat;
+
+	return 0;
+}
+
+static int mtk_mdp_m2m_enum_fmt_mplane_vid_cap(struct file *file, void *priv,
+				       struct v4l2_fmtdesc *f)
+{
+	return mtk_mdp_enum_fmt_mplane(f, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+}
+
+static int mtk_mdp_m2m_enum_fmt_mplane_vid_out(struct file *file, void *priv,
+				       struct v4l2_fmtdesc *f)
+{
+	return mtk_mdp_enum_fmt_mplane(f, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+}
+
+static int mtk_mdp_g_fmt_mplane(struct mtk_mdp_ctx *ctx, struct v4l2_format *f)
+{
+	struct mtk_mdp_frame *frame;
+	struct v4l2_pix_format_mplane *pix_mp;
+	int i;
+
+	mtk_mdp_dbg(2, "[%d] type:%d", ctx->id, f->type);
+
+	frame = mtk_mdp_ctx_get_frame(ctx, f->type);
+	pix_mp = &f->fmt.pix_mp;
+
+	pix_mp->width = frame->width;
+	pix_mp->height = frame->height;
+	pix_mp->field = V4L2_FIELD_NONE;
+	pix_mp->pixelformat = frame->fmt->pixelformat;
+	pix_mp->num_planes = frame->fmt->num_planes;
+	pix_mp->colorspace = ctx->colorspace;
+	pix_mp->xfer_func = ctx->xfer_func;
+	pix_mp->ycbcr_enc = ctx->ycbcr_enc;
+	pix_mp->quantization = ctx->quant;
+	mtk_mdp_dbg(2, "[%d] wxh:%dx%d", ctx->id,
+		    pix_mp->width, pix_mp->height);
+
+	for (i = 0; i < pix_mp->num_planes; ++i) {
+		pix_mp->plane_fmt[i].bytesperline = (frame->width *
+			frame->fmt->depth[i]) / 8;
+		pix_mp->plane_fmt[i].sizeimage =
+			 pix_mp->plane_fmt[i].bytesperline * frame->height;
+
+		mtk_mdp_dbg(2, "[%d] p%d, bpl:%d, sizeimage:%d", ctx->id, i,
+			    pix_mp->plane_fmt[i].bytesperline,
+			    pix_mp->plane_fmt[i].sizeimage);
+	}
+
+	return 0;
+}
+
+static int mtk_mdp_m2m_g_fmt_mplane(struct file *file, void *fh,
+				    struct v4l2_format *f)
+{
+	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
+
+	return mtk_mdp_g_fmt_mplane(ctx, f);
+}
+
+static int mtk_mdp_m2m_try_fmt_mplane(struct file *file, void *fh,
+				      struct v4l2_format *f)
+{
+	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
+
+	if (!mtk_mdp_try_fmt_mplane(ctx, f))
+		return -EINVAL;
+	return 0;
+}
+
+static int mtk_mdp_m2m_s_fmt_mplane(struct file *file, void *fh,
+				    struct v4l2_format *f)
+{
+	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
+	struct vb2_queue *vq;
+	struct mtk_mdp_frame *frame;
+	struct v4l2_pix_format_mplane *pix_mp;
+	const struct mtk_mdp_fmt *fmt;
+	int i;
+
+	mtk_mdp_dbg(2, "[%d] type:%d", ctx->id, f->type);
+
+	frame = mtk_mdp_ctx_get_frame(ctx, f->type);
+	fmt = mtk_mdp_try_fmt_mplane(ctx, f);
+	if (!fmt) {
+		mtk_mdp_err("[%d] try_fmt failed, type:%d", ctx->id, f->type);
+		return -EINVAL;
+	}
+	frame->fmt = fmt;
+
+	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+	if (vb2_is_streaming(vq)) {
+		dev_info(&ctx->mdp_dev->pdev->dev, "queue %d busy", f->type);
+		return -EBUSY;
+	}
+
+	pix_mp = &f->fmt.pix_mp;
+	for (i = 0; i < frame->fmt->num_planes; i++) {
+		frame->payload[i] = pix_mp->plane_fmt[i].sizeimage;
+		frame->pitch[i] = pix_mp->plane_fmt[i].bytesperline;
+	}
+
+	mtk_mdp_set_frame_size(frame, pix_mp->width, pix_mp->height);
+	if (V4L2_TYPE_IS_OUTPUT(f->type)) {
+		ctx->colorspace = pix_mp->colorspace;
+		ctx->xfer_func = pix_mp->xfer_func;
+		ctx->ycbcr_enc = pix_mp->ycbcr_enc;
+		ctx->quant = pix_mp->quantization;
+	}
+
+	if (V4L2_TYPE_IS_OUTPUT(f->type))
+		mtk_mdp_ctx_state_lock_set(ctx, MTK_MDP_SRC_FMT);
+	else
+		mtk_mdp_ctx_state_lock_set(ctx, MTK_MDP_DST_FMT);
+
+	mtk_mdp_dbg(2, "[%d] type:%d, frame:%dx%d", ctx->id, f->type,
+		    frame->width, frame->height);
+
+	return 0;
+}
+
+static int mtk_mdp_m2m_reqbufs(struct file *file, void *fh,
+			       struct v4l2_requestbuffers *reqbufs)
+{
+	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
+
+	if (reqbufs->count == 0) {
+		if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+			mtk_mdp_ctx_state_lock_clear(ctx, MTK_MDP_SRC_FMT);
+		else
+			mtk_mdp_ctx_state_lock_clear(ctx, MTK_MDP_DST_FMT);
+	}
+
+	return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int mtk_mdp_m2m_streamon(struct file *file, void *fh,
+				enum v4l2_buf_type type)
+{
+	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
+	int ret;
+
+	/* The source and target color format need to be set */
+	if (V4L2_TYPE_IS_OUTPUT(type)) {
+		if (!mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_SRC_FMT))
+			return -EINVAL;
+	} else if (!mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_DST_FMT)) {
+		return -EINVAL;
+	}
+
+	if (!mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_VPU_INIT)) {
+		ret = mtk_mdp_vpu_init(&ctx->vpu);
+		if (ret < 0) {
+			dev_err(&ctx->mdp_dev->pdev->dev,
+				"vpu init failed %d\n",
+				ret);
+			return -EINVAL;
+		}
+		mtk_mdp_ctx_state_lock_set(ctx, MTK_MDP_VPU_INIT);
+	}
+
+	return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+/*
+ * Return true if rectangle a is enclosed in rectangle b, or false otherwise.
+ */
+static bool mtk_mdp_m2m_is_rectangle_enclosed(struct v4l2_rect *a,
+					     struct v4l2_rect *b)
+{
+	if (a->left < b->left || a->top < b->top)
+		return false;
+
+	if (a->left + a->width > b->left + b->width)
+		return false;
+
+	if (a->top + a->height > b->top + b->height)
+		return false;
+
+	return true;
+}
+
+static int mtk_mdp_m2m_g_selection(struct file *file, void *fh,
+				   struct v4l2_selection *s)
+{
+	struct mtk_mdp_frame *frame;
+	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
+
+	if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+	    (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)) {
+		mtk_mdp_dbg(1, "[%d] invalid type:%d", ctx->id, s->type);
+		return -EINVAL;
+	}
+
+	frame = mtk_mdp_ctx_get_frame(ctx, s->type);
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+		s->r.left = 0;
+		s->r.top = 0;
+		s->r.width = frame->width;
+		s->r.height = frame->height;
+		return 0;
+
+	case V4L2_SEL_TGT_COMPOSE:
+	case V4L2_SEL_TGT_CROP:
+		s->r.left = frame->crop.left;
+		s->r.top = frame->crop.top;
+		s->r.width = frame->crop.width;
+		s->r.height = frame->crop.height;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int mtk_mdp_check_scaler_ratio(struct mtk_mdp_variant *var, int src_w,
+				      int src_h, int dst_w, int dst_h, int rot)
+{
+	int tmp_w, tmp_h;
+
+	if (rot == 90 || rot == 270) {
+		tmp_w = dst_h;
+		tmp_h = dst_w;
+	} else {
+		tmp_w = dst_w;
+		tmp_h = dst_h;
+	}
+
+	if ((src_w / tmp_w) > var->h_scale_down_max ||
+	    (src_h / tmp_h) > var->v_scale_down_max ||
+	    (tmp_w / src_w) > var->h_scale_up_max ||
+	    (tmp_h / src_h) > var->v_scale_up_max)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int mtk_mdp_m2m_s_selection(struct file *file, void *fh,
+				   struct v4l2_selection *s)
+{
+	struct mtk_mdp_frame *frame;
+	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
+	struct v4l2_crop cr;
+	struct mtk_mdp_variant *variant = ctx->mdp_dev->variant;
+	int ret;
+
+	cr.type = s->type;
+	cr.c = s->r;
+
+	if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+	    (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)) {
+		mtk_mdp_dbg(1, "[%d] invalid type:%d", ctx->id, s->type);
+		return -EINVAL;
+	}
+
+	ret = mtk_mdp_try_crop(ctx, &cr);
+	if (ret)
+		return ret;
+
+	if (s->flags & V4L2_SEL_FLAG_LE &&
+	    !mtk_mdp_m2m_is_rectangle_enclosed(&cr.c, &s->r))
+		return -ERANGE;
+
+	if (s->flags & V4L2_SEL_FLAG_GE &&
+	    !mtk_mdp_m2m_is_rectangle_enclosed(&s->r, &cr.c))
+		return -ERANGE;
+
+	s->r = cr.c;
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE:
+		frame = &ctx->s_frame;
+		break;
+
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+	case V4L2_SEL_TGT_CROP:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+		frame = &ctx->d_frame;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Check to see if scaling ratio is within supported range */
+	if (mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_DST_FMT | MTK_MDP_SRC_FMT)) {
+		if (V4L2_TYPE_IS_OUTPUT(s->type)) {
+			ret = mtk_mdp_check_scaler_ratio(variant, cr.c.width,
+				cr.c.height, ctx->d_frame.crop.width,
+				ctx->d_frame.crop.height,
+				ctx->ctrls.rotate->val);
+		} else {
+			ret = mtk_mdp_check_scaler_ratio(variant,
+				ctx->s_frame.crop.width,
+				ctx->s_frame.crop.height, cr.c.width,
+				cr.c.height, ctx->ctrls.rotate->val);
+		}
+
+		if (ret) {
+			dev_info(&ctx->mdp_dev->pdev->dev,
+				"Out of scaler range");
+			return -EINVAL;
+		}
+	}
+
+	frame->crop = cr.c;
+
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops mtk_mdp_m2m_ioctl_ops = {
+	.vidioc_querycap		= mtk_mdp_m2m_querycap,
+	.vidioc_enum_fmt_vid_cap_mplane	= mtk_mdp_m2m_enum_fmt_mplane_vid_cap,
+	.vidioc_enum_fmt_vid_out_mplane	= mtk_mdp_m2m_enum_fmt_mplane_vid_out,
+	.vidioc_g_fmt_vid_cap_mplane	= mtk_mdp_m2m_g_fmt_mplane,
+	.vidioc_g_fmt_vid_out_mplane	= mtk_mdp_m2m_g_fmt_mplane,
+	.vidioc_try_fmt_vid_cap_mplane	= mtk_mdp_m2m_try_fmt_mplane,
+	.vidioc_try_fmt_vid_out_mplane	= mtk_mdp_m2m_try_fmt_mplane,
+	.vidioc_s_fmt_vid_cap_mplane	= mtk_mdp_m2m_s_fmt_mplane,
+	.vidioc_s_fmt_vid_out_mplane	= mtk_mdp_m2m_s_fmt_mplane,
+	.vidioc_reqbufs			= mtk_mdp_m2m_reqbufs,
+	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,
+	.vidioc_expbuf			= v4l2_m2m_ioctl_expbuf,
+	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
+	.vidioc_querybuf		= v4l2_m2m_ioctl_querybuf,
+	.vidioc_qbuf			= v4l2_m2m_ioctl_qbuf,
+	.vidioc_dqbuf			= v4l2_m2m_ioctl_dqbuf,
+	.vidioc_streamon		= mtk_mdp_m2m_streamon,
+	.vidioc_streamoff		= v4l2_m2m_ioctl_streamoff,
+	.vidioc_g_selection		= mtk_mdp_m2m_g_selection,
+	.vidioc_s_selection		= mtk_mdp_m2m_s_selection
+};
+
+static int mtk_mdp_m2m_queue_init(void *priv, struct vb2_queue *src_vq,
+				  struct vb2_queue *dst_vq)
+{
+	struct mtk_mdp_ctx *ctx = priv;
+	int ret;
+
+	memset(src_vq, 0, sizeof(*src_vq));
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+	src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+	src_vq->drv_priv = ctx;
+	src_vq->ops = &mtk_mdp_m2m_qops;
+	src_vq->mem_ops = &vb2_dma_contig_memops;
+	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	src_vq->dev = &ctx->mdp_dev->pdev->dev;
+
+	ret = vb2_queue_init(src_vq);
+	if (ret)
+		return ret;
+
+	memset(dst_vq, 0, sizeof(*dst_vq));
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+	dst_vq->drv_priv = ctx;
+	dst_vq->ops = &mtk_mdp_m2m_qops;
+	dst_vq->mem_ops = &vb2_dma_contig_memops;
+	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	dst_vq->dev = &ctx->mdp_dev->pdev->dev;
+
+	return vb2_queue_init(dst_vq);
+}
+
+static int mtk_mdp_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct mtk_mdp_ctx *ctx = ctrl_to_ctx(ctrl);
+	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
+	struct mtk_mdp_variant *variant = mdp->variant;
+	u32 state = MTK_MDP_DST_FMT | MTK_MDP_SRC_FMT;
+	int ret = 0;
+
+	if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
+		return 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_HFLIP:
+		ctx->hflip = ctrl->val;
+		break;
+	case V4L2_CID_VFLIP:
+		ctx->vflip = ctrl->val;
+		break;
+	case V4L2_CID_ROTATE:
+		if (mtk_mdp_ctx_state_is_set(ctx, state)) {
+			ret = mtk_mdp_check_scaler_ratio(variant,
+					ctx->s_frame.crop.width,
+					ctx->s_frame.crop.height,
+					ctx->d_frame.crop.width,
+					ctx->d_frame.crop.height,
+					ctx->ctrls.rotate->val);
+
+			if (ret)
+				return -EINVAL;
+		}
+
+		ctx->rotation = ctrl->val;
+		break;
+	case V4L2_CID_ALPHA_COMPONENT:
+		ctx->d_frame.alpha = ctrl->val;
+		break;
+	}
+
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops mtk_mdp_ctrl_ops = {
+	.s_ctrl = mtk_mdp_s_ctrl,
+};
+
+static int mtk_mdp_ctrls_create(struct mtk_mdp_ctx *ctx)
+{
+	v4l2_ctrl_handler_init(&ctx->ctrl_handler, MTK_MDP_MAX_CTRL_NUM);
+
+	ctx->ctrls.rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+			&mtk_mdp_ctrl_ops, V4L2_CID_ROTATE, 0, 270, 90, 0);
+	ctx->ctrls.hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+					     &mtk_mdp_ctrl_ops,
+					     V4L2_CID_HFLIP,
+					     0, 1, 1, 0);
+	ctx->ctrls.vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+					     &mtk_mdp_ctrl_ops,
+					     V4L2_CID_VFLIP,
+					     0, 1, 1, 0);
+	ctx->ctrls.global_alpha = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+						    &mtk_mdp_ctrl_ops,
+						    V4L2_CID_ALPHA_COMPONENT,
+						    0, 255, 1, 0);
+	ctx->ctrls_rdy = ctx->ctrl_handler.error == 0;
+
+	if (ctx->ctrl_handler.error) {
+		int err = ctx->ctrl_handler.error;
+
+		v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+		dev_err(&ctx->mdp_dev->pdev->dev,
+			"Failed to create control handlers\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static void mtk_mdp_set_default_params(struct mtk_mdp_ctx *ctx)
+{
+	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
+	struct mtk_mdp_frame *frame;
+
+	frame = mtk_mdp_ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+	frame->fmt = mtk_mdp_find_fmt_by_index(0,
+					V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+	frame->width = mdp->variant->pix_min->org_w;
+	frame->height = mdp->variant->pix_min->org_h;
+	frame->payload[0] = frame->width * frame->height;
+	frame->payload[1] = frame->payload[0] / 2;
+
+	frame = mtk_mdp_ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+	frame->fmt = mtk_mdp_find_fmt_by_index(0,
+					V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+	frame->width = mdp->variant->pix_min->target_rot_dis_w;
+	frame->height = mdp->variant->pix_min->target_rot_dis_h;
+	frame->payload[0] = frame->width * frame->height;
+	frame->payload[1] = frame->payload[0] / 2;
+
+}
+
+static int mtk_mdp_m2m_open(struct file *file)
+{
+	struct mtk_mdp_dev *mdp = video_drvdata(file);
+	struct video_device *vfd = video_devdata(file);
+	struct mtk_mdp_ctx *ctx = NULL;
+	int ret;
+
+	if (mutex_lock_interruptible(&mdp->lock))
+		return -ERESTARTSYS;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx) {
+		ret = -ENOMEM;
+		goto err_ctx_alloc;
+	}
+
+	mutex_init(&ctx->slock);
+	ctx->id = mdp->id_counter++;
+	v4l2_fh_init(&ctx->fh, vfd);
+	file->private_data = &ctx->fh;
+	ret = mtk_mdp_ctrls_create(ctx);
+	if (ret)
+		goto error_ctrls;
+
+	/* Use separate control handler per file handle */
+	ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+	v4l2_fh_add(&ctx->fh);
+	INIT_LIST_HEAD(&ctx->list);
+
+	ctx->mdp_dev = mdp;
+	mtk_mdp_set_default_params(ctx);
+
+	INIT_WORK(&ctx->work, mtk_mdp_m2m_worker);
+	ctx->m2m_ctx = v4l2_m2m_ctx_init(mdp->m2m_dev, ctx,
+					 mtk_mdp_m2m_queue_init);
+	if (IS_ERR(ctx->m2m_ctx)) {
+		dev_err(&mdp->pdev->dev, "Failed to initialize m2m context");
+		ret = PTR_ERR(ctx->m2m_ctx);
+		goto error_m2m_ctx;
+	}
+	ctx->fh.m2m_ctx = ctx->m2m_ctx;
+	if (mdp->ctx_num++ == 0) {
+		ret = vpu_load_firmware(mdp->vpu_dev);
+		if (ret < 0) {
+			dev_err(&mdp->pdev->dev,
+				"vpu_load_firmware failed %d\n", ret);
+			goto err_load_vpu;
+		}
+
+		ret = mtk_mdp_vpu_register(mdp->pdev);
+		if (ret < 0) {
+			dev_err(&mdp->pdev->dev,
+				"mdp_vpu register failed %d\n", ret);
+			goto err_load_vpu;
+		}
+	}
+
+	list_add(&ctx->list, &mdp->ctx_list);
+	mutex_unlock(&mdp->lock);
+
+	mtk_mdp_dbg(0, "%s [%d]", dev_name(&mdp->pdev->dev), ctx->id);
+
+	return 0;
+
+err_load_vpu:
+	mdp->ctx_num--;
+	v4l2_m2m_ctx_release(ctx->m2m_ctx);
+error_m2m_ctx:
+	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+error_ctrls:
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+err_ctx_alloc:
+	kfree(ctx);
+	mutex_unlock(&mdp->lock);
+
+	return ret;
+}
+
+static int mtk_mdp_m2m_release(struct file *file)
+{
+	struct mtk_mdp_ctx *ctx = fh_to_ctx(file->private_data);
+	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
+
+	flush_workqueue(mdp->job_wq);
+	mutex_lock(&mdp->lock);
+	v4l2_m2m_ctx_release(ctx->m2m_ctx);
+	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	mtk_mdp_vpu_deinit(&ctx->vpu);
+	mdp->ctx_num--;
+	list_del_init(&ctx->list);
+
+	mtk_mdp_dbg(0, "%s [%d]", dev_name(&mdp->pdev->dev), ctx->id);
+
+	mutex_unlock(&mdp->lock);
+	kfree(ctx);
+
+	return 0;
+}
+
+static const struct v4l2_file_operations mtk_mdp_m2m_fops = {
+	.owner		= THIS_MODULE,
+	.open		= mtk_mdp_m2m_open,
+	.release	= mtk_mdp_m2m_release,
+	.poll		= v4l2_m2m_fop_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= v4l2_m2m_fop_mmap,
+};
+
+static struct v4l2_m2m_ops mtk_mdp_m2m_ops = {
+	.device_run	= mtk_mdp_m2m_device_run,
+	.job_abort	= mtk_mdp_m2m_job_abort,
+};
+
+int mtk_mdp_register_m2m_device(struct mtk_mdp_dev *mdp)
+{
+	struct device *dev = &mdp->pdev->dev;
+	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",
+		 MTK_MDP_MODULE_NAME);
+	video_set_drvdata(&mdp->vdev, mdp);
+
+	mdp->m2m_dev = v4l2_m2m_init(&mtk_mdp_m2m_ops);
+	if (IS_ERR(mdp->m2m_dev)) {
+		dev_err(dev, "failed to initialize v4l2-m2m device\n");
+		ret = PTR_ERR(mdp->m2m_dev);
+		goto err_m2m_init;
+	}
+
+	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);
+	return 0;
+
+err_vdev_register:
+	v4l2_m2m_release(mdp->m2m_dev);
+err_m2m_init:
+	video_device_release(&mdp->vdev);
+
+	return ret;
+}
+
+void mtk_mdp_unregister_m2m_device(struct mtk_mdp_dev *mdp)
+{
+	video_device_release(&mdp->vdev);
+	v4l2_m2m_release(mdp->m2m_dev);
+}
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h
new file mode 100644
index 0000000..45afd36
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __MTK_MDP_M2M_H__
+#define __MTK_MDP_M2M_H__
+
+void mtk_mdp_ctx_state_lock_set(struct mtk_mdp_ctx *ctx, u32 state);
+int mtk_mdp_register_m2m_device(struct mtk_mdp_dev *mdp);
+void mtk_mdp_unregister_m2m_device(struct mtk_mdp_dev *mdp);
+
+#endif /* __MTK_MDP_M2M_H__ */
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_regs.c b/drivers/media/platform/mtk-mdp/mtk_mdp_regs.c
new file mode 100644
index 0000000..063e7b1
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_regs.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2015-2016 MediaTek Inc.
+ * Author: Houlong Wei <houlong.wei at mediatek.com>
+ *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/platform_device.h>
+
+#include "mtk_mdp_core.h"
+#include "mtk_mdp_regs.h"
+
+
+#define MDP_COLORFMT_PACK(VIDEO, PLANE, COPLANE, HF, VF, BITS, GROUP, SWAP, ID)\
+	(((VIDEO) << 27) | ((PLANE) << 24) | ((COPLANE) << 22) |\
+	((HF) << 20) | ((VF) << 18) | ((BITS) << 8) | ((GROUP) << 6) |\
+	((SWAP) << 5) | ((ID) << 0))
+
+enum MDP_COLOR_ENUM {
+	MDP_COLOR_UNKNOWN = 0,
+	MDP_COLOR_NV12 = MDP_COLORFMT_PACK(0, 2, 1, 1, 1, 8, 1, 0, 12),
+	MDP_COLOR_I420 = MDP_COLORFMT_PACK(0, 3, 0, 1, 1, 8, 1, 0, 8),
+	/* Mediatek proprietary format */
+	MDP_COLOR_420_MT21 = MDP_COLORFMT_PACK(5, 2, 1, 1, 1, 256, 1, 0, 12),
+};
+
+static int32_t mtk_mdp_map_color_format(int v4l2_format)
+{
+	switch (v4l2_format) {
+	case V4L2_PIX_FMT_NV12M:
+	case V4L2_PIX_FMT_NV12:
+		return MDP_COLOR_NV12;
+	case V4L2_PIX_FMT_MT21:
+		return MDP_COLOR_420_MT21;
+	case V4L2_PIX_FMT_YUV420M:
+	case V4L2_PIX_FMT_YUV420:
+		return MDP_COLOR_I420;
+	}
+
+	mtk_mdp_err("Unknown format 0x%x", v4l2_format);
+
+	return MDP_COLOR_UNKNOWN;
+}
+
+void mtk_mdp_hw_set_input_addr(struct mtk_mdp_ctx *ctx,
+			       struct mtk_mdp_addr *addr)
+{
+	struct mdp_buffer *src_buf = &ctx->vpu.vsi->src_buffer;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(addr->addr); i++)
+		src_buf->addr_mva[i] = (uint64_t)addr->addr[i];
+}
+
+void mtk_mdp_hw_set_output_addr(struct mtk_mdp_ctx *ctx,
+				struct mtk_mdp_addr *addr)
+{
+	struct mdp_buffer *dst_buf = &ctx->vpu.vsi->dst_buffer;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(addr->addr); i++)
+		dst_buf->addr_mva[i] = (uint64_t)addr->addr[i];
+}
+
+void mtk_mdp_hw_set_in_size(struct mtk_mdp_ctx *ctx)
+{
+	struct mtk_mdp_frame *frame = &ctx->s_frame;
+	struct mdp_config *config = &ctx->vpu.vsi->src_config;
+
+	/* Set input pixel offset */
+	config->crop_x = frame->crop.left;
+	config->crop_y = frame->crop.top;
+
+	/* Set input cropped size */
+	config->crop_w = frame->crop.width;
+	config->crop_h = frame->crop.height;
+
+	/* Set input original size */
+	config->x = 0;
+	config->y = 0;
+	config->w = frame->width;
+	config->h = frame->height;
+}
+
+void mtk_mdp_hw_set_in_image_format(struct mtk_mdp_ctx *ctx)
+{
+	unsigned int i;
+	struct mtk_mdp_frame *frame = &ctx->s_frame;
+	struct mdp_config *config = &ctx->vpu.vsi->src_config;
+	struct mdp_buffer *src_buf = &ctx->vpu.vsi->src_buffer;
+
+	src_buf->plane_num = frame->fmt->num_planes;
+	config->format = mtk_mdp_map_color_format(frame->fmt->pixelformat);
+	config->w_stride = 0; /* MDP will calculate it by color format. */
+	config->h_stride = 0; /* MDP will calculate it by color format. */
+
+	for (i = 0; i < src_buf->plane_num; i++)
+		src_buf->plane_size[i] = frame->payload[i];
+}
+
+void mtk_mdp_hw_set_out_size(struct mtk_mdp_ctx *ctx)
+{
+	struct mtk_mdp_frame *frame = &ctx->d_frame;
+	struct mdp_config *config = &ctx->vpu.vsi->dst_config;
+
+	config->crop_x = frame->crop.left;
+	config->crop_y = frame->crop.top;
+	config->crop_w = frame->crop.width;
+	config->crop_h = frame->crop.height;
+	config->x = 0;
+	config->y = 0;
+	config->w = frame->width;
+	config->h = frame->height;
+}
+
+void mtk_mdp_hw_set_out_image_format(struct mtk_mdp_ctx *ctx)
+{
+	unsigned int i;
+	struct mtk_mdp_frame *frame = &ctx->d_frame;
+	struct mdp_config *config = &ctx->vpu.vsi->dst_config;
+	struct mdp_buffer *dst_buf = &ctx->vpu.vsi->dst_buffer;
+
+	dst_buf->plane_num = frame->fmt->num_planes;
+	config->format = mtk_mdp_map_color_format(frame->fmt->pixelformat);
+	config->w_stride = 0; /* MDP will calculate it by color format. */
+	config->h_stride = 0; /* MDP will calculate it by color format. */
+	for (i = 0; i < dst_buf->plane_num; i++)
+		dst_buf->plane_size[i] = frame->payload[i];
+}
+
+void mtk_mdp_hw_set_rotation(struct mtk_mdp_ctx *ctx)
+{
+	struct mdp_config_misc *misc = &ctx->vpu.vsi->misc;
+
+	misc->orientation = ctx->ctrls.rotate->val;
+	misc->hflip = ctx->ctrls.hflip->val;
+	misc->vflip = ctx->ctrls.vflip->val;
+}
+
+void mtk_mdp_hw_set_global_alpha(struct mtk_mdp_ctx *ctx)
+{
+	struct mdp_config_misc *misc = &ctx->vpu.vsi->misc;
+
+	misc->alpha = ctx->ctrls.global_alpha->val;
+}
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_regs.h b/drivers/media/platform/mtk-mdp/mtk_mdp_regs.h
new file mode 100644
index 0000000..42bd057
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_regs.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __MTK_MDP_REGS_H__
+#define __MTK_MDP_REGS_H__
+
+
+void mtk_mdp_hw_set_input_addr(struct mtk_mdp_ctx *ctx,
+			       struct mtk_mdp_addr *addr);
+void mtk_mdp_hw_set_output_addr(struct mtk_mdp_ctx *ctx,
+				struct mtk_mdp_addr *addr);
+void mtk_mdp_hw_set_in_size(struct mtk_mdp_ctx *ctx);
+void mtk_mdp_hw_set_in_image_format(struct mtk_mdp_ctx *ctx);
+void mtk_mdp_hw_set_out_size(struct mtk_mdp_ctx *ctx);
+void mtk_mdp_hw_set_out_image_format(struct mtk_mdp_ctx *ctx);
+void mtk_mdp_hw_set_rotation(struct mtk_mdp_ctx *ctx);
+void mtk_mdp_hw_set_global_alpha(struct mtk_mdp_ctx *ctx);
+
+
+#endif /* __MTK_MDP_REGS_H__ */
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c b/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c
new file mode 100644
index 0000000..fb07bf3
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2015-2016 MediaTek Inc.
+ * Author: Houlong Wei <houlong.wei at mediatek.com>
+ *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include "mtk_mdp_core.h"
+#include "mtk_mdp_vpu.h"
+#include "mtk_vpu.h"
+
+
+static inline struct mtk_mdp_ctx *vpu_to_ctx(struct mtk_mdp_vpu *vpu)
+{
+	return container_of(vpu, struct mtk_mdp_ctx, vpu);
+}
+
+static void mtk_mdp_vpu_handle_init_ack(struct mdp_ipi_comm_ack *msg)
+{
+	struct mtk_mdp_vpu *vpu = (struct mtk_mdp_vpu *)msg->ap_inst;
+
+	/* mapping VPU address to kernel virtual address */
+	vpu->vsi = (struct mdp_process_vsi *)
+			vpu_mapping_dm_addr(vpu->pdev, msg->vpu_inst_addr);
+	vpu->inst_addr = msg->vpu_inst_addr;
+}
+
+static void mtk_mdp_vpu_ipi_handler(void *data, unsigned int len, void *priv)
+{
+	unsigned int msg_id = *(unsigned int *)data;
+	struct mdp_ipi_comm_ack *msg = (struct mdp_ipi_comm_ack *)data;
+	struct mtk_mdp_vpu *vpu = (struct mtk_mdp_vpu *)msg->ap_inst;
+	struct mtk_mdp_ctx *ctx;
+
+	vpu->failure = msg->status;
+	if (!vpu->failure) {
+		switch (msg_id) {
+		case VPU_MDP_INIT_ACK:
+			mtk_mdp_vpu_handle_init_ack(data);
+			break;
+		case VPU_MDP_DEINIT_ACK:
+		case VPU_MDP_PROCESS_ACK:
+			break;
+		default:
+			ctx = vpu_to_ctx(vpu);
+			dev_err(&ctx->mdp_dev->pdev->dev,
+				"handle unknown ipi msg:0x%x\n",
+				msg_id);
+			break;
+		}
+	} else {
+		ctx = vpu_to_ctx(vpu);
+		mtk_mdp_dbg(0, "[%d]:msg 0x%x, failure:%d", ctx->id,
+			    msg_id, vpu->failure);
+	}
+}
+
+int mtk_mdp_vpu_register(struct platform_device *pdev)
+{
+	struct mtk_mdp_dev *mdp = platform_get_drvdata(pdev);
+	int err;
+
+	err = vpu_ipi_register(mdp->vpu_dev, IPI_MDP,
+			       mtk_mdp_vpu_ipi_handler, "mdp_vpu", NULL);
+	if (err)
+		dev_err(&mdp->pdev->dev,
+			"vpu_ipi_registration fail status=%d\n", err);
+
+	return err;
+}
+
+static int mtk_mdp_vpu_send_msg(void *msg, int len, struct mtk_mdp_vpu *vpu,
+				int id)
+{
+	struct mtk_mdp_ctx *ctx = vpu_to_ctx(vpu);
+	int err;
+
+	if (!vpu->pdev) {
+		mtk_mdp_dbg(1, "[%d]:vpu pdev is NULL", ctx->id);
+		return -EINVAL;
+	}
+
+	mutex_lock(&ctx->mdp_dev->vpulock);
+	err = vpu_ipi_send(vpu->pdev, (enum ipi_id)id, msg, len);
+	if (err) {
+		mutex_unlock(&ctx->mdp_dev->vpulock);
+		dev_err(&ctx->mdp_dev->pdev->dev,
+			"vpu_ipi_send fail status %d\n", err);
+	}
+	mutex_unlock(&ctx->mdp_dev->vpulock);
+
+	return err;
+}
+
+static int mtk_mdp_vpu_send_ap_ipi(struct mtk_mdp_vpu *vpu, uint32_t msg_id)
+{
+	int err;
+	struct mdp_ipi_comm msg;
+
+	msg.msg_id = msg_id;
+	msg.ipi_id = IPI_MDP;
+	msg.vpu_inst_addr = vpu->inst_addr;
+	msg.ap_inst = (uint64_t)vpu;
+	err = mtk_mdp_vpu_send_msg((void *)&msg, sizeof(msg), vpu, IPI_MDP);
+	if (!err && vpu->failure)
+		err = -EINVAL;
+
+	return err;
+}
+
+int mtk_mdp_vpu_init(struct mtk_mdp_vpu *vpu)
+{
+	int err;
+	struct mdp_ipi_init msg;
+	struct mtk_mdp_ctx *ctx = vpu_to_ctx(vpu);
+
+	vpu->pdev = ctx->mdp_dev->vpu_dev;
+
+	msg.msg_id = AP_MDP_INIT;
+	msg.ipi_id = IPI_MDP;
+	msg.ap_inst = (uint64_t)vpu;
+	err = mtk_mdp_vpu_send_msg((void *)&msg, sizeof(msg), vpu, IPI_MDP);
+	if (!err && vpu->failure)
+		err = -EINVAL;
+
+	return err;
+}
+
+int mtk_mdp_vpu_deinit(struct mtk_mdp_vpu *vpu)
+{
+	return mtk_mdp_vpu_send_ap_ipi(vpu, AP_MDP_DEINIT);
+}
+
+int mtk_mdp_vpu_process(struct mtk_mdp_vpu *vpu)
+{
+	return mtk_mdp_vpu_send_ap_ipi(vpu, AP_MDP_PROCESS);
+}
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h b/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h
new file mode 100644
index 0000000..df4bdda
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015-2016 MediaTek Inc.
+ * Author: Houlong Wei <houlong.wei at mediatek.com>
+ *         Ming Hsiu Tsai <minghsiu.tsai at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __MTK_MDP_VPU_H__
+#define __MTK_MDP_VPU_H__
+
+#include "mtk_mdp_ipi.h"
+
+
+/**
+ * struct mtk_mdp_vpu - VPU instance for MDP
+ * @pdev	: pointer to the VPU platform device
+ * @inst_addr	: VPU MDP instance address
+ * @failure	: VPU execution result status
+ * @vsi		: VPU shared information
+ */
+struct mtk_mdp_vpu {
+	struct platform_device	*pdev;
+	uint32_t		inst_addr;
+	int32_t			failure;
+	struct mdp_process_vsi	*vsi;
+};
+
+int mtk_mdp_vpu_register(struct platform_device *pdev);
+int mtk_mdp_vpu_init(struct mtk_mdp_vpu *vpu);
+int mtk_mdp_vpu_deinit(struct mtk_mdp_vpu *vpu);
+int mtk_mdp_vpu_process(struct mtk_mdp_vpu *vpu);
+
+#endif /* __MTK_MDP_VPU_H__ */
-- 
1.7.9.5



From elfring at users.sourceforge.net  Fri Jul 22 03:56:23 2016
From: elfring at users.sourceforge.net (SF Markus Elfring)
Date: Fri, 22 Jul 2016 12:56:23 +0200
Subject: [PATCH] GPU-DRM: Delete an unnecessary check before
 drm_property_unreference_blob()
In-Reply-To: <5317A59D.4@users.sourceforge.net>
References: <5307CAA2.8060406@users.sourceforge.net>
 <alpine.DEB.2.02.1402212321410.2043@localhost6.localdomain6>
 <530A086E.8010901@users.sourceforge.net>
 <alpine.DEB.2.02.1402231635510.1985@localhost6.localdomain6>
 <530A72AA.3000601@users.sourceforge.net>
 <alpine.DEB.2.02.1402240658210.2090@localhost6.localdomain6>
 <530B5FB6.6010207@users.sourceforge.net>
 <alpine.DEB.2.10.1402241710370.2074@hadrien>
 <530C5E18.1020800@users.sourceforge.net>
 <alpine.DEB.2.10.1402251014170.2080@hadrien>
 <530CD2C4.4050903@users.sourceforge.net>
 <alpine.DEB.2.10.1402251840450.7035@hadrien>
 <530CF8FF.8080600@users.sourceforge.net>
 <alpine.DEB.2.02.1402252117150.2047@localhost6.localdomain6>
 <530DD06F.4090703@users.sourceforge.net>
 <alpine.DEB.2.02.1402262129250.2221@localhost6.localdomain6>
 <5317A59D.4@users.sourceforge.net>
Message-ID: <515bcb7e-3e00-3438-cc47-227cfcd41990@users.sourceforge.net>

From: Markus Elfring <elfring at users.sourceforge.net>
Date: Fri, 22 Jul 2016 12:48:12 +0200

The drm_property_unreference_blob() function tests whether its argument
is NULL and then returns immediately.
Thus the test around the call is not needed.

This issue was detected by using the Coccinelle software.

Signed-off-by: Markus Elfring <elfring at users.sourceforge.net>
---
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index 24aa3ba..07541d0 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -112,9 +112,7 @@ static void mtk_drm_crtc_reset(struct drm_crtc *crtc)
 	struct mtk_crtc_state *state;
 
 	if (crtc->state) {
-		if (crtc->state->mode_blob)
-			drm_property_unreference_blob(crtc->state->mode_blob);
-
+		drm_property_unreference_blob(crtc->state->mode_blob);
 		state = to_mtk_crtc_state(crtc->state);
 		memset(state, 0, sizeof(*state));
 	} else {
-- 
2.9.2



From jic23 at kernel.org  Fri Jul 22 22:45:23 2016
From: jic23 at kernel.org (Jonathan Cameron)
Date: Sat, 23 Jul 2016 07:45:23 +0200
Subject: [PATCH v5 2/3] iio: adc: mt2701: Add Mediatek auxadc driver for
 mt2701.
In-Reply-To: <alpine.DEB.2.02.1607210956290.30580@pmeerw.net>
References: <1469085449-22679-1-git-send-email-zhiyong.tao@mediatek.com>
 <1469085449-22679-3-git-send-email-zhiyong.tao@mediatek.com>
 <alpine.DEB.2.02.1607210956290.30580@pmeerw.net>
Message-ID: <cfe7e8c5-1ff1-35df-b44c-6a077fb049ef@kernel.org>

On 21/07/16 10:05, Peter Meerwald-Stadler wrote:
> On Thu, 21 Jul 2016, Zhiyong Tao wrote:
> 
>> Add Mediatek auxadc driver based on iio.
>> It will register a device in iio and support iio.
>> So thermal can read auxadc channel to sample data by iio device.
>> It is tested successfully on mt2701 platform.
>> Mt8173 and mt6577 platforms are not tested.
>> But the expectation is compatible.
> 
> minor comments below, consider if you do another respin
>  
>> Signed-off-by: Zhiyong Tao <zhiyong.tao at mediatek.com>
>> ---
>>  drivers/iio/adc/Kconfig         |   13 ++
>>  drivers/iio/adc/Makefile        |    1 +
>>  drivers/iio/adc/mt6577_auxadc.c |  289 +++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 303 insertions(+)
>>  create mode 100644 drivers/iio/adc/mt6577_auxadc.c
>>
>> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
>> index 25378c5..14929fc 100644
>> --- a/drivers/iio/adc/Kconfig
>> +++ b/drivers/iio/adc/Kconfig
>> @@ -305,6 +305,19 @@ config MCP3422
>>  	  This driver can also be built as a module. If so, the module will be
>>  	  called mcp3422.
>>  
>> +config MEDIATEK_MT6577_AUXADC
>> +        tristate "MediaTek AUXADC driver"
>> +        depends on ARCH_MEDIATEK || COMPILE_TEST
>> +        depends on HAS_IOMEM
>> +        help
>> +          Say yes here to enable support for MediaTek mt65xx AUXADC.
>> +
>> +          The driver supports immediate mode operation to read from one of sixteen
>> +          channels (external or internal).
>> +
>> +          This driver can also be built as a module. If so, the module will be
>> +          called mt6577_auxadc.
>> +
>>  config MEN_Z188_ADC
>>  	tristate "MEN 16z188 ADC IP Core support"
>>  	depends on MCB
>> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
>> index 38638d4..8306347 100644
>> --- a/drivers/iio/adc/Makefile
>> +++ b/drivers/iio/adc/Makefile
>> @@ -30,6 +30,7 @@ obj-$(CONFIG_MAX1027) += max1027.o
>>  obj-$(CONFIG_MAX1363) += max1363.o
>>  obj-$(CONFIG_MCP320X) += mcp320x.o
>>  obj-$(CONFIG_MCP3422) += mcp3422.o
>> +obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
>>  obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
>>  obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
>>  obj-$(CONFIG_NAU7802) += nau7802.o
>> diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c
>> new file mode 100644
>> index 0000000..6240236
>> --- /dev/null
>> +++ b/drivers/iio/adc/mt6577_auxadc.c
>> @@ -0,0 +1,289 @@
>> +/*
>> + * Copyright (c) 2016 MediaTek Inc.
>> + * Author: Zhiyong Tao <zhiyong.tao at mediatek.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * 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.
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/delay.h>
>> +#include <linux/err.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/of_device.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/iopoll.h>
>> +#include <linux/io.h>
>> +#include <linux/iio/iio.h>
>> +
>> +/* Register definitions */
>> +#define MT6577_AUXADC_CON0                    0x00
>> +#define MT6577_AUXADC_CON1                    0x04
>> +#define MT6577_AUXADC_CON2                    0x10
>> +#define MT6577_AUXADC_STA                     BIT(0)
>> +
>> +#define MT6577_AUXADC_DAT0                    0x14
>> +#define MT6577_AUXADC_RDY0                    BIT(12)
>> +
>> +#define MT6577_AUXADC_MISC                    0x94
>> +#define MT6577_AUXADC_PDN_EN                  BIT(14)
>> +
>> +#define MT6577_AUXADC_DAT_MASK                0xfff
>> +#define MT6577_AUXADC_SLEEP_US                1000
>> +#define MT6577_AUXADC_TIMEOUT_US              10000
>> +#define MT6577_AUXADC_POWER_READY_MS          1
>> +#define MT6577_AUXADC_SAMPLE_READY_US         25
>> +
>> +struct mt6577_auxadc_device {
>> +	void __iomem *reg_base;
>> +	struct clk *adc_clk;
>> +	struct mutex lock;
>> +};
>> +
>> +#define MT6577_AUXADC_CHANNEL(idx) {				    \
>> +		.type = IIO_VOLTAGE,				    \
>> +		.indexed = 1,					    \
>> +		.channel = (idx),				    \
>> +		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
>> +}
>> +
>> +static const struct iio_chan_spec mt6577_auxadc_iio_channels[] = {
>> +	MT6577_AUXADC_CHANNEL(0),
>> +	MT6577_AUXADC_CHANNEL(1),
>> +	MT6577_AUXADC_CHANNEL(2),
>> +	MT6577_AUXADC_CHANNEL(3),
>> +	MT6577_AUXADC_CHANNEL(4),
>> +	MT6577_AUXADC_CHANNEL(5),
>> +	MT6577_AUXADC_CHANNEL(6),
>> +	MT6577_AUXADC_CHANNEL(7),
>> +	MT6577_AUXADC_CHANNEL(8),
>> +	MT6577_AUXADC_CHANNEL(9),
>> +	MT6577_AUXADC_CHANNEL(10),
>> +	MT6577_AUXADC_CHANNEL(11),
>> +	MT6577_AUXADC_CHANNEL(12),
>> +	MT6577_AUXADC_CHANNEL(13),
>> +	MT6577_AUXADC_CHANNEL(14),
>> +	MT6577_AUXADC_CHANNEL(15),
>> +};
>> +
>> +static int mt6577_auxadc_read(struct iio_dev *indio_dev,
>> +			      struct iio_chan_spec const *chan)
>> +{
>> +	u32 rawdata, val;
> 
> could drop rawdata variable and use val instead
> 
>> +	void __iomem *reg_channel;
>> +	int ret;
>> +	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
>> +
>> +	reg_channel = adc_dev->reg_base + MT6577_AUXADC_DAT0 +
>> +		      chan->channel * 0x04;
>> +
>> +	mutex_lock(&adc_dev->lock);
>> +
>> +	val = readl(adc_dev->reg_base + MT6577_AUXADC_CON1);
>> +	val &= ~(1 << chan->channel);
>> +	writel(val, adc_dev->reg_base + MT6577_AUXADC_CON1);
>> +
>> +	/* read channel and make sure old ready bit == 0 */
>> +	ret = readl_poll_timeout(reg_channel, val,
>> +				 ((val & MT6577_AUXADC_RDY0) == 0),
>> +				 MT6577_AUXADC_SLEEP_US,
>> +				 MT6577_AUXADC_TIMEOUT_US);
>> +	if (ret < 0) {
>> +		dev_err(indio_dev->dev.parent,
>> +			"wait for channel[%d] ready bit clear time out\n",
>> +			chan->channel);
>> +
>> +		mutex_unlock(&adc_dev->lock);
>> +
>> +		return -ETIMEDOUT;
>> +	}
>> +
>> +	/* set bit to trigger sample */
>> +	val = readl(adc_dev->reg_base + MT6577_AUXADC_CON1);
>> +	val |= 1 << chan->channel;
>> +	writel(val, adc_dev->reg_base + MT6577_AUXADC_CON1);
>> +
>> +	/* we must delay here for hardware sample channel data */
>> +	udelay(MT6577_AUXADC_SAMPLE_READY_US);
>> +
>> +	/* check MTK_AUXADC_CON2 if auxadc is idle */
>> +	ret = readl_poll_timeout(adc_dev->reg_base + MT6577_AUXADC_CON2, val,
>> +				 ((val & MT6577_AUXADC_STA) == 0),
>> +				 MT6577_AUXADC_SLEEP_US,
>> +				 MT6577_AUXADC_TIMEOUT_US);
>> +	if (ret < 0) {
>> +		dev_err(indio_dev->dev.parent,
>> +			"wait for auxadc idle time out\n");
>> +
>> +		mutex_unlock(&adc_dev->lock);
>> +
>> +		return -ETIMEDOUT;
>> +	}
>> +
>> +	/* read channel and make sure ready bit == 1 */
>> +	ret = readl_poll_timeout(reg_channel, val,
>> +				 ((val & MT6577_AUXADC_RDY0) != 0),
>> +				 MT6577_AUXADC_SLEEP_US,
>> +				 MT6577_AUXADC_TIMEOUT_US);
>> +	if (ret < 0) {
>> +		dev_err(indio_dev->dev.parent,
>> +			"wait for channel[%d] data ready time out\n",
>> +			chan->channel);
>> +
>> +		mutex_unlock(&adc_dev->lock);
>> +
>> +		return -ETIMEDOUT;
>> +	}
>> +
>> +	/* read data */
>> +	rawdata = readl(reg_channel) & MT6577_AUXADC_DAT_MASK;
>> +
>> +	mutex_unlock(&adc_dev->lock);
>> +
>> +	return rawdata;
>> +}
>> +
>> +static int mt6577_auxadc_read_raw(struct iio_dev *indio_dev,
>> +				  struct iio_chan_spec const *chan,
>> +				  int *val,
>> +				  int *val2,
>> +				  long info)
>> +{
>> +	switch (info) {
>> +	case IIO_CHAN_INFO_PROCESSED:
>> +		*val = mt6577_auxadc_read(indio_dev, chan);
>> +		if (*val < 0) {
>> +			dev_err(indio_dev->dev.parent,
>> +				"failed to sample data on channel[%d]\n",
>> +				chan->channel);
>> +			return *val;
>> +		}
>> +		return IIO_VAL_INT;
>> +
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +}
>> +
>> +static const struct iio_info mt6577_auxadc_info = {
>> +	.driver_module = THIS_MODULE,
>> +	.read_raw = &mt6577_auxadc_read_raw,
>> +};
>> +
>> +static int mt6577_auxadc_probe(struct platform_device *pdev)
>> +{
>> +	struct mt6577_auxadc_device *adc_dev;
>> +	unsigned long adc_clk_rate;
>> +	struct resource *res;
>> +	struct iio_dev *indio_dev;
>> +	int ret;
>> +	u32 val;
>> +
>> +	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
>> +	if (!indio_dev)
>> +		return -ENOMEM;
>> +
>> +	adc_dev = iio_priv(indio_dev);
>> +	indio_dev->dev.parent = &pdev->dev;
>> +	indio_dev->name = dev_name(&pdev->dev);
>> +	indio_dev->info = &mt6577_auxadc_info;
>> +	indio_dev->modes = INDIO_DIRECT_MODE;
>> +	indio_dev->channels = mt6577_auxadc_iio_channels;
>> +	indio_dev->num_channels = ARRAY_SIZE(mt6577_auxadc_iio_channels);
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	adc_dev->reg_base = devm_ioremap_resource(&pdev->dev, res);
>> +	if (IS_ERR(adc_dev->reg_base)) {
>> +		dev_err(&pdev->dev, "failed to get auxadc base address.\n");
> 
> this is the only error msg ending with a '.'
> 
>> +		return PTR_ERR(adc_dev->reg_base);
>> +	}
>> +
>> +	adc_dev->adc_clk = devm_clk_get(&pdev->dev, "main");
>> +	if (IS_ERR(adc_dev->adc_clk)) {
>> +		dev_err(&pdev->dev, "failed to get auxadc clock\n");
>> +		return PTR_ERR(adc_dev->adc_clk);
>> +	}
>> +
>> +	ret = clk_prepare_enable(adc_dev->adc_clk);
>> +	if (ret) {
>> +		dev_err(&pdev->dev, "failed to enable auxadc clock\n");
>> +		return ret;
>> +	}
>> +
>> +	adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
>> +	if (!adc_clk_rate) {
>> +		dev_err(&pdev->dev, "null clock rate!\n");
>> +		goto err_disable_clk;
>> +	}
>> +
>> +	mutex_init(&adc_dev->lock);
>> +
>> +	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
>> +	val |= MT6577_AUXADC_PDN_EN;
>> +	writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
>> +	mdelay(MT6577_AUXADC_POWER_READY_MS);
>> +
>> +	platform_set_drvdata(pdev, indio_dev);
>> +
>> +	ret = iio_device_register(indio_dev);
>> +	if (ret < 0) {
>> +		dev_err(&pdev->dev, "failed to register iio device!\n");
>> +		goto err_power_off;
>> +	}
>> +
>> +	return 0;
>> +
>> +err_power_off:
>> +	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
>> +	val &= ~MT6577_AUXADC_PDN_EN;
>> +	writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
>> +err_disable_clk:
>> +	clk_disable_unprepare(adc_dev->adc_clk);
>> +	return -EINVAL;
> 
> not happy with inventing error codes; IMHO you should return the ret given 
> e.g. by iio_device_register()
This is a definite change I'd like to see so please do respin.
> 
>> +}
>> +
>> +static int mt6577_auxadc_remove(struct platform_device *pdev)
>> +{
>> +	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
>> +	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
>> +	u32 val;
>> +
>> +	iio_device_unregister(indio_dev);
>> +
>> +	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
>> +	val &= ~MT6577_AUXADC_PDN_EN;
>> +	writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
> 
> maybe the read/modify/write code sequence could be put into a function to 
> save some lines
> 
> something like 
> mt6577_auxadc_mod_reg(reg, or_mask, and_mask) {
> val = readl(reg)
> val |= or_mask;
> val &= ~and_mask;
> writel(val, reg)
> }
Makes sense.  Probably not worth bothering with regmap
here which would give you an equivalent function. So
just spin a local version like Peter suggested.
> 
>> +
>> +	clk_disable_unprepare(adc_dev->adc_clk);
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct of_device_id mt6577_auxadc_of_match[] = {
>> +	{ .compatible = "mediatek,mt2701-auxadc", },
>> +	{ .compatible = "mediatek,mt8173-auxadc", },
>> +	{ }
>> +};
>> +MODULE_DEVICE_TABLE(of, mt6577_auxadc_of_match);
>> +
>> +static struct platform_driver mt6577_auxadc_driver = {
>> +	.driver = {
>> +		.name   = "mt6577-auxadc",
>> +		.of_match_table = mt6577_auxadc_of_match,
>> +	},
>> +	.probe	= mt6577_auxadc_probe,
>> +	.remove	= mt6577_auxadc_remove,
>> +};
>> +module_platform_driver(mt6577_auxadc_driver);
>> +
>> +MODULE_AUTHOR("Zhiyong Tao <zhiyong.tao at mediatek.com>");
>> +MODULE_DESCRIPTION("MTK AUXADC Device Driver");
>> +MODULE_LICENSE("GPL v2");
>>
> 



From jic23 at kernel.org  Fri Jul 22 22:49:31 2016
From: jic23 at kernel.org (Jonathan Cameron)
Date: Sat, 23 Jul 2016 07:49:31 +0200
Subject: [PATCH v5 2/3] iio: adc: mt2701: Add Mediatek auxadc driver for
 mt2701.
In-Reply-To: <1469085449-22679-3-git-send-email-zhiyong.tao@mediatek.com>
References: <1469085449-22679-1-git-send-email-zhiyong.tao@mediatek.com>
 <1469085449-22679-3-git-send-email-zhiyong.tao@mediatek.com>
Message-ID: <ee510c3e-451b-af15-b32c-ec78a7c69aef@kernel.org>

On 21/07/16 09:17, Zhiyong Tao wrote:
> Add Mediatek auxadc driver based on iio.
> It will register a device in iio and support iio.
> So thermal can read auxadc channel to sample data by iio device.
> It is tested successfully on mt2701 platform.
> Mt8173 and mt6577 platforms are not tested.
> But the expectation is compatible.
> 
> Signed-off-by: Zhiyong Tao <zhiyong.tao at mediatek.com>
As you are re spinning anyway to address Peter's comments one
more minor point from me inline

Shaping up to be a nice little driver.

Jonathan
> ---
>  drivers/iio/adc/Kconfig         |   13 ++
>  drivers/iio/adc/Makefile        |    1 +
>  drivers/iio/adc/mt6577_auxadc.c |  289 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 303 insertions(+)
>  create mode 100644 drivers/iio/adc/mt6577_auxadc.c
> 
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 25378c5..14929fc 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -305,6 +305,19 @@ config MCP3422
>  	  This driver can also be built as a module. If so, the module will be
>  	  called mcp3422.
>  
> +config MEDIATEK_MT6577_AUXADC
> +        tristate "MediaTek AUXADC driver"
> +        depends on ARCH_MEDIATEK || COMPILE_TEST
> +        depends on HAS_IOMEM
> +        help
> +          Say yes here to enable support for MediaTek mt65xx AUXADC.
> +
> +          The driver supports immediate mode operation to read from one of sixteen
> +          channels (external or internal).
> +
> +          This driver can also be built as a module. If so, the module will be
> +          called mt6577_auxadc.
> +
>  config MEN_Z188_ADC
>  	tristate "MEN 16z188 ADC IP Core support"
>  	depends on MCB
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index 38638d4..8306347 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -30,6 +30,7 @@ obj-$(CONFIG_MAX1027) += max1027.o
>  obj-$(CONFIG_MAX1363) += max1363.o
>  obj-$(CONFIG_MCP320X) += mcp320x.o
>  obj-$(CONFIG_MCP3422) += mcp3422.o
> +obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
>  obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
>  obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
>  obj-$(CONFIG_NAU7802) += nau7802.o
> diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c
> new file mode 100644
> index 0000000..6240236
> --- /dev/null
> +++ b/drivers/iio/adc/mt6577_auxadc.c
> @@ -0,0 +1,289 @@
> +/*
> + * Copyright (c) 2016 MediaTek Inc.
> + * Author: Zhiyong Tao <zhiyong.tao at mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/iopoll.h>
> +#include <linux/io.h>
> +#include <linux/iio/iio.h>
> +
> +/* Register definitions */
> +#define MT6577_AUXADC_CON0                    0x00
> +#define MT6577_AUXADC_CON1                    0x04
> +#define MT6577_AUXADC_CON2                    0x10
> +#define MT6577_AUXADC_STA                     BIT(0)
> +
> +#define MT6577_AUXADC_DAT0                    0x14
> +#define MT6577_AUXADC_RDY0                    BIT(12)
> +
> +#define MT6577_AUXADC_MISC                    0x94
> +#define MT6577_AUXADC_PDN_EN                  BIT(14)
> +
> +#define MT6577_AUXADC_DAT_MASK                0xfff
> +#define MT6577_AUXADC_SLEEP_US                1000
> +#define MT6577_AUXADC_TIMEOUT_US              10000
> +#define MT6577_AUXADC_POWER_READY_MS          1
> +#define MT6577_AUXADC_SAMPLE_READY_US         25
> +
> +struct mt6577_auxadc_device {
> +	void __iomem *reg_base;
> +	struct clk *adc_clk;
> +	struct mutex lock;
> +};
> +
> +#define MT6577_AUXADC_CHANNEL(idx) {				    \
> +		.type = IIO_VOLTAGE,				    \
> +		.indexed = 1,					    \
> +		.channel = (idx),				    \
> +		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
> +}
> +
> +static const struct iio_chan_spec mt6577_auxadc_iio_channels[] = {
> +	MT6577_AUXADC_CHANNEL(0),
> +	MT6577_AUXADC_CHANNEL(1),
> +	MT6577_AUXADC_CHANNEL(2),
> +	MT6577_AUXADC_CHANNEL(3),
> +	MT6577_AUXADC_CHANNEL(4),
> +	MT6577_AUXADC_CHANNEL(5),
> +	MT6577_AUXADC_CHANNEL(6),
> +	MT6577_AUXADC_CHANNEL(7),
> +	MT6577_AUXADC_CHANNEL(8),
> +	MT6577_AUXADC_CHANNEL(9),
> +	MT6577_AUXADC_CHANNEL(10),
> +	MT6577_AUXADC_CHANNEL(11),
> +	MT6577_AUXADC_CHANNEL(12),
> +	MT6577_AUXADC_CHANNEL(13),
> +	MT6577_AUXADC_CHANNEL(14),
> +	MT6577_AUXADC_CHANNEL(15),
> +};
> +
> +static int mt6577_auxadc_read(struct iio_dev *indio_dev,
> +			      struct iio_chan_spec const *chan)
> +{
> +	u32 rawdata, val;
> +	void __iomem *reg_channel;
> +	int ret;
> +	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
> +
> +	reg_channel = adc_dev->reg_base + MT6577_AUXADC_DAT0 +
> +		      chan->channel * 0x04;
> +
> +	mutex_lock(&adc_dev->lock);
> +
> +	val = readl(adc_dev->reg_base + MT6577_AUXADC_CON1);
> +	val &= ~(1 << chan->channel);
> +	writel(val, adc_dev->reg_base + MT6577_AUXADC_CON1);
> +
> +	/* read channel and make sure old ready bit == 0 */
> +	ret = readl_poll_timeout(reg_channel, val,
> +				 ((val & MT6577_AUXADC_RDY0) == 0),
> +				 MT6577_AUXADC_SLEEP_US,
> +				 MT6577_AUXADC_TIMEOUT_US);
> +	if (ret < 0) {
> +		dev_err(indio_dev->dev.parent,
> +			"wait for channel[%d] ready bit clear time out\n",
> +			chan->channel);
> +
> +		mutex_unlock(&adc_dev->lock);
I'd prefer a goto taking us to the mutex unlock a the
end of the driver.  Makes it harder to get editing
this driver and breaking the locking wrong in the
future!
> +
> +		return -ETIMEDOUT;
> +	}
> +
> +	/* set bit to trigger sample */
> +	val = readl(adc_dev->reg_base + MT6577_AUXADC_CON1);
> +	val |= 1 << chan->channel;
> +	writel(val, adc_dev->reg_base + MT6577_AUXADC_CON1);
> +
> +	/* we must delay here for hardware sample channel data */
> +	udelay(MT6577_AUXADC_SAMPLE_READY_US);
> +
> +	/* check MTK_AUXADC_CON2 if auxadc is idle */
> +	ret = readl_poll_timeout(adc_dev->reg_base + MT6577_AUXADC_CON2, val,
> +				 ((val & MT6577_AUXADC_STA) == 0),
> +				 MT6577_AUXADC_SLEEP_US,
> +				 MT6577_AUXADC_TIMEOUT_US);
> +	if (ret < 0) {
> +		dev_err(indio_dev->dev.parent,
> +			"wait for auxadc idle time out\n");
> +
> +		mutex_unlock(&adc_dev->lock);
> +
> +		return -ETIMEDOUT;
> +	}
> +
> +	/* read channel and make sure ready bit == 1 */
> +	ret = readl_poll_timeout(reg_channel, val,
> +				 ((val & MT6577_AUXADC_RDY0) != 0),
> +				 MT6577_AUXADC_SLEEP_US,
> +				 MT6577_AUXADC_TIMEOUT_US);
> +	if (ret < 0) {
> +		dev_err(indio_dev->dev.parent,
> +			"wait for channel[%d] data ready time out\n",
> +			chan->channel);
> +
> +		mutex_unlock(&adc_dev->lock);
> +
> +		return -ETIMEDOUT;
> +	}
> +
> +	/* read data */
> +	rawdata = readl(reg_channel) & MT6577_AUXADC_DAT_MASK;
> +
> +	mutex_unlock(&adc_dev->lock);
> +
> +	return rawdata;
> +}
> +
> +static int mt6577_auxadc_read_raw(struct iio_dev *indio_dev,
> +				  struct iio_chan_spec const *chan,
> +				  int *val,
> +				  int *val2,
> +				  long info)
> +{
> +	switch (info) {
> +	case IIO_CHAN_INFO_PROCESSED:
> +		*val = mt6577_auxadc_read(indio_dev, chan);
> +		if (*val < 0) {
> +			dev_err(indio_dev->dev.parent,
> +				"failed to sample data on channel[%d]\n",
> +				chan->channel);
> +			return *val;
> +		}
> +		return IIO_VAL_INT;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static const struct iio_info mt6577_auxadc_info = {
> +	.driver_module = THIS_MODULE,
> +	.read_raw = &mt6577_auxadc_read_raw,
> +};
> +
> +static int mt6577_auxadc_probe(struct platform_device *pdev)
> +{
> +	struct mt6577_auxadc_device *adc_dev;
> +	unsigned long adc_clk_rate;
> +	struct resource *res;
> +	struct iio_dev *indio_dev;
> +	int ret;
> +	u32 val;
> +
> +	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
> +	if (!indio_dev)
> +		return -ENOMEM;
> +
> +	adc_dev = iio_priv(indio_dev);
> +	indio_dev->dev.parent = &pdev->dev;
> +	indio_dev->name = dev_name(&pdev->dev);
> +	indio_dev->info = &mt6577_auxadc_info;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->channels = mt6577_auxadc_iio_channels;
> +	indio_dev->num_channels = ARRAY_SIZE(mt6577_auxadc_iio_channels);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	adc_dev->reg_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(adc_dev->reg_base)) {
> +		dev_err(&pdev->dev, "failed to get auxadc base address.\n");
> +		return PTR_ERR(adc_dev->reg_base);
> +	}
> +
> +	adc_dev->adc_clk = devm_clk_get(&pdev->dev, "main");
> +	if (IS_ERR(adc_dev->adc_clk)) {
> +		dev_err(&pdev->dev, "failed to get auxadc clock\n");
> +		return PTR_ERR(adc_dev->adc_clk);
> +	}
> +
> +	ret = clk_prepare_enable(adc_dev->adc_clk);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to enable auxadc clock\n");
> +		return ret;
> +	}
> +
> +	adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
> +	if (!adc_clk_rate) {
> +		dev_err(&pdev->dev, "null clock rate!\n");
> +		goto err_disable_clk;
> +	}
> +
> +	mutex_init(&adc_dev->lock);
> +
> +	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
> +	val |= MT6577_AUXADC_PDN_EN;
> +	writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
> +	mdelay(MT6577_AUXADC_POWER_READY_MS);
> +
> +	platform_set_drvdata(pdev, indio_dev);
> +
> +	ret = iio_device_register(indio_dev);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "failed to register iio device!\n");
> +		goto err_power_off;
> +	}
> +
> +	return 0;
> +
> +err_power_off:
> +	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
> +	val &= ~MT6577_AUXADC_PDN_EN;
> +	writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
> +err_disable_clk:
> +	clk_disable_unprepare(adc_dev->adc_clk);
> +	return -EINVAL;
> +}
> +
> +static int mt6577_auxadc_remove(struct platform_device *pdev)
> +{
> +	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
> +	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
> +	u32 val;
> +
> +	iio_device_unregister(indio_dev);
> +
> +	val = readl(adc_dev->reg_base + MT6577_AUXADC_MISC);
> +	val &= ~MT6577_AUXADC_PDN_EN;
> +	writel(val, adc_dev->reg_base + MT6577_AUXADC_MISC);
> +
> +	clk_disable_unprepare(adc_dev->adc_clk);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mt6577_auxadc_of_match[] = {
> +	{ .compatible = "mediatek,mt2701-auxadc", },
> +	{ .compatible = "mediatek,mt8173-auxadc", },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, mt6577_auxadc_of_match);
> +
> +static struct platform_driver mt6577_auxadc_driver = {
> +	.driver = {
> +		.name   = "mt6577-auxadc",
> +		.of_match_table = mt6577_auxadc_of_match,
> +	},
> +	.probe	= mt6577_auxadc_probe,
> +	.remove	= mt6577_auxadc_remove,
> +};
> +module_platform_driver(mt6577_auxadc_driver);
> +
> +MODULE_AUTHOR("Zhiyong Tao <zhiyong.tao at mediatek.com>");
> +MODULE_DESCRIPTION("MTK AUXADC Device Driver");
> +MODULE_LICENSE("GPL v2");
> 



From lkp at intel.com  Sat Jul 23 16:00:53 2016
From: lkp at intel.com (kbuild test robot)
Date: Sun, 24 Jul 2016 07:00:53 +0800
Subject: [PATCH v5 3/3] arm: dts: mt2701: Add auxadc node.
In-Reply-To: <1469085449-22679-4-git-send-email-zhiyong.tao@mediatek.com>
Message-ID: <201607240649.gukdrhZS%fengguang.wu@intel.com>

Hi,

[auto build test ERROR on robh/for-next]
[also build test ERROR on v4.7-rc7 next-20160722]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Zhiyong-Tao/AUXADC-Mediatek-auxadc-driver/20160724-043228
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: arm-allnoconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 5.4.0-6) 5.4.0 20160609
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm 

All errors (new ones prefixed by >>):

   Error: arch/arm/boot/dts/mt2701.dtsi:145.22-23 syntax error
>> FATAL ERROR: Unable to parse input tree

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/octet-stream
Size: 5589 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mediatek/attachments/20160724/761900ac/attachment.obj>

From bibby.hsieh at mediatek.com  Sun Jul 24 23:15:35 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Mon, 25 Jul 2016 14:15:35 +0800
Subject: [PATCH 2/4] drm/mediatek: enhance the HDMI driving current
In-Reply-To: <1468998902.11841.54.camel@mtksdaap41>
References: <1468987385-37353-1-git-send-email-bibby.hsieh@mediatek.com>
 <1468987385-37353-3-git-send-email-bibby.hsieh@mediatek.com>
 <1468998902.11841.54.camel@mtksdaap41>
Message-ID: <1469427335.26205.12.camel@mtksdaap41>

Hi, CK,

I'm appreciate your comment.

On Wed, 2016-07-20 at 15:15 +0800, CK Hu wrote:
> Hi, Bibby:
> 
> One comment inline.
> 
> On Wed, 2016-07-20 at 12:03 +0800, Bibby Hsieh wrote:
> > From: Junzhi Zhao <junzhi.zhao at mediatek.com>
> > 
> > In order to improve 4K resolution performance,
> > we have to enhance the HDMI driving currend
> > when clock rate is greater than 165MHz.
> > 
> > Signed-off-by: Junzhi Zhao <junzhi.zhao at mediatek.com>
> > Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> > ---
> >  drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c |   89 +++++++++++++++++-------
> >  1 file changed, 63 insertions(+), 26 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
> > index 8a24754..a871c14 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
> > @@ -298,32 +298,69 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
> >  			  (0x1 << PLL_BR_SHIFT),
> >  			  RG_HDMITX_PLL_BP | RG_HDMITX_PLL_BC |
> >  			  RG_HDMITX_PLL_BR);
> > -	mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON3, RG_HDMITX_PRD_IMP_EN);
> > -	mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON4,
> > -			  (0x3 << PRD_IBIAS_CLK_SHIFT) |
> > -			  (0x3 << PRD_IBIAS_D2_SHIFT) |
> > -			  (0x3 << PRD_IBIAS_D1_SHIFT) |
> > -			  (0x3 << PRD_IBIAS_D0_SHIFT),
> > -			  RG_HDMITX_PRD_IBIAS_CLK |
> > -			  RG_HDMITX_PRD_IBIAS_D2 |
> > -			  RG_HDMITX_PRD_IBIAS_D1 |
> > -			  RG_HDMITX_PRD_IBIAS_D0);
> > -	mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON3,
> > -			  (0x0 << DRV_IMP_EN_SHIFT), RG_HDMITX_DRV_IMP_EN);
> > -	mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6,
> > -			  (hdmi_phy->drv_imp_clk << DRV_IMP_CLK_SHIFT) |
> > -			  (hdmi_phy->drv_imp_d2 << DRV_IMP_D2_SHIFT) |
> > -			  (hdmi_phy->drv_imp_d1 << DRV_IMP_D1_SHIFT) |
> > -			  (hdmi_phy->drv_imp_d0 << DRV_IMP_D0_SHIFT),
> > -			  RG_HDMITX_DRV_IMP_CLK | RG_HDMITX_DRV_IMP_D2 |
> > -			  RG_HDMITX_DRV_IMP_D1 | RG_HDMITX_DRV_IMP_D0);
> > -	mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON5,
> > -			  (hdmi_phy->ibias << DRV_IBIAS_CLK_SHIFT) |
> > -			  (hdmi_phy->ibias << DRV_IBIAS_D2_SHIFT) |
> > -			  (hdmi_phy->ibias << DRV_IBIAS_D1_SHIFT) |
> > -			  (hdmi_phy->ibias << DRV_IBIAS_D0_SHIFT),
> > -			  RG_HDMITX_DRV_IBIAS_CLK | RG_HDMITX_DRV_IBIAS_D2 |
> > -			  RG_HDMITX_DRV_IBIAS_D1 | RG_HDMITX_DRV_IBIAS_D0);
> > +	if (rate < 165000000) {
> > +		mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON3,
> > +					RG_HDMITX_PRD_IMP_EN);
> > +		mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON4,
> > +				  (0x3 << PRD_IBIAS_CLK_SHIFT) |
> > +				  (0x3 << PRD_IBIAS_D2_SHIFT) |
> > +				  (0x3 << PRD_IBIAS_D1_SHIFT) |
> > +				  (0x3 << PRD_IBIAS_D0_SHIFT),
> > +				  RG_HDMITX_PRD_IBIAS_CLK |
> > +				  RG_HDMITX_PRD_IBIAS_D2 |
> > +				  RG_HDMITX_PRD_IBIAS_D1 |
> > +				  RG_HDMITX_PRD_IBIAS_D0);
> > +		mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON3,
> > +				  (0x0 << DRV_IMP_EN_SHIFT),
> > +				  RG_HDMITX_DRV_IMP_EN);
> > +		mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6,
> > +				  (hdmi_phy->drv_imp_clk << DRV_IMP_CLK_SHIFT) |
> > +				  (hdmi_phy->drv_imp_d2 << DRV_IMP_D2_SHIFT) |
> > +				  (hdmi_phy->drv_imp_d1 << DRV_IMP_D1_SHIFT) |
> > +				  (hdmi_phy->drv_imp_d0 << DRV_IMP_D0_SHIFT),
> > +				  RG_HDMITX_DRV_IMP_CLK | RG_HDMITX_DRV_IMP_D2 |
> > +				  RG_HDMITX_DRV_IMP_D1 | RG_HDMITX_DRV_IMP_D0);
> > +		mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON5,
> > +				  (hdmi_phy->ibias << DRV_IBIAS_CLK_SHIFT) |
> > +				  (hdmi_phy->ibias << DRV_IBIAS_D2_SHIFT) |
> > +				  (hdmi_phy->ibias << DRV_IBIAS_D1_SHIFT) |
> > +				  (hdmi_phy->ibias << DRV_IBIAS_D0_SHIFT),
> > +				  RG_HDMITX_DRV_IBIAS_CLK |
> > +				  RG_HDMITX_DRV_IBIAS_D2 |
> > +				  RG_HDMITX_DRV_IBIAS_D1 |
> > +				  RG_HDMITX_DRV_IBIAS_D0);
> > +	} else {
> > +		mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON3,
> > +				      RG_HDMITX_PRD_IMP_EN);
> > +		mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON4,
> > +				  (0x6 << PRD_IBIAS_CLK_SHIFT) |
> > +				  (0x6 << PRD_IBIAS_D2_SHIFT) |
> > +				  (0x6 << PRD_IBIAS_D1_SHIFT) |
> > +				  (0x6 << PRD_IBIAS_D0_SHIFT),
> > +				  RG_HDMITX_PRD_IBIAS_CLK |
> > +				  RG_HDMITX_PRD_IBIAS_D2 |
> > +				  RG_HDMITX_PRD_IBIAS_D1 |
> > +				  RG_HDMITX_PRD_IBIAS_D0);
> > +		mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON3,
> > +				  (0xf << DRV_IMP_EN_SHIFT),
> > +				  RG_HDMITX_DRV_IMP_EN);
> > +		mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6,
> > +				  (hdmi_phy->drv_imp_clk << DRV_IMP_CLK_SHIFT) |
> > +				  (hdmi_phy->drv_imp_d2 << DRV_IMP_D2_SHIFT) |
> > +				  (hdmi_phy->drv_imp_d1 << DRV_IMP_D1_SHIFT) |
> > +				  (hdmi_phy->drv_imp_d0 << DRV_IMP_D0_SHIFT),
> > +				  RG_HDMITX_DRV_IMP_CLK | RG_HDMITX_DRV_IMP_D2 |
> > +				  RG_HDMITX_DRV_IMP_D1 | RG_HDMITX_DRV_IMP_D0);
> > +		mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON5,
> > +				  (hdmi_phy->ibias_up << DRV_IBIAS_CLK_SHIFT) |
> > +				  (hdmi_phy->ibias_up << DRV_IBIAS_D2_SHIFT) |
> > +				  (hdmi_phy->ibias_up << DRV_IBIAS_D1_SHIFT) |
> > +				  (hdmi_phy->ibias_up << DRV_IBIAS_D0_SHIFT),
> > +				  RG_HDMITX_DRV_IBIAS_CLK |
> > +				  RG_HDMITX_DRV_IBIAS_D2 |
> > +				  RG_HDMITX_DRV_IBIAS_D1 |
> > +				  RG_HDMITX_DRV_IBIAS_D0);
> > +	}
> 
> 'if' part and 'else' part looks almost the same. Use variable for
> difference and merge these two part. For example:
> 
> if (rate < 165000000)
> 	prd_ibias = 0x3;
> else
> 	prd_ibias = 0x6;
> 
> mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON4,
> 		  (prd_ibias << PRD_IBIAS_CLK_SHIFT) |
> 		  (prd_ibias << PRD_IBIAS_D2_SHIFT) |
> 		  (prd_ibias << PRD_IBIAS_D1_SHIFT) |
> 		  (prd_ibias << PRD_IBIAS_D0_SHIFT),
> 		  RG_HDMITX_PRD_IBIAS_CLK |
> 		  RG_HDMITX_PRD_IBIAS_D2 |
> 		  RG_HDMITX_PRD_IBIAS_D1 |
> 		  RG_HDMITX_PRD_IBIAS_D0);
> 
> >  	return 0;
> >  }
> >  
Ok, I will use variable instead of that.
> 
> Regards,
> CK
> 




From bibby.hsieh at mediatek.com  Sun Jul 24 23:24:05 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Mon, 25 Jul 2016 14:24:05 +0800
Subject: [PATCH 3/4] drm/mediatek: fix the wrong pixel clock when
 resolution is 4K
In-Reply-To: <1469001443.11841.59.camel@mtksdaap41>
References: <1468987385-37353-1-git-send-email-bibby.hsieh@mediatek.com>
 <1468987385-37353-4-git-send-email-bibby.hsieh@mediatek.com>
 <1469001443.11841.59.camel@mtksdaap41>
Message-ID: <1469427845.26205.17.camel@mtksdaap41>

Hi, CK,

Thanks for your comments.

On Wed, 2016-07-20 at 15:57 +0800, CK Hu wrote:
> Hi, Bibby:
> 
> Some comments inline.
> 
> On Wed, 2016-07-20 at 12:03 +0800, Bibby Hsieh wrote:
> > From: Junzhi Zhao <junzhi.zhao at mediatek.com>
> > 
> > Pixel clock should be 297MHz when resolution is 4K.
> > 
> > Signed-off-by: Junzhi Zhao <junzhi.zhao at mediatek.com>
> > Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> > ---
> >  drivers/gpu/drm/mediatek/mtk_dpi.c |  184 +++++++++++++++++++++++++-----------
> >  1 file changed, 131 insertions(+), 53 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
> > index d05ca79..c0f04d2 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_dpi.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
> > @@ -60,14 +60,35 @@ enum mtk_dpi_out_color_format {
> >  	MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL
> >  };
> >  
> > +enum mtk_dpi_clk_id {
> > +	MTK_DPI_CLK_DPI_ENGINE,
> > +	MTK_DPI_CLK_DPI_PIXEL,
> > +	MTK_DPI_CLK_TVD_PLL,
> > +	MTK_DPI_CLK_TVDPLL_MUX,
> > +	MTK_DPI_CLK_TVDPLL_D2,
> > +	MTK_DPI_CLK_TVDPLL_D4,
> > +	MTK_DPI_CLK_TVDPLL_D8,
> > +	MTK_DPI_CLK_TVDPLL_D16,
> > +	MTK_DPI_CLK_COUNT,
> > +};
> > +
> > +static const char * const mtk_dpi_clk_names[MTK_DPI_CLK_COUNT] = {
> > +	[MTK_DPI_CLK_DPI_ENGINE] = "engine",
> > +	[MTK_DPI_CLK_DPI_PIXEL] = "pixel",
> > +	[MTK_DPI_CLK_TVD_PLL] = "pll",
> > +	[MTK_DPI_CLK_TVDPLL_MUX] = "tvdpll_mux",
> > +	[MTK_DPI_CLK_TVDPLL_D2] = "tvdpll_d2",
> > +	[MTK_DPI_CLK_TVDPLL_D4] = "tvdpll_d4",
> > +	[MTK_DPI_CLK_TVDPLL_D8] = "tvdpll_d8",
> > +	[MTK_DPI_CLK_TVDPLL_D16] = "tvdpll_d16",
> > +};
> > +
> >  struct mtk_dpi {
> >  	struct mtk_ddp_comp ddp_comp;
> >  	struct drm_encoder encoder;
> >  	void __iomem *regs;
> >  	struct device *dev;
> > -	struct clk *engine_clk;
> > -	struct clk *pixel_clk;
> > -	struct clk *tvd_clk;
> > +	struct clk *clk[MTK_DPI_CLK_COUNT];
> >  	int irq;
> >  	struct drm_display_mode mode;
> >  	enum mtk_dpi_out_color_format color_format;
> > @@ -76,6 +97,7 @@ struct mtk_dpi {
> >  	enum mtk_dpi_out_channel_swap channel_swap;
> >  	bool power_sta;
> >  	u8 power_ctl;
> > +	void *data;
> >  };
> >  
> >  static inline struct mtk_dpi *mtk_dpi_from_encoder(struct drm_encoder *e)
> > @@ -114,6 +136,11 @@ struct mtk_dpi_yc_limit {
> >  	u16 c_bottom;
> >  };
> >  
> > +struct mtk_dpi_conf {
> > +	int (*parse_clk_from_dt)(struct mtk_dpi *dpi, struct device_node *np);
> > +	int (*clk_config)(struct mtk_dpi *dpi, struct drm_display_mode *mode);
> > +};
> > +
> >  static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask)
> >  {
> >  	u32 tmp = readl(dpi->regs + offset) & ~mask;
> > @@ -377,8 +404,8 @@ static void mtk_dpi_power_off(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl)
> >  		return;
> >  
> >  	mtk_dpi_disable(dpi);
> > -	clk_disable_unprepare(dpi->pixel_clk);
> > -	clk_disable_unprepare(dpi->engine_clk);
> > +	clk_disable_unprepare(dpi->clk[MTK_DPI_CLK_DPI_PIXEL]);
> > +	clk_disable_unprepare(dpi->clk[MTK_DPI_CLK_DPI_ENGINE]);
> >  	dpi->power_sta = false;
> >  }
> >  
> > @@ -395,13 +422,13 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl)
> >  	if (dpi->power_sta)
> >  		return 0;
> >  
> > -	ret = clk_prepare_enable(dpi->engine_clk);
> > +	ret = clk_prepare_enable(dpi->clk[MTK_DPI_CLK_DPI_ENGINE]);
> >  	if (ret) {
> >  		dev_err(dpi->dev, "Failed to enable engine clock: %d\n", ret);
> >  		goto err_eng;
> >  	}
> >  
> > -	ret = clk_prepare_enable(dpi->pixel_clk);
> > +	ret = clk_prepare_enable(dpi->clk[MTK_DPI_CLK_DPI_PIXEL]);
> >  	if (ret) {
> >  		dev_err(dpi->dev, "Failed to enable pixel clock: %d\n", ret);
> >  		goto err_pixel;
> > @@ -412,7 +439,7 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl)
> >  	return 0;
> >  
> >  err_pixel:
> > -	clk_disable_unprepare(dpi->engine_clk);
> > +	clk_disable_unprepare(dpi->clk[MTK_DPI_CLK_DPI_ENGINE]);
> >  err_eng:
> >  	dpi->power_ctl &= ~pctl;
> >  	return ret;
> > @@ -428,34 +455,16 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
> >  	struct mtk_dpi_sync_param vsync_leven = { 0 };
> >  	struct mtk_dpi_sync_param vsync_rodd = { 0 };
> >  	struct mtk_dpi_sync_param vsync_reven = { 0 };
> > -	unsigned long pix_rate;
> > -	unsigned long pll_rate;
> > -	unsigned int factor;
> > +	struct mtk_dpi_conf *conf;
> > +	int ret;
> >  
> >  	if (!dpi) {
> >  		dev_err(dpi->dev, "invalid argument\n");
> >  		return -EINVAL;
> >  	}
> >  
> > -	pix_rate = 1000UL * mode->clock;
> > -	if (mode->clock <= 74000)
> > -		factor = 8 * 3;
> > -	else
> > -		factor = 4 * 3;
> > -	pll_rate = pix_rate * factor;
> > -
> > -	dev_dbg(dpi->dev, "Want PLL %lu Hz, pixel clock %lu Hz\n",
> > -		pll_rate, pix_rate);
> > -
> > -	clk_set_rate(dpi->tvd_clk, pll_rate);
> > -	pll_rate = clk_get_rate(dpi->tvd_clk);
> > -
> > -	pix_rate = pll_rate / factor;
> > -	clk_set_rate(dpi->pixel_clk, pix_rate);
> > -	pix_rate = clk_get_rate(dpi->pixel_clk);
> > -
> > -	dev_dbg(dpi->dev, "Got  PLL %lu Hz, pixel clock %lu Hz\n",
> > -		pll_rate, pix_rate);
> > +	conf = (struct mtk_dpi_conf *)dpi->data;
> > +	ret = conf->clk_config(dpi, mode);
> 
> Nothing to do with return error?
> 
Ok, I will fix that.
> >  
> >  	limit.c_bottom = 0x0010;
> >  	limit.c_top = 0x0FE0;
> > @@ -656,20 +665,109 @@ static const struct component_ops mtk_dpi_component_ops = {
> >  	.unbind = mtk_dpi_unbind,
> >  };
> >  
> > +static int mt8173_parse_clk_from_dt(struct mtk_dpi *dpi, struct device_node *np)
> > +{
> > +	int i;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(mtk_dpi_clk_names); i++) {
> > +		dpi->clk[i] = of_clk_get_by_name(np,
> > +						  mtk_dpi_clk_names[i]);
> > +		if (IS_ERR(dpi->clk[i]))
> > +			return PTR_ERR(dpi->clk[i]);
> > +	}
> > +	return 0;
> > +}
> 
> I think parsing device tree is a pure SW behavior. Would this vary for
> different MTK soc?
> 
Yes
> > +
> > +static int mt8173_clk_config(struct mtk_dpi *dpi, struct drm_display_mode *mode)
> > +{
> > +	unsigned long pix_rate;
> > +	unsigned long pll_rate;
> > +	unsigned int factor;
> > +	struct clk *parent;
> > +	int ret;
> > +
> > +	if (mode->clock <= 27000) {
> > +		factor = 16 * 3;
> > +		parent = dpi->clk[MTK_DPI_CLK_TVDPLL_D16];
> > +	} else if (mode->clock <= 74250) {
> > +		factor = 8 * 3;
> > +		parent = dpi->clk[MTK_DPI_CLK_TVDPLL_D8];
> > +	} else if (mode->clock <= 167000) {
> > +		factor = 4 * 3;
> > +		parent = dpi->clk[MTK_DPI_CLK_TVDPLL_D4];
> > +	} else {
> > +		factor = 2 * 3;
> > +		parent = dpi->clk[MTK_DPI_CLK_TVDPLL_D2];
> > +	}
> > +
> > +	pix_rate = 1000UL * mode->clock;
> > +	pll_rate = pix_rate * factor;
> > +
> > +	dev_dbg(dpi->dev, "Want PLL %lu Hz, pixel clock %lu Hz\n",
> > +		pll_rate, pix_rate);
> > +
> > +	ret = clk_prepare_enable(dpi->clk[MTK_DPI_CLK_TVDPLL_MUX]);
> > +	if (ret) {
> > +		dev_err(dpi->dev, "tvdpll_mux enable fail\n");
> > +		return ret;
> > +	}
> > +
> > +	ret = clk_set_parent(dpi->clk[MTK_DPI_CLK_TVDPLL_MUX], parent);
> > +	if (ret) {
> > +		dev_err(dpi->dev, "tvdpll_mux set parent fail\n");
> 
> Before return, you may undo something.
I think we can remove this function at the new version, because we make
some changes here according Philipp' comments.
> 
> > +		return ret;
> > +	}
> > +	clk_disable_unprepare(dpi->clk[MTK_DPI_CLK_TVDPLL_MUX]);
> > +
> > +	ret = clk_set_rate(dpi->clk[MTK_DPI_CLK_TVD_PLL], pll_rate);
> > +	if (ret) {
> > +		dev_err(dpi->dev, "dpi pll_rate set rate fail\n");
> > +		return ret;
> > +	}
> > +	pll_rate = clk_get_rate(dpi->clk[MTK_DPI_CLK_TVD_PLL]);
> > +	pix_rate = clk_get_rate(dpi->clk[MTK_DPI_CLK_DPI_PIXEL]);
> > +
> > +	dev_dbg(dpi->dev, "Got  PLL %lu Hz, pixel clock %lu Hz\n",
> > +		pll_rate, pix_rate);
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct mtk_dpi_conf mt8173_conf = {
> > +	.parse_clk_from_dt = mt8173_parse_clk_from_dt,
> > +	.clk_config = mt8173_clk_config,
> > +};
> > +
> > +static const struct of_device_id mtk_dpi_of_ids[] = {
> > +	{ .compatible = "mediatek,mt8173-dpi",
> > +		.data = &mt8173_conf,
> > +	},
> > +	{}
> > +};
> > +
> >  static int mtk_dpi_probe(struct platform_device *pdev)
> >  {
> >  	struct device *dev = &pdev->dev;
> >  	struct mtk_dpi *dpi;
> >  	struct resource *mem;
> > +	struct device_node *np = dev->of_node;
> >  	struct device_node *ep, *bridge_node = NULL;
> >  	int comp_id;
> > +	const struct of_device_id *match;
> > +	struct mtk_dpi_conf *conf;
> >  	int ret;
> >  
> > +	match = of_match_node(mtk_dpi_of_ids, dev->of_node);
> > +	if (!match)
> > +		return -ENODEV;
> > +
> >  	dpi = devm_kzalloc(dev, sizeof(*dpi), GFP_KERNEL);
> >  	if (!dpi)
> >  		return -ENOMEM;
> >  
> >  	dpi->dev = dev;
> > +	dpi->data = (void *)match->data;
> > +	conf = (struct mtk_dpi_conf *)match->data;
> >  
> >  	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >  	dpi->regs = devm_ioremap_resource(dev, mem);
> > @@ -679,24 +777,9 @@ static int mtk_dpi_probe(struct platform_device *pdev)
> >  		return ret;
> >  	}
> >  
> > -	dpi->engine_clk = devm_clk_get(dev, "engine");
> > -	if (IS_ERR(dpi->engine_clk)) {
> > -		ret = PTR_ERR(dpi->engine_clk);
> > -		dev_err(dev, "Failed to get engine clock: %d\n", ret);
> > -		return ret;
> > -	}
> > -
> > -	dpi->pixel_clk = devm_clk_get(dev, "pixel");
> > -	if (IS_ERR(dpi->pixel_clk)) {
> > -		ret = PTR_ERR(dpi->pixel_clk);
> > -		dev_err(dev, "Failed to get pixel clock: %d\n", ret);
> > -		return ret;
> > -	}
> > -
> > -	dpi->tvd_clk = devm_clk_get(dev, "pll");
> > -	if (IS_ERR(dpi->tvd_clk)) {
> > -		ret = PTR_ERR(dpi->tvd_clk);
> > -		dev_err(dev, "Failed to get tvdpll clock: %d\n", ret);
> > +	ret = conf->parse_clk_from_dt(dpi, np);
> > +	if (ret) {
> > +		dev_err(dev, "parse tvd div clk failed!");
> >  		return ret;
> >  	}
> >  
> > @@ -754,11 +837,6 @@ static int mtk_dpi_remove(struct platform_device *pdev)
> >  	return 0;
> >  }
> >  
> > -static const struct of_device_id mtk_dpi_of_ids[] = {
> > -	{ .compatible = "mediatek,mt8173-dpi", },
> > -	{}
> > -};
> > -
> >  struct platform_driver mtk_dpi_driver = {
> >  	.probe = mtk_dpi_probe,
> >  	.remove = mtk_dpi_remove,
> 
> Regards,
> CK
> 




From bibby.hsieh at mediatek.com  Sun Jul 24 23:25:37 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Mon, 25 Jul 2016 14:25:37 +0800
Subject: [PATCH 3/4] drm/mediatek: fix the wrong pixel clock when
 resolution is 4K
In-Reply-To: <1469007718.5809.32.camel@pengutronix.de>
References: <1468987385-37353-1-git-send-email-bibby.hsieh@mediatek.com>
 <1468987385-37353-4-git-send-email-bibby.hsieh@mediatek.com>
 <1469007718.5809.32.camel@pengutronix.de>
Message-ID: <1469427937.26205.19.camel@mtksdaap41>

Hi, Philipp,

Thanks for your comment.

On Wed, 2016-07-20 at 11:41 +0200, Philipp Zabel wrote:
> Am Mittwoch, den 20.07.2016, 12:03 +0800 schrieb Bibby Hsieh:
> > From: Junzhi Zhao <junzhi.zhao at mediatek.com>
> > 
> > Pixel clock should be 297MHz when resolution is 4K.
> > 
> > Signed-off-by: Junzhi Zhao <junzhi.zhao at mediatek.com>
> > Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> > ---
> >  drivers/gpu/drm/mediatek/mtk_dpi.c |  184 +++++++++++++++++++++++++-----------
> >  1 file changed, 131 insertions(+), 53 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
> > index d05ca79..c0f04d2 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_dpi.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
> > @@ -60,14 +60,35 @@ enum mtk_dpi_out_color_format {
> >  	MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL
> >  };
> >  
> > +enum mtk_dpi_clk_id {
> > +	MTK_DPI_CLK_DPI_ENGINE,
> > +	MTK_DPI_CLK_DPI_PIXEL,
> > +	MTK_DPI_CLK_TVD_PLL,
> > +	MTK_DPI_CLK_TVDPLL_MUX,
> > +	MTK_DPI_CLK_TVDPLL_D2,
> > +	MTK_DPI_CLK_TVDPLL_D4,
> > +	MTK_DPI_CLK_TVDPLL_D8,
> > +	MTK_DPI_CLK_TVDPLL_D16,
> > +	MTK_DPI_CLK_COUNT,
> > +};
> 
> I think this is going in the wrong direction. If the pixel clock output
> isn't correct after a clk_set_rate(dpi->pixel_clk, rate), the clock
> drivers should be fixed, not worked around in the dpi driver.
> 
> The TVDPLL_* mux and dividers are not direct inputs to the DPI module:
> 
>    tvdpll ("pll")
>      |               ..|\
>      v               ..| | mm_sel ----> mm_dpi_engine ("engine")
>    tvdpll_594m(1/3)  ..|/
>      |
>      |`-> tvdpll_d2 -->|\
>      |`-> tvdpll_d4 -->| | dpi0_sel --> mm_dpi_pixel ("pixel")
>      |`-> tvdpll_d8 -->| |
>      `--> tvdpll_d16 ->|/
> 
> Currently the code first sets the "pll" to the desired multiple of the
> pixel clock manually (*3*4, *3*8) and than calls clk_set_rate on the
> "pixel" clock which gets propagated by the clock framework up to
> dpi0_sel. Since dpi0_sel doesn't have the CLK_SET_RATE_PARENT flag set,
> it should just choose the tvdpll_d* input divider. I'd like not to give
> the dpi driver direct access to all the intermediate clocks.
> 
Ok, I will make some modifications according to your comment.

> regards
> Philipp




From ck.hu at mediatek.com  Sun Jul 24 23:49:35 2016
From: ck.hu at mediatek.com (CK Hu)
Date: Mon, 25 Jul 2016 14:49:35 +0800
Subject: [PATCH 3/4] drm/mediatek: fix the wrong pixel clock when
 resolution is 4K
In-Reply-To: <1469427845.26205.17.camel@mtksdaap41>
References: <1468987385-37353-1-git-send-email-bibby.hsieh@mediatek.com>
 <1468987385-37353-4-git-send-email-bibby.hsieh@mediatek.com>
 <1469001443.11841.59.camel@mtksdaap41>
 <1469427845.26205.17.camel@mtksdaap41>
Message-ID: <1469429375.11841.69.camel@mtksdaap41>

Hi, Bibby:

On Mon, 2016-07-25 at 14:24 +0800, Bibby Hsieh wrote:
> Hi, CK,
> 
> Thanks for your comments.
> 
> On Wed, 2016-07-20 at 15:57 +0800, CK Hu wrote:
> > Hi, Bibby:
> > 
> > Some comments inline.
> > 
> > On Wed, 2016-07-20 at 12:03 +0800, Bibby Hsieh wrote:
> > > From: Junzhi Zhao <junzhi.zhao at mediatek.com>
> > > 
> > > Pixel clock should be 297MHz when resolution is 4K.
> > > 
> > > Signed-off-by: Junzhi Zhao <junzhi.zhao at mediatek.com>
> > > Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> > > ---
> > >  drivers/gpu/drm/mediatek/mtk_dpi.c |  184 +++++++++++++++++++++++++-----------
> > >  1 file changed, 131 insertions(+), 53 deletions(-)
> > > 

[snip...]

> > >  
> > > +static int mt8173_parse_clk_from_dt(struct mtk_dpi *dpi, struct device_node *np)
> > > +{
> > > +	int i;
> > > +
> > > +	for (i = 0; i < ARRAY_SIZE(mtk_dpi_clk_names); i++) {
> > > +		dpi->clk[i] = of_clk_get_by_name(np,
> > > +						  mtk_dpi_clk_names[i]);
> > > +		if (IS_ERR(dpi->clk[i]))
> > > +			return PTR_ERR(dpi->clk[i]);
> > > +	}
> > > +	return 0;
> > > +}
> > 
> > I think parsing device tree is a pure SW behavior. Would this vary for
> > different MTK soc?
> > 
> Yes

I can not imaging that, so could you give me an example source code of
other MTK soc for parse_clk_from_dt()?

> > > +
> > > +
> > > +static const struct mtk_dpi_conf mt8173_conf = {
> > > +	.parse_clk_from_dt = mt8173_parse_clk_from_dt,
> > > +	.clk_config = mt8173_clk_config,
> > > +};
> > > +
> > > +static const struct of_device_id mtk_dpi_of_ids[] = {
> > > +	{ .compatible = "mediatek,mt8173-dpi",
> > > +		.data = &mt8173_conf,
> > > +	},
> > > +	{}
> > > +};
> > > +
> > >  static int mtk_dpi_probe(struct platform_device *pdev)
> > >  {
> > >  	struct device *dev = &pdev->dev;
> > >  	struct mtk_dpi *dpi;
> > >  	struct resource *mem;
> > > +	struct device_node *np = dev->of_node;
> > >  	struct device_node *ep, *bridge_node = NULL;
> > >  	int comp_id;
> > > +	const struct of_device_id *match;
> > > +	struct mtk_dpi_conf *conf;
> > >  	int ret;
> > >  
> > > +	match = of_match_node(mtk_dpi_of_ids, dev->of_node);
> > > +	if (!match)
> > > +		return -ENODEV;
> > > +
> > >  	dpi = devm_kzalloc(dev, sizeof(*dpi), GFP_KERNEL);
> > >  	if (!dpi)
> > >  		return -ENOMEM;
> > >  
> > >  	dpi->dev = dev;
> > > +	dpi->data = (void *)match->data;
> > > +	conf = (struct mtk_dpi_conf *)match->data;
> > >  
> > >  	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > >  	dpi->regs = devm_ioremap_resource(dev, mem);
> > > @@ -679,24 +777,9 @@ static int mtk_dpi_probe(struct platform_device *pdev)
> > >  		return ret;
> > >  	}
> > >  
> > > -	dpi->engine_clk = devm_clk_get(dev, "engine");
> > > -	if (IS_ERR(dpi->engine_clk)) {
> > > -		ret = PTR_ERR(dpi->engine_clk);
> > > -		dev_err(dev, "Failed to get engine clock: %d\n", ret);
> > > -		return ret;
> > > -	}
> > > -
> > > -	dpi->pixel_clk = devm_clk_get(dev, "pixel");
> > > -	if (IS_ERR(dpi->pixel_clk)) {
> > > -		ret = PTR_ERR(dpi->pixel_clk);
> > > -		dev_err(dev, "Failed to get pixel clock: %d\n", ret);
> > > -		return ret;
> > > -	}
> > > -
> > > -	dpi->tvd_clk = devm_clk_get(dev, "pll");
> > > -	if (IS_ERR(dpi->tvd_clk)) {
> > > -		ret = PTR_ERR(dpi->tvd_clk);
> > > -		dev_err(dev, "Failed to get tvdpll clock: %d\n", ret);
> > > +	ret = conf->parse_clk_from_dt(dpi, np);
> > > +	if (ret) {
> > > +		dev_err(dev, "parse tvd div clk failed!");
> > >  		return ret;
> > >  	}
> > >  
> > > @@ -754,11 +837,6 @@ static int mtk_dpi_remove(struct platform_device *pdev)
> > >  	return 0;
> > >  }
> > >  
> > > -static const struct of_device_id mtk_dpi_of_ids[] = {
> > > -	{ .compatible = "mediatek,mt8173-dpi", },
> > > -	{}
> > > -};
> > > -
> > >  struct platform_driver mtk_dpi_driver = {
> > >  	.probe = mtk_dpi_probe,
> > >  	.remove = mtk_dpi_remove,
> > 
> > Regards,
> > CK
> > 
> 


Regards,
CK
> 




From bibby.hsieh at mediatek.com  Mon Jul 25 01:37:50 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Mon, 25 Jul 2016 16:37:50 +0800
Subject: [PATCH 3/4] drm/mediatek: fix the wrong pixel clock when
 resolution is 4K
In-Reply-To: <1469429375.11841.69.camel@mtksdaap41>
References: <1468987385-37353-1-git-send-email-bibby.hsieh@mediatek.com>
 <1468987385-37353-4-git-send-email-bibby.hsieh@mediatek.com>
 <1469001443.11841.59.camel@mtksdaap41>
 <1469427845.26205.17.camel@mtksdaap41>
 <1469429375.11841.69.camel@mtksdaap41>
Message-ID: <1469435870.26205.20.camel@mtksdaap41>

Hi, CK,

Thanks for your comments.

On Mon, 2016-07-25 at 14:49 +0800, CK Hu wrote:
> Hi, Bibby:
> 
> On Mon, 2016-07-25 at 14:24 +0800, Bibby Hsieh wrote:
> > Hi, CK,
> > 
> > Thanks for your comments.
> > 
> > On Wed, 2016-07-20 at 15:57 +0800, CK Hu wrote:
> > > Hi, Bibby:
> > > 
> > > Some comments inline.
> > > 
> > > On Wed, 2016-07-20 at 12:03 +0800, Bibby Hsieh wrote:
> > > > From: Junzhi Zhao <junzhi.zhao at mediatek.com>
> > > > 
> > > > Pixel clock should be 297MHz when resolution is 4K.
> > > > 
> > > > Signed-off-by: Junzhi Zhao <junzhi.zhao at mediatek.com>
> > > > Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> > > > ---
> > > >  drivers/gpu/drm/mediatek/mtk_dpi.c |  184 +++++++++++++++++++++++++-----------
> > > >  1 file changed, 131 insertions(+), 53 deletions(-)
> > > > 
> 
> [snip...]
> 
> > > >  
> > > > +static int mt8173_parse_clk_from_dt(struct mtk_dpi *dpi, struct device_node *np)
> > > > +{
> > > > +	int i;
> > > > +
> > > > +	for (i = 0; i < ARRAY_SIZE(mtk_dpi_clk_names); i++) {
> > > > +		dpi->clk[i] = of_clk_get_by_name(np,
> > > > +						  mtk_dpi_clk_names[i]);
> > > > +		if (IS_ERR(dpi->clk[i]))
> > > > +			return PTR_ERR(dpi->clk[i]);
> > > > +	}
> > > > +	return 0;
> > > > +}
> > > 
> > > I think parsing device tree is a pure SW behavior. Would this vary for
> > > different MTK soc?
> > > 
> > Yes
> 
> I can not imaging that, so could you give me an example source code of
> other MTK soc for parse_clk_from_dt()?
> 
I will do some changes according to your comments. 

> > > > +
> > > > +
> > > > +static const struct mtk_dpi_conf mt8173_conf = {
> > > > +	.parse_clk_from_dt = mt8173_parse_clk_from_dt,
> > > > +	.clk_config = mt8173_clk_config,
> > > > +};
> > > > +
> > > > +static const struct of_device_id mtk_dpi_of_ids[] = {
> > > > +	{ .compatible = "mediatek,mt8173-dpi",
> > > > +		.data = &mt8173_conf,
> > > > +	},
> > > > +	{}
> > > > +};
> > > > +
> > > >  static int mtk_dpi_probe(struct platform_device *pdev)
> > > >  {
> > > >  	struct device *dev = &pdev->dev;
> > > >  	struct mtk_dpi *dpi;
> > > >  	struct resource *mem;
> > > > +	struct device_node *np = dev->of_node;
> > > >  	struct device_node *ep, *bridge_node = NULL;
> > > >  	int comp_id;
> > > > +	const struct of_device_id *match;
> > > > +	struct mtk_dpi_conf *conf;
> > > >  	int ret;
> > > >  
> > > > +	match = of_match_node(mtk_dpi_of_ids, dev->of_node);
> > > > +	if (!match)
> > > > +		return -ENODEV;
> > > > +
> > > >  	dpi = devm_kzalloc(dev, sizeof(*dpi), GFP_KERNEL);
> > > >  	if (!dpi)
> > > >  		return -ENOMEM;
> > > >  
> > > >  	dpi->dev = dev;
> > > > +	dpi->data = (void *)match->data;
> > > > +	conf = (struct mtk_dpi_conf *)match->data;
> > > >  
> > > >  	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > > >  	dpi->regs = devm_ioremap_resource(dev, mem);
> > > > @@ -679,24 +777,9 @@ static int mtk_dpi_probe(struct platform_device *pdev)
> > > >  		return ret;
> > > >  	}
> > > >  
> > > > -	dpi->engine_clk = devm_clk_get(dev, "engine");
> > > > -	if (IS_ERR(dpi->engine_clk)) {
> > > > -		ret = PTR_ERR(dpi->engine_clk);
> > > > -		dev_err(dev, "Failed to get engine clock: %d\n", ret);
> > > > -		return ret;
> > > > -	}
> > > > -
> > > > -	dpi->pixel_clk = devm_clk_get(dev, "pixel");
> > > > -	if (IS_ERR(dpi->pixel_clk)) {
> > > > -		ret = PTR_ERR(dpi->pixel_clk);
> > > > -		dev_err(dev, "Failed to get pixel clock: %d\n", ret);
> > > > -		return ret;
> > > > -	}
> > > > -
> > > > -	dpi->tvd_clk = devm_clk_get(dev, "pll");
> > > > -	if (IS_ERR(dpi->tvd_clk)) {
> > > > -		ret = PTR_ERR(dpi->tvd_clk);
> > > > -		dev_err(dev, "Failed to get tvdpll clock: %d\n", ret);
> > > > +	ret = conf->parse_clk_from_dt(dpi, np);
> > > > +	if (ret) {
> > > > +		dev_err(dev, "parse tvd div clk failed!");
> > > >  		return ret;
> > > >  	}
> > > >  
> > > > @@ -754,11 +837,6 @@ static int mtk_dpi_remove(struct platform_device *pdev)
> > > >  	return 0;
> > > >  }
> > > >  
> > > > -static const struct of_device_id mtk_dpi_of_ids[] = {
> > > > -	{ .compatible = "mediatek,mt8173-dpi", },
> > > > -	{}
> > > > -};
> > > > -
> > > >  struct platform_driver mtk_dpi_driver = {
> > > >  	.probe = mtk_dpi_probe,
> > > >  	.remove = mtk_dpi_remove,
> > > 
> > > Regards,
> > > CK
> > > 
> > 
> 
> 
> Regards,
> CK
> > 
> 
> 




From matthias.bgg at gmail.com  Mon Jul 25 01:39:52 2016
From: matthias.bgg at gmail.com (Matthias Brugger)
Date: Mon, 25 Jul 2016 10:39:52 +0200
Subject: [PATCH 1/3] memory: mediatek: Add a new interface
 mtk_smi_larb_is_ready
In-Reply-To: <1468983721-3627-1-git-send-email-yong.wu@mediatek.com>
References: <1468983721-3627-1-git-send-email-yong.wu@mediatek.com>
Message-ID: <cd01b829-f869-606b-5c1a-8077fbddb085@gmail.com>



On 20/07/16 05:01, Yong Wu wrote:
> Currently the iommu consumer always call iommu_present to get whether
> the iommu is ready. But in MTK IOMMU, this function can't indicate
> this. The IOMMU call bus_set_iommu->mtk_iommu_add_device->
> mtk_iommu_attach_device to parse the iommu data, then it's able to
> transfer "struct mtk_smi_iommu" to SMI-LARB, and the iommu uses the
> larbs as compoents, the iommu will finish its probe until all the larbs
> probe done.
>
> If the iommu consumer(like DRM) begin to probe after the time of
> calling bus_set_iommu and before the time of SMI probe finish, it
> will hang like this:
>
> [    7.832359] Call trace:
> [    7.834778] [<ffffffc000764424>] mtk_smi_larb_get+0x24/0xa8
> [    7.840300] [<ffffffc0005a1390>] mtk_drm_crtc_enable+0x6c/0x450
>
> Because the larb->mmu is NULL at that time.
>
> In order to avoid this issue, we add a new interface
> (mtk_smi_larb_is_ready) for checking whether the IOMMU and SMI have
> finished their probe. If it return false, the iommu consumer should
> probe-defer for the IOMMU and SMI.
>

Can't we just skip the functions in the probe and call bus_set_iommu 
only if we were able to bind all components?
Something like this:

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index c3043d8..0bef49b 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -649,10 +649,14 @@ static int mtk_iommu_probe(struct platform_device 
*pdev)
         if (ret)
                 return ret;

+       ret = component_master_add_with_match(dev, &mtk_iommu_com_ops, 
match);
+       if (ret)
+               return ret;
+
         if (!iommu_present(&platform_bus_type))
                 bus_set_iommu(&platform_bus_type, &mtk_iommu_ops);

-       return component_master_add_with_match(dev, &mtk_iommu_com_ops, 
match);
+       return ret;
  } 

 

  static int mtk_iommu_remove(struct platform_device *pdev)

Regards,
Matthias


From matthias.bgg at gmail.com  Mon Jul 25 01:43:32 2016
From: matthias.bgg at gmail.com (Matthias Brugger)
Date: Mon, 25 Jul 2016 10:43:32 +0200
Subject: [PATCH] GPU-DRM: Delete an unnecessary check before
 drm_property_unreference_blob()
In-Reply-To: <515bcb7e-3e00-3438-cc47-227cfcd41990@users.sourceforge.net>
References: <5307CAA2.8060406@users.sourceforge.net>
 <alpine.DEB.2.02.1402212321410.2043@localhost6.localdomain6>
 <530A086E.8010901@users.sourceforge.net>
 <alpine.DEB.2.02.1402231635510.1985@localhost6.localdomain6>
 <530A72AA.3000601@users.sourceforge.net>
 <alpine.DEB.2.02.1402240658210.2090@localhost6.localdomain6>
 <530B5FB6.6010207@users.sourceforge.net>
 <alpine.DEB.2.10.1402241710370.2074@hadrien>
 <530C5E18.1020800@users.sourceforge.net>
 <alpine.DEB.2.10.1402251014170.2080@hadrien>
 <530CD2C4.4050903@users.sourceforge.net>
 <alpine.DEB.2.10.1402251840450.7035@hadrien>
 <530CF8FF.8080600@users.sourceforge.net>
 <alpine.DEB.2.02.1402252117150.2047@localhost6.localdomain6>
 <530DD06F.4090703@users.sourceforge.net>
 <alpine.DEB.2.02.1402262129250.2221@localhost6.localdomain6>
 <5317A59D.4@users.sourceforge.net>
 <515bcb7e-3e00-3438-cc47-227cfcd41990@users.sourceforge.net>
Message-ID: <69fe77a4-d9fd-83b4-7821-f0a3c13d737f@gmail.com>



On 22/07/16 12:56, SF Markus Elfring wrote:
> From: Markus Elfring <elfring at users.sourceforge.net>
> Date: Fri, 22 Jul 2016 12:48:12 +0200
>
> The drm_property_unreference_blob() function tests whether its argument
> is NULL and then returns immediately.
> Thus the test around the call is not needed.
>
> This issue was detected by using the Coccinelle software.
>
> Signed-off-by: Markus Elfring <elfring at users.sourceforge.net>
> ---
>  drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 4 +---
>  1 file changed, 1 insertion(+), 3 deletions(-)
>

Reviewed-by: Matthias Brugger <matthias.bgg at gmail.com>

> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> index 24aa3ba..07541d0 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> @@ -112,9 +112,7 @@ static void mtk_drm_crtc_reset(struct drm_crtc *crtc)
>  	struct mtk_crtc_state *state;
>
>  	if (crtc->state) {
> -		if (crtc->state->mode_blob)
> -			drm_property_unreference_blob(crtc->state->mode_blob);
> -
> +		drm_property_unreference_blob(crtc->state->mode_blob);
>  		state = to_mtk_crtc_state(crtc->state);
>  		memset(state, 0, sizeof(*state));
>  	} else {
>


From yong.wu at mediatek.com  Mon Jul 25 18:31:48 2016
From: yong.wu at mediatek.com (Yong Wu)
Date: Tue, 26 Jul 2016 09:31:48 +0800
Subject: [PATCH 1/3] memory: mediatek: Add a new interface
 mtk_smi_larb_is_ready
In-Reply-To: <cd01b829-f869-606b-5c1a-8077fbddb085@gmail.com>
References: <1468983721-3627-1-git-send-email-yong.wu@mediatek.com>
 <cd01b829-f869-606b-5c1a-8077fbddb085@gmail.com>
Message-ID: <1469496708.3072.4.camel@mhfsdcap03>

On Mon, 2016-07-25 at 10:39 +0200, Matthias Brugger wrote:
> 
> On 20/07/16 05:01, Yong Wu wrote:
> > Currently the iommu consumer always call iommu_present to get whether
> > the iommu is ready. But in MTK IOMMU, this function can't indicate
> > this. The IOMMU call bus_set_iommu->mtk_iommu_add_device->
> > mtk_iommu_attach_device to parse the iommu data, then it's able to
> > transfer "struct mtk_smi_iommu" to SMI-LARB, and the iommu uses the
> > larbs as compoents, the iommu will finish its probe until all the larbs
> > probe done.
> >
> > If the iommu consumer(like DRM) begin to probe after the time of
> > calling bus_set_iommu and before the time of SMI probe finish, it
> > will hang like this:
> >
> > [    7.832359] Call trace:
> > [    7.834778] [<ffffffc000764424>] mtk_smi_larb_get+0x24/0xa8
> > [    7.840300] [<ffffffc0005a1390>] mtk_drm_crtc_enable+0x6c/0x450
> >
> > Because the larb->mmu is NULL at that time.
> >
> > In order to avoid this issue, we add a new interface
> > (mtk_smi_larb_is_ready) for checking whether the IOMMU and SMI have
> > finished their probe. If it return false, the iommu consumer should
> > probe-defer for the IOMMU and SMI.
> >
> 
> Can't we just skip the functions in the probe and call bus_set_iommu 
> only if we were able to bind all components?
> Something like this:
> 
> diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
> index c3043d8..0bef49b 100644
> --- a/drivers/iommu/mtk_iommu.c
> +++ b/drivers/iommu/mtk_iommu.c
> @@ -649,10 +649,14 @@ static int mtk_iommu_probe(struct platform_device 
> *pdev)
>          if (ret)
>                  return ret;
> 
> +       ret = component_master_add_with_match(dev, &mtk_iommu_com_ops, 
> match);
> +       if (ret)
> +               return ret;
> +
>          if (!iommu_present(&platform_bus_type))
>                  bus_set_iommu(&platform_bus_type, &mtk_iommu_ops);
> 
> -       return component_master_add_with_match(dev, &mtk_iommu_com_ops, 
> match);
> +       return ret;
>   } 

Thanks very much for your suggestion, I have tried and this seems don't
work.

I don't know much about component, so add some logs.
                                                                
 component_master_add_with_match only add the ops into a list, it won't
wait for the smi-larb probe done. Below is the log, it will return
quickly. 

[    0.095073] mtk-iommu 10205000.iommu: begin to probe 
[    0.095922] mtk-iommu 10205000.iommu: probe hw init
[    0.095948] mtk-iommu 10205000.iommu: trying to bring up master
[    0.095967] mtk-iommu 10205000.iommu: master has incomplete
components

The binder callback(mtk_iommu_bind) is called in this backtrace:

[    0.555718] [<ffff00000849e6ec>] mtk_iommu_bind+0x14/0x48
[    0.556405] [<ffff00000850a860>] try_to_bring_up_master.part.6
+0x38/0x88
[    0.557255] [<ffff00000850b014>] component_add+0x158/0x208
[    0.557954] [<ffff0000087352a4>] mtk_smi_larb_probe+0xf8/0x134
[    0.558696] [<ffff000008511838>] platform_drv_probe+0x50/0xc8
[    0.559427] [<ffff00000850fcfc>] driver_probe_device+0x224/0x2c4
[    0.560191] [<ffff00000850ff08>] __device_attach_driver+0x98/0xc8
[    0.560966] [<ffff00000850dea0>] bus_for_each_drv+0x58/0x98
[    0.561676] [<ffff00000850fa3c>] __device_attach+0xbc/0x124
[    0.562385] [<ffff0000085100a4>] device_initial_probe+0x10/0x18
[    0.563138] [<ffff00000850ef48>] bus_probe_device+0x90/0x98
[    0.563848] [<ffff00000850f3e4>] deferred_probe_work_func+0x7c/0xb0

Thus, It looks like mtk_iommu_bind is called in mtk_smi_larb_probe which
will be delayed by power-domain.
then iommu_present is true even though M4U and SMI-larb have not
finished their component binding.

> 
>  
> 
>   static int mtk_iommu_remove(struct platform_device *pdev)
> 
> Regards,
> Matthias




From tfiga at google.com  Mon Jul 25 19:30:42 2016
From: tfiga at google.com (Tomasz Figa)
Date: Tue, 26 Jul 2016 11:30:42 +0900
Subject: [PATCH 1/3] memory: mediatek: Add a new interface
 mtk_smi_larb_is_ready
In-Reply-To: <cd01b829-f869-606b-5c1a-8077fbddb085@gmail.com>
References: <1468983721-3627-1-git-send-email-yong.wu@mediatek.com>
 <cd01b829-f869-606b-5c1a-8077fbddb085@gmail.com>
Message-ID: <CAAFQd5AXXpVQU7+ek0Jb_aNm5md=1GVrysEDD5GO7erLUByzrw@mail.gmail.com>

Hi,

On Mon, Jul 25, 2016 at 5:39 PM, Matthias Brugger
<matthias.bgg at gmail.com> wrote:
>
>
> On 20/07/16 05:01, Yong Wu wrote:
>>
>> Currently the iommu consumer always call iommu_present to get whether
>> the iommu is ready. But in MTK IOMMU, this function can't indicate
>> this. The IOMMU call bus_set_iommu->mtk_iommu_add_device->
>> mtk_iommu_attach_device to parse the iommu data, then it's able to
>> transfer "struct mtk_smi_iommu" to SMI-LARB, and the iommu uses the
>> larbs as compoents, the iommu will finish its probe until all the larbs
>> probe done.
>>
>> If the iommu consumer(like DRM) begin to probe after the time of
>> calling bus_set_iommu and before the time of SMI probe finish, it
>> will hang like this:
>>
>> [    7.832359] Call trace:
>> [    7.834778] [<ffffffc000764424>] mtk_smi_larb_get+0x24/0xa8
>> [    7.840300] [<ffffffc0005a1390>] mtk_drm_crtc_enable+0x6c/0x450
>>
>> Because the larb->mmu is NULL at that time.
>>
>> In order to avoid this issue, we add a new interface
>> (mtk_smi_larb_is_ready) for checking whether the IOMMU and SMI have
>> finished their probe. If it return false, the iommu consumer should
>> probe-defer for the IOMMU and SMI.
>>
>
> Can't we just skip the functions in the probe and call bus_set_iommu only if
> we were able to bind all components?
> Something like this:

Note that we have to call bus_set_iommu() and actually have
.add_device() and .attach_device() called before any of the slave
devices probe. I found a similar problem with rockchip IOMMU after
adding power domain and runtime PM handling there. I also found that
current design of IOMMU core and related DMA mapping code is utterly
broken regarding the device add/probe ordering (no support for
deferring things properly).

So my idea is to keep .add_device() as is, since typically it doesn't
seem to require anything from the IOMMU hardware and just initializes
some per-device data, but make .attach_device() being able to defer
probe of that device if respective IOMMU has not probed yet. I'm still
in process of figuring out the right way to achieve it, though...

Best regards,
Tomasz


From weiyj.lk at gmail.com  Tue Jul 26 07:56:50 2016
From: weiyj.lk at gmail.com (Wei Yongjun)
Date: Tue, 26 Jul 2016 14:56:50 +0000
Subject: [PATCH] spi: mediatek: remove spi_master_put in mtk_spi_remove()
Message-ID: <1469545010-32327-1-git-send-email-weiyj.lk@gmail.com>

The call to spi_master_put() in mtk_spi_remove() is redundant since
the master is registered using devm_spi_register_master() and no
reference hold by using spi_master_get() in mtk_spi_remove().

This is detected by Coccinelle semantic patch.

Signed-off-by: Wei Yongjun <weiyj.lk at gmail.com>
---
 drivers/spi/spi-mt65xx.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c
index 0be89e0..899d7a8 100644
--- a/drivers/spi/spi-mt65xx.c
+++ b/drivers/spi/spi-mt65xx.c
@@ -685,7 +685,6 @@ static int mtk_spi_remove(struct platform_device *pdev)
 	pm_runtime_disable(&pdev->dev);
 
 	mtk_spi_reset(mdata);
-	spi_master_put(master);
 
 	return 0;
 }



From ville.syrjala at linux.intel.com  Tue Jul 26 09:07:03 2016
From: ville.syrjala at linux.intel.com (ville.syrjala at linux.intel.com)
Date: Tue, 26 Jul 2016 19:07:03 +0300
Subject: [PATCH 8/9] drm/mediatek: Use drm_plane_helper_check_state()
In-Reply-To: <1469549224-1860-1-git-send-email-ville.syrjala@linux.intel.com>
References: <1469549224-1860-1-git-send-email-ville.syrjala@linux.intel.com>
Message-ID: <1469549224-1860-9-git-send-email-ville.syrjala@linux.intel.com>

From: Ville Syrj?l? <ville.syrjala at linux.intel.com>

Replace the use of drm_plane_helper_check_update() with
drm_plane_helper_check_state() since we have a plane state.

This also eliminates the double clipping the driver was doing
in both check and commit phases). And it should fix src coordinate
addr adjustement. Previously the driver was expecting negative dst
coordinates after clipping, which is not going happen, so any clipping
induced addr adjustment simply didn't happen. Neither did the driver
respect any user configured src coordinates, so panning and such would
have been totally broken. It should be all good now.

Cc: CK Hu <ck.hu at mediatek.com>
Cc: linux-mediatek at lists.infradead.org
Signed-off-by: Ville Syrj?l? <ville.syrjala at linux.intel.com>
---
 drivers/gpu/drm/mediatek/mtk_drm_plane.c | 72 +++++++++-----------------------
 1 file changed, 20 insertions(+), 52 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
index 3995765a90dc..5f2516fca079 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
@@ -30,15 +30,20 @@ static const u32 formats[] = {
 	DRM_FORMAT_RGB565,
 };
 
-static void mtk_plane_enable(struct mtk_drm_plane *mtk_plane, bool enable,
-			     dma_addr_t addr, struct drm_rect *dest)
+static void mtk_plane_enable(struct mtk_drm_plane *mtk_plane,
+			     dma_addr_t addr)
 {
 	struct drm_plane *plane = &mtk_plane->base;
 	struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
 	unsigned int pitch, format;
-	int x, y;
+	bool enable;
 
-	if (WARN_ON(!plane->state || (enable && !plane->state->fb)))
+	if (WARN_ON(!plane->state))
+		return;
+
+	enable = state->base.visible;
+
+	if (WARN_ON(enable && !plane->state->fb))
 		return;
 
 	if (plane->state->fb) {
@@ -49,27 +54,17 @@ static void mtk_plane_enable(struct mtk_drm_plane *mtk_plane, bool enable,
 		format = DRM_FORMAT_RGBA8888;
 	}
 
-	x = plane->state->crtc_x;
-	y = plane->state->crtc_y;
-
-	if (x < 0) {
-		addr -= x * 4;
-		x = 0;
-	}
-
-	if (y < 0) {
-		addr -= y * pitch;
-		y = 0;
-	}
+	addr += (state->base.src.x1 >> 16) * 4;
+	addr += (state->base.src.y1 >> 16) * pitch;
 
 	state->pending.enable = enable;
 	state->pending.pitch = pitch;
 	state->pending.format = format;
 	state->pending.addr = addr;
-	state->pending.x = x;
-	state->pending.y = y;
-	state->pending.width = dest->x2 - dest->x1;
-	state->pending.height = dest->y2 - dest->y1;
+	state->pending.x = state->base.dst.x1;
+	state->pending.y = state->base.dst.y1;
+	state->pending.width = drm_rect_width(&state->base.dst);
+	state->pending.height = drm_rect_height(&state->base.dst);
 	wmb(); /* Make sure the above parameters are set before update */
 	state->pending.dirty = true;
 }
@@ -134,20 +129,6 @@ static int mtk_plane_atomic_check(struct drm_plane *plane,
 {
 	struct drm_framebuffer *fb = state->fb;
 	struct drm_crtc_state *crtc_state;
-	bool visible;
-	struct drm_rect dest = {
-		.x1 = state->crtc_x,
-		.y1 = state->crtc_y,
-		.x2 = state->crtc_x + state->crtc_w,
-		.y2 = state->crtc_y + state->crtc_h,
-	};
-	struct drm_rect src = {
-		/* 16.16 fixed point */
-		.x1 = state->src_x,
-		.y1 = state->src_y,
-		.x2 = state->src_x + state->src_w,
-		.y2 = state->src_y + state->src_h,
-	};
 	struct drm_rect clip = { 0, };
 
 	if (!fb)
@@ -168,12 +149,10 @@ static int mtk_plane_atomic_check(struct drm_plane *plane,
 	clip.x2 = crtc_state->mode.hdisplay;
 	clip.y2 = crtc_state->mode.vdisplay;
 
-	return drm_plane_helper_check_update(plane, state->crtc, fb,
-					     &src, &dest, &clip,
-					     state->rotation,
-					     DRM_PLANE_HELPER_NO_SCALING,
-					     DRM_PLANE_HELPER_NO_SCALING,
-					     true, true, &visible);
+	return drm_plane_helper_check_state(state, &clip,
+					    DRM_PLANE_HELPER_NO_SCALING,
+					    DRM_PLANE_HELPER_NO_SCALING,
+					    true, true);
 }
 
 static void mtk_plane_atomic_update(struct drm_plane *plane,
@@ -184,24 +163,13 @@ static void mtk_plane_atomic_update(struct drm_plane *plane,
 	struct drm_gem_object *gem;
 	struct mtk_drm_gem_obj *mtk_gem;
 	struct mtk_drm_plane *mtk_plane = to_mtk_plane(plane);
-	struct drm_rect dest = {
-		.x1 = state->base.crtc_x,
-		.y1 = state->base.crtc_y,
-		.x2 = state->base.crtc_x + state->base.crtc_w,
-		.y2 = state->base.crtc_y + state->base.crtc_h,
-	};
-	struct drm_rect clip = { 0, };
 
 	if (!crtc)
 		return;
 
-	clip.x2 = state->base.crtc->state->mode.hdisplay;
-	clip.y2 = state->base.crtc->state->mode.vdisplay;
-	drm_rect_intersect(&dest, &clip);
-
 	gem = mtk_fb_get_gem_obj(state->base.fb);
 	mtk_gem = to_mtk_gem_obj(gem);
-	mtk_plane_enable(mtk_plane, true, mtk_gem->dma_addr, &dest);
+	mtk_plane_enable(mtk_plane, mtk_gem->dma_addr);
 }
 
 static void mtk_plane_atomic_disable(struct drm_plane *plane,
-- 
2.7.4



From robh at kernel.org  Tue Jul 26 11:54:34 2016
From: robh at kernel.org (Rob Herring)
Date: Tue, 26 Jul 2016 13:54:34 -0500
Subject: [PATCH v2 2/4] dt-bindings: Add a binding for Mediatek MDP
In-Reply-To: <1469176383-35210-3-git-send-email-minghsiu.tsai@mediatek.com>
References: <1469176383-35210-1-git-send-email-minghsiu.tsai@mediatek.com>
 <1469176383-35210-3-git-send-email-minghsiu.tsai@mediatek.com>
Message-ID: <20160726185433.GA14609@rob-hp-laptop>

On Fri, Jul 22, 2016 at 04:33:01PM +0800, Minghsiu Tsai wrote:
> Add a DT binding documentation of MDP for the MT8173 SoC
> from Mediatek
> 
> Signed-off-by: Minghsiu Tsai <minghsiu.tsai at mediatek.com>
> ---
>  .../devicetree/bindings/media/mediatek-mdp.txt     |   96 ++++++++++++++++++++
>  1 file changed, 96 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/media/mediatek-mdp.txt
> 
> diff --git a/Documentation/devicetree/bindings/media/mediatek-mdp.txt b/Documentation/devicetree/bindings/media/mediatek-mdp.txt
> new file mode 100644
> index 0000000..2dad031
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/mediatek-mdp.txt
> @@ -0,0 +1,96 @@
> +* Mediatek Media Data Path
> +
> +Media Data Path is used for scaling and color space conversion.
> +
> +Required properties (all function blocks):
> +- compatible: "mediatek,<chip>-mdp"

What is this, ...

> +        "mediatek,<chip>-mdp-<function>", one of

and this?

> +        "mediatek,<chip>-mdp-rdma"  - read DMA
> +        "mediatek,<chip>-mdp-rsz"   - resizer
> +        "mediatek,<chip>-mdp-wdma"  - write DMA
> +        "mediatek,<chip>-mdp-wrot"  - write DMA with rotation

List what are valid values of <chip>.

> +- reg: Physical base address and length of the function block register space
> +- clocks: device clocks
> +- power-domains: a phandle to the power domain.
> +- mediatek,vpu: the node of video processor unit
> +
> +Required properties (DMA function blocks):
> +- compatible: Should be one of
> +        "mediatek,<chip>-mdp-rdma"
> +        "mediatek,<chip>-mdp-wdma"
> +        "mediatek,<chip>-mdp-wrot"
> +- iommus: should point to the respective IOMMU block with master port as
> +  argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
> +  for details.
> +- mediatek,larb: must contain the local arbiters in the current Socs.

It is still not clear which properties apply to which compatible 
strings.

> +
> +Example:
> +	mdp_rdma0: rdma at 14001000 {
> +		compatible = "mediatek,mt8173-mdp-rdma",
> +			     "mediatek,mt8173-mdp";
> +		reg = <0 0x14001000 0 0x1000>;
> +		clocks = <&mmsys CLK_MM_MDP_RDMA0>,
> +			 <&mmsys CLK_MM_MUTEX_32K>;
> +		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
> +		iommus = <&iommu M4U_PORT_MDP_RDMA0>;
> +		mediatek,larb = <&larb0>;
> +		mediatek,vpu = <&vpu>;
> +	};
> +
> +	mdp_rdma1: rdma at 14002000 {
> +		compatible = "mediatek,mt8173-mdp-rdma";
> +		reg = <0 0x14002000 0 0x1000>;
> +		clocks = <&mmsys CLK_MM_MDP_RDMA1>,
> +			 <&mmsys CLK_MM_MUTEX_32K>;
> +		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
> +		iommus = <&iommu M4U_PORT_MDP_RDMA1>;
> +		mediatek,larb = <&larb4>;
> +	};
> +
> +	mdp_rsz0: rsz at 14003000 {
> +		compatible = "mediatek,mt8173-mdp-rsz";
> +		reg = <0 0x14003000 0 0x1000>;
> +		clocks = <&mmsys CLK_MM_MDP_RSZ0>;
> +		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
> +	};
> +
> +	mdp_rsz1: rsz at 14004000 {
> +		compatible = "mediatek,mt8173-mdp-rsz";
> +		reg = <0 0x14004000 0 0x1000>;
> +		clocks = <&mmsys CLK_MM_MDP_RSZ1>;
> +		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
> +	};
> +
> +	mdp_rsz2: rsz at 14005000 {
> +		compatible = "mediatek,mt8173-mdp-rsz";
> +		reg = <0 0x14005000 0 0x1000>;
> +		clocks = <&mmsys CLK_MM_MDP_RSZ2>;
> +		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
> +	};
> +
> +	mdp_wdma0: wdma at 14006000 {
> +		compatible = "mediatek,mt8173-mdp-wdma";
> +		reg = <0 0x14006000 0 0x1000>;
> +		clocks = <&mmsys CLK_MM_MDP_WDMA>;
> +		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
> +		iommus = <&iommu M4U_PORT_MDP_WDMA>;
> +		mediatek,larb = <&larb0>;
> +	};
> +
> +	mdp_wrot0: wrot at 14007000 {
> +		compatible = "mediatek,mt8173-mdp-wrot";
> +		reg = <0 0x14007000 0 0x1000>;
> +		clocks = <&mmsys CLK_MM_MDP_WROT0>;
> +		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
> +		iommus = <&iommu M4U_PORT_MDP_WROT0>;
> +		mediatek,larb = <&larb0>;
> +	};
> +
> +	mdp_wrot1: wrot at 14008000 {
> +		compatible = "mediatek,mt8173-mdp-wrot";
> +		reg = <0 0x14008000 0 0x1000>;
> +		clocks = <&mmsys CLK_MM_MDP_WROT1>;
> +		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
> +		iommus = <&iommu M4U_PORT_MDP_WROT1>;
> +		mediatek,larb = <&larb4>;
> +	};
> -- 
> 1.7.9.5
> 


From minghsiu.tsai at mediatek.com  Tue Jul 26 18:44:46 2016
From: minghsiu.tsai at mediatek.com (Minghsiu Tsai)
Date: Wed, 27 Jul 2016 09:44:46 +0800
Subject: [PATCH v2 2/4] dt-bindings: Add a binding for Mediatek MDP
In-Reply-To: <20160726185433.GA14609@rob-hp-laptop>
References: <1469176383-35210-1-git-send-email-minghsiu.tsai@mediatek.com>
 <1469176383-35210-3-git-send-email-minghsiu.tsai@mediatek.com>
 <20160726185433.GA14609@rob-hp-laptop>
Message-ID: <1469583886.27630.18.camel@mtksdaap41>

On Tue, 2016-07-26 at 13:54 -0500, Rob Herring wrote:
> On Fri, Jul 22, 2016 at 04:33:01PM +0800, Minghsiu Tsai wrote:
> > Add a DT binding documentation of MDP for the MT8173 SoC
> > from Mediatek
> > 
> > Signed-off-by: Minghsiu Tsai <minghsiu.tsai at mediatek.com>
> > ---
> >  .../devicetree/bindings/media/mediatek-mdp.txt     |   96 ++++++++++++++++++++
> >  1 file changed, 96 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/media/mediatek-mdp.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/media/mediatek-mdp.txt b/Documentation/devicetree/bindings/media/mediatek-mdp.txt
> > new file mode 100644
> > index 0000000..2dad031
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/media/mediatek-mdp.txt
> > @@ -0,0 +1,96 @@
> > +* Mediatek Media Data Path
> > +
> > +Media Data Path is used for scaling and color space conversion.
> > +
> > +Required properties (all function blocks):
> > +- compatible: "mediatek,<chip>-mdp"
> 
> What is this, ...
> 

It is used to match platform driver.


> > +        "mediatek,<chip>-mdp-<function>", one of
> 
> and this?
> 

It is string format of HW block. <chip> could be "mt8173", and
<function> are "rdma", "rsz", "wdma", and "wrot".  


> > +        "mediatek,<chip>-mdp-rdma"  - read DMA
> > +        "mediatek,<chip>-mdp-rsz"   - resizer
> > +        "mediatek,<chip>-mdp-wdma"  - write DMA
> > +        "mediatek,<chip>-mdp-wrot"  - write DMA with rotation
> 
> List what are valid values of <chip>.
> 

<chip> - mt8173. There should be other chip added in future.
I will change the property as blow:

- compatible: "mediatek,<chip>-mdp"
        Should be one of
        "mediatek,<chip>-mdp-rdma"  - read DMA
        "mediatek,<chip>-mdp-rsz"   - resizer
        "mediatek,<chip>-mdp-wdma"  - write DMA
        "mediatek,<chip>-mdp-wrot"  - write DMA with rotation
        <chip> - could be 8173


If don't need <chip>, I also can change it as below. It is more clear.
- compatible: "mediatek,mt8173-mdp"
        Should be one of
        "mediatek,mt8173-mdp-rdma"  - read DMA
        "mediatek,mt8173-mdp-rsz"   - resizer
        "mediatek,mt8173-mdp-wdma"  - write DMA
        "mediatek,mt8173-mdp-wrot"  - write DMA with rotation


> > +- reg: Physical base address and length of the function block register space
> > +- clocks: device clocks
> > +- power-domains: a phandle to the power domain.
> > +- mediatek,vpu: the node of video processor unit
> > +
> > +Required properties (DMA function blocks):
> > +- compatible: Should be one of
> > +        "mediatek,<chip>-mdp-rdma"
> > +        "mediatek,<chip>-mdp-wdma"
> > +        "mediatek,<chip>-mdp-wrot"
> > +- iommus: should point to the respective IOMMU block with master port as
> > +  argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
> > +  for details.
> > +- mediatek,larb: must contain the local arbiters in the current Socs.
> 
> It is still not clear which properties apply to which compatible 
> strings.
> 

I found out the document for larb. 
I will change the property as below:

- mediatek,larb: must contain the local arbiters in the current Socs,
see
Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt 
  for details.


> > +
> > +Example:
> > +	mdp_rdma0: rdma at 14001000 {
> > +		compatible = "mediatek,mt8173-mdp-rdma",
> > +			     "mediatek,mt8173-mdp";
> > +		reg = <0 0x14001000 0 0x1000>;
> > +		clocks = <&mmsys CLK_MM_MDP_RDMA0>,
> > +			 <&mmsys CLK_MM_MUTEX_32K>;
> > +		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
> > +		iommus = <&iommu M4U_PORT_MDP_RDMA0>;
> > +		mediatek,larb = <&larb0>;
> > +		mediatek,vpu = <&vpu>;
> > +	};
> > +
> > +	mdp_rdma1: rdma at 14002000 {
> > +		compatible = "mediatek,mt8173-mdp-rdma";
> > +		reg = <0 0x14002000 0 0x1000>;
> > +		clocks = <&mmsys CLK_MM_MDP_RDMA1>,
> > +			 <&mmsys CLK_MM_MUTEX_32K>;
> > +		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
> > +		iommus = <&iommu M4U_PORT_MDP_RDMA1>;
> > +		mediatek,larb = <&larb4>;
> > +	};
> > +
> > +	mdp_rsz0: rsz at 14003000 {
> > +		compatible = "mediatek,mt8173-mdp-rsz";
> > +		reg = <0 0x14003000 0 0x1000>;
> > +		clocks = <&mmsys CLK_MM_MDP_RSZ0>;
> > +		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
> > +	};
> > +
> > +	mdp_rsz1: rsz at 14004000 {
> > +		compatible = "mediatek,mt8173-mdp-rsz";
> > +		reg = <0 0x14004000 0 0x1000>;
> > +		clocks = <&mmsys CLK_MM_MDP_RSZ1>;
> > +		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
> > +	};
> > +
> > +	mdp_rsz2: rsz at 14005000 {
> > +		compatible = "mediatek,mt8173-mdp-rsz";
> > +		reg = <0 0x14005000 0 0x1000>;
> > +		clocks = <&mmsys CLK_MM_MDP_RSZ2>;
> > +		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
> > +	};
> > +
> > +	mdp_wdma0: wdma at 14006000 {
> > +		compatible = "mediatek,mt8173-mdp-wdma";
> > +		reg = <0 0x14006000 0 0x1000>;
> > +		clocks = <&mmsys CLK_MM_MDP_WDMA>;
> > +		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
> > +		iommus = <&iommu M4U_PORT_MDP_WDMA>;
> > +		mediatek,larb = <&larb0>;
> > +	};
> > +
> > +	mdp_wrot0: wrot at 14007000 {
> > +		compatible = "mediatek,mt8173-mdp-wrot";
> > +		reg = <0 0x14007000 0 0x1000>;
> > +		clocks = <&mmsys CLK_MM_MDP_WROT0>;
> > +		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
> > +		iommus = <&iommu M4U_PORT_MDP_WROT0>;
> > +		mediatek,larb = <&larb0>;
> > +	};
> > +
> > +	mdp_wrot1: wrot at 14008000 {
> > +		compatible = "mediatek,mt8173-mdp-wrot";
> > +		reg = <0 0x14008000 0 0x1000>;
> > +		clocks = <&mmsys CLK_MM_MDP_WROT1>;
> > +		power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
> > +		iommus = <&iommu M4U_PORT_MDP_WROT1>;
> > +		mediatek,larb = <&larb4>;
> > +	};
> > -- 
> > 1.7.9.5
> > 




From hs.liao at mediatek.com  Wed Jul 27 00:14:09 2016
From: hs.liao at mediatek.com (HS Liao)
Date: Wed, 27 Jul 2016 15:14:09 +0800
Subject: [PATCH v11 0/4] Mediatek MT8173 CMDQ support
Message-ID: <1469603653-9733-1-git-send-email-hs.liao@mediatek.com>


Hi,

This is Mediatek MT8173 Command Queue(CMDQ) driver. The CMDQ is used
to help write registers with critical time limitation, such as
updating display configuration during the vblank. It controls Global
Command Engine (GCE) hardware to achieve this requirement.

These patches have a build dependency on top of v4.7-rc1.

Changes since v10:
 - remove module.h

Best regards,
HS Liao

HS Liao (4):
  dt-bindings: soc: Add documentation for the MediaTek GCE unit
  CMDQ: Mediatek CMDQ driver
  arm64: dts: mt8173: Add GCE node
  CMDQ: save more energy in idle

 .../devicetree/bindings/soc/mediatek/gce.txt       |  47 +
 arch/arm64/boot/dts/mediatek/mt8173.dtsi           |  10 +
 drivers/soc/mediatek/Kconfig                       |  11 +
 drivers/soc/mediatek/Makefile                      |   1 +
 drivers/soc/mediatek/mtk-cmdq.c                    | 986 +++++++++++++++++++++
 include/soc/mediatek/cmdq.h                        | 179 ++++
 6 files changed, 1234 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/soc/mediatek/gce.txt
 create mode 100644 drivers/soc/mediatek/mtk-cmdq.c
 create mode 100644 include/soc/mediatek/cmdq.h

-- 
1.9.1



From hs.liao at mediatek.com  Wed Jul 27 00:14:10 2016
From: hs.liao at mediatek.com (HS Liao)
Date: Wed, 27 Jul 2016 15:14:10 +0800
Subject: [PATCH v11 1/4] dt-bindings: soc: Add documentation for the MediaTek
 GCE unit
In-Reply-To: <1469603653-9733-1-git-send-email-hs.liao@mediatek.com>
References: <1469603653-9733-1-git-send-email-hs.liao@mediatek.com>
Message-ID: <1469603653-9733-2-git-send-email-hs.liao@mediatek.com>

This adds documentation for the MediaTek Global Command Engine (GCE) unit
found in MT8173 SoCs.

Signed-off-by: HS Liao <hs.liao at mediatek.com>
Acked-by: Rob Herring <robh at kernel.org>
---
 .../devicetree/bindings/soc/mediatek/gce.txt       | 47 ++++++++++++++++++++++
 1 file changed, 47 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/soc/mediatek/gce.txt

diff --git a/Documentation/devicetree/bindings/soc/mediatek/gce.txt b/Documentation/devicetree/bindings/soc/mediatek/gce.txt
new file mode 100644
index 0000000..2b3e655
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/mediatek/gce.txt
@@ -0,0 +1,47 @@
+MediaTek GCE
+===============
+
+The Global Command Engine (GCE) is used to help read/write registers with
+critical time limitation, such as updating display configuration during the
+vblank. The GCE can be used to implement the Command Queue (CMDQ) driver.
+
+CMDQ driver uses mailbox framework for communication. Please refer to
+../../mailbox/mailbox.txt for generic information about mailbox device-tree
+bindings.
+
+Required properties:
+- compatible: Must be "mediatek,mt8173-gce"
+- reg: Address range of the GCE unit
+- interrupts: The interrupt signal from the GCE block
+- clock: Clocks according to the common clock binding
+- clock-names: Must be "gce" to stand for GCE clock
+- #mbox-cells: Should be 2
+
+Required properties for a client device:
+- mediatek,gce: If a client asks GCE to access its registers, it should have
+  this property and point to the respective GCE block.
+- mboxes: If a client will communicate with GCE via mailbox, it should have
+  this property and list of phandle, mailbox channel specifiers, and atomic
+  execution flag.
+
+Example:
+
+	gce: gce at 10212000 {
+		compatible = "mediatek,mt8173-gce";
+		reg = <0 0x10212000 0 0x1000>;
+		interrupts = <GIC_SPI 135 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&infracfg CLK_INFRA_GCE>;
+		clock-names = "gce";
+
+		#mbox-cells = <2>;
+	};
+
+Example for a client device:
+
+	mmsys: clock-controller at 14000000 {
+		compatible = "mediatek,mt8173-mmsys";
+		mediatek,gce = <&gce>;
+		mboxes = <&gce 0 1 /* main display with atomic execution */
+			  &gce 1 1>; /* sub display with atomic execution */
+		...
+	};
-- 
1.9.1



From hs.liao at mediatek.com  Wed Jul 27 00:14:11 2016
From: hs.liao at mediatek.com (HS Liao)
Date: Wed, 27 Jul 2016 15:14:11 +0800
Subject: [PATCH v11 2/4] CMDQ: Mediatek CMDQ driver
In-Reply-To: <1469603653-9733-1-git-send-email-hs.liao@mediatek.com>
References: <1469603653-9733-1-git-send-email-hs.liao@mediatek.com>
Message-ID: <1469603653-9733-3-git-send-email-hs.liao@mediatek.com>

This patch is first version of Mediatek Command Queue(CMDQ) driver. The
CMDQ is used to help write registers with critical time limitation,
such as updating display configuration during the vblank. It controls
Global Command Engine (GCE) hardware to achieve this requirement.
Currently, CMDQ only supports display related hardwares, but we expect
it can be extended to other hardwares for future requirements.

Signed-off-by: HS Liao <hs.liao at mediatek.com>
Signed-off-by: CK Hu <ck.hu at mediatek.com>
---
 drivers/soc/mediatek/Kconfig    |  11 +
 drivers/soc/mediatek/Makefile   |   1 +
 drivers/soc/mediatek/mtk-cmdq.c | 947 ++++++++++++++++++++++++++++++++++++++++
 include/soc/mediatek/cmdq.h     | 179 ++++++++
 4 files changed, 1138 insertions(+)
 create mode 100644 drivers/soc/mediatek/mtk-cmdq.c
 create mode 100644 include/soc/mediatek/cmdq.h

diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
index 0a4ea80..50869e4 100644
--- a/drivers/soc/mediatek/Kconfig
+++ b/drivers/soc/mediatek/Kconfig
@@ -1,6 +1,17 @@
 #
 # MediaTek SoC drivers
 #
+config MTK_CMDQ
+	bool "MediaTek CMDQ Support"
+	depends on ARM64 && ( ARCH_MEDIATEK || COMPILE_TEST )
+	select MAILBOX
+	select MTK_INFRACFG
+	help
+	  Say yes here to add support for the MediaTek Command Queue (CMDQ)
+	  driver. The CMDQ is used to help read/write registers with critical
+	  time limitation, such as updating display configuration during the
+	  vblank.
+
 config MTK_INFRACFG
 	bool "MediaTek INFRACFG Support"
 	depends on ARCH_MEDIATEK || COMPILE_TEST
diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
index 12998b0..f7397ef 100644
--- a/drivers/soc/mediatek/Makefile
+++ b/drivers/soc/mediatek/Makefile
@@ -1,3 +1,4 @@
+obj-$(CONFIG_MTK_CMDQ) += mtk-cmdq.o
 obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o
 obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
 obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
diff --git a/drivers/soc/mediatek/mtk-cmdq.c b/drivers/soc/mediatek/mtk-cmdq.c
new file mode 100644
index 0000000..ec384f9
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-cmdq.c
@@ -0,0 +1,947 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * 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.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/completion.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/mailbox_client.h>
+#include <linux/mailbox_controller.h>
+#include <linux/mutex.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/suspend.h>
+#include <linux/timer.h>
+#include <soc/mediatek/cmdq.h>
+
+#define CMDQ_THR_MAX_COUNT		3 /* main, sub, general(misc) */
+#define CMDQ_INST_SIZE			8 /* instruction is 64-bit */
+#define CMDQ_TIMEOUT_MS			1000
+#define CMDQ_IRQ_MASK			0xffff
+#define CMDQ_NUM_CMD(t)			(t->cmd_buf_size / CMDQ_INST_SIZE)
+
+#define CMDQ_CURR_IRQ_STATUS		0x10
+#define CMDQ_THR_SLOT_CYCLES		0x30
+
+#define CMDQ_THR_BASE			0x100
+#define CMDQ_THR_SIZE			0x80
+#define CMDQ_THR_WARM_RESET		0x00
+#define CMDQ_THR_ENABLE_TASK		0x04
+#define CMDQ_THR_SUSPEND_TASK		0x08
+#define CMDQ_THR_CURR_STATUS		0x0c
+#define CMDQ_THR_IRQ_STATUS		0x10
+#define CMDQ_THR_IRQ_ENABLE		0x14
+#define CMDQ_THR_CURR_ADDR		0x20
+#define CMDQ_THR_END_ADDR		0x24
+
+#define CMDQ_THR_ENABLED		0x1
+#define CMDQ_THR_DISABLED		0x0
+#define CMDQ_THR_SUSPEND		0x1
+#define CMDQ_THR_RESUME			0x0
+#define CMDQ_THR_STATUS_SUSPENDED	BIT(1)
+#define CMDQ_THR_DO_WARM_RESET		BIT(0)
+#define CMDQ_THR_ACTIVE_SLOT_CYCLES	0x3200
+#define CMDQ_THR_IRQ_DONE		0x1
+#define CMDQ_THR_IRQ_ERROR		0x12
+#define CMDQ_THR_IRQ_EN			(CMDQ_THR_IRQ_ERROR | CMDQ_THR_IRQ_DONE)
+
+#define CMDQ_OP_CODE_SHIFT		24
+#define CMDQ_SUBSYS_SHIFT		16
+
+#define CMDQ_ARG_A_WRITE_MASK		0xffff
+#define CMDQ_OP_CODE_MASK		(0xff << CMDQ_OP_CODE_SHIFT)
+
+#define CMDQ_WRITE_ENABLE_MASK		BIT(0)
+#define CMDQ_JUMP_BY_OFFSET		0x10000000
+#define CMDQ_JUMP_BY_PA			0x10000001
+#define CMDQ_JUMP_PASS			CMDQ_INST_SIZE
+#define CMDQ_WFE_UPDATE			BIT(31)
+#define CMDQ_WFE_WAIT			BIT(15)
+#define CMDQ_WFE_WAIT_VALUE		0x1
+#define CMDQ_EOC_IRQ_EN			BIT(0)
+
+/*
+ * CMDQ_CODE_MASK:
+ *   set write mask
+ *   format: op mask
+ * CMDQ_CODE_WRITE:
+ *   write value into target register
+ *   format: op subsys address value
+ * CMDQ_CODE_JUMP:
+ *   jump by offset
+ *   format: op offset
+ * CMDQ_CODE_WFE:
+ *   wait for event and clear
+ *   it is just clear if no wait
+ *   format: [wait]  op event update:1 to_wait:1 wait:1
+ *           [clear] op event update:1 to_wait:0 wait:0
+ * CMDQ_CODE_EOC:
+ *   end of command
+ *   format: op irq_flag
+ */
+enum cmdq_code {
+	CMDQ_CODE_MASK = 0x02,
+	CMDQ_CODE_WRITE = 0x04,
+	CMDQ_CODE_JUMP = 0x10,
+	CMDQ_CODE_WFE = 0x20,
+	CMDQ_CODE_EOC = 0x40,
+};
+
+struct cmdq_task_cb {
+	cmdq_async_flush_cb	cb;
+	void			*data;
+};
+
+struct cmdq_thread {
+	struct mbox_chan	*chan;
+	void __iomem		*base;
+	struct list_head	task_busy_list;
+	struct timer_list	timeout;
+	bool			atomic_exec;
+};
+
+struct cmdq_task {
+	struct cmdq		*cmdq;
+	struct list_head	list_entry;
+	void			*va_base;
+	dma_addr_t		pa_base;
+	size_t			cmd_buf_size; /* command occupied size */
+	size_t			buf_size; /* real buffer size */
+	bool			finalized;
+	struct cmdq_thread	*thread;
+	struct cmdq_task_cb	cb;
+};
+
+struct cmdq {
+	struct mbox_controller	mbox;
+	void __iomem		*base;
+	u32			irq;
+	struct cmdq_thread	thread[CMDQ_THR_MAX_COUNT];
+	struct mutex		task_mutex;
+	struct clk		*clock;
+	bool			suspended;
+};
+
+struct cmdq_subsys {
+	u32	base;
+	int	id;
+};
+
+static const struct cmdq_subsys gce_subsys[] = {
+	{0x1400, 1},
+	{0x1401, 2},
+	{0x1402, 3},
+};
+
+static int cmdq_subsys_base_to_id(u32 base)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(gce_subsys); i++)
+		if (gce_subsys[i].base == base)
+			return gce_subsys[i].id;
+	return -EFAULT;
+}
+
+static int cmdq_thread_suspend(struct cmdq *cmdq, struct cmdq_thread *thread)
+{
+	u32 status;
+
+	writel(CMDQ_THR_SUSPEND, thread->base + CMDQ_THR_SUSPEND_TASK);
+
+	/* If already disabled, treat as suspended successful. */
+	if (!(readl(thread->base + CMDQ_THR_ENABLE_TASK) & CMDQ_THR_ENABLED))
+		return 0;
+
+	if (readl_poll_timeout_atomic(thread->base + CMDQ_THR_CURR_STATUS,
+			status, status & CMDQ_THR_STATUS_SUSPENDED, 0, 10)) {
+		dev_err(cmdq->mbox.dev, "suspend GCE thread 0x%x failed\n",
+			(u32)(thread->base - cmdq->base));
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static void cmdq_thread_resume(struct cmdq_thread *thread)
+{
+	writel(CMDQ_THR_RESUME, thread->base + CMDQ_THR_SUSPEND_TASK);
+}
+
+static int cmdq_thread_reset(struct cmdq *cmdq, struct cmdq_thread *thread)
+{
+	u32 warm_reset;
+
+	writel(CMDQ_THR_DO_WARM_RESET, thread->base + CMDQ_THR_WARM_RESET);
+	if (readl_poll_timeout_atomic(thread->base + CMDQ_THR_WARM_RESET,
+			warm_reset, !(warm_reset & CMDQ_THR_DO_WARM_RESET),
+			0, 10)) {
+		dev_err(cmdq->mbox.dev, "reset GCE thread 0x%x failed\n",
+			(u32)(thread->base - cmdq->base));
+		return -EFAULT;
+	}
+	writel(CMDQ_THR_ACTIVE_SLOT_CYCLES, cmdq->base + CMDQ_THR_SLOT_CYCLES);
+	return 0;
+}
+
+static void cmdq_thread_disable(struct cmdq *cmdq, struct cmdq_thread *thread)
+{
+	cmdq_thread_reset(cmdq, thread);
+	writel(CMDQ_THR_DISABLED, thread->base + CMDQ_THR_ENABLE_TASK);
+}
+
+/* notify GCE to re-fetch commands by setting GCE thread PC */
+static void cmdq_thread_invalidate_fetched_data(struct cmdq_thread *thread)
+{
+	writel(readl(thread->base + CMDQ_THR_CURR_ADDR),
+	       thread->base + CMDQ_THR_CURR_ADDR);
+}
+
+static void cmdq_task_insert_into_thread(struct cmdq_task *task)
+{
+	struct device *dev = task->cmdq->mbox.dev;
+	struct cmdq_thread *thread = task->thread;
+	struct cmdq_task *prev_task = list_last_entry(
+			&thread->task_busy_list, typeof(*task), list_entry);
+	u64 *prev_task_base = prev_task->va_base;
+
+	/* let previous task jump to this task */
+	dma_sync_single_for_cpu(dev, prev_task->pa_base,
+				prev_task->cmd_buf_size, DMA_TO_DEVICE);
+	prev_task_base[CMDQ_NUM_CMD(prev_task) - 1] =
+		(u64)CMDQ_JUMP_BY_PA << 32 | task->pa_base;
+	dma_sync_single_for_device(dev, prev_task->pa_base,
+				   prev_task->cmd_buf_size, DMA_TO_DEVICE);
+
+	cmdq_thread_invalidate_fetched_data(thread);
+}
+
+static bool cmdq_command_is_wfe(u64 cmd)
+{
+	u64 wfe_option = CMDQ_WFE_UPDATE | CMDQ_WFE_WAIT | CMDQ_WFE_WAIT_VALUE;
+	u64 wfe_op = (u64)(CMDQ_CODE_WFE << CMDQ_OP_CODE_SHIFT) << 32;
+	u64 wfe_mask = (u64)CMDQ_OP_CODE_MASK << 32 | 0xffffffff;
+
+	return ((cmd & wfe_mask) == (wfe_op | wfe_option));
+}
+
+/* we assume tasks in the same display GCE thread are waiting the same event. */
+static void cmdq_task_remove_wfe(struct cmdq_task *task)
+{
+	struct device *dev = task->cmdq->mbox.dev;
+	u64 *base = task->va_base;
+	int i;
+
+	dma_sync_single_for_cpu(dev, task->pa_base, task->cmd_buf_size,
+				DMA_TO_DEVICE);
+	for (i = 0; i < CMDQ_NUM_CMD(task); i++)
+		if (cmdq_command_is_wfe(base[i]))
+			base[i] = (u64)CMDQ_JUMP_BY_OFFSET << 32 |
+				  CMDQ_JUMP_PASS;
+	dma_sync_single_for_device(dev, task->pa_base, task->cmd_buf_size,
+				   DMA_TO_DEVICE);
+}
+
+static bool cmdq_thread_is_in_wfe(struct cmdq_thread *thread,
+				  unsigned long curr_pa)
+{
+	struct device *dev = thread->chan->mbox->dev;
+	struct cmdq_task *task;
+	u32 task_end_pa;
+	u64 *va;
+	bool ret;
+
+	task = list_first_entry(&thread->task_busy_list, struct cmdq_task,
+				list_entry);
+	task_end_pa = task->pa_base + task->cmd_buf_size;
+	if (!(curr_pa >= task->pa_base &&
+	      curr_pa < task_end_pa - CMDQ_INST_SIZE))
+		return false;
+
+	va = task->va_base + (curr_pa - task->pa_base);
+	dma_sync_single_for_cpu(dev, task->pa_base, task->cmd_buf_size,
+				DMA_TO_DEVICE);
+	ret = cmdq_command_is_wfe(*va);
+	dma_sync_single_for_device(dev, task->pa_base, task->cmd_buf_size,
+				   DMA_TO_DEVICE);
+	return ret;
+}
+
+static void cmdq_thread_wait_end(struct cmdq_thread *thread,
+				 unsigned long end_pa)
+{
+	struct device *dev = thread->chan->mbox->dev;
+	unsigned long curr_pa;
+
+	if (readl_poll_timeout_atomic(thread->base + CMDQ_THR_CURR_ADDR,
+			curr_pa, curr_pa == end_pa, 1, 20))
+		dev_err(dev, "GCE thread cannot run to end.\n");
+}
+
+static void cmdq_task_exec(struct cmdq_task *task, struct cmdq_thread *thread)
+{
+	struct cmdq *cmdq = task->cmdq;
+	unsigned long curr_pa, end_pa;
+
+	task->thread = thread;
+	if (list_empty(&thread->task_busy_list)) {
+		WARN_ON(clk_enable(cmdq->clock) < 0);
+		WARN_ON(cmdq_thread_reset(cmdq, thread) < 0);
+
+		writel(task->pa_base, thread->base + CMDQ_THR_CURR_ADDR);
+		writel(task->pa_base + task->cmd_buf_size,
+		       thread->base + CMDQ_THR_END_ADDR);
+		writel(CMDQ_THR_IRQ_EN, thread->base + CMDQ_THR_IRQ_ENABLE);
+		writel(CMDQ_THR_ENABLED, thread->base + CMDQ_THR_ENABLE_TASK);
+
+		mod_timer(&thread->timeout,
+			  jiffies + msecs_to_jiffies(CMDQ_TIMEOUT_MS));
+	} else {
+		WARN_ON(cmdq_thread_suspend(cmdq, thread) < 0);
+		curr_pa = readl(thread->base + CMDQ_THR_CURR_ADDR);
+		end_pa = readl(thread->base + CMDQ_THR_END_ADDR);
+
+		/*
+		 * Atomic exection should remove the following wfe, i.e. only
+		 * wait event at first task, and prevent to pause when running.
+		 */
+		if (thread->atomic_exec) {
+			/* GCE is executing if command is not WFE */
+			if (!cmdq_thread_is_in_wfe(thread, curr_pa)) {
+				cmdq_thread_resume(thread);
+				cmdq_thread_wait_end(thread, end_pa);
+				WARN_ON(cmdq_thread_suspend(cmdq, thread) < 0);
+				/* set to this task directly */
+				writel(task->pa_base,
+				       thread->base + CMDQ_THR_CURR_ADDR);
+			} else {
+				cmdq_task_insert_into_thread(task);
+				cmdq_task_remove_wfe(task);
+				smp_mb(); /* modify jump before enable thread */
+			}
+		} else {
+			/* check boundary */
+			if (curr_pa == end_pa - CMDQ_INST_SIZE ||
+			    curr_pa == end_pa) {
+				/* set to this task directly */
+				writel(task->pa_base,
+				       thread->base + CMDQ_THR_CURR_ADDR);
+			} else {
+				cmdq_task_insert_into_thread(task);
+				smp_mb(); /* modify jump before enable thread */
+			}
+		}
+		writel(task->pa_base + task->cmd_buf_size,
+		       thread->base + CMDQ_THR_END_ADDR);
+		cmdq_thread_resume(thread);
+	}
+	list_move_tail(&task->list_entry, &thread->task_busy_list);
+}
+
+static void cmdq_task_exec_done(struct cmdq_task *task, bool err)
+{
+	struct device *dev = task->cmdq->mbox.dev;
+	struct cmdq_cb_data cmdq_cb_data;
+
+	if (task->cb.cb) {
+		cmdq_cb_data.err = err;
+		cmdq_cb_data.data = task->cb.data;
+		task->cb.cb(cmdq_cb_data);
+	}
+	list_del(&task->list_entry);
+	dma_unmap_single(dev, task->pa_base, task->cmd_buf_size, DMA_TO_DEVICE);
+	kfree(task->va_base);
+}
+
+static void cmdq_task_handle_error(struct cmdq_task *task)
+{
+	struct cmdq_thread *thread = task->thread;
+	struct cmdq_task *next_task;
+
+	dev_err(task->cmdq->mbox.dev, "task 0x%p error\n", task);
+	WARN_ON(cmdq_thread_suspend(task->cmdq, thread) < 0);
+	next_task = list_first_entry_or_null(&thread->task_busy_list,
+			struct cmdq_task, list_entry);
+	if (next_task)
+		writel(next_task->pa_base, thread->base + CMDQ_THR_CURR_ADDR);
+	cmdq_thread_resume(thread);
+}
+
+static void cmdq_thread_irq_handler(struct cmdq *cmdq,
+				    struct cmdq_thread *thread)
+{
+	struct cmdq_task *task, *tmp, *curr_task = NULL;
+	u32 curr_pa, irq_flag, task_end_pa;
+	bool err;
+
+	irq_flag = readl(thread->base + CMDQ_THR_IRQ_STATUS);
+	writel(~irq_flag, thread->base + CMDQ_THR_IRQ_STATUS);
+
+	/*
+	 * When ISR call this function, another CPU core could run
+	 * "release task" right before we acquire the spin lock, and thus
+	 * reset / disable this GCE thread, so we need to check the enable
+	 * bit of this GCE thread.
+	 */
+	if (!(readl(thread->base + CMDQ_THR_ENABLE_TASK) & CMDQ_THR_ENABLED))
+		return;
+
+	if (irq_flag & CMDQ_THR_IRQ_ERROR)
+		err = true;
+	else if (irq_flag & CMDQ_THR_IRQ_DONE)
+		err = false;
+	else
+		return;
+
+	curr_pa = readl(thread->base + CMDQ_THR_CURR_ADDR);
+
+	list_for_each_entry_safe(task, tmp, &thread->task_busy_list,
+				 list_entry) {
+		task_end_pa = task->pa_base + task->cmd_buf_size;
+		if (curr_pa >= task->pa_base && curr_pa < task_end_pa)
+			curr_task = task;
+
+		if (!curr_task || curr_pa == task_end_pa - CMDQ_INST_SIZE) {
+			cmdq_task_exec_done(task, false);
+			kfree(task);
+		} else if (err) {
+			cmdq_task_exec_done(task, true);
+			cmdq_task_handle_error(curr_task);
+			kfree(task);
+		}
+
+		if (curr_task)
+			break;
+	}
+
+	if (list_empty(&thread->task_busy_list)) {
+		cmdq_thread_disable(cmdq, thread);
+		clk_disable(cmdq->clock);
+	} else {
+		mod_timer(&thread->timeout,
+			  jiffies + msecs_to_jiffies(CMDQ_TIMEOUT_MS));
+	}
+}
+
+static irqreturn_t cmdq_irq_handler(int irq, void *dev)
+{
+	struct cmdq *cmdq = dev;
+	unsigned long irq_status, flags = 0L;
+	int bit;
+
+	irq_status = readl(cmdq->base + CMDQ_CURR_IRQ_STATUS) & CMDQ_IRQ_MASK;
+	if (!(irq_status ^ CMDQ_IRQ_MASK))
+		return IRQ_NONE;
+
+	for_each_clear_bit(bit, &irq_status, fls(CMDQ_IRQ_MASK)) {
+		struct cmdq_thread *thread = &cmdq->thread[bit];
+
+		spin_lock_irqsave(&thread->chan->lock, flags);
+		cmdq_thread_irq_handler(cmdq, thread);
+		spin_unlock_irqrestore(&thread->chan->lock, flags);
+	}
+	return IRQ_HANDLED;
+}
+
+static void cmdq_thread_handle_timeout(unsigned long data)
+{
+	struct cmdq_thread *thread = (struct cmdq_thread *)data;
+	struct cmdq *cmdq = container_of(thread->chan->mbox, struct cmdq, mbox);
+	struct cmdq_task *task, *tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&thread->chan->lock, flags);
+	WARN_ON(cmdq_thread_suspend(cmdq, thread) < 0);
+
+	/*
+	 * Although IRQ is disabled, GCE continues to execute.
+	 * It may have pending IRQ before GCE thread is suspended,
+	 * so check this condition again.
+	 */
+	cmdq_thread_irq_handler(cmdq, thread);
+
+	if (list_empty(&thread->task_busy_list)) {
+		cmdq_thread_resume(thread);
+		spin_unlock_irqrestore(&thread->chan->lock, flags);
+		return;
+	}
+
+	dev_err(cmdq->mbox.dev, "timeout\n");
+	list_for_each_entry_safe(task, tmp, &thread->task_busy_list,
+				 list_entry) {
+		cmdq_task_exec_done(task, true);
+		kfree(task);
+	}
+
+	cmdq_thread_resume(thread);
+	cmdq_thread_disable(cmdq, thread);
+	clk_disable(cmdq->clock);
+	spin_unlock_irqrestore(&thread->chan->lock, flags);
+}
+
+static int cmdq_task_realloc_cmd_buffer(struct cmdq_task *task, size_t size)
+{
+	void *new_buf;
+
+	new_buf = krealloc(task->va_base, size, GFP_KERNEL | __GFP_ZERO);
+	if (!new_buf)
+		return -ENOMEM;
+	task->va_base = new_buf;
+	task->buf_size = size;
+	return 0;
+}
+
+struct cmdq_base *cmdq_register_device(struct device *dev)
+{
+	struct cmdq_base *cmdq_base;
+	struct resource res;
+	int subsys;
+	u32 base;
+
+	if (of_address_to_resource(dev->of_node, 0, &res))
+		return NULL;
+	base = (u32)res.start;
+
+	subsys = cmdq_subsys_base_to_id(base >> 16);
+	if (subsys < 0)
+		return NULL;
+
+	cmdq_base = devm_kmalloc(dev, sizeof(*cmdq_base), GFP_KERNEL);
+	if (!cmdq_base)
+		return NULL;
+	cmdq_base->subsys = subsys;
+	cmdq_base->base = base;
+
+	return cmdq_base;
+}
+EXPORT_SYMBOL(cmdq_register_device);
+
+struct cmdq_client *cmdq_mbox_create(struct device *dev, int index)
+{
+	struct cmdq_client *client;
+
+	client = kzalloc(sizeof(*client), GFP_KERNEL);
+	client->client.dev = dev;
+	client->client.tx_block = false;
+	client->chan = mbox_request_channel(&client->client, index);
+	return client;
+}
+EXPORT_SYMBOL(cmdq_mbox_create);
+
+int cmdq_task_create(struct device *dev, struct cmdq_task **task_ptr)
+{
+	struct cmdq_task *task;
+	int err;
+
+	task = kzalloc(sizeof(*task), GFP_KERNEL);
+	if (!task)
+		return -ENOMEM;
+	task->cmdq = dev_get_drvdata(dev);
+	err = cmdq_task_realloc_cmd_buffer(task, PAGE_SIZE);
+	if (err < 0) {
+		kfree(task);
+		return err;
+	}
+	*task_ptr = task;
+	return 0;
+}
+EXPORT_SYMBOL(cmdq_task_create);
+
+static int cmdq_task_append_command(struct cmdq_task *task, enum cmdq_code code,
+				    u32 arg_a, u32 arg_b)
+{
+	u64 *cmd_ptr;
+	int err;
+
+	if (WARN_ON(task->finalized))
+		return -EBUSY;
+	if (unlikely(task->cmd_buf_size + CMDQ_INST_SIZE > task->buf_size)) {
+		err = cmdq_task_realloc_cmd_buffer(task, task->buf_size * 2);
+		if (err < 0)
+			return err;
+	}
+	cmd_ptr = task->va_base + task->cmd_buf_size;
+	(*cmd_ptr) = (u64)((code << CMDQ_OP_CODE_SHIFT) | arg_a) << 32 | arg_b;
+	task->cmd_buf_size += CMDQ_INST_SIZE;
+	return 0;
+}
+
+int cmdq_task_write(struct cmdq_task *task, u32 value, struct cmdq_base *base,
+		    u32 offset)
+{
+	u32 arg_a = ((base->base + offset) & CMDQ_ARG_A_WRITE_MASK) |
+		    (base->subsys << CMDQ_SUBSYS_SHIFT);
+	return cmdq_task_append_command(task, CMDQ_CODE_WRITE, arg_a, value);
+}
+EXPORT_SYMBOL(cmdq_task_write);
+
+int cmdq_task_write_mask(struct cmdq_task *task, u32 value,
+			 struct cmdq_base *base, u32 offset, u32 mask)
+{
+	u32 offset_mask = offset;
+	int err;
+
+	if (mask != 0xffffffff) {
+		err = cmdq_task_append_command(task, CMDQ_CODE_MASK, 0, ~mask);
+		if (err < 0)
+			return err;
+		offset_mask |= CMDQ_WRITE_ENABLE_MASK;
+	}
+	return cmdq_task_write(task, value, base, offset_mask);
+}
+EXPORT_SYMBOL(cmdq_task_write_mask);
+
+static const u32 cmdq_event_value[CMDQ_MAX_EVENT] = {
+	/* Display start of frame(SOF) events */
+	[CMDQ_EVENT_DISP_OVL0_SOF] = 11,
+	[CMDQ_EVENT_DISP_OVL1_SOF] = 12,
+	[CMDQ_EVENT_DISP_RDMA0_SOF] = 13,
+	[CMDQ_EVENT_DISP_RDMA1_SOF] = 14,
+	[CMDQ_EVENT_DISP_RDMA2_SOF] = 15,
+	[CMDQ_EVENT_DISP_WDMA0_SOF] = 16,
+	[CMDQ_EVENT_DISP_WDMA1_SOF] = 17,
+	/* Display end of frame(EOF) events */
+	[CMDQ_EVENT_DISP_OVL0_EOF] = 39,
+	[CMDQ_EVENT_DISP_OVL1_EOF] = 40,
+	[CMDQ_EVENT_DISP_RDMA0_EOF] = 41,
+	[CMDQ_EVENT_DISP_RDMA1_EOF] = 42,
+	[CMDQ_EVENT_DISP_RDMA2_EOF] = 43,
+	[CMDQ_EVENT_DISP_WDMA0_EOF] = 44,
+	[CMDQ_EVENT_DISP_WDMA1_EOF] = 45,
+	/* Mutex end of frame(EOF) events */
+	[CMDQ_EVENT_MUTEX0_STREAM_EOF] = 53,
+	[CMDQ_EVENT_MUTEX1_STREAM_EOF] = 54,
+	[CMDQ_EVENT_MUTEX2_STREAM_EOF] = 55,
+	[CMDQ_EVENT_MUTEX3_STREAM_EOF] = 56,
+	[CMDQ_EVENT_MUTEX4_STREAM_EOF] = 57,
+	/* Display underrun events */
+	[CMDQ_EVENT_DISP_RDMA0_UNDERRUN] = 63,
+	[CMDQ_EVENT_DISP_RDMA1_UNDERRUN] = 64,
+	[CMDQ_EVENT_DISP_RDMA2_UNDERRUN] = 65,
+};
+
+int cmdq_task_wfe(struct cmdq_task *task, enum cmdq_event event)
+{
+	u32 arg_b;
+
+	if (event >= CMDQ_MAX_EVENT || event < 0)
+		return -EINVAL;
+
+	/*
+	 * WFE arg_b
+	 * bit 0-11: wait value
+	 * bit 15: 1 - wait, 0 - no wait
+	 * bit 16-27: update value
+	 * bit 31: 1 - update, 0 - no update
+	 */
+	arg_b = CMDQ_WFE_UPDATE | CMDQ_WFE_WAIT | CMDQ_WFE_WAIT_VALUE;
+	return cmdq_task_append_command(task, CMDQ_CODE_WFE,
+			cmdq_event_value[event], arg_b);
+}
+EXPORT_SYMBOL(cmdq_task_wfe);
+
+int cmdq_task_clear_event(struct cmdq_task *task, enum cmdq_event event)
+{
+	if (event >= CMDQ_MAX_EVENT || event < 0)
+		return -EINVAL;
+
+	return cmdq_task_append_command(task, CMDQ_CODE_WFE,
+			cmdq_event_value[event], CMDQ_WFE_UPDATE);
+}
+EXPORT_SYMBOL(cmdq_task_clear_event);
+
+static int cmdq_task_finalize(struct cmdq_task *task)
+{
+	int err;
+
+	if (task->finalized)
+		return 0;
+
+	/* insert EOC and generate IRQ for each command iteration */
+	err = cmdq_task_append_command(task, CMDQ_CODE_EOC, 0, CMDQ_EOC_IRQ_EN);
+	if (err < 0)
+		return err;
+
+	/* JUMP to end */
+	err = cmdq_task_append_command(task, CMDQ_CODE_JUMP, 0, CMDQ_JUMP_PASS);
+	if (err < 0)
+		return err;
+
+	task->finalized = true;
+	return 0;
+}
+
+int cmdq_task_flush_async(struct cmdq_client *client, struct cmdq_task *task,
+			  cmdq_async_flush_cb cb, void *data)
+{
+	struct cmdq *cmdq = task->cmdq;
+	int err;
+
+	mutex_lock(&cmdq->task_mutex);
+	if (cmdq->suspended) {
+		dev_err(cmdq->mbox.dev, "%s is called after suspended\n",
+			__func__);
+		mutex_unlock(&cmdq->task_mutex);
+		return -EPERM;
+	}
+
+	err = cmdq_task_finalize(task);
+	if (err < 0) {
+		mutex_unlock(&cmdq->task_mutex);
+		return err;
+	}
+
+	INIT_LIST_HEAD(&task->list_entry);
+	task->cb.cb = cb;
+	task->cb.data = data;
+	task->pa_base = dma_map_single(cmdq->mbox.dev, task->va_base,
+				       task->cmd_buf_size, DMA_TO_DEVICE);
+
+	mbox_send_message(client->chan, task);
+	/* We can send next task immediately, so just call txdone. */
+	mbox_client_txdone(client->chan, 0);
+	mutex_unlock(&cmdq->task_mutex);
+	return 0;
+}
+EXPORT_SYMBOL(cmdq_task_flush_async);
+
+struct cmdq_flush_completion {
+	struct completion cmplt;
+	bool err;
+};
+
+static void cmdq_task_flush_cb(struct cmdq_cb_data data)
+{
+	struct cmdq_flush_completion *cmplt = data.data;
+
+	cmplt->err = data.err;
+	complete(&cmplt->cmplt);
+}
+
+int cmdq_task_flush(struct cmdq_client *client, struct cmdq_task *task)
+{
+	struct cmdq_flush_completion cmplt;
+	int err;
+
+	init_completion(&cmplt.cmplt);
+	err = cmdq_task_flush_async(client, task, cmdq_task_flush_cb, &cmplt);
+	if (err < 0)
+		return err;
+	wait_for_completion(&cmplt.cmplt);
+	return cmplt.err ? -EFAULT : 0;
+}
+EXPORT_SYMBOL(cmdq_task_flush);
+
+void cmdq_mbox_free(struct cmdq_client *client)
+{
+	mbox_free_channel(client->chan);
+	kfree(client);
+}
+EXPORT_SYMBOL(cmdq_mbox_free);
+
+static int cmdq_suspend(struct device *dev)
+{
+	struct cmdq *cmdq = dev_get_drvdata(dev);
+	struct cmdq_thread *thread;
+	int i;
+	bool task_running = false;
+
+	mutex_lock(&cmdq->task_mutex);
+	cmdq->suspended = true;
+	mutex_unlock(&cmdq->task_mutex);
+
+	for (i = 0; i < ARRAY_SIZE(cmdq->thread); i++) {
+		thread = &cmdq->thread[i];
+		if (!list_empty(&thread->task_busy_list)) {
+			mod_timer(&thread->timeout, jiffies + 1);
+			task_running = true;
+		}
+	}
+
+	if (task_running) {
+		dev_warn(dev, "exist running task(s) in suspend\n");
+		msleep(20);
+	}
+
+	clk_unprepare(cmdq->clock);
+	return 0;
+}
+
+static int cmdq_resume(struct device *dev)
+{
+	struct cmdq *cmdq = dev_get_drvdata(dev);
+
+	WARN_ON(clk_prepare(cmdq->clock) < 0);
+	cmdq->suspended = false;
+	return 0;
+}
+
+static int cmdq_remove(struct platform_device *pdev)
+{
+	struct cmdq *cmdq = platform_get_drvdata(pdev);
+
+	mbox_controller_unregister(&cmdq->mbox);
+	clk_unprepare(cmdq->clock);
+	return 0;
+}
+
+static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data)
+{
+	cmdq_task_exec(data, chan->con_priv);
+	return 0;
+}
+
+static int cmdq_mbox_startup(struct mbox_chan *chan)
+{
+	return 0;
+}
+
+static void cmdq_mbox_shutdown(struct mbox_chan *chan)
+{
+}
+
+static bool cmdq_mbox_last_tx_done(struct mbox_chan *chan)
+{
+	return true;
+}
+
+static const struct mbox_chan_ops cmdq_mbox_chan_ops = {
+	.send_data = cmdq_mbox_send_data,
+	.startup = cmdq_mbox_startup,
+	.shutdown = cmdq_mbox_shutdown,
+	.last_tx_done = cmdq_mbox_last_tx_done,
+};
+
+static struct mbox_chan *cmdq_xlate(struct mbox_controller *mbox,
+		const struct of_phandle_args *sp)
+{
+	int ind = sp->args[0];
+	struct cmdq_thread *thread;
+
+	if (ind >= mbox->num_chans)
+		return ERR_PTR(-EINVAL);
+
+	thread = mbox->chans[ind].con_priv;
+	thread->atomic_exec = (sp->args[1] != 0);
+	thread->chan = &mbox->chans[ind];
+
+	return &mbox->chans[ind];
+}
+
+static int cmdq_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	struct resource *res;
+	struct cmdq *cmdq;
+	int err, i;
+
+	cmdq = devm_kzalloc(dev, sizeof(*cmdq), GFP_KERNEL);
+	if (!cmdq)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	cmdq->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(cmdq->base)) {
+		dev_err(dev, "failed to ioremap gce\n");
+		return PTR_ERR(cmdq->base);
+	}
+
+	cmdq->irq = irq_of_parse_and_map(node, 0);
+	if (!cmdq->irq) {
+		dev_err(dev, "failed to get irq\n");
+		return -EINVAL;
+	}
+	err = devm_request_irq(dev, cmdq->irq, cmdq_irq_handler, IRQF_SHARED,
+			       "mtk_cmdq", cmdq);
+	if (err < 0) {
+		dev_err(dev, "failed to register ISR (%d)\n", err);
+		return err;
+	}
+
+	dev_dbg(dev, "cmdq device: addr:0x%p, va:0x%p, irq:%d\n",
+		dev, cmdq->base, cmdq->irq);
+
+	cmdq->clock = devm_clk_get(dev, "gce");
+	if (IS_ERR(cmdq->clock)) {
+		dev_err(dev, "failed to get gce clk\n");
+		return PTR_ERR(cmdq->clock);
+	}
+
+	cmdq->mbox.dev = dev;
+	cmdq->mbox.chans = devm_kcalloc(dev, CMDQ_THR_MAX_COUNT,
+					sizeof(*cmdq->mbox.chans), GFP_KERNEL);
+	if (!cmdq->mbox.chans)
+		return -ENOMEM;
+
+	cmdq->mbox.num_chans = CMDQ_THR_MAX_COUNT;
+	cmdq->mbox.ops = &cmdq_mbox_chan_ops;
+	cmdq->mbox.of_xlate = cmdq_xlate;
+
+	/* make use of TXDONE_BY_ACK */
+	cmdq->mbox.txdone_irq = false;
+	cmdq->mbox.txdone_poll = false;
+
+	for (i = 0; i < ARRAY_SIZE(cmdq->thread); i++) {
+		cmdq->thread[i].base = cmdq->base + CMDQ_THR_BASE +
+				CMDQ_THR_SIZE * i;
+		INIT_LIST_HEAD(&cmdq->thread[i].task_busy_list);
+		init_timer(&cmdq->thread[i].timeout);
+		cmdq->thread[i].timeout.function = cmdq_thread_handle_timeout;
+		cmdq->thread[i].timeout.data = (unsigned long)&cmdq->thread[i];
+		cmdq->mbox.chans[i].con_priv = &cmdq->thread[i];
+	}
+
+	err = mbox_controller_register(&cmdq->mbox);
+	if (err < 0) {
+		dev_err(dev, "failed to register mailbox: %d\n", err);
+		return err;
+	}
+
+	mutex_init(&cmdq->task_mutex);
+	platform_set_drvdata(pdev, cmdq);
+	WARN_ON(clk_prepare(cmdq->clock) < 0);
+	return 0;
+}
+
+static const struct dev_pm_ops cmdq_pm_ops = {
+	.suspend = cmdq_suspend,
+	.resume = cmdq_resume,
+};
+
+static const struct of_device_id cmdq_of_ids[] = {
+	{.compatible = "mediatek,mt8173-gce",},
+	{}
+};
+
+static struct platform_driver cmdq_drv = {
+	.probe = cmdq_probe,
+	.remove = cmdq_remove,
+	.driver = {
+		.name = "mtk_cmdq",
+		.owner = THIS_MODULE,
+		.pm = &cmdq_pm_ops,
+		.of_match_table = cmdq_of_ids,
+	}
+};
+
+builtin_platform_driver(cmdq_drv);
diff --git a/include/soc/mediatek/cmdq.h b/include/soc/mediatek/cmdq.h
new file mode 100644
index 0000000..1ee2eb0
--- /dev/null
+++ b/include/soc/mediatek/cmdq.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * 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.
+ */
+
+#ifndef __MTK_CMDQ_H__
+#define __MTK_CMDQ_H__
+
+#include <linux/mailbox_client.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+/* display events in command queue(CMDQ) */
+enum cmdq_event {
+	/* Display start of frame(SOF) events */
+	CMDQ_EVENT_DISP_OVL0_SOF,
+	CMDQ_EVENT_DISP_OVL1_SOF,
+	CMDQ_EVENT_DISP_RDMA0_SOF,
+	CMDQ_EVENT_DISP_RDMA1_SOF,
+	CMDQ_EVENT_DISP_RDMA2_SOF,
+	CMDQ_EVENT_DISP_WDMA0_SOF,
+	CMDQ_EVENT_DISP_WDMA1_SOF,
+	/* Display end of frame(EOF) events */
+	CMDQ_EVENT_DISP_OVL0_EOF,
+	CMDQ_EVENT_DISP_OVL1_EOF,
+	CMDQ_EVENT_DISP_RDMA0_EOF,
+	CMDQ_EVENT_DISP_RDMA1_EOF,
+	CMDQ_EVENT_DISP_RDMA2_EOF,
+	CMDQ_EVENT_DISP_WDMA0_EOF,
+	CMDQ_EVENT_DISP_WDMA1_EOF,
+	/* Mutex end of frame(EOF) events */
+	CMDQ_EVENT_MUTEX0_STREAM_EOF,
+	CMDQ_EVENT_MUTEX1_STREAM_EOF,
+	CMDQ_EVENT_MUTEX2_STREAM_EOF,
+	CMDQ_EVENT_MUTEX3_STREAM_EOF,
+	CMDQ_EVENT_MUTEX4_STREAM_EOF,
+	/* Display underrun events */
+	CMDQ_EVENT_DISP_RDMA0_UNDERRUN,
+	CMDQ_EVENT_DISP_RDMA1_UNDERRUN,
+	CMDQ_EVENT_DISP_RDMA2_UNDERRUN,
+	/* Keep this at the end */
+	CMDQ_MAX_EVENT,
+};
+
+struct cmdq_cb_data {
+	bool	err;
+	void	*data;
+};
+
+typedef void (*cmdq_async_flush_cb)(struct cmdq_cb_data data);
+
+struct cmdq_task;
+
+struct cmdq_base {
+	int	subsys;
+	u32	base;
+};
+
+struct cmdq_client {
+	struct mbox_client client;
+	struct mbox_chan *chan;
+};
+
+/**
+ * cmdq_register_device() - register device which needs CMDQ
+ * @dev:	device for CMDQ to access its registers
+ *
+ * Return: cmdq_base pointer or NULL for failed
+ */
+struct cmdq_base *cmdq_register_device(struct device *dev);
+
+/**
+ * cmdq_mbox_create() - create CMDQ mailbox client and channel
+ * @dev:	device of CMDQ mailbox client
+ * @index:	index of CMDQ mailbox channel
+ *
+ * Return: CMDQ mailbox client pointer
+ */
+struct cmdq_client *cmdq_mbox_create(struct device *dev, int index);
+
+/**
+ * cmdq_task_create() - create CMDQ task
+ * @dev:	CMDQ device
+ * @task_ptr:	CMDQ task pointer to retrieve cmdq_task
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_task_create(struct device *dev, struct cmdq_task **task_ptr);
+
+/**
+ * cmdq_task_write() - append write command to the CMDQ task
+ * @task:	the CMDQ task
+ * @value:	the specified target register value
+ * @base:	the CMDQ base
+ * @offset:	register offset from module base
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_task_write(struct cmdq_task *task, u32 value,
+		    struct cmdq_base *base, u32 offset);
+
+/**
+ * cmdq_task_write_mask() - append write command with mask to the CMDQ task
+ * @task:	the CMDQ task
+ * @value:	the specified target register value
+ * @base:	the CMDQ base
+ * @offset:	register offset from module base
+ * @mask:	the specified target register mask
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_task_write_mask(struct cmdq_task *task, u32 value,
+			 struct cmdq_base *base, u32 offset, u32 mask);
+
+/**
+ * cmdq_task_wfe() - append wait for event command to the CMDQ task
+ * @task:	the CMDQ task
+ * @event:	the desired event type to "wait and CLEAR"
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_task_wfe(struct cmdq_task *task, enum cmdq_event event);
+
+/**
+ * cmdq_task_clear_event() - append clear event command to the CMDQ task
+ * @task:	the CMDQ task
+ * @event:	the desired event to be cleared
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_task_clear_event(struct cmdq_task *task, enum cmdq_event event);
+
+/**
+ * cmdq_task_flush() - trigger CMDQ to execute the recorded commands
+ * @client:	the CMDQ mailbox client
+ * @task:	the CMDQ task
+ *
+ * Return: 0 for success; else the error code is returned
+ *
+ * Trigger CMDQ to execute the recorded commands. Note that this is a
+ * synchronous flush function. When the function returned, the recorded
+ * commands have been done. CMDQ task will be destroy automatically
+ * after CMDQ finish all the recorded commands.
+ */
+int cmdq_task_flush(struct cmdq_client *client, struct cmdq_task *task);
+
+/**
+ * cmdq_task_flush_async() - trigger CMDQ to asynchronously execute the recorded
+ *			     commands and call back at the end of ISR
+ * @client:	the CMDQ mailbox client
+ * @task:	the CMDQ task
+ * @cb:		called at the end of CMDQ ISR
+ * @data:	this data will pass back to cb
+ *
+ * Return: 0 for success; else the error code is returned
+ *
+ * Trigger CMDQ to asynchronously execute the recorded commands and call back
+ * at the end of ISR. Note that this is an ASYNC function. When the function
+ * returned, it may or may not be finished. CMDQ task will be destroy
+ * automatically after CMDQ finish all the recorded commands.
+ */
+int cmdq_task_flush_async(struct cmdq_client *client, struct cmdq_task *task,
+			  cmdq_async_flush_cb cb, void *data);
+
+/**
+ * cmdq_mbox_free() - destroy CMDQ mailbox client and channel
+ * @client:	the CMDQ mailbox client
+ */
+void cmdq_mbox_free(struct cmdq_client *client);
+
+#endif	/* __MTK_CMDQ_H__ */
-- 
1.9.1



From hs.liao at mediatek.com  Wed Jul 27 00:14:12 2016
From: hs.liao at mediatek.com (HS Liao)
Date: Wed, 27 Jul 2016 15:14:12 +0800
Subject: [PATCH v11 3/4] arm64: dts: mt8173: Add GCE node
In-Reply-To: <1469603653-9733-1-git-send-email-hs.liao@mediatek.com>
References: <1469603653-9733-1-git-send-email-hs.liao@mediatek.com>
Message-ID: <1469603653-9733-4-git-send-email-hs.liao@mediatek.com>

This patch adds the device node of the GCE hardware for CMDQ module.

Signed-off-by: HS Liao <hs.liao at mediatek.com>
---
 arch/arm64/boot/dts/mediatek/mt8173.dtsi | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
index 05f89c4..a68207c 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -343,6 +343,16 @@
 			#clock-cells = <1>;
 		};
 
+		gce: gce at 10212000 {
+			compatible = "mediatek,mt8173-gce";
+			reg = <0 0x10212000 0 0x1000>;
+			interrupts = <GIC_SPI 135 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&infracfg CLK_INFRA_GCE>;
+			clock-names = "gce";
+
+			#mbox-cells = <2>;
+		};
+
 		gic: interrupt-controller at 10220000 {
 			compatible = "arm,gic-400";
 			#interrupt-cells = <3>;
-- 
1.9.1



From hs.liao at mediatek.com  Wed Jul 27 00:14:13 2016
From: hs.liao at mediatek.com (HS Liao)
Date: Wed, 27 Jul 2016 15:14:13 +0800
Subject: [PATCH v11 4/4] CMDQ: save more energy in idle
In-Reply-To: <1469603653-9733-1-git-send-email-hs.liao@mediatek.com>
References: <1469603653-9733-1-git-send-email-hs.liao@mediatek.com>
Message-ID: <1469603653-9733-5-git-send-email-hs.liao@mediatek.com>

Use clk_disable_unprepare instead of clk_disable to save more energy
when CMDQ is idle.

Signed-off-by: HS Liao <hs.liao at mediatek.com>
---
 drivers/soc/mediatek/mtk-cmdq.c | 55 +++++++++++++++++++++++++++++++++++------
 1 file changed, 47 insertions(+), 8 deletions(-)

diff --git a/drivers/soc/mediatek/mtk-cmdq.c b/drivers/soc/mediatek/mtk-cmdq.c
index ec384f9..155caf7 100644
--- a/drivers/soc/mediatek/mtk-cmdq.c
+++ b/drivers/soc/mediatek/mtk-cmdq.c
@@ -31,6 +31,7 @@
 #include <linux/spinlock.h>
 #include <linux/suspend.h>
 #include <linux/timer.h>
+#include <linux/workqueue.h>
 #include <soc/mediatek/cmdq.h>
 
 #define CMDQ_THR_MAX_COUNT		3 /* main, sub, general(misc) */
@@ -131,10 +132,16 @@ struct cmdq_task {
 	struct cmdq_task_cb	cb;
 };
 
+struct cmdq_clk_release {
+	struct cmdq		*cmdq;
+	struct work_struct	release_work;
+};
+
 struct cmdq {
 	struct mbox_controller	mbox;
 	void __iomem		*base;
 	u32			irq;
+	struct workqueue_struct	*clk_release_wq;
 	struct cmdq_thread	thread[CMDQ_THR_MAX_COUNT];
 	struct mutex		task_mutex;
 	struct clk		*clock;
@@ -300,11 +307,19 @@ static void cmdq_thread_wait_end(struct cmdq_thread *thread,
 static void cmdq_task_exec(struct cmdq_task *task, struct cmdq_thread *thread)
 {
 	struct cmdq *cmdq = task->cmdq;
-	unsigned long curr_pa, end_pa;
+	unsigned long curr_pa, end_pa, flags;
 
 	task->thread = thread;
 	if (list_empty(&thread->task_busy_list)) {
-		WARN_ON(clk_enable(cmdq->clock) < 0);
+		/*
+		 * Unlock for clk prepare (sleeping function).
+		 * We are safe to do that since we have task_mutex and
+		 * only flush will add task.
+		 */
+		spin_unlock_irqrestore(&thread->chan->lock, flags);
+		WARN_ON(clk_prepare_enable(cmdq->clock) < 0);
+		spin_lock_irqsave(&thread->chan->lock, flags);
+
 		WARN_ON(cmdq_thread_reset(cmdq, thread) < 0);
 
 		writel(task->pa_base, thread->base + CMDQ_THR_CURR_ADDR);
@@ -386,6 +401,26 @@ static void cmdq_task_handle_error(struct cmdq_task *task)
 	cmdq_thread_resume(thread);
 }
 
+static void cmdq_clk_release_work(struct work_struct *work_item)
+{
+	struct cmdq_clk_release *clk_release = container_of(work_item,
+			struct cmdq_clk_release, release_work);
+	struct cmdq *cmdq = clk_release->cmdq;
+
+	clk_disable_unprepare(cmdq->clock);
+	kfree(clk_release);
+}
+
+static void cmdq_clk_release_schedule(struct cmdq *cmdq)
+{
+	struct cmdq_clk_release *clk_release;
+
+	clk_release = kmalloc(sizeof(*clk_release), GFP_ATOMIC);
+	clk_release->cmdq = cmdq;
+	INIT_WORK(&clk_release->release_work, cmdq_clk_release_work);
+	queue_work(cmdq->clk_release_wq, &clk_release->release_work);
+}
+
 static void cmdq_thread_irq_handler(struct cmdq *cmdq,
 				    struct cmdq_thread *thread)
 {
@@ -435,7 +470,7 @@ static void cmdq_thread_irq_handler(struct cmdq *cmdq,
 
 	if (list_empty(&thread->task_busy_list)) {
 		cmdq_thread_disable(cmdq, thread);
-		clk_disable(cmdq->clock);
+		cmdq_clk_release_schedule(cmdq);
 	} else {
 		mod_timer(&thread->timeout,
 			  jiffies + msecs_to_jiffies(CMDQ_TIMEOUT_MS));
@@ -494,7 +529,7 @@ static void cmdq_thread_handle_timeout(unsigned long data)
 
 	cmdq_thread_resume(thread);
 	cmdq_thread_disable(cmdq, thread);
-	clk_disable(cmdq->clock);
+	cmdq_clk_release_schedule(cmdq);
 	spin_unlock_irqrestore(&thread->chan->lock, flags);
 }
 
@@ -782,7 +817,7 @@ static int cmdq_suspend(struct device *dev)
 		msleep(20);
 	}
 
-	clk_unprepare(cmdq->clock);
+	flush_workqueue(cmdq->clk_release_wq);
 	return 0;
 }
 
@@ -790,7 +825,6 @@ static int cmdq_resume(struct device *dev)
 {
 	struct cmdq *cmdq = dev_get_drvdata(dev);
 
-	WARN_ON(clk_prepare(cmdq->clock) < 0);
 	cmdq->suspended = false;
 	return 0;
 }
@@ -799,8 +833,8 @@ static int cmdq_remove(struct platform_device *pdev)
 {
 	struct cmdq *cmdq = platform_get_drvdata(pdev);
 
+	destroy_workqueue(cmdq->clk_release_wq);
 	mbox_controller_unregister(&cmdq->mbox);
-	clk_unprepare(cmdq->clock);
 	return 0;
 }
 
@@ -918,8 +952,13 @@ static int cmdq_probe(struct platform_device *pdev)
 	}
 
 	mutex_init(&cmdq->task_mutex);
+
+	cmdq->clk_release_wq = alloc_ordered_workqueue(
+			"%s", WQ_MEM_RECLAIM | WQ_HIGHPRI,
+			"cmdq_clk_release");
+
 	platform_set_drvdata(pdev, cmdq);
-	WARN_ON(clk_prepare(cmdq->clock) < 0);
+
 	return 0;
 }
 
-- 
1.9.1



From bibby.hsieh at mediatek.com  Wed Jul 27 00:58:16 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Wed, 27 Jul 2016 15:58:16 +0800
Subject: [PATCH v2] arm64: dts: mt8173: add mmsel clocks for 4K support
Message-ID: <1469606296-50515-1-git-send-email-bibby.hsieh@mediatek.com>

If MT8173 can support HDMI 4K resoultion,
the VENCPLL should be configured to 800MHZ.
We didn't set VENCPLL directly, we set the
mm_sel to 400MHz statically in the board
device tree.

Changes since v1:
 - Do not set the VENCPLL by clk_set_rate
   at display driver.
 - Configure the mm_sel to 400MHz statically
   in the board device tree.

Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
---
 arch/arm64/boot/dts/mediatek/mt8173.dtsi |    6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
index 78529e4..e89aca6 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -690,6 +690,8 @@
 			compatible = "mediatek,mt8173-mmsys", "syscon";
 			reg = <0 0x14000000 0 0x1000>;
 			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+			clocks = <&topckgen CLK_TOP_MM_SEL>;
+			clock-names = "mmsel";
 			#clock-cells = <1>;
 		};
 
@@ -858,8 +860,8 @@
 			interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_LOW>;
 			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
 			clocks = <&mmsys CLK_MM_DPI_PIXEL>,
-				 <&mmsys CLK_MM_DPI_ENGINE>,
-				 <&apmixedsys CLK_APMIXED_TVDPLL>;
+					 <&mmsys CLK_MM_DPI_ENGINE>,
+					 <&apmixedsys CLK_APMIXED_TVDPLL>;
 			clock-names = "pixel", "engine", "pll";
 			status = "disabled";
 		};
-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Wed Jul 27 01:25:14 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Wed, 27 Jul 2016 16:25:14 +0800
Subject: [PATCH v3] arm64: dts: mt8173: add mmsel clocks for 4K support
Message-ID: <1469607914-64831-1-git-send-email-bibby.hsieh@mediatek.com>

If MT8173 can support HDMI 4K resoultion, the
VENCPLL should be configured to 800MHZ.
We didn't set VENCPLL directly, we set the
mm_sel to 400MHz statically in the board device tree.

Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
---
Changes since v2:
 - Align the clocks of dpi0 node.

Changes since v1:
 - Do not set the VENCPLL by clk_set_rate
   at display driver.
 - Configure the mm_sel to 400MHz statically
   in the board device tree.
---
 arch/arm64/boot/dts/mediatek/mt8173.dtsi |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
index 78529e4..9c22204 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -690,7 +690,9 @@
 			compatible = "mediatek,mt8173-mmsys", "syscon";
 			reg = <0 0x14000000 0 0x1000>;
 			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+			clocks = <&topckgen CLK_TOP_MM_SEL>;
 			#clock-cells = <1>;
+			clock-frequency  = <400000000>;
 		};
 
 		ovl0: ovl at 1400c000 {
-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Wed Jul 27 01:31:30 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Wed, 27 Jul 2016 16:31:30 +0800
Subject: [PATCH v2 1/3] drm/mediatek: do mtk_hdmi_send_infoframe after HDMI
 clock enable
In-Reply-To: <1469608292-6106-1-git-send-email-bibby.hsieh@mediatek.com>
References: <1469608292-6106-1-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1469608292-6106-2-git-send-email-bibby.hsieh@mediatek.com>

From: Junzhi Zhao <junzhi.zhao at mediatek.com>

The mtk_hdmi_send_infoframe have to
be run after PLL and PIXEL clock of HDMI enable.
Make sure that HDMI inforframes can be sent
successfully.

Signed-off-by: Junzhi Zhao <junzhi.zhao at mediatek.com>
Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_hdmi.c |   19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
index ba812ef..d8609f5 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
@@ -1133,12 +1133,6 @@ static int mtk_hdmi_output_set_display_mode(struct mtk_hdmi *hdmi,
 	phy_power_on(hdmi->phy);
 	mtk_hdmi_aud_output_config(hdmi, mode);
 
-	mtk_hdmi_setup_audio_infoframe(hdmi);
-	mtk_hdmi_setup_avi_infoframe(hdmi, mode);
-	mtk_hdmi_setup_spd_infoframe(hdmi, "mediatek", "On-chip HDMI");
-	if (mode->flags & DRM_MODE_FLAG_3D_MASK)
-		mtk_hdmi_setup_vendor_specific_infoframe(hdmi, mode);
-
 	mtk_hdmi_hw_vid_black(hdmi, false);
 	mtk_hdmi_hw_aud_unmute(hdmi);
 	mtk_hdmi_hw_send_av_unmute(hdmi);
@@ -1401,14 +1395,25 @@ static void mtk_hdmi_bridge_pre_enable(struct drm_bridge *bridge)
 	hdmi->powered = true;
 }
 
+static void mtk_hdmi_send_infoframe(struct mtk_hdmi *hdmi,
+				    struct drm_display_mode *mode)
+{
+	mtk_hdmi_setup_audio_infoframe(hdmi);
+	mtk_hdmi_setup_avi_infoframe(hdmi, mode);
+	mtk_hdmi_setup_spd_infoframe(hdmi, "mediatek", "On-chip HDMI");
+	if (mode->flags & DRM_MODE_FLAG_3D_MASK)
+		mtk_hdmi_setup_vendor_specific_infoframe(hdmi, mode);
+}
+
 static void mtk_hdmi_bridge_enable(struct drm_bridge *bridge)
 {
 	struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
 
+	phy_power_on(hdmi->phy);
 	mtk_hdmi_output_set_display_mode(hdmi, &hdmi->mode);
 	clk_prepare_enable(hdmi->clk[MTK_HDMI_CLK_HDMI_PLL]);
 	clk_prepare_enable(hdmi->clk[MTK_HDMI_CLK_HDMI_PIXEL]);
-	phy_power_on(hdmi->phy);
+	mtk_hdmi_send_infoframe(hdmi, &hdmi->mode);
 
 	hdmi->enabled = true;
 }
-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Wed Jul 27 01:31:31 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Wed, 27 Jul 2016 16:31:31 +0800
Subject: [PATCH v2 2/3] drm/mediatek: enhance the HDMI driving current
In-Reply-To: <1469608292-6106-1-git-send-email-bibby.hsieh@mediatek.com>
References: <1469608292-6106-1-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1469608292-6106-3-git-send-email-bibby.hsieh@mediatek.com>

From: Junzhi Zhao <junzhi.zhao at mediatek.com>

In order to improve 4K resolution performance,
we have to enhance the HDMI driving currend
when clock rate is greater than 165MHz.

Signed-off-by: Junzhi Zhao <junzhi.zhao at mediatek.com>
Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c |   42 +++++++++++++++++-------
 1 file changed, 30 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
index 8a24754..51cb9cf 100644
--- a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
+++ b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
@@ -265,6 +265,9 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
 	struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
 	unsigned int pre_div;
 	unsigned int div;
+	unsigned int pre_ibias;
+	unsigned int hdmi_ibias;
+	unsigned int imp_en;
 
 	dev_dbg(hdmi_phy->dev, "%s: %lu Hz, parent: %lu Hz\n", __func__,
 		rate, parent_rate);
@@ -298,18 +301,31 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
 			  (0x1 << PLL_BR_SHIFT),
 			  RG_HDMITX_PLL_BP | RG_HDMITX_PLL_BC |
 			  RG_HDMITX_PLL_BR);
-	mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON3, RG_HDMITX_PRD_IMP_EN);
+	if (rate < 165000000) {
+		mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON3,
+					RG_HDMITX_PRD_IMP_EN);
+		pre_ibias = 0x3;
+		imp_en = 0x0;
+		hdmi_ibias = hdmi_phy->ibias;
+	} else {
+		mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON3,
+				      RG_HDMITX_PRD_IMP_EN);
+		pre_ibias = 0x6;
+		imp_en = 0xf;
+		hdmi_ibias = hdmi_phy->ibias_up;
+	}
 	mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON4,
-			  (0x3 << PRD_IBIAS_CLK_SHIFT) |
-			  (0x3 << PRD_IBIAS_D2_SHIFT) |
-			  (0x3 << PRD_IBIAS_D1_SHIFT) |
-			  (0x3 << PRD_IBIAS_D0_SHIFT),
+			  (pre_ibias << PRD_IBIAS_CLK_SHIFT) |
+			  (pre_ibias << PRD_IBIAS_D2_SHIFT) |
+			  (pre_ibias << PRD_IBIAS_D1_SHIFT) |
+			  (pre_ibias << PRD_IBIAS_D0_SHIFT),
 			  RG_HDMITX_PRD_IBIAS_CLK |
 			  RG_HDMITX_PRD_IBIAS_D2 |
 			  RG_HDMITX_PRD_IBIAS_D1 |
 			  RG_HDMITX_PRD_IBIAS_D0);
 	mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON3,
-			  (0x0 << DRV_IMP_EN_SHIFT), RG_HDMITX_DRV_IMP_EN);
+			  (imp_en << DRV_IMP_EN_SHIFT),
+			  RG_HDMITX_DRV_IMP_EN);
 	mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6,
 			  (hdmi_phy->drv_imp_clk << DRV_IMP_CLK_SHIFT) |
 			  (hdmi_phy->drv_imp_d2 << DRV_IMP_D2_SHIFT) |
@@ -318,12 +334,14 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
 			  RG_HDMITX_DRV_IMP_CLK | RG_HDMITX_DRV_IMP_D2 |
 			  RG_HDMITX_DRV_IMP_D1 | RG_HDMITX_DRV_IMP_D0);
 	mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON5,
-			  (hdmi_phy->ibias << DRV_IBIAS_CLK_SHIFT) |
-			  (hdmi_phy->ibias << DRV_IBIAS_D2_SHIFT) |
-			  (hdmi_phy->ibias << DRV_IBIAS_D1_SHIFT) |
-			  (hdmi_phy->ibias << DRV_IBIAS_D0_SHIFT),
-			  RG_HDMITX_DRV_IBIAS_CLK | RG_HDMITX_DRV_IBIAS_D2 |
-			  RG_HDMITX_DRV_IBIAS_D1 | RG_HDMITX_DRV_IBIAS_D0);
+			  (hdmi_ibias << DRV_IBIAS_CLK_SHIFT) |
+			  (hdmi_ibias << DRV_IBIAS_D2_SHIFT) |
+			  (hdmi_ibias << DRV_IBIAS_D1_SHIFT) |
+			  (hdmi_ibias << DRV_IBIAS_D0_SHIFT),
+			  RG_HDMITX_DRV_IBIAS_CLK |
+			  RG_HDMITX_DRV_IBIAS_D2 |
+			  RG_HDMITX_DRV_IBIAS_D1 |
+			  RG_HDMITX_DRV_IBIAS_D0);
 	return 0;
 }
 
-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Wed Jul 27 01:31:32 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Wed, 27 Jul 2016 16:31:32 +0800
Subject: [PATCH v2 3/3] drm/mediatek: fix the wrong pixel clock when
 resolution is 4K
In-Reply-To: <1469608292-6106-1-git-send-email-bibby.hsieh@mediatek.com>
References: <1469608292-6106-1-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1469608292-6106-4-git-send-email-bibby.hsieh@mediatek.com>

From: Junzhi Zhao <junzhi.zhao at mediatek.com>

Pixel clock should be 297MHz when resolution is 4K.

Signed-off-by: Junzhi Zhao <junzhi.zhao at mediatek.com>
Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_dpi.c |  149 +++++++++++++++++++++++-------------
 1 file changed, 96 insertions(+), 53 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index d05ca79..fa390e0 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -60,14 +60,25 @@ enum mtk_dpi_out_color_format {
 	MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL
 };
 
+enum mtk_dpi_clk_id {
+	MTK_DPI_CLK_DPI_ENGINE,
+	MTK_DPI_CLK_DPI_PIXEL,
+	MTK_DPI_CLK_TVD_PLL,
+	MTK_DPI_CLK_COUNT,
+};
+
+static const char * const mtk_dpi_clk_names[MTK_DPI_CLK_COUNT] = {
+	[MTK_DPI_CLK_DPI_ENGINE] = "engine",
+	[MTK_DPI_CLK_DPI_PIXEL] = "pixel",
+	[MTK_DPI_CLK_TVD_PLL] = "pll",
+};
+
 struct mtk_dpi {
 	struct mtk_ddp_comp ddp_comp;
 	struct drm_encoder encoder;
 	void __iomem *regs;
 	struct device *dev;
-	struct clk *engine_clk;
-	struct clk *pixel_clk;
-	struct clk *tvd_clk;
+	struct clk *clk[MTK_DPI_CLK_COUNT];
 	int irq;
 	struct drm_display_mode mode;
 	enum mtk_dpi_out_color_format color_format;
@@ -76,6 +87,7 @@ struct mtk_dpi {
 	enum mtk_dpi_out_channel_swap channel_swap;
 	bool power_sta;
 	u8 power_ctl;
+	void *data;
 };
 
 static inline struct mtk_dpi *mtk_dpi_from_encoder(struct drm_encoder *e)
@@ -114,6 +126,10 @@ struct mtk_dpi_yc_limit {
 	u16 c_bottom;
 };
 
+struct mtk_dpi_conf {
+	int (*clk_config)(struct mtk_dpi *dpi, struct drm_display_mode *mode);
+};
+
 static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask)
 {
 	u32 tmp = readl(dpi->regs + offset) & ~mask;
@@ -377,8 +393,8 @@ static void mtk_dpi_power_off(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl)
 		return;
 
 	mtk_dpi_disable(dpi);
-	clk_disable_unprepare(dpi->pixel_clk);
-	clk_disable_unprepare(dpi->engine_clk);
+	clk_disable_unprepare(dpi->clk[MTK_DPI_CLK_DPI_PIXEL]);
+	clk_disable_unprepare(dpi->clk[MTK_DPI_CLK_DPI_ENGINE]);
 	dpi->power_sta = false;
 }
 
@@ -395,13 +411,13 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl)
 	if (dpi->power_sta)
 		return 0;
 
-	ret = clk_prepare_enable(dpi->engine_clk);
+	ret = clk_prepare_enable(dpi->clk[MTK_DPI_CLK_DPI_ENGINE]);
 	if (ret) {
 		dev_err(dpi->dev, "Failed to enable engine clock: %d\n", ret);
 		goto err_eng;
 	}
 
-	ret = clk_prepare_enable(dpi->pixel_clk);
+	ret = clk_prepare_enable(dpi->clk[MTK_DPI_CLK_DPI_PIXEL]);
 	if (ret) {
 		dev_err(dpi->dev, "Failed to enable pixel clock: %d\n", ret);
 		goto err_pixel;
@@ -412,7 +428,7 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl)
 	return 0;
 
 err_pixel:
-	clk_disable_unprepare(dpi->engine_clk);
+	clk_disable_unprepare(dpi->clk[MTK_DPI_CLK_DPI_ENGINE]);
 err_eng:
 	dpi->power_ctl &= ~pctl;
 	return ret;
@@ -428,34 +444,18 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
 	struct mtk_dpi_sync_param vsync_leven = { 0 };
 	struct mtk_dpi_sync_param vsync_rodd = { 0 };
 	struct mtk_dpi_sync_param vsync_reven = { 0 };
-	unsigned long pix_rate;
-	unsigned long pll_rate;
-	unsigned int factor;
+	struct mtk_dpi_conf *conf;
+	int ret;
 
 	if (!dpi) {
 		dev_err(dpi->dev, "invalid argument\n");
 		return -EINVAL;
 	}
 
-	pix_rate = 1000UL * mode->clock;
-	if (mode->clock <= 74000)
-		factor = 8 * 3;
-	else
-		factor = 4 * 3;
-	pll_rate = pix_rate * factor;
-
-	dev_dbg(dpi->dev, "Want PLL %lu Hz, pixel clock %lu Hz\n",
-		pll_rate, pix_rate);
-
-	clk_set_rate(dpi->tvd_clk, pll_rate);
-	pll_rate = clk_get_rate(dpi->tvd_clk);
-
-	pix_rate = pll_rate / factor;
-	clk_set_rate(dpi->pixel_clk, pix_rate);
-	pix_rate = clk_get_rate(dpi->pixel_clk);
-
-	dev_dbg(dpi->dev, "Got  PLL %lu Hz, pixel clock %lu Hz\n",
-		pll_rate, pix_rate);
+	conf = (struct mtk_dpi_conf *)dpi->data;
+	ret = conf->clk_config(dpi, mode);
+	if (ret)
+		dev_err(dpi->dev, "dpi clk set fail\n");
 
 	limit.c_bottom = 0x0010;
 	limit.c_top = 0x0FE0;
@@ -656,20 +656,83 @@ static const struct component_ops mtk_dpi_component_ops = {
 	.unbind = mtk_dpi_unbind,
 };
 
+static int mtk_dpi_parse_clk_from_dt(struct mtk_dpi *dpi,
+				     struct device_node *np)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mtk_dpi_clk_names); i++) {
+		dpi->clk[i] = of_clk_get_by_name(np,
+						  mtk_dpi_clk_names[i]);
+		if (IS_ERR(dpi->clk[i]))
+			return PTR_ERR(dpi->clk[i]);
+	}
+	return 0;
+}
+
+static int mt8173_clk_config(struct mtk_dpi *dpi, struct drm_display_mode *mode)
+{
+	unsigned long pix_rate;
+	unsigned long pll_rate;
+	unsigned int factor;
+
+	pix_rate = 1000UL * mode->clock;
+	if (mode->clock <= 27000)
+		factor = 16 * 3;
+	else if (mode->clock <= 74250)
+		factor = 8 * 3;
+	else if (mode->clock <= 167000)
+		factor = 4 * 3;
+	else
+		factor = 2 * 3;
+	pll_rate = pix_rate * factor;
+
+	dev_dbg(dpi->dev, "Want PLL %lu Hz, pixel clock %lu Hz\n",
+		pll_rate, pix_rate);
+
+	pll_rate = clk_get_rate(dpi->clk[MTK_DPI_CLK_TVD_PLL]);
+	pix_rate = pll_rate / factor;
+	clk_set_rate(dpi->clk[MTK_DPI_CLK_DPI_PIXEL], pix_rate);
+	dev_dbg(dpi->dev, "Got  PLL %lu Hz, pixel clock %lu Hz\n",
+		pll_rate, pix_rate);
+
+	return 0;
+}
+
+static const struct mtk_dpi_conf mt8173_conf = {
+	.clk_config = mt8173_clk_config,
+};
+
+static const struct of_device_id mtk_dpi_of_ids[] = {
+	{ .compatible = "mediatek,mt8173-dpi",
+		.data = &mt8173_conf,
+	},
+	{}
+};
+
 static int mtk_dpi_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct mtk_dpi *dpi;
 	struct resource *mem;
+	struct device_node *np = dev->of_node;
 	struct device_node *ep, *bridge_node = NULL;
 	int comp_id;
+	const struct of_device_id *match;
+	struct mtk_dpi_conf *conf;
 	int ret;
 
+	match = of_match_node(mtk_dpi_of_ids, dev->of_node);
+	if (!match)
+		return -ENODEV;
+
 	dpi = devm_kzalloc(dev, sizeof(*dpi), GFP_KERNEL);
 	if (!dpi)
 		return -ENOMEM;
 
 	dpi->dev = dev;
+	dpi->data = (void *)match->data;
+	conf = (struct mtk_dpi_conf *)match->data;
 
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	dpi->regs = devm_ioremap_resource(dev, mem);
@@ -679,24 +742,9 @@ static int mtk_dpi_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	dpi->engine_clk = devm_clk_get(dev, "engine");
-	if (IS_ERR(dpi->engine_clk)) {
-		ret = PTR_ERR(dpi->engine_clk);
-		dev_err(dev, "Failed to get engine clock: %d\n", ret);
-		return ret;
-	}
-
-	dpi->pixel_clk = devm_clk_get(dev, "pixel");
-	if (IS_ERR(dpi->pixel_clk)) {
-		ret = PTR_ERR(dpi->pixel_clk);
-		dev_err(dev, "Failed to get pixel clock: %d\n", ret);
-		return ret;
-	}
-
-	dpi->tvd_clk = devm_clk_get(dev, "pll");
-	if (IS_ERR(dpi->tvd_clk)) {
-		ret = PTR_ERR(dpi->tvd_clk);
-		dev_err(dev, "Failed to get tvdpll clock: %d\n", ret);
+	ret = mtk_dpi_parse_clk_from_dt(dpi, np);
+	if (ret) {
+		dev_err(dev, "parse tvd div clk failed!");
 		return ret;
 	}
 
@@ -754,11 +802,6 @@ static int mtk_dpi_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static const struct of_device_id mtk_dpi_of_ids[] = {
-	{ .compatible = "mediatek,mt8173-dpi", },
-	{}
-};
-
 struct platform_driver mtk_dpi_driver = {
 	.probe = mtk_dpi_probe,
 	.remove = mtk_dpi_remove,
-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Wed Jul 27 01:31:29 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Wed, 27 Jul 2016 16:31:29 +0800
Subject: [PATCH v2 0/3] MT8173 HDMI 4K support
Message-ID: <1469608292-6106-1-git-send-email-bibby.hsieh@mediatek.com>

This is MT8173 HDMI 4K support PATCH v2, based on 4.7-rc1.

In order to support HDMI 4K on MT8173,
we have to make some modifications.
1) Make sure that mtk_hdmi_send_infoframe is sent successfully.
2) Enhance the HDMI driving current to improve performance.
3) Make sure that pixel clock is 297MHz when resolution is 4K.

Changes since v1:
 - According to the suggestion from philipp, We use the new
   dpi0_sel rate set method.
 - calls clk_set_rate to set the dpi0_sel according to the
   pixel clock.
 - Remove the direct access to all the intermediate clock part.
 - Remove the intermediate tvdpll_d* clocks in dts.
 - According to suggestion from CK, we rename the clock parse
   function and remove it from mtk_dpi_conf struct.
 - Merges the hdmi Pll set rate for pixel clock greater than
   165MHz and smaller parts.

The PATCH depends on the following patch:
https://patchwork.kernel.org/patch/9249445/ (arm64: dts: mt8173: add mmsel clocks for 4K support)

Thank you.
Bibby Hsieh

Junzhi Zhao (3):
  drm/mediatek: do mtk_hdmi_send_infoframe after HDMI clock enable
  drm/mediatek: enhance the HDMI driving current
  drm/mediatek: fix the wrong pixel clock when resolution is 4K

 drivers/gpu/drm/mediatek/mtk_dpi.c             |  149 +++++++++++++++---------
 drivers/gpu/drm/mediatek/mtk_hdmi.c            |   19 +--
 drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c |   42 +++++--
 3 files changed, 138 insertions(+), 72 deletions(-)

-- 
1.7.9.5



From p.zabel at pengutronix.de  Wed Jul 27 02:23:50 2016
From: p.zabel at pengutronix.de (Philipp Zabel)
Date: Wed, 27 Jul 2016 11:23:50 +0200
Subject: [PATCH v2 3/3] drm/mediatek: fix the wrong pixel clock when
 resolution is 4K
In-Reply-To: <1469608292-6106-4-git-send-email-bibby.hsieh@mediatek.com>
References: <1469608292-6106-1-git-send-email-bibby.hsieh@mediatek.com>
 <1469608292-6106-4-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1469611430.2470.20.camel@pengutronix.de>

Am Mittwoch, den 27.07.2016, 16:31 +0800 schrieb Bibby Hsieh:
> From: Junzhi Zhao <junzhi.zhao at mediatek.com>
> 
> Pixel clock should be 297MHz when resolution is 4K.

This patch does two different things, please don't conflate them.

First, it adds support for 16*3 and 2*3 factors between PLL and pixel
clock. This should be a separate patch and does what this patch
description says.

The second part moves the clocks into an array and adds an indirection
to clock registration depending on of_match_node. This should be a
separate patch. I suppose this change is in preparation for mt2701
support, but I'm not sure yet if it is needed at all.

regards
Philipp

> Signed-off-by: Junzhi Zhao <junzhi.zhao at mediatek.com>
> Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_dpi.c |  149 +++++++++++++++++++++++-------------
>  1 file changed, 96 insertions(+), 53 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
> index d05ca79..fa390e0 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dpi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
> @@ -60,14 +60,25 @@ enum mtk_dpi_out_color_format {
>  	MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL
>  };
>  
> +enum mtk_dpi_clk_id {
> +	MTK_DPI_CLK_DPI_ENGINE,
> +	MTK_DPI_CLK_DPI_PIXEL,
> +	MTK_DPI_CLK_TVD_PLL,
> +	MTK_DPI_CLK_COUNT,
> +};
> +
> +static const char * const mtk_dpi_clk_names[MTK_DPI_CLK_COUNT] = {
> +	[MTK_DPI_CLK_DPI_ENGINE] = "engine",
> +	[MTK_DPI_CLK_DPI_PIXEL] = "pixel",
> +	[MTK_DPI_CLK_TVD_PLL] = "pll",
> +};
> +
>  struct mtk_dpi {
>  	struct mtk_ddp_comp ddp_comp;
>  	struct drm_encoder encoder;
>  	void __iomem *regs;
>  	struct device *dev;
> -	struct clk *engine_clk;
> -	struct clk *pixel_clk;
> -	struct clk *tvd_clk;
> +	struct clk *clk[MTK_DPI_CLK_COUNT];
>  	int irq;
>  	struct drm_display_mode mode;
>  	enum mtk_dpi_out_color_format color_format;
> @@ -76,6 +87,7 @@ struct mtk_dpi {
>  	enum mtk_dpi_out_channel_swap channel_swap;
>  	bool power_sta;
>  	u8 power_ctl;
> +	void *data;
>  };
>  
>  static inline struct mtk_dpi *mtk_dpi_from_encoder(struct drm_encoder *e)
> @@ -114,6 +126,10 @@ struct mtk_dpi_yc_limit {
>  	u16 c_bottom;
>  };
>  
> +struct mtk_dpi_conf {
> +	int (*clk_config)(struct mtk_dpi *dpi, struct drm_display_mode *mode);
> +};
> +
>  static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask)
>  {
>  	u32 tmp = readl(dpi->regs + offset) & ~mask;
> @@ -377,8 +393,8 @@ static void mtk_dpi_power_off(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl)
>  		return;
>  
>  	mtk_dpi_disable(dpi);
> -	clk_disable_unprepare(dpi->pixel_clk);
> -	clk_disable_unprepare(dpi->engine_clk);
> +	clk_disable_unprepare(dpi->clk[MTK_DPI_CLK_DPI_PIXEL]);
> +	clk_disable_unprepare(dpi->clk[MTK_DPI_CLK_DPI_ENGINE]);
>  	dpi->power_sta = false;
>  }
>  
> @@ -395,13 +411,13 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl)
>  	if (dpi->power_sta)
>  		return 0;
>  
> -	ret = clk_prepare_enable(dpi->engine_clk);
> +	ret = clk_prepare_enable(dpi->clk[MTK_DPI_CLK_DPI_ENGINE]);
>  	if (ret) {
>  		dev_err(dpi->dev, "Failed to enable engine clock: %d\n", ret);
>  		goto err_eng;
>  	}
>  
> -	ret = clk_prepare_enable(dpi->pixel_clk);
> +	ret = clk_prepare_enable(dpi->clk[MTK_DPI_CLK_DPI_PIXEL]);
>  	if (ret) {
>  		dev_err(dpi->dev, "Failed to enable pixel clock: %d\n", ret);
>  		goto err_pixel;
> @@ -412,7 +428,7 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl)
>  	return 0;
>  
>  err_pixel:
> -	clk_disable_unprepare(dpi->engine_clk);
> +	clk_disable_unprepare(dpi->clk[MTK_DPI_CLK_DPI_ENGINE]);
>  err_eng:
>  	dpi->power_ctl &= ~pctl;
>  	return ret;
> @@ -428,34 +444,18 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
>  	struct mtk_dpi_sync_param vsync_leven = { 0 };
>  	struct mtk_dpi_sync_param vsync_rodd = { 0 };
>  	struct mtk_dpi_sync_param vsync_reven = { 0 };
> -	unsigned long pix_rate;
> -	unsigned long pll_rate;
> -	unsigned int factor;
> +	struct mtk_dpi_conf *conf;
> +	int ret;
>  
>  	if (!dpi) {
>  		dev_err(dpi->dev, "invalid argument\n");
>  		return -EINVAL;
>  	}
>  
> -	pix_rate = 1000UL * mode->clock;
> -	if (mode->clock <= 74000)
> -		factor = 8 * 3;
> -	else
> -		factor = 4 * 3;
> -	pll_rate = pix_rate * factor;
> -
> -	dev_dbg(dpi->dev, "Want PLL %lu Hz, pixel clock %lu Hz\n",
> -		pll_rate, pix_rate);
> -
> -	clk_set_rate(dpi->tvd_clk, pll_rate);
> -	pll_rate = clk_get_rate(dpi->tvd_clk);
> -
> -	pix_rate = pll_rate / factor;
> -	clk_set_rate(dpi->pixel_clk, pix_rate);
> -	pix_rate = clk_get_rate(dpi->pixel_clk);
> -
> -	dev_dbg(dpi->dev, "Got  PLL %lu Hz, pixel clock %lu Hz\n",
> -		pll_rate, pix_rate);
> +	conf = (struct mtk_dpi_conf *)dpi->data;
> +	ret = conf->clk_config(dpi, mode);
> +	if (ret)
> +		dev_err(dpi->dev, "dpi clk set fail\n");
>  
>  	limit.c_bottom = 0x0010;
>  	limit.c_top = 0x0FE0;
> @@ -656,20 +656,83 @@ static const struct component_ops mtk_dpi_component_ops = {
>  	.unbind = mtk_dpi_unbind,
>  };
>  
> +static int mtk_dpi_parse_clk_from_dt(struct mtk_dpi *dpi,
> +				     struct device_node *np)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(mtk_dpi_clk_names); i++) {
> +		dpi->clk[i] = of_clk_get_by_name(np,
> +						  mtk_dpi_clk_names[i]);
> +		if (IS_ERR(dpi->clk[i]))
> +			return PTR_ERR(dpi->clk[i]);
> +	}
> +	return 0;
> +}
> +
> +static int mt8173_clk_config(struct mtk_dpi *dpi, struct drm_display_mode *mode)
> +{
> +	unsigned long pix_rate;
> +	unsigned long pll_rate;
> +	unsigned int factor;
> +
> +	pix_rate = 1000UL * mode->clock;
> +	if (mode->clock <= 27000)
> +		factor = 16 * 3;
> +	else if (mode->clock <= 74250)
> +		factor = 8 * 3;
> +	else if (mode->clock <= 167000)
> +		factor = 4 * 3;
> +	else
> +		factor = 2 * 3;
> +	pll_rate = pix_rate * factor;
> +
> +	dev_dbg(dpi->dev, "Want PLL %lu Hz, pixel clock %lu Hz\n",
> +		pll_rate, pix_rate);
> +
> +	pll_rate = clk_get_rate(dpi->clk[MTK_DPI_CLK_TVD_PLL]);
> +	pix_rate = pll_rate / factor;
> +	clk_set_rate(dpi->clk[MTK_DPI_CLK_DPI_PIXEL], pix_rate);
> +	dev_dbg(dpi->dev, "Got  PLL %lu Hz, pixel clock %lu Hz\n",
> +		pll_rate, pix_rate);
> +
> +	return 0;
> +}
> +
> +static const struct mtk_dpi_conf mt8173_conf = {
> +	.clk_config = mt8173_clk_config,
> +};
> +
> +static const struct of_device_id mtk_dpi_of_ids[] = {
> +	{ .compatible = "mediatek,mt8173-dpi",
> +		.data = &mt8173_conf,
> +	},
> +	{}
> +};
> +
>  static int mtk_dpi_probe(struct platform_device *pdev)
>  {
>  	struct device *dev = &pdev->dev;
>  	struct mtk_dpi *dpi;
>  	struct resource *mem;
> +	struct device_node *np = dev->of_node;
>  	struct device_node *ep, *bridge_node = NULL;
>  	int comp_id;
> +	const struct of_device_id *match;
> +	struct mtk_dpi_conf *conf;
>  	int ret;
>  
> +	match = of_match_node(mtk_dpi_of_ids, dev->of_node);
> +	if (!match)
> +		return -ENODEV;
> +
>  	dpi = devm_kzalloc(dev, sizeof(*dpi), GFP_KERNEL);
>  	if (!dpi)
>  		return -ENOMEM;
>  
>  	dpi->dev = dev;
> +	dpi->data = (void *)match->data;
> +	conf = (struct mtk_dpi_conf *)match->data;
>  
>  	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	dpi->regs = devm_ioremap_resource(dev, mem);
> @@ -679,24 +742,9 @@ static int mtk_dpi_probe(struct platform_device *pdev)
>  		return ret;
>  	}
>  
> -	dpi->engine_clk = devm_clk_get(dev, "engine");
> -	if (IS_ERR(dpi->engine_clk)) {
> -		ret = PTR_ERR(dpi->engine_clk);
> -		dev_err(dev, "Failed to get engine clock: %d\n", ret);
> -		return ret;
> -	}
> -
> -	dpi->pixel_clk = devm_clk_get(dev, "pixel");
> -	if (IS_ERR(dpi->pixel_clk)) {
> -		ret = PTR_ERR(dpi->pixel_clk);
> -		dev_err(dev, "Failed to get pixel clock: %d\n", ret);
> -		return ret;
> -	}
> -
> -	dpi->tvd_clk = devm_clk_get(dev, "pll");
> -	if (IS_ERR(dpi->tvd_clk)) {
> -		ret = PTR_ERR(dpi->tvd_clk);
> -		dev_err(dev, "Failed to get tvdpll clock: %d\n", ret);
> +	ret = mtk_dpi_parse_clk_from_dt(dpi, np);
> +	if (ret) {
> +		dev_err(dev, "parse tvd div clk failed!");
>  		return ret;
>  	}
>  
> @@ -754,11 +802,6 @@ static int mtk_dpi_remove(struct platform_device *pdev)
>  	return 0;
>  }
>  
> -static const struct of_device_id mtk_dpi_of_ids[] = {
> -	{ .compatible = "mediatek,mt8173-dpi", },
> -	{}
> -};
> -
>  struct platform_driver mtk_dpi_driver = {
>  	.probe = mtk_dpi_probe,
>  	.remove = mtk_dpi_remove,




From p.zabel at pengutronix.de  Wed Jul 27 02:25:50 2016
From: p.zabel at pengutronix.de (Philipp Zabel)
Date: Wed, 27 Jul 2016 11:25:50 +0200
Subject: [PATCH v2 2/3] drm/mediatek: enhance the HDMI driving current
In-Reply-To: <1469608292-6106-3-git-send-email-bibby.hsieh@mediatek.com>
References: <1469608292-6106-1-git-send-email-bibby.hsieh@mediatek.com>
 <1469608292-6106-3-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1469611550.2470.22.camel@pengutronix.de>

Am Mittwoch, den 27.07.2016, 16:31 +0800 schrieb Bibby Hsieh:
> From: Junzhi Zhao <junzhi.zhao at mediatek.com>
> 
> In order to improve 4K resolution performance,
> we have to enhance the HDMI driving currend
                                           ^
Typo, s/currend/current/

Besides that, this patch looks good to me.

regards
Philipp

> when clock rate is greater than 165MHz.
> 
> Signed-off-by: Junzhi Zhao <junzhi.zhao at mediatek.com>
> Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c |   42 +++++++++++++++++-------
>  1 file changed, 30 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
> index 8a24754..51cb9cf 100644
> --- a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
> +++ b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
> @@ -265,6 +265,9 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
>  	struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
>  	unsigned int pre_div;
>  	unsigned int div;
> +	unsigned int pre_ibias;
> +	unsigned int hdmi_ibias;
> +	unsigned int imp_en;
>  
>  	dev_dbg(hdmi_phy->dev, "%s: %lu Hz, parent: %lu Hz\n", __func__,
>  		rate, parent_rate);
> @@ -298,18 +301,31 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
>  			  (0x1 << PLL_BR_SHIFT),
>  			  RG_HDMITX_PLL_BP | RG_HDMITX_PLL_BC |
>  			  RG_HDMITX_PLL_BR);
> -	mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON3, RG_HDMITX_PRD_IMP_EN);
> +	if (rate < 165000000) {
> +		mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON3,
> +					RG_HDMITX_PRD_IMP_EN);
> +		pre_ibias = 0x3;
> +		imp_en = 0x0;
> +		hdmi_ibias = hdmi_phy->ibias;
> +	} else {
> +		mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON3,
> +				      RG_HDMITX_PRD_IMP_EN);
> +		pre_ibias = 0x6;
> +		imp_en = 0xf;
> +		hdmi_ibias = hdmi_phy->ibias_up;
> +	}
>  	mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON4,
> -			  (0x3 << PRD_IBIAS_CLK_SHIFT) |
> -			  (0x3 << PRD_IBIAS_D2_SHIFT) |
> -			  (0x3 << PRD_IBIAS_D1_SHIFT) |
> -			  (0x3 << PRD_IBIAS_D0_SHIFT),
> +			  (pre_ibias << PRD_IBIAS_CLK_SHIFT) |
> +			  (pre_ibias << PRD_IBIAS_D2_SHIFT) |
> +			  (pre_ibias << PRD_IBIAS_D1_SHIFT) |
> +			  (pre_ibias << PRD_IBIAS_D0_SHIFT),
>  			  RG_HDMITX_PRD_IBIAS_CLK |
>  			  RG_HDMITX_PRD_IBIAS_D2 |
>  			  RG_HDMITX_PRD_IBIAS_D1 |
>  			  RG_HDMITX_PRD_IBIAS_D0);
>  	mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON3,
> -			  (0x0 << DRV_IMP_EN_SHIFT), RG_HDMITX_DRV_IMP_EN);
> +			  (imp_en << DRV_IMP_EN_SHIFT),
> +			  RG_HDMITX_DRV_IMP_EN);
>  	mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6,
>  			  (hdmi_phy->drv_imp_clk << DRV_IMP_CLK_SHIFT) |
>  			  (hdmi_phy->drv_imp_d2 << DRV_IMP_D2_SHIFT) |
> @@ -318,12 +334,14 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
>  			  RG_HDMITX_DRV_IMP_CLK | RG_HDMITX_DRV_IMP_D2 |
>  			  RG_HDMITX_DRV_IMP_D1 | RG_HDMITX_DRV_IMP_D0);
>  	mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON5,
> -			  (hdmi_phy->ibias << DRV_IBIAS_CLK_SHIFT) |
> -			  (hdmi_phy->ibias << DRV_IBIAS_D2_SHIFT) |
> -			  (hdmi_phy->ibias << DRV_IBIAS_D1_SHIFT) |
> -			  (hdmi_phy->ibias << DRV_IBIAS_D0_SHIFT),
> -			  RG_HDMITX_DRV_IBIAS_CLK | RG_HDMITX_DRV_IBIAS_D2 |
> -			  RG_HDMITX_DRV_IBIAS_D1 | RG_HDMITX_DRV_IBIAS_D0);
> +			  (hdmi_ibias << DRV_IBIAS_CLK_SHIFT) |
> +			  (hdmi_ibias << DRV_IBIAS_D2_SHIFT) |
> +			  (hdmi_ibias << DRV_IBIAS_D1_SHIFT) |
> +			  (hdmi_ibias << DRV_IBIAS_D0_SHIFT),
> +			  RG_HDMITX_DRV_IBIAS_CLK |
> +			  RG_HDMITX_DRV_IBIAS_D2 |
> +			  RG_HDMITX_DRV_IBIAS_D1 |
> +			  RG_HDMITX_DRV_IBIAS_D0);
>  	return 0;
>  }
>  




From ck.hu at mediatek.com  Wed Jul 27 02:25:56 2016
From: ck.hu at mediatek.com (CK Hu)
Date: Wed, 27 Jul 2016 17:25:56 +0800
Subject: [PATCH v3] arm64: dts: mt8173: add mmsel clocks for 4K support
In-Reply-To: <1469607914-64831-1-git-send-email-bibby.hsieh@mediatek.com>
References: <1469607914-64831-1-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1469611556.11841.77.camel@mtksdaap41>

Hi, Bibby:

On Wed, 2016-07-27 at 16:25 +0800, Bibby Hsieh wrote:
> If MT8173 can support HDMI 4K resoultion, the
> VENCPLL should be configured to 800MHZ.
> We didn't set VENCPLL directly, we set the
> mm_sel to 400MHz statically in the board device tree.

You may rewrite the description as below:

'To support HDMI 4K resolution, mmsys need clock mm_sel to be 400MHz.'

You need not to mention VENCPLL because it's controlled by clock driver.

> 
> Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> ---
> Changes since v2:
>  - Align the clocks of dpi0 node.
> 
> Changes since v1:
>  - Do not set the VENCPLL by clk_set_rate
>    at display driver.
>  - Configure the mm_sel to 400MHz statically
>    in the board device tree.
> ---
>  arch/arm64/boot/dts/mediatek/mt8173.dtsi |    2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
> index 78529e4..9c22204 100644
> --- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
> +++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
> @@ -690,7 +690,9 @@
>  			compatible = "mediatek,mt8173-mmsys", "syscon";
>  			reg = <0 0x14000000 0 0x1000>;
>  			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
> +			clocks = <&topckgen CLK_TOP_MM_SEL>;
>  			#clock-cells = <1>;
> +			clock-frequency  = <400000000>;
>  		};
>  
>  		ovl0: ovl at 1400c000 {

Regards,
CK



From p.zabel at pengutronix.de  Wed Jul 27 02:27:16 2016
From: p.zabel at pengutronix.de (Philipp Zabel)
Date: Wed, 27 Jul 2016 11:27:16 +0200
Subject: [PATCH v2 1/3] drm/mediatek: do mtk_hdmi_send_infoframe after
 HDMI clock enable
In-Reply-To: <1469608292-6106-2-git-send-email-bibby.hsieh@mediatek.com>
References: <1469608292-6106-1-git-send-email-bibby.hsieh@mediatek.com>
 <1469608292-6106-2-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1469611636.2470.24.camel@pengutronix.de>

Am Mittwoch, den 27.07.2016, 16:31 +0800 schrieb Bibby Hsieh:
> From: Junzhi Zhao <junzhi.zhao at mediatek.com>
> 
> The mtk_hdmi_send_infoframe have to
> be run after PLL and PIXEL clock of HDMI enable.
> Make sure that HDMI inforframes can be sent
> successfully.
> 
> Signed-off-by: Junzhi Zhao <junzhi.zhao at mediatek.com>
> Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_hdmi.c |   19 ++++++++++++-------
>  1 file changed, 12 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> index ba812ef..d8609f5 100644
> --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> @@ -1133,12 +1133,6 @@ static int mtk_hdmi_output_set_display_mode(struct mtk_hdmi *hdmi,
>  	phy_power_on(hdmi->phy);
>  	mtk_hdmi_aud_output_config(hdmi, mode);
>  
> -	mtk_hdmi_setup_audio_infoframe(hdmi);
> -	mtk_hdmi_setup_avi_infoframe(hdmi, mode);
> -	mtk_hdmi_setup_spd_infoframe(hdmi, "mediatek", "On-chip HDMI");
> -	if (mode->flags & DRM_MODE_FLAG_3D_MASK)
> -		mtk_hdmi_setup_vendor_specific_infoframe(hdmi, mode);
> -
>  	mtk_hdmi_hw_vid_black(hdmi, false);
>  	mtk_hdmi_hw_aud_unmute(hdmi);
>  	mtk_hdmi_hw_send_av_unmute(hdmi);
> @@ -1401,14 +1395,25 @@ static void mtk_hdmi_bridge_pre_enable(struct drm_bridge *bridge)
>  	hdmi->powered = true;
>  }
>  
> +static void mtk_hdmi_send_infoframe(struct mtk_hdmi *hdmi,
> +				    struct drm_display_mode *mode)
> +{
> +	mtk_hdmi_setup_audio_infoframe(hdmi);
> +	mtk_hdmi_setup_avi_infoframe(hdmi, mode);
> +	mtk_hdmi_setup_spd_infoframe(hdmi, "mediatek", "On-chip HDMI");
> +	if (mode->flags & DRM_MODE_FLAG_3D_MASK)
> +		mtk_hdmi_setup_vendor_specific_infoframe(hdmi, mode);
> +}
> +
>  static void mtk_hdmi_bridge_enable(struct drm_bridge *bridge)
>  {
>  	struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
>  
> +	phy_power_on(hdmi->phy);
>  	mtk_hdmi_output_set_display_mode(hdmi, &hdmi->mode);
>  	clk_prepare_enable(hdmi->clk[MTK_HDMI_CLK_HDMI_PLL]);
>  	clk_prepare_enable(hdmi->clk[MTK_HDMI_CLK_HDMI_PIXEL]);
> -	phy_power_on(hdmi->phy);

This change is not described in the patch description. Why is the phy
power on moved after the pixel clock enable?

> +	mtk_hdmi_send_infoframe(hdmi, &hdmi->mode);
>  
>  	hdmi->enabled = true;
>  }

regards
Philipp



From p.zabel at pengutronix.de  Wed Jul 27 02:32:44 2016
From: p.zabel at pengutronix.de (Philipp Zabel)
Date: Wed, 27 Jul 2016 11:32:44 +0200
Subject: [PATCH v3] arm64: dts: mt8173: add mmsel clocks for 4K support
In-Reply-To: <1469607914-64831-1-git-send-email-bibby.hsieh@mediatek.com>
References: <1469607914-64831-1-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1469611964.2470.30.camel@pengutronix.de>

Am Mittwoch, den 27.07.2016, 16:25 +0800 schrieb Bibby Hsieh:
> If MT8173 can support HDMI 4K resoultion, the
> VENCPLL should be configured to 800MHZ.
> We didn't set VENCPLL directly, we set the
> mm_sel to 400MHz statically in the board device tree.

Maybe add a comment that the board .dts file should override the clock
rate property with the higher VENCPLL frequency the board supports HDMI
4K resolution.

> Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> ---
> Changes since v2:
>  - Align the clocks of dpi0 node.
> 
> Changes since v1:
>  - Do not set the VENCPLL by clk_set_rate
>    at display driver.
>  - Configure the mm_sel to 400MHz statically
>    in the board device tree.
> ---
>  arch/arm64/boot/dts/mediatek/mt8173.dtsi |    2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
> index 78529e4..9c22204 100644
> --- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
> +++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
> @@ -690,7 +690,9 @@
>  			compatible = "mediatek,mt8173-mmsys", "syscon";
>  			reg = <0 0x14000000 0 0x1000>;
>  			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
> +			clocks = <&topckgen CLK_TOP_MM_SEL>;
>  			#clock-cells = <1>;
> +			clock-frequency  = <400000000>;

According to the "Assigned clock parents and rates" section in
Documentation/devicetree/bindings/clock/clock-bindings.txt,
this should be:
			assigned-clocks = <&topckgen CLK_TOP_MM_SEL>;
			assigned-clock-rates = <400000000>;

regards
Philipp



From yt.shen at mediatek.com  Tue Jul 26 03:42:36 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Tue, 26 Jul 2016 18:42:36 +0800
Subject: [PATCH v4 6/8] drm/mediatek: add dsi transfer function
In-Reply-To: <1468994346.11841.31.camel@mtksdaap41>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
 <1468577274-6178-7-git-send-email-yt.shen@mediatek.com>
 <1468994346.11841.31.camel@mtksdaap41>
Message-ID: <1469529756.4678.30.camel@mtksdaap41>

Hi CK,

Thanks for the review.

On Wed, 2016-07-20 at 13:59 +0800, CK Hu wrote:
> Hi, YT:
> 
> Some comments inline.
> 
> On Fri, 2016-07-15 at 18:07 +0800, YT Shen wrote:
> > From: shaoming chen <shaoming.chen at mediatek.com>
> > 
> > add dsi read/write commands for transfer function
> > 
> > Signed-off-by: shaoming chen <shaoming.chen at mediatek.com>
> > ---
> >  drivers/gpu/drm/mediatek/mtk_dsi.c |  322 ++++++++++++++++++++++++++++++++++++
> >  1 file changed, 322 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
> > index de5ad7f..1f99894 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_dsi.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
> > @@ -24,6 +24,7 @@
> >  #include <linux/of_graph.h>
> >  #include <linux/phy/phy.h>
> >  #include <linux/platform_device.h>
> > +#include <video/mipi_display.h>
> >  #include <video/videomode.h>
> >  
> >  #include "mtk_drm_ddp_comp.h"
> > @@ -80,8 +81,16 @@
> >  #define DSI_HBP_WC		0x54
> >  #define DSI_HFP_WC		0x58
> >  
> > +#define DSI_CMDQ_SIZE		0x60
> > +#define CMDQ_SIZE		0x3f
> > +
> >  #define DSI_HSTX_CKL_WC		0x64
> >  
> > +#define DSI_RX_DATA0		0x74
> > +#define DSI_RX_DATA1		0x78
> > +#define DSI_RX_DATA2		0x7c
> > +#define DSI_RX_DATA3		0x80
> > +
> >  #define DSI_RACK		0x84
> >  #define RACK			BIT(0)
> >  
> > @@ -117,8 +126,25 @@
> >  #define CLK_HS_POST			(0xff << 8)
> >  #define CLK_HS_EXIT			(0xff << 16)
> >  
> > +#define DSI_CMDQ0		0x180
> > +
> >  #define NS_TO_CYCLE(n, c)    ((n) / (c) + (((n) % (c)) ? 1 : 0))
> >  
> > +#define MTK_DSI_HOST_IS_READ(type) \
> > +	((type == MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM) || \
> > +	(type == MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM) || \
> > +	(type == MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM) || \
> > +	(type == MIPI_DSI_DCS_READ))
> > +
> > +#define MTK_DSI_HOST_IS_WRITE(type) \
> > +	((type == MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM) || \
> > +	(type == MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM) || \
> > +	(type == MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM) || \
> > +	(type == MIPI_DSI_DCS_SHORT_WRITE) || \
> > +	(type == MIPI_DSI_DCS_SHORT_WRITE_PARAM) || \
> > +	(type == MIPI_DSI_GENERIC_LONG_WRITE) || \
> > +	(type == MIPI_DSI_DCS_LONG_WRITE))
> > +
> >  struct phy;
> >  
> >  struct mtk_dsi {
> > @@ -148,6 +174,38 @@ struct mtk_dsi {
> >  	int irq_num, irq_data;
> >  };
> >  
> > +struct dsi_cmd_t0 {
> > +	u8 config;
> > +	u8 type;
> > +	u8 data0;
> > +	u8 data1;
> > +};
> > +
> > +struct dsi_cmd_t2 {
> > +	u8 config;
> > +	u8 type;
> > +	u16 wc16;
> > +	u8 *pdata;
> > +};
> > +
> > +struct dsi_rx_data {
> > +	u8 byte0;
> > +	u8 byte1;
> > +	u8 byte2;
> > +	u8 byte3;
> > +};
> > +
> > +struct dsi_tx_cmdq {
> > +	u8 byte0;
> > +	u8 byte1;
> > +	u8 byte2;
> > +	u8 byte3;
> > +};
> > +
> > +struct dsi_tx_cmdq_regs {
> > +	struct dsi_tx_cmdq data[128];
> > +};
> > +
> >  enum {
> >  	DSI_INT_SLEEPOUT_DONE_FLAG	= BIT(6),
> >  	DSI_INT_VM_CMD_DONE_FLAG	= BIT(5),
> > @@ -858,9 +916,273 @@ static int mtk_dsi_host_detach(struct mipi_dsi_host *host,
> >  	return 0;
> >  }
> >  
> > +static void mtk_dsi_set_cmdq(void __iomem *reg, u32 mask, u32 data)
> > +{
> > +	u32 temp = readl(reg);
> > +
> > +	writel((temp & ~mask) | (data & mask), reg);
> > +}
> > +
> > +static void mtk_dsi_wait_for_idle(struct mtk_dsi *dsi)
> > +{
> > +	u32 timeout_ms = 500000; /* total 1s ~ 2s timeout */
> > +
> > +	while (timeout_ms--) {
> > +		if (!(readl(dsi->regs + DSI_INTSTA) & DSI_BUSY))
> > +			break;
> > +
> > +		usleep_range(2, 4);
> > +	}
> > +
> > +	if (timeout_ms == 0) {
> > +		dev_info(dsi->dev, "polling dsi wait not busy timeout!\n");
> > +
> > +		mtk_dsi_enable(dsi);
> > +		mtk_dsi_reset_engine(dsi);
> > +	}
> > +}
> > +
> > +static ssize_t mtk_dsi_host_read_cmd(struct mtk_dsi *dsi,
> > +				     const struct mipi_dsi_msg *msg)
> > +{
> > +	u8 max_try_count = 5;
> > +	u32 recv_data_cnt, tmp_val;
> > +	u32 recv_data0, recv_data1, recv_data2, recv_data3;
> > +	struct dsi_rx_data read_data0, read_data1, read_data2, read_data3;
> > +	struct dsi_cmd_t0 t0;
> > +	s32 ret;
> > +
> > +	u8 *buffer = msg->rx_buf;
> > +	u8 buffer_size = msg->rx_len;
> > +	u8 packet_type;
> > +
> > +	if (readl(dsi->regs + DSI_MODE_CTRL) & 0x03) {
> > +		dev_info(dsi->dev, "dsi engine is not command mode\n");
> > +		return -1;
> > +	}
> > +
> > +	if (!buffer) {
> > +		dev_info(dsi->dev, "dsi receive buffer size may be NULL\n");
> > +		return -1;
> > +	}
> > +
> > +	do {
> > +		if (max_try_count == 0) {
> > +			dev_info(dsi->dev, "dsi engine read counter has been maxinum\n");
> > +			return -1;
> > +		}
> > +
> > +		max_try_count--;
> > +		recv_data_cnt = 0;
> > +
> > +		mtk_dsi_wait_for_idle(dsi);
> > +
> > +		t0.config = 0x04;
> > +		t0.data0 = *((u8 *)(msg->tx_buf));
> > +
> > +		if (buffer_size < 0x3)
> 
> It's better to use '3' instead of '0x3'.
OK.

> 
> > +			t0.type = MIPI_DSI_DCS_READ;
> > +		else
> > +			t0.type = MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM;
> > +
> > +		t0.data1 = 0;
> > +
> > +		tmp_val = (t0.data1 << 24) | (t0.data0 << 16) | (t0.type << 8) |
> > +			t0.config;
> 
> Why need 'struct dsi_cmd_t0 t0'? I think code is more simple when get
> rid of this structure. The code looks like:
> 
> tmp_val = (data1 << 24) | (data0 << 16) | (type << 8) | config;
We will check this part.

> 
> > +
> > +		writel(tmp_val, dsi->regs + DSI_CMDQ0);
> > +		mtk_dsi_mask(dsi, DSI_CMDQ_SIZE, CMDQ_SIZE, 1);
> > +
> > +		mtk_dsi_mask(dsi, DSI_RACK, RACK, RACK);
> > +		mtk_dsi_mask(dsi, DSI_INTSTA, LPRX_RD_RDY_INT_FLAG,
> > +			     ~LPRX_RD_RDY_INT_FLAG);
> > +		mtk_dsi_mask(dsi, DSI_INTSTA, CMD_DONE_INT_FLAG,
> > +			     ~CMD_DONE_INT_FLAG);
> 
> I think interrupt status should be cleared in irq handler. So you need
> not to clear it here.
will remove.

> 
> > +		mtk_dsi_mask(dsi, DSI_INTEN, DSI_INT_LPRX_RD_RDY_FLAG,
> > +			     DSI_INT_LPRX_RD_RDY_FLAG);
> > +		mtk_dsi_mask(dsi, DSI_INTEN, DSI_INT_CMD_DONE_FLAG,
> > +			     DSI_INT_CMD_DONE_FLAG);
> 
> Why enable cmd_done interrupt? You just need interrupt of LPRX_RD_RDY.
will remove.

> 
> > +
> > +		mtk_dsi_start(dsi);
> > +
> > +		dev_info(dsi->dev, "Start polling DSI read ready!!!\n");
> > +
> > +		 /* 2s timeout*/
> > +		ret = mtk_dsi_wait_for_irq_timeout(dsi,
> > +						   DSI_INT_LPRX_RD_RDY_FLAG,
> > +						   2000);
> > +		if (ret) {
> > +			dev_info(dsi->dev, "Polling DSI read ready timeout!!!\n");
> > +
> > +			mtk_dsi_enable(dsi);
> > +			mtk_dsi_reset_engine(dsi);
> > +
> > +			return ret;
> > +		}
> > +
> > +		dev_info(dsi->dev, "End polling DSI read ready!!!\n");
> > +
> > +		mtk_dsi_mask(dsi, DSI_RACK, RACK, RACK);
> > +		mtk_dsi_mask(dsi, DSI_INTSTA, LPRX_RD_RDY_INT_FLAG,
> > +			     ~LPRX_RD_RDY_INT_FLAG);
> > +
> > +		recv_data0 = readl(dsi->regs + DSI_RX_DATA0);
> > +		recv_data1 = readl(dsi->regs + DSI_RX_DATA1);
> > +		recv_data2 = readl(dsi->regs + DSI_RX_DATA2);
> > +		recv_data3 = readl(dsi->regs + DSI_RX_DATA3);
> > +
> > +		read_data0 = *((struct dsi_rx_data *)(&recv_data0));
> > +		read_data1 = *((struct dsi_rx_data *)(&recv_data1));
> > +		read_data2 = *((struct dsi_rx_data *)(&recv_data2));
> > +		read_data3 = *((struct dsi_rx_data *)(&recv_data3));
> 
> You only use read_data0. read_data1, read_data2, and read_data3 are just
> for debug. Remove the debug only modification if they are not necessary.
> Or move them to another patch to make this patch clear.
We will remove the debug messages here.

> 
> > +
> > +		ret = readl(dsi->regs + DSI_CMDQ_SIZE);
> > +		dev_info(dsi->dev, "DSI_CMDQ_SIZE : 0x%x\n", ret & CMDQ_SIZE);
> > +
> > +		ret = readl(dsi->regs + DSI_CMDQ0);
> > +		dev_info(dsi->dev, "DSI_CMDQ_DATA0 : 0x%x\n",
> > +			 ret & 0xff);
> > +		dev_info(dsi->dev, "DSI_CMDQ_DATA1 : 0x%x\n",
> > +			 (ret >> 8) & 0xff);
> > +		dev_info(dsi->dev, "DSI_CMDQ_DATA2 : 0x%x\n",
> > +			 (ret >> 16) & 0xff);
> > +		dev_info(dsi->dev, "DSI_CMDQ_DATA3 : 0x%x\n",
> > +			 (ret >> 24) & 0xff);
> > +
> > +		dev_info(dsi->dev, "DSI_RX_DATA0: 0x%x\n", recv_data0);
> > +		dev_info(dsi->dev, "DSI_RX_DATA1: 0x%x\n", recv_data1);
> > +		dev_info(dsi->dev, "DSI_RX_DATA2: 0x%x\n", recv_data2);
> > +		dev_info(dsi->dev, "DSI_RX_DATA3: 0x%x\n", recv_data3);
> > +
> > +		dev_info(dsi->dev, "read_data0: %x,%x,%x,%x\n",
> > +			 read_data0.byte0, read_data0.byte1, read_data0.byte2,
> > +			 read_data0.byte3);
> > +		dev_info(dsi->dev, "read_data1: %x,%x,%x,%x\n",
> > +			 read_data1.byte0, read_data1.byte1, read_data1.byte2,
> > +			 read_data1.byte3);
> > +		dev_info(dsi->dev, "read_data2: %x,%x,%x,%x\n",
> > +			 read_data2.byte0, read_data2.byte1, read_data2.byte2,
> > +			 read_data2.byte3);
> > +		dev_info(dsi->dev, "read_data3: %x,%x,%x,%x\n",
> > +			 read_data3.byte0, read_data3.byte1, read_data3.byte2,
> > +			 read_data3.byte3);
> > +
> > +		packet_type = read_data0.byte0;
> > +		dev_info(dsi->dev, "DSI read packet_type is 0x%x\n",
> > +			 packet_type);
> > +
> > +		if (packet_type == 0x1a || packet_type == 0x1c) {
> > +			void *read_tmp = (void *)&recv_data1;
> > +
> > +			recv_data_cnt = read_data0.byte1 +
> > +					read_data0.byte2 * 16;
> > +			if (recv_data_cnt > 10)
> > +				recv_data_cnt = 10;
> 
> Why do you drop data over size of 10? Isn't it an error?
We will update these codes in the next version.

> 
> > +
> > +			if (recv_data_cnt > buffer_size)
> > +				recv_data_cnt = buffer_size;
> 
> Isn't it an error while you drop data over the buffer size?
We will update these codes in the next version.

> 
> > +
> > +			memcpy(buffer, read_tmp, recv_data_cnt);
> > +		} else {
> > +			/* short  packet */
> > +			recv_data_cnt = 2;
> > +			if (recv_data_cnt > buffer_size)
> > +				recv_data_cnt = buffer_size;
> 
> Isn't it an error while you drop data over the buffer size?
We will update these codes in the next version.

> 
> > +
> > +			memcpy(buffer, &read_data0.byte1, 2);
> 
> If buffer_size is 1, why do you still copy 2 bytes?
Will fix.

> 
> > +		}
> > +	} while (packet_type != 0x1c && packet_type != 0x21 &&
> > +		packet_type != 0x22 && packet_type != 0x1a);
> 
> Could you give these magic number a descriptive name?
OK.

> 
> > +
> > +	dev_info(dsi->dev, "dsi get %d byte data from the panel address(0x%x)\n",
> > +		 recv_data_cnt, *((u8 *)(msg->tx_buf)));
> > +
> > +	return recv_data_cnt;
> > +}
> > +
> > +static ssize_t mtk_dsi_host_write_cmd(struct mtk_dsi *dsi,
> > +				      const struct mipi_dsi_msg *msg)
> > +{
> > +	u32 i;
> > +	u32 goto_addr, mask_para, set_para, reg_val;
> > +	void __iomem *cmdq_reg;
> > +	struct dsi_cmd_t0 t0;
> > +	struct dsi_cmd_t2 t2;
> > +	const char *tx_buf = msg->tx_buf;
> > +	struct dsi_tx_cmdq_regs *dsi_cmd_reg;
> > +
> > +	dsi_cmd_reg = (struct dsi_tx_cmdq_regs *)(dsi->regs + DSI_CMDQ0);
> > +
> > +	mtk_dsi_wait_for_idle(dsi);
> > +
> > +	if (msg->tx_len > 2) {
> > +		t2.config = 2;
> > +		t2.type = msg->type;
> > +		t2.wc16 = msg->tx_len;
> > +
> > +		reg_val = (t2.wc16 << 16) | (t2.type << 8) | t2.config;
> 
> Why need 'struct dsi_cmd_t2 t2'? I think code is more simple when get
> rid of this structure. The code looks like:
> 
> reg_val = (wc16 << 16) | (type << 8) | config;
We will check this part.

> 
> > +
> > +		writel(reg_val, &dsi_cmd_reg->data[0]);
> > +
> > +		goto_addr = (u32)(&dsi_cmd_reg->data[1].byte0);
> > +		mask_para = (0xff << ((goto_addr & 0x3) * 8));
> > +		set_para = (tx_buf[0] << ((goto_addr & 0x3) * 8));
> > +		cmdq_reg = (void __iomem *)(goto_addr & (~0x3));
> > +		mtk_dsi_set_cmdq(cmdq_reg, mask_para, set_para);
> 
> I think you can merge this setting into 'for loop' and the loop look
> like this:
> 
> for (i = 0; i < msg->tx_len; i++) {
> 	goto_addr = (u32)(&dsi_cmd_reg->data[1].byte0) + i;
> 	mask_para = (0xff << ((goto_addr & 0x3) * 8));
> 	set_para = (tx_buf[i] << ((goto_addr & 0x3) * 8));
> 	cmdq_reg = (void __iomem *)(goto_addr & (~0x3));
> 	mtk_dsi_set_cmdq(cmdq_reg, mask_para, set_para);
> }
OK, we will merge it into the loop.

> 
> > +
> > +		for (i = 1; i < msg->tx_len; i++) {
> > +			goto_addr = (u32)(&dsi_cmd_reg->data[1].byte1) + i - 1;
> > +			mask_para = (0xff << ((goto_addr & 0x3) * 8));
> > +			set_para = (tx_buf[i] << ((goto_addr & 0x3) * 8));
> > +			cmdq_reg = (void __iomem *)(goto_addr & (~0x3));
> > +			mtk_dsi_set_cmdq(cmdq_reg, mask_para, set_para);
> > +		}
> > +
> > +		mtk_dsi_mask(dsi, DSI_CMDQ_SIZE, CMDQ_SIZE,
> > +			     2 + (msg->tx_len - 1) / 4);
> 
> I think it is better to change formula of DSI_CMDQ_SIZE to '1 +
> (msg->tx_len + 3) / 4'. The '1' means the first cmd which describe the
> size of tx_buf, and the rest means the other cmds for body of tx_buf.
OK.

Regards,
yt.shen

> 
> > +	} else {
> > +		t0.config = 0;
> > +		t0.data0 = tx_buf[0];
> > +		if (msg->tx_len == 2) {
> > +			t0.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM;
> > +			t0.data1 = tx_buf[1];
> > +		} else {
> > +			t0.type = MIPI_DSI_DCS_SHORT_WRITE;
> > +			t0.data1 = 0;
> > +		}
> > +
> > +		reg_val = (t0.data1 << 24) | (t0.data0 << 16) | (t0.type << 8) |
> > +			   t0.config;
> > +
> > +		writel(reg_val, &dsi_cmd_reg->data[0]);
> > +		mtk_dsi_mask(dsi, DSI_CMDQ_SIZE, CMDQ_SIZE, 1);
> > +	}
> > +
> > +	mtk_dsi_start(dsi);
> > +	mtk_dsi_wait_for_idle(dsi);
> > +
> > +	return 0;
> > +}
> > +
> > +static ssize_t mtk_dsi_host_transfer(struct mipi_dsi_host *host,
> > +				     const struct mipi_dsi_msg *msg)
> > +{
> > +	struct mtk_dsi *dsi = host_to_dsi(host);
> > +	u8 type = msg->type;
> > +	ssize_t ret = 0;
> > +
> > +	if (MTK_DSI_HOST_IS_READ(type))
> > +		ret = mtk_dsi_host_read_cmd(dsi, msg);
> > +	else if (MTK_DSI_HOST_IS_WRITE(type))
> > +		ret = mtk_dsi_host_write_cmd(dsi, msg);
> > +
> > +	return ret;
> > +}
> > +
> >  static const struct mipi_dsi_host_ops mtk_dsi_ops = {
> >  	.attach = mtk_dsi_host_attach,
> >  	.detach = mtk_dsi_host_detach,
> > +	.transfer = mtk_dsi_host_transfer,
> >  };
> >  
> >  static int mtk_dsi_bind(struct device *dev, struct device *master, void *data)
> 
> 
> Regards,
> CK
> 




From yt.shen at mediatek.com  Tue Jul 26 03:42:54 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Tue, 26 Jul 2016 18:42:54 +0800
Subject: [PATCH v4 4/8] drm/mediatek: add support for Mediatek SoC MT2701
In-Reply-To: <1468997599.11841.49.camel@mtksdaap41>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
 <1468577274-6178-5-git-send-email-yt.shen@mediatek.com>
 <1468997599.11841.49.camel@mtksdaap41>
Message-ID: <1469529774.4678.34.camel@mtksdaap41>

Hi CK,

On Wed, 2016-07-20 at 14:53 +0800, CK Hu wrote:
> Hi, YT:
> 
> Some comments inline.
> 
> On Fri, 2016-07-15 at 18:07 +0800, YT Shen wrote:
> > This patch add support for the Mediatek MT2701 DISP subsystem.
> > There is only one OVL engine in MT2701.
> > 
> > Signed-off-by: YT Shen <yt.shen at mediatek.com>
> > ---
> >  drivers/gpu/drm/mediatek/mtk_disp_ovl.c     |    6 ++++
> >  drivers/gpu/drm/mediatek/mtk_disp_rdma.c    |    6 ++++
> >  drivers/gpu/drm/mediatek/mtk_drm_ddp.c      |   41 +++++++++++++++++++++++++++
> >  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |    7 +++++
> >  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |    1 +
> >  drivers/gpu/drm/mediatek/mtk_drm_drv.c      |   31 ++++++++++++++++++++
> >  6 files changed, 92 insertions(+)
> > 
> 
> [snip...]
> 
> >  
> >  static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
> > +	{ .compatible = "mediatek,mt2701-disp-ovl",   .data = (void *)MTK_DISP_OVL },
> >  	{ .compatible = "mediatek,mt8173-disp-ovl",   .data = (void *)MTK_DISP_OVL },
> > +	{ .compatible = "mediatek,mt2701-disp-rdma",  .data = (void *)MTK_DISP_RDMA },
> >  	{ .compatible = "mediatek,mt8173-disp-rdma",  .data = (void *)MTK_DISP_RDMA },
> > +	{ .compatible = "mediatek,mt2701-disp-wdma",  .data = (void *)MTK_DISP_WDMA },
> 
> Is WDMA different from MT8173 to MT2701. If they are the same, you need
> not to add compatible of 'mediatek,mt2701-disp-wdma' because use
> 'mediatek,mt8173-disp-wdma' is enough.
Yes, the hardware has differences, so we need add new compatible
'mt2701-disp-wdma'

> 
> >  	{ .compatible = "mediatek,mt8173-disp-wdma",  .data = (void *)MTK_DISP_WDMA },
> > +	{ .compatible = "mediatek,mt2701-disp-color", .data = (void *)MTK_DISP_COLOR },
> >  	{ .compatible = "mediatek,mt8173-disp-color", .data = (void *)MTK_DISP_COLOR },
> >  	{ .compatible = "mediatek,mt8173-disp-aal",   .data = (void *)MTK_DISP_AAL},
> >  	{ .compatible = "mediatek,mt8173-disp-gamma", .data = (void *)MTK_DISP_GAMMA, },
> >  	{ .compatible = "mediatek,mt8173-disp-ufoe",  .data = (void *)MTK_DISP_UFOE },
> > +	{ .compatible = "mediatek,mt2701-dsi",	      .data = (void *)MTK_DSI },
> >  	{ .compatible = "mediatek,mt8173-dsi",        .data = (void *)MTK_DSI },
> > +	{ .compatible = "mediatek,mt2701-dpi",	      .data = (void *)MTK_DPI },
> 
> Is DPI different from MT8173 to MT2701. If they are the same, you need
> not to add compatible of 'mediatek,mt2701-dpi' because use
> 'mediatek,mt8173-dpi' is enough.
Yes, the hardware has differences, so we need add new compatible
'mt2701-dpi'

> 
> >  	{ .compatible = "mediatek,mt8173-dpi",        .data = (void *)MTK_DPI },
> > +	{ .compatible = "mediatek,mt2701-disp-mutex", .data = (void *)MTK_DISP_MUTEX },
> >  	{ .compatible = "mediatek,mt8173-disp-mutex", .data = (void *)MTK_DISP_MUTEX },
> > +	{ .compatible = "mediatek,mt2701-disp-pwm",   .data = (void *)MTK_DISP_PWM },
> 
> Is pwm different from MT8173 to MT2701. If they are the same, you need
> not to add compatible of 'mediatek,mt2701-disp-pwm' because use
> 'mediatek,mt8173-disp-pwm' is enough.
Yes, the hardware has differences, so we need add new compatible
'mt2701-disp-pwm'

Regards,
yt.shen

> 
> >  	{ .compatible = "mediatek,mt8173-disp-pwm",   .data = (void *)MTK_DISP_PWM },
> >  	{ .compatible = "mediatek,mt8173-disp-od",    .data = (void *)MTK_DISP_OD },
> >  	{ }
> > @@ -514,6 +543,8 @@ static SIMPLE_DEV_PM_OPS(mtk_drm_pm_ops, mtk_drm_sys_suspend,
> >  			 mtk_drm_sys_resume);
> >  
> >  static const struct of_device_id mtk_drm_of_ids[] = {
> > +	{ .compatible = "mediatek,mt2701-mmsys",
> > +	  .data = &mt2701_mmsys_driver_data},
> >  	{ .compatible = "mediatek,mt8173-mmsys",
> >  	  .data = &mt8173_mmsys_driver_data},
> >  	{ }
> 
> Regards,
> CK
> 




From yt.shen at mediatek.com  Tue Jul 26 03:42:47 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Tue, 26 Jul 2016 18:42:47 +0800
Subject: [PATCH v4 7/8] drm/mediatek: add mipi panel support
In-Reply-To: <1468996076.11841.43.camel@mtksdaap41>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
 <1468577274-6178-8-git-send-email-yt.shen@mediatek.com>
 <1468996076.11841.43.camel@mtksdaap41>
Message-ID: <1469529767.4678.32.camel@mtksdaap41>

Hi CK,

On Wed, 2016-07-20 at 14:27 +0800, CK Hu wrote:
> Hi, YT:
> 
> Some comments inline.
> 
> On Fri, 2016-07-15 at 18:07 +0800, YT Shen wrote:
> > From: shaoming chen <shaoming.chen at mediatek.com>
> > 
> > add dsi and mipi tx driver for mipi panel support
> > 
> > Signed-off-by: shaoming chen <shaoming.chen at mediatek.com>
> > ---
> >  drivers/gpu/drm/mediatek/mtk_dsi.c     |  169 ++++++++++++++++++++++----------
> >  drivers/gpu/drm/mediatek/mtk_mipi_tx.c |   82 +++++++++++-----
> >  2 files changed, 173 insertions(+), 78 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
> > index 1f99894..4eae63c 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_dsi.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
> > @@ -29,9 +29,6 @@
> >  
> >  #include "mtk_drm_ddp_comp.h"
> >  
> > -#define DSI_VIDEO_FIFO_DEPTH	(1920 / 4)
> > -#define DSI_HOST_FIFO_DEPTH	64
> > -
> 
> I think this should be moved to a 'cleaning up and refine' patch.
OK.

> 
> >  #define DSI_START		0x00
> >  
> >  #define DSI_INTEN		0x08
> > @@ -55,7 +52,7 @@
> >  #define MIX_MODE			BIT(17)
> >  
> >  #define DSI_TXRX_CTRL		0x18
> > -#define VC_NUM				(2 << 0)
> > +#define VC_NUM				BIT(1)
> 
> I think this should be moved to a 'cleaning up and refine' patch.
OK.

> 
> >  #define LANE_NUM			(0xf << 2)
> >  #define DIS_EOT				BIT(6)
> >  #define NULL_EN				BIT(7)
> > @@ -94,6 +91,8 @@
> >  #define DSI_RACK		0x84
> >  #define RACK			BIT(0)
> >  
> > +#define DSI_MEM_CONTI		0x90
> > +
> >  #define DSI_PHY_LCCON		0x104
> >  #define LC_HS_TX_EN			BIT(0)
> >  #define LC_ULPM_EN			BIT(1)
> > @@ -126,6 +125,10 @@
> >  #define CLK_HS_POST			(0xff << 8)
> >  #define CLK_HS_EXIT			(0xff << 16)
> >  
> > +#define DSI_VM_CMD_CON		0x130
> > +#define VM_CMD_EN		BIT(0)
> > +#define TS_VFP_EN		BIT(5)
> 
> The bitwise definition should add one more tab to align other bitwise
> definition in this file.
Will do.

> 
> > +
> >  #define DSI_CMDQ0		0x180
> >  
> >  #define NS_TO_CYCLE(n, c)    ((n) / (c) + (((n) % (c)) ? 1 : 0))
> > @@ -239,11 +242,11 @@ static void mtk_dsi_mask(struct mtk_dsi *dsi, u32 offset, u32 mask, u32 data)
> >  	writel((temp & ~mask) | (data & mask), dsi->regs + offset);
> >  }
> >  
> > -static void dsi_phy_timconfig(struct mtk_dsi *dsi)
> > +static void mtk_dsi_phy_timconfig(struct mtk_dsi *dsi)
> 
> I think this should be moved to a 'cleaning up and refine' patch.
OK.

> 
> >  {
> >  	u32 timcon0, timcon1, timcon2, timcon3;
> > -	unsigned int ui, cycle_time;
> > -	unsigned int lpx;
> > +	u32 ui, cycle_time;
> > +	u32 lpx;
> 
> I think this should be moved to a 'cleaning up and refine' patch.
OK.

> 
> >  
> >  	ui = 1000 / dsi->data_rate + 0x01;
> >  	cycle_time = 8000 / dsi->data_rate + 0x01;
> > @@ -273,7 +276,7 @@ static void mtk_dsi_disable(struct mtk_dsi *dsi)
> >  	mtk_dsi_mask(dsi, DSI_CON_CTRL, DSI_EN, 0);
> >  }
> >  
> > -static void mtk_dsi_reset(struct mtk_dsi *dsi)
> > +static void mtk_dsi_reset_engine(struct mtk_dsi *dsi)
> >  {
> >  	mtk_dsi_mask(dsi, DSI_CON_CTRL, DSI_RESET, DSI_RESET);
> >  	mtk_dsi_mask(dsi, DSI_CON_CTRL, DSI_RESET, 0);
> > @@ -293,7 +296,9 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi)
> >  	 * mipi_ratio is mipi clk coefficient for balance the pixel clk in mipi.
> >  	 * we set mipi_ratio is 1.05.
> >  	 */
> > -	dsi->data_rate = dsi->vm.pixelclock * 3 * 21 / (1 * 1000 * 10);
> > +	dsi->data_rate = dsi->vm.pixelclock * 12 * 21;
> > +	dsi->data_rate /= (dsi->lanes * 1000 * 10);
> > +	dev_info(dev, "set mipitx's data rate: %dMHz\n", dsi->data_rate);
> >  
> >  	ret = clk_set_rate(dsi->hs_clk, dsi->data_rate * 1000000);
> >  	if (ret < 0) {
> > @@ -315,10 +320,6 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi)
> >  		goto err_disable_engine_clk;
> >  	}
> >  
> > -	mtk_dsi_enable(dsi);
> > -	mtk_dsi_reset(dsi);
> > -	dsi_phy_timconfig(dsi);
> > -
> >  	return 0;
> >  
> >  err_disable_engine_clk:
> > @@ -330,33 +331,33 @@ err_refcount:
> >  	return ret;
> >  }
> >  
> > -static void dsi_clk_ulp_mode_enter(struct mtk_dsi *dsi)
> > +static void mtk_dsi_clk_ulp_mode_enter(struct mtk_dsi *dsi)
> 
> I think this should be moved to a 'cleaning up and refine' patch.
OK.

> 
> >  {
> >  	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, 0);
> > -	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_ULPM_EN, 0);
> > +	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_ULPM_EN, LC_ULPM_EN);
> >  }
> >  
> > -static void dsi_clk_ulp_mode_leave(struct mtk_dsi *dsi)
> > +static void mtk_dsi_clk_ulp_mode_leave(struct mtk_dsi *dsi)
> 
> I think this should be moved to a 'cleaning up and refine' patch.
OK.

> 
> >  {
> >  	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_ULPM_EN, 0);
> >  	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_WAKEUP_EN, LC_WAKEUP_EN);
> >  	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_WAKEUP_EN, 0);
> >  }
> >  
> > -static void dsi_lane0_ulp_mode_enter(struct mtk_dsi *dsi)
> > +static void mtk_dsi_lane0_ulp_mode_enter(struct mtk_dsi *dsi)
> 
> I think this should be moved to a 'cleaning up and refine' patch.
OK.

> 
> >  {
> >  	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_HS_TX_EN, 0);
> > -	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_ULPM_EN, 0);
> > +	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_ULPM_EN, LD0_ULPM_EN);
> >  }
> >  
> > -static void dsi_lane0_ulp_mode_leave(struct mtk_dsi *dsi)
> > +static void mtk_dsi_lane0_ulp_mode_leave(struct mtk_dsi *dsi)
> >  {
> >  	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_ULPM_EN, 0);
> >  	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_WAKEUP_EN, LD0_WAKEUP_EN);
> >  	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_WAKEUP_EN, 0);
> >  }
> >  
> > -static bool dsi_clk_hs_state(struct mtk_dsi *dsi)
> > +static bool mtk_dsi_clk_hs_state(struct mtk_dsi *dsi)
> 
> I think this should be moved to a 'cleaning up and refine' patch.
OK.

> 
> >  {
> >  	u32 tmp_reg1;
> >  
> > @@ -364,15 +365,15 @@ static bool dsi_clk_hs_state(struct mtk_dsi *dsi)
> >  	return ((tmp_reg1 & LC_HS_TX_EN) == 1) ? true : false;
> >  }
> >  
> > -static void dsi_clk_hs_mode(struct mtk_dsi *dsi, bool enter)
> > +static void mtk_dsi_clk_hs_mode(struct mtk_dsi *dsi, bool enter)
> 
> I think this should be moved to a 'cleaning up and refine' patch.
OK.

> 
> >  {
> > -	if (enter && !dsi_clk_hs_state(dsi))
> > +	if (enter && !mtk_dsi_clk_hs_state(dsi))
> >  		mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, LC_HS_TX_EN);
> > -	else if (!enter && dsi_clk_hs_state(dsi))
> > +	else if (!enter && mtk_dsi_clk_hs_state(dsi))
> >  		mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, 0);
> >  }
> >  
> > -static void dsi_set_mode(struct mtk_dsi *dsi)
> > +static void mtk_dsi_set_mode(struct mtk_dsi *dsi)
> 
> I think this should be moved to a 'cleaning up and refine' patch.
OK.

> 
> >  {
> >  	u32 vid_mode = CMD_MODE;
> >  
> > @@ -382,12 +383,22 @@ static void dsi_set_mode(struct mtk_dsi *dsi)
> >  		if ((dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) &&
> >  		    !(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE))
> >  			vid_mode = BURST_MODE;
> > +		else
> > +			vid_mode = SYNC_EVENT_MODE;
> >  	}
> >  
> >  	writel(vid_mode, dsi->regs + DSI_MODE_CTRL);
> >  }
> >  
> > -static void dsi_ps_control_vact(struct mtk_dsi *dsi)
> > +static void mtk_dsi_set_vm_cmd(struct mtk_dsi *dsi)
> > +{
> > +	writel(0x3c, dsi->regs + DSI_MEM_CONTI);
> > +
> > +	mtk_dsi_mask(dsi, DSI_VM_CMD_CON, VM_CMD_EN, VM_CMD_EN);
> > +	mtk_dsi_mask(dsi, DSI_VM_CMD_CON, TS_VFP_EN, TS_VFP_EN);
> > +}
> > +
> > +static void mtk_dsi_ps_control_vact(struct mtk_dsi *dsi)
> >  {
> >  	struct videomode *vm = &dsi->vm;
> >  	u32 dsi_buf_bpp, ps_wc;
> > @@ -421,7 +432,7 @@ static void dsi_ps_control_vact(struct mtk_dsi *dsi)
> >  	writel(ps_wc, dsi->regs + DSI_HSTX_CKL_WC);
> >  }
> >  
> > -static void dsi_rxtx_control(struct mtk_dsi *dsi)
> > +static void mtk_dsi_rxtx_control(struct mtk_dsi *dsi)
> 
> I think this should be moved to a 'cleaning up and refine' patch.
OK.

> 
> >  {
> >  	u32 tmp_reg;
> >  
> > @@ -443,12 +454,15 @@ static void dsi_rxtx_control(struct mtk_dsi *dsi)
> >  		break;
> >  	}
> >  
> > +	tmp_reg |= (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) << 6;
> > +	tmp_reg |= (dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET) >> 3;
> > +
> >  	writel(tmp_reg, dsi->regs + DSI_TXRX_CTRL);
> >  }
> >  
> > -static void dsi_ps_control(struct mtk_dsi *dsi)
> > +static void mtk_dsi_ps_control(struct mtk_dsi *dsi)
> 
> I think this should be moved to a 'cleaning up and refine' patch.
OK.

> 
> >  {
> > -	unsigned int dsi_tmp_buf_bpp;
> > +	u32 dsi_tmp_buf_bpp;
> >  	u32 tmp_reg;
> >  
> >  	switch (dsi->format) {
> > @@ -478,12 +492,12 @@ static void dsi_ps_control(struct mtk_dsi *dsi)
> >  	writel(tmp_reg, dsi->regs + DSI_PSCTRL);
> >  }
> >  
> > -static void dsi_config_vdo_timing(struct mtk_dsi *dsi)
> > +static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi)
> 
> I think this should be moved to a 'cleaning up and refine' patch.
OK.

> 
> >  {
> > -	unsigned int horizontal_sync_active_byte;
> > -	unsigned int horizontal_backporch_byte;
> > -	unsigned int horizontal_frontporch_byte;
> > -	unsigned int dsi_tmp_buf_bpp;
> > +	u32 horizontal_sync_active_byte;
> > +	u32 horizontal_backporch_byte;
> > +	u32 horizontal_frontporch_byte;
> > +	u32 dsi_tmp_buf_bpp;
> 
> I think this should be moved to a 'cleaning up and refine' patch.
OK.

> 
> >  
> >  	struct videomode *vm = &dsi->vm;
> >  
> > @@ -512,7 +526,7 @@ static void dsi_config_vdo_timing(struct mtk_dsi *dsi)
> >  	writel(horizontal_backporch_byte, dsi->regs + DSI_HBP_WC);
> >  	writel(horizontal_frontporch_byte, dsi->regs + DSI_HFP_WC);
> >  
> > -	dsi_ps_control(dsi);
> > +	mtk_dsi_ps_control(dsi);
> >  }
> >  
> >  static void mtk_dsi_start(struct mtk_dsi *dsi)
> > @@ -521,6 +535,19 @@ static void mtk_dsi_start(struct mtk_dsi *dsi)
> >  	writel(1, dsi->regs + DSI_START);
> >  }
> >  
> > +static void mtk_dsi_stop(struct mtk_dsi *dsi)
> > +{
> > +	writel(0, dsi->regs + DSI_START);
> > +}
> > +
> > +static void mtk_dsi_set_cmd_mode(struct mtk_dsi *dsi)
> > +{
> > +	u32 tmp_reg1;
> > +
> > +	tmp_reg1 = CMD_MODE;
> > +	writel(tmp_reg1, dsi->regs + DSI_MODE_CTRL);
> > +}
> > +
> >  static void mtk_dsi_set_interrupt_enable(struct mtk_dsi *dsi)
> >  {
> >  	u32 inten = DSI_INT_ALL_BITS;
> > @@ -609,6 +636,21 @@ static s32 mtk_dsi_wait_for_irq_timeout(struct mtk_dsi *dsi, u32 irq_bit,
> >  	return -1;
> >  }
> >  
> > +static void mtk_dsi_switch_to_cmd_mode(struct mtk_dsi *dsi)
> > +{
> > +	s32 ret = 0;
> > +
> > +	mtk_dsi_set_cmd_mode(dsi);
> > +
> > +	ret = mtk_dsi_wait_for_irq_timeout(dsi, DSI_INT_VM_DONE_FLAG, 500);
> > +	if (ret != 0) {
> > +		dev_info(dsi->dev, "dsi wait engine idle timeout\n");
> > +
> > +		mtk_dsi_enable(dsi);
> > +		mtk_dsi_reset_engine(dsi);
> > +	}
> > +}
> > +
> >  static void mtk_dsi_poweroff(struct mtk_dsi *dsi)
> >  {
> >  	if (WARN_ON(dsi->refcount == 0))
> > @@ -617,8 +659,19 @@ static void mtk_dsi_poweroff(struct mtk_dsi *dsi)
> >  	if (--dsi->refcount != 0)
> >  		return;
> >  
> > -	dsi_lane0_ulp_mode_enter(dsi);
> > -	dsi_clk_ulp_mode_enter(dsi);
> > +	mtk_dsi_switch_to_cmd_mode(dsi);
> > +
> > +	if (dsi->panel) {
> > +		if (drm_panel_unprepare(dsi->panel)) {
> > +			DRM_ERROR("failed to unprepare the panel\n");
> > +			return;
> > +		}
> > +	}
> > +
> > +	mtk_dsi_reset_engine(dsi);
> > +
> > +	mtk_dsi_lane0_ulp_mode_enter(dsi);
> > +	mtk_dsi_clk_ulp_mode_enter(dsi);
> >  
> >  	mtk_dsi_disable(dsi);
> >  
> > @@ -635,32 +688,40 @@ static void mtk_output_dsi_enable(struct mtk_dsi *dsi)
> >  	if (dsi->enabled)
> >  		return;
> >  
> > -	if (dsi->panel) {
> > -		if (drm_panel_prepare(dsi->panel)) {
> > -			DRM_ERROR("failed to setup the panel\n");
> > -			return;
> > -		}
> > -	}
> > -
> >  	ret = mtk_dsi_poweron(dsi);
> >  	if (ret < 0) {
> >  		DRM_ERROR("failed to power on dsi\n");
> >  		return;
> >  	}
> >  
> > -	dsi_rxtx_control(dsi);
> > +	usleep_range(20000, 21000);
> >  
> > -	dsi_clk_ulp_mode_leave(dsi);
> > -	dsi_lane0_ulp_mode_leave(dsi);
> > -	dsi_clk_hs_mode(dsi, 0);
> > -	dsi_set_mode(dsi);
> > -
> > -	dsi_ps_control_vact(dsi);
> > -	dsi_config_vdo_timing(dsi);
> > +	mtk_dsi_rxtx_control(dsi);
> > +	mtk_dsi_phy_timconfig(dsi);
> > +	mtk_dsi_ps_control_vact(dsi);
> > +	mtk_dsi_set_vm_cmd(dsi);
> > +	mtk_dsi_config_vdo_timing(dsi);
> >  	mtk_dsi_set_interrupt_enable(dsi);
> >  
> > -	dsi_set_mode(dsi);
> > -	dsi_clk_hs_mode(dsi, 1);
> > +	mtk_dsi_enable(dsi);
> > +	mtk_dsi_clk_ulp_mode_leave(dsi);
> > +	mtk_dsi_lane0_ulp_mode_leave(dsi);
> > +	mtk_dsi_clk_hs_mode(dsi, 0);
> > +
> > +	if (dsi->panel) {
> > +		if (drm_panel_prepare(dsi->panel)) {
> > +			DRM_ERROR("failed to prepare the panel\n");
> > +			return;
> > +		}
> > +
> > +		if (drm_panel_enable(dsi->panel)) {
> > +			DRM_ERROR("failed to enable the panel\n");
> > +			return;
> > +		}
> > +	}
> > +
> > +	mtk_dsi_set_mode(dsi);
> > +	mtk_dsi_clk_hs_mode(dsi, 1);
> >  
> >  	mtk_dsi_start(dsi);
> >  
> > @@ -679,6 +740,7 @@ static void mtk_output_dsi_disable(struct mtk_dsi *dsi)
> >  		}
> >  	}
> >  
> > +	mtk_dsi_stop(dsi);
> >  	mtk_dsi_poweroff(dsi);
> >  
> >  	dsi->enabled = false;
> > @@ -1351,6 +1413,7 @@ static int mtk_dsi_remove(struct platform_device *pdev)
> >  }
> >  
> >  static const struct of_device_id mtk_dsi_of_match[] = {
> > +	{ .compatible = "mediatek,mt2701-dsi" },
> 
> This is not related to 'mipi panel support'. So move this modification
> to another patch.
We will split common part to another patch.

> 
> >  	{ .compatible = "mediatek,mt8173-dsi" },
> >  	{ },
> >  };
> > diff --git a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
> > index cf8f38d..3bffc40 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
> > @@ -16,6 +16,7 @@
> >  #include <linux/delay.h>
> >  #include <linux/io.h>
> >  #include <linux/module.h>
> > +#include <linux/of_device.h>
> >  #include <linux/platform_device.h>
> >  #include <linux/phy/phy.h>
> >  
> > @@ -87,6 +88,9 @@
> >  
> >  #define MIPITX_DSI_PLL_CON2	0x58
> >  
> > +#define MIPITX_DSI_PLL_TOP	0x64
> > +#define RG_DSI_MPPLL_PRESERVE		(0xff << 8)
> > +
> >  #define MIPITX_DSI_PLL_PWR	0x68
> >  #define RG_DSI_MPPLL_SDM_PWR_ON		BIT(0)
> >  #define RG_DSI_MPPLL_SDM_ISO_EN		BIT(1)
> > @@ -123,10 +127,32 @@
> >  #define SW_LNT2_HSTX_PRE_OE		BIT(24)
> >  #define SW_LNT2_HSTX_OE			BIT(25)
> >  
> > +struct mtk_mipitx_data {
> > +	const u32 data;
> > +};
> > +
> > +static const struct mtk_mipitx_data mt2701_mipitx_data = {
> > +	.data = (3 << 8)
> > +};
> > +
> > +static const struct mtk_mipitx_data mt8173_mipitx_data = {
> > +	.data = (0 << 8)
> > +};
> > +
> > +static const struct of_device_id mtk_mipi_tx_match[] = {
> > +	{ .compatible = "mediatek,mt2701-mipi-tx",
> > +	  .data = &mt2701_mipitx_data },
> > +	{ .compatible = "mediatek,mt8173-mipi-tx",
> > +	  .data = &mt8173_mipitx_data },
> > +	{},
> > +};
> 
> This looks more like 'mt2701 support' rather than 'mipi panel support'.
> So move this modification to another patch.
We will split common part to another patch.

> 
> > +
> >  struct mtk_mipi_tx {
> >  	struct device *dev;
> >  	void __iomem *regs;
> > -	unsigned int data_rate;
> > +	u32 data_rate;
> > +	const struct mtk_mipitx_data *driver_data;
> > +
> >  	struct clk_hw pll_hw;
> >  	struct clk *pll;
> >  };
> > @@ -163,12 +189,14 @@ static void mtk_mipi_tx_update_bits(struct mtk_mipi_tx *mipi_tx, u32 offset,
> >  static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw)
> >  {
> >  	struct mtk_mipi_tx *mipi_tx = mtk_mipi_tx_from_clk_hw(hw);
> > -	unsigned int txdiv, txdiv0, txdiv1;
> > +	u8 txdiv, txdiv0, txdiv1;
> >  	u64 pcw;
> >  
> >  	dev_dbg(mipi_tx->dev, "prepare: %u Hz\n", mipi_tx->data_rate);
> >  
> > -	if (mipi_tx->data_rate >= 500000000) {
> > +	if (mipi_tx->data_rate > 1250000000) {
> > +		return -EINVAL;
> > +	} else if (mipi_tx->data_rate >= 500000000) {
> >  		txdiv = 1;
> >  		txdiv0 = 0;
> >  		txdiv1 = 0;
> > @@ -192,6 +220,10 @@ static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw)
> >  		return -EINVAL;
> >  	}
> >  
> > +	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_TOP_CON,
> > +				RG_DSI_LNT_IMP_CAL_CODE | RG_DSI_LNT_HS_BIAS_EN,
> > +				(8 << 4) | RG_DSI_LNT_HS_BIAS_EN);
> > +
> >  	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_BG_CON,
> >  				RG_DSI_VOUT_MSK |
> >  				RG_DSI_BG_CKEN | RG_DSI_BG_CORE_EN,
> > @@ -201,24 +233,18 @@ static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw)
> >  
> >  	usleep_range(30, 100);
> >  
> > -	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_TOP_CON,
> > -				RG_DSI_LNT_IMP_CAL_CODE | RG_DSI_LNT_HS_BIAS_EN,
> > -				(8 << 4) | RG_DSI_LNT_HS_BIAS_EN);
> > -
> > -	mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_CON,
> > -			     RG_DSI_CKG_LDOOUT_EN | RG_DSI_LDOCORE_EN);
> > +	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_CON,
> > +				RG_DSI_CKG_LDOOUT_EN | RG_DSI_LDOCORE_EN,
> > +				RG_DSI_CKG_LDOOUT_EN | RG_DSI_LDOCORE_EN);
> >  
> >  	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_PWR,
> >  				RG_DSI_MPPLL_SDM_PWR_ON |
> >  				RG_DSI_MPPLL_SDM_ISO_EN,
> >  				RG_DSI_MPPLL_SDM_PWR_ON);
> >  
> > -	mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON0,
> > -			       RG_DSI_MPPLL_PLL_EN);
> > -
> >  	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_CON0,
> > -				RG_DSI_MPPLL_TXDIV0 | RG_DSI_MPPLL_TXDIV1 |
> > -				RG_DSI_MPPLL_PREDIV,
> > +				RG_DSI_MPPLL_PREDIV | RG_DSI_MPPLL_TXDIV0 |
> > +				RG_DSI_MPPLL_TXDIV1 | RG_DSI_MPPLL_POSDIV,
> >  				(txdiv0 << 3) | (txdiv1 << 5));
> >  
> >  	/*
> > @@ -233,15 +259,21 @@ static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw)
> >  		      26000000);
> >  	writel(pcw, mipi_tx->regs + MIPITX_DSI_PLL_CON2);
> >  
> > -	mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_PLL_CON1,
> > -			     RG_DSI_MPPLL_SDM_FRA_EN);
> > +	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_CON1,
> > +				RG_DSI_MPPLL_SDM_FRA_EN,
> > +				RG_DSI_MPPLL_SDM_FRA_EN);
> >  
> > -	mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_PLL_CON0, RG_DSI_MPPLL_PLL_EN);
> > +	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_CON0,
> > +				RG_DSI_MPPLL_PLL_EN, RG_DSI_MPPLL_PLL_EN);
> >  
> >  	usleep_range(20, 100);
> >  
> >  	mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON1,
> > -			       RG_DSI_MPPLL_SDM_SSC_EN);
> > +					RG_DSI_MPPLL_SDM_SSC_EN);
> > +
> > +	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_TOP,
> > +				RG_DSI_MPPLL_PRESERVE,
> > +				mipi_tx->driver_data->data);
> >  
> >  	return 0;
> >  }
> > @@ -255,6 +287,10 @@ static void mtk_mipi_tx_pll_unprepare(struct clk_hw *hw)
> >  	mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON0,
> >  			       RG_DSI_MPPLL_PLL_EN);
> >  
> > +	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_TOP,
> > +				RG_DSI_MPPLL_PRESERVE,
> > +				mipi_tx->driver_data->data);
> > +
> >  	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_PWR,
> >  				RG_DSI_MPPLL_SDM_ISO_EN |
> >  				RG_DSI_MPPLL_SDM_PWR_ON,
> > @@ -310,7 +346,7 @@ static const struct clk_ops mtk_mipi_tx_pll_ops = {
> >  static int mtk_mipi_tx_power_on_signal(struct phy *phy)
> >  {
> >  	struct mtk_mipi_tx *mipi_tx = phy_get_drvdata(phy);
> > -	unsigned int reg;
> > +	u32 reg;
> 
> I think this should be moved to a 'cleaning up and refine' patch.
OK.

> 
> >  
> >  	for (reg = MIPITX_DSI_CLOCK_LANE;
> >  	     reg <= MIPITX_DSI_DATA_LANE3; reg += 4)
> > @@ -341,7 +377,7 @@ static int mtk_mipi_tx_power_on(struct phy *phy)
> >  static void mtk_mipi_tx_power_off_signal(struct phy *phy)
> >  {
> >  	struct mtk_mipi_tx *mipi_tx = phy_get_drvdata(phy);
> > -	unsigned int reg;
> > +	u32 reg;
> 
> I think this should be moved to a 'cleaning up and refine' patch.
OK.

> 
> >  
> >  	mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_TOP_CON,
> >  			     RG_DSI_PAD_TIE_LOW_EN);
> > @@ -391,6 +427,7 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev)
> >  	if (!mipi_tx)
> >  		return -ENOMEM;
> >  
> > +	mipi_tx->driver_data = of_device_get_match_data(dev);
> >  	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >  	mipi_tx->regs = devm_ioremap_resource(dev, mem);
> >  	if (IS_ERR(mipi_tx->regs)) {
> > @@ -448,11 +485,6 @@ static int mtk_mipi_tx_remove(struct platform_device *pdev)
> >  	return 0;
> >  }
> >  
> > -static const struct of_device_id mtk_mipi_tx_match[] = {
> > -	{ .compatible = "mediatek,mt8173-mipi-tx", },
> > -	{},
> > -};
> > -
> >  struct platform_driver mtk_mipi_tx_driver = {
> >  	.probe = mtk_mipi_tx_probe,
> >  	.remove = mtk_mipi_tx_remove,
> 
> Regards,
> CK
> 




From zhiyong.tao at mediatek.com  Wed Jul 27 03:02:58 2016
From: zhiyong.tao at mediatek.com (Zhiyong Tao)
Date: Wed, 27 Jul 2016 18:02:58 +0800
Subject: [PATCH v6 0/3] AUXADC: Mediatek auxadc driver 
Message-ID: <1469613781-1296-1-git-send-email-zhiyong.tao@mediatek.com>

This series includes three patches:
1.Change the device tree binding documentation.
2.Add auxadc driver based on linux iio.
3.Add auxadc nodes in the mediatek MT2701 dtsi file.

Changes in patch v6:
1).Add commit message in auxadc node patch which dependents on "Add clock support for Mediatek MT2701"[1].
2).Use val variable instead of rawdata variable and Change 'mutex_unlock' to 'goto err_timeout' in 'mt6577_auxadc_read'.
3).Remove '.' in the log when failed to get auxadc base address.
4).Change 'return -EINVAL' to 'return ret' and add 'ret = -EINVAL' when get null clock rate.
5).Add inline function 'mt6577_auxadc_mod_reg' to replace read/modify/write code sequence.

Changes in patch v5:
1).Add 'Acked-by' information in commit message.
1).Change auxadc compatible in binding document.
2).Remove power on failed check.
3).Moved power off error unwind block to 'err_power_off'.

Changes in patch v4:
1).Change the file name 'mt65xx_auxdc.txt' to 'mt6577_auxdc.txt'.
2).Remove 'break' after 'return' in 'mt6577_auxadc_read_raw'.
3).Use 'mt2701' instead of 'auxadc' in dts commit message.
4).Change 'auxadc@' to 'adc@' in mt2701.dtsi.

Changes in patch v3:
1).Add '#' before 'io-channel-cells' and change 'auxadc@' to 'adc@' in auxadc binding document.
2).Fix CONFIG_MEDIATEK_MT65XX_AUXADC sequence as alphabetical order.
3).Change the prefix 'MT65XX' to 'MT6577' to match auxadc driver name.
4).Remove the delays stored in 'mt6577_auxadc_device' and use the defined delay directly.
5).Use '-ETIMEDOUT' instead of '-EINVAL'.
6).Return value directly in 'mt6577_auxadc_read_raw'.
7).Add power off and unprepare clock if 'iio_device_register' failed.
8).Change 'Registers' to 'Register'.

Changes in patch v2:
1).Change the file name mt65xx_auxadc.c to mt6577_auxadc.c.
2).Add 'depends on ARCH_MEDIATEK || COMPILE_TEST and HAS_IOMEM' for MEDIATEK_MT65XX_AUXADC config.
3).Add check case for return value of 'readl_poll_timeout'.
4).Remove returning 1 and 0 for SCALE and OFFSET. use channel type 'IIO_CHAN_INFO_PROCESSED' instead of 'IIO_CHAN_INFO_RAW'.
5).Remove 'IIO_CHAN_INFO_OFFSET' and 'IIO_CHAN_INFO_SCALE' in 'MT65XX_AUXADC_CHANNEL' channel type.
6).Add check case when auxadc power on failure. if auxadc power on failure, clk_disable_unprepare should be executed.
7).Put 'platform_set_drvdata' before 'iio_device_register'.
8).Fix coding style and spelling error.

Zhiyong Tao (3):
  dt-bindings: auxadc: Add binding document for Mediatek auxadc.
  iio: adc: mt2701: Add Mediatek auxadc driver for mt2701.
  arm: dts: mt2701: Add auxadc node.

 .../auxadc.txt => iio/adc/mt6577_auxadc.txt}       |   18 +-
 arch/arm/boot/dts/mt2701.dtsi                      |    9 +
 drivers/iio/adc/Kconfig                            |   13 +
 drivers/iio/adc/Makefile                           |    1 +
 drivers/iio/adc/mt6577_auxadc.c                    |  291 ++++++++++++++++++++
 5 files changed, 327 insertions(+), 5 deletions(-)
 rename Documentation/devicetree/bindings/{soc/mediatek/auxadc.txt => iio/adc/mt6577_auxadc.txt} (46%)
 create mode 100644 drivers/iio/adc/mt6577_auxadc.c



From zhiyong.tao at mediatek.com  Wed Jul 27 03:03:01 2016
From: zhiyong.tao at mediatek.com (Zhiyong Tao)
Date: Wed, 27 Jul 2016 18:03:01 +0800
Subject: [PATCH v6 3/3] arm: dts: mt2701: Add auxadc node.
In-Reply-To: <1469613781-1296-1-git-send-email-zhiyong.tao@mediatek.com>
References: <1469613781-1296-1-git-send-email-zhiyong.tao@mediatek.com>
Message-ID: <1469613781-1296-4-git-send-email-zhiyong.tao@mediatek.com>

The commit adds auxadc nodes to the Mediatek MT2701 dtsi file.

Signed-off-by: Zhiyong Tao <zhiyong.tao at mediatek.com>
---
This patch dependents on "Add clock support for Mediatek MT2701"[1].
Please accept this patch together with [1].
[1]http://lists.infradead.org/pipermail/linux-mediatek/2016-June/005969.html
---
 arch/arm/boot/dts/mt2701.dtsi |    9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
index 42d5a37..c0a2644 100644
--- a/arch/arm/boot/dts/mt2701.dtsi
+++ b/arch/arm/boot/dts/mt2701.dtsi
@@ -187,6 +187,15 @@
 		      <0 0x10216000 0 0x2000>;
 	};
 
+	auxadc: adc at 11001000 {
+		compatible = "mediatek,mt2701-auxadc";
+		reg = <0 0x11001000 0 0x1000>;
+		clocks = <&pericfg CLK_PERI_AUXADC>;
+		clock-names = "main";
+		#io-channel-cells = <1>;
+		status = "disabled";
+	};
+
 	uart0: serial at 11002000 {
 		compatible = "mediatek,mt2701-uart",
 			     "mediatek,mt6577-uart";
-- 
1.7.9.5



From zhiyong.tao at mediatek.com  Wed Jul 27 03:02:59 2016
From: zhiyong.tao at mediatek.com (Zhiyong Tao)
Date: Wed, 27 Jul 2016 18:02:59 +0800
Subject: [PATCH v6 1/3] dt-bindings: auxadc: Add binding document for Mediatek
 auxadc.
In-Reply-To: <1469613781-1296-1-git-send-email-zhiyong.tao@mediatek.com>
References: <1469613781-1296-1-git-send-email-zhiyong.tao@mediatek.com>
Message-ID: <1469613781-1296-2-git-send-email-zhiyong.tao@mediatek.com>

The commit adds the device tree binding documentation for the mediatek
auxadc found on Mediatek MT2701.
Thermal gets auxadc sample data by iio device.
So the commit changes auxadc device tree binding documentation from
/soc/mediatek/auxadc.txt to /iio/adc/mt6577_auxadc.txt.

Acked-by: Rob Herring <robh at kernel.org>
Signed-off-by: Zhiyong Tao <zhiyong.tao at mediatek.com>
---
 .../auxadc.txt => iio/adc/mt6577_auxadc.txt}       |   18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)
 rename Documentation/devicetree/bindings/{soc/mediatek/auxadc.txt => iio/adc/mt6577_auxadc.txt} (46%)

diff --git a/Documentation/devicetree/bindings/soc/mediatek/auxadc.txt b/Documentation/devicetree/bindings/iio/adc/mt6577_auxadc.txt
similarity index 46%
rename from Documentation/devicetree/bindings/soc/mediatek/auxadc.txt
rename to Documentation/devicetree/bindings/iio/adc/mt6577_auxadc.txt
index bdb7829..68c45cb 100644
--- a/Documentation/devicetree/bindings/soc/mediatek/auxadc.txt
+++ b/Documentation/devicetree/bindings/iio/adc/mt6577_auxadc.txt
@@ -1,4 +1,4 @@
-MediaTek AUXADC
+* Mediatek AUXADC - Analog to Digital Converter on Mediatek mobile soc (mt65xx/mt81xx/mt27xx)
 ===============
 
 The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found
@@ -10,12 +10,20 @@ Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
 for the Thermal Controller which holds a phandle to the AUXADC.
 
 Required properties:
-- compatible: Must be "mediatek,mt8173-auxadc"
-- reg: Address range of the AUXADC unit
+  - compatible: Should be one of:
+    - "mediatek,mt2701-auxadc": For MT2701 family of SoCs
+    - "mediatek,mt8173-auxadc": For MT8173 family of SoCs
+  - reg: Address range of the AUXADC unit.
+  - clocks: Should contain a clock specifier for each entry in clock-names
+  - clock-names: Should contain "main".
+  - #io-channel-cells: Should be 1, see ../iio-bindings.txt
 
 Example:
 
-auxadc: auxadc at 11001000 {
-	compatible = "mediatek,mt8173-auxadc";
+auxadc: adc at 11001000 {
+	compatible = "mediatek,mt2701-auxadc";
 	reg = <0 0x11001000 0 0x1000>;
+	clocks = <&pericfg CLK_PERI_AUXADC>;
+	clock-names = "main";
+	#io-channel-cells = <1>;
 };
-- 
1.7.9.5



From zhiyong.tao at mediatek.com  Wed Jul 27 03:03:00 2016
From: zhiyong.tao at mediatek.com (Zhiyong Tao)
Date: Wed, 27 Jul 2016 18:03:00 +0800
Subject: [PATCH v6 2/3] iio: adc: mt2701: Add Mediatek auxadc driver for
 mt2701.
In-Reply-To: <1469613781-1296-1-git-send-email-zhiyong.tao@mediatek.com>
References: <1469613781-1296-1-git-send-email-zhiyong.tao@mediatek.com>
Message-ID: <1469613781-1296-3-git-send-email-zhiyong.tao@mediatek.com>

Add Mediatek auxadc driver based on iio.
It will register a device in iio and support iio.
So thermal can read auxadc channel to sample data by iio device.
It is tested successfully on mt2701 platform.
Mt8173 and mt6577 platforms are not tested.
But the expectation is compatible.

Signed-off-by: Zhiyong Tao <zhiyong.tao at mediatek.com>
---
 drivers/iio/adc/Kconfig         |   13 ++
 drivers/iio/adc/Makefile        |    1 +
 drivers/iio/adc/mt6577_auxadc.c |  291 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 305 insertions(+)
 create mode 100644 drivers/iio/adc/mt6577_auxadc.c

diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 25378c5..14929fc 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -305,6 +305,19 @@ config MCP3422
 	  This driver can also be built as a module. If so, the module will be
 	  called mcp3422.
 
+config MEDIATEK_MT6577_AUXADC
+        tristate "MediaTek AUXADC driver"
+        depends on ARCH_MEDIATEK || COMPILE_TEST
+        depends on HAS_IOMEM
+        help
+          Say yes here to enable support for MediaTek mt65xx AUXADC.
+
+          The driver supports immediate mode operation to read from one of sixteen
+          channels (external or internal).
+
+          This driver can also be built as a module. If so, the module will be
+          called mt6577_auxadc.
+
 config MEN_Z188_ADC
 	tristate "MEN 16z188 ADC IP Core support"
 	depends on MCB
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 38638d4..8306347 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_MAX1027) += max1027.o
 obj-$(CONFIG_MAX1363) += max1363.o
 obj-$(CONFIG_MCP320X) += mcp320x.o
 obj-$(CONFIG_MCP3422) += mcp3422.o
+obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
 obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
 obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
 obj-$(CONFIG_NAU7802) += nau7802.o
diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c
new file mode 100644
index 0000000..2d104c8
--- /dev/null
+++ b/drivers/iio/adc/mt6577_auxadc.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Zhiyong Tao <zhiyong.tao at mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/iopoll.h>
+#include <linux/io.h>
+#include <linux/iio/iio.h>
+
+/* Register definitions */
+#define MT6577_AUXADC_CON0                    0x00
+#define MT6577_AUXADC_CON1                    0x04
+#define MT6577_AUXADC_CON2                    0x10
+#define MT6577_AUXADC_STA                     BIT(0)
+
+#define MT6577_AUXADC_DAT0                    0x14
+#define MT6577_AUXADC_RDY0                    BIT(12)
+
+#define MT6577_AUXADC_MISC                    0x94
+#define MT6577_AUXADC_PDN_EN                  BIT(14)
+
+#define MT6577_AUXADC_DAT_MASK                0xfff
+#define MT6577_AUXADC_SLEEP_US                1000
+#define MT6577_AUXADC_TIMEOUT_US              10000
+#define MT6577_AUXADC_POWER_READY_MS          1
+#define MT6577_AUXADC_SAMPLE_READY_US         25
+
+struct mt6577_auxadc_device {
+	void __iomem *reg_base;
+	struct clk *adc_clk;
+	struct mutex lock;
+};
+
+#define MT6577_AUXADC_CHANNEL(idx) {				    \
+		.type = IIO_VOLTAGE,				    \
+		.indexed = 1,					    \
+		.channel = (idx),				    \
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
+}
+
+static const struct iio_chan_spec mt6577_auxadc_iio_channels[] = {
+	MT6577_AUXADC_CHANNEL(0),
+	MT6577_AUXADC_CHANNEL(1),
+	MT6577_AUXADC_CHANNEL(2),
+	MT6577_AUXADC_CHANNEL(3),
+	MT6577_AUXADC_CHANNEL(4),
+	MT6577_AUXADC_CHANNEL(5),
+	MT6577_AUXADC_CHANNEL(6),
+	MT6577_AUXADC_CHANNEL(7),
+	MT6577_AUXADC_CHANNEL(8),
+	MT6577_AUXADC_CHANNEL(9),
+	MT6577_AUXADC_CHANNEL(10),
+	MT6577_AUXADC_CHANNEL(11),
+	MT6577_AUXADC_CHANNEL(12),
+	MT6577_AUXADC_CHANNEL(13),
+	MT6577_AUXADC_CHANNEL(14),
+	MT6577_AUXADC_CHANNEL(15),
+};
+
+static inline void mt6577_auxadc_mod_reg(void __iomem *reg,
+					 u32 or_mask, u32 and_mask)
+{
+	u32 val;
+
+	val = readl(reg);
+	val |= or_mask;
+	val &= ~and_mask;
+	writel(val, reg);
+}
+
+static int mt6577_auxadc_read(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan)
+{
+	u32 val;
+	void __iomem *reg_channel;
+	int ret;
+	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
+
+	reg_channel = adc_dev->reg_base + MT6577_AUXADC_DAT0 +
+		      chan->channel * 0x04;
+
+	mutex_lock(&adc_dev->lock);
+
+	mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_CON1,
+			      0, 1 << chan->channel);
+
+	/* read channel and make sure old ready bit == 0 */
+	ret = readl_poll_timeout(reg_channel, val,
+				 ((val & MT6577_AUXADC_RDY0) == 0),
+				 MT6577_AUXADC_SLEEP_US,
+				 MT6577_AUXADC_TIMEOUT_US);
+	if (ret < 0) {
+		dev_err(indio_dev->dev.parent,
+			"wait for channel[%d] ready bit clear time out\n",
+			chan->channel);
+		goto err_timeout;
+	}
+
+	/* set bit to trigger sample */
+	mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_CON1,
+			      1 << chan->channel, 0);
+
+	/* we must delay here for hardware sample channel data */
+	udelay(MT6577_AUXADC_SAMPLE_READY_US);
+
+	/* check MTK_AUXADC_CON2 if auxadc is idle */
+	ret = readl_poll_timeout(adc_dev->reg_base + MT6577_AUXADC_CON2, val,
+				 ((val & MT6577_AUXADC_STA) == 0),
+				 MT6577_AUXADC_SLEEP_US,
+				 MT6577_AUXADC_TIMEOUT_US);
+	if (ret < 0) {
+		dev_err(indio_dev->dev.parent,
+			"wait for auxadc idle time out\n");
+		goto err_timeout;
+	}
+
+	/* read channel and make sure ready bit == 1 */
+	ret = readl_poll_timeout(reg_channel, val,
+				 ((val & MT6577_AUXADC_RDY0) != 0),
+				 MT6577_AUXADC_SLEEP_US,
+				 MT6577_AUXADC_TIMEOUT_US);
+	if (ret < 0) {
+		dev_err(indio_dev->dev.parent,
+			"wait for channel[%d] data ready time out\n",
+			chan->channel);
+		goto err_timeout;
+	}
+
+	/* read data */
+	val = readl(reg_channel) & MT6577_AUXADC_DAT_MASK;
+
+	mutex_unlock(&adc_dev->lock);
+
+	return val;
+
+err_timeout:
+
+	mutex_unlock(&adc_dev->lock);
+
+	return -ETIMEDOUT;
+}
+
+static int mt6577_auxadc_read_raw(struct iio_dev *indio_dev,
+				  struct iio_chan_spec const *chan,
+				  int *val,
+				  int *val2,
+				  long info)
+{
+	switch (info) {
+	case IIO_CHAN_INFO_PROCESSED:
+		*val = mt6577_auxadc_read(indio_dev, chan);
+		if (*val < 0) {
+			dev_err(indio_dev->dev.parent,
+				"failed to sample data on channel[%d]\n",
+				chan->channel);
+			return *val;
+		}
+		return IIO_VAL_INT;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info mt6577_auxadc_info = {
+	.driver_module = THIS_MODULE,
+	.read_raw = &mt6577_auxadc_read_raw,
+};
+
+static int mt6577_auxadc_probe(struct platform_device *pdev)
+{
+	struct mt6577_auxadc_device *adc_dev;
+	unsigned long adc_clk_rate;
+	struct resource *res;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	adc_dev = iio_priv(indio_dev);
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->name = dev_name(&pdev->dev);
+	indio_dev->info = &mt6577_auxadc_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = mt6577_auxadc_iio_channels;
+	indio_dev->num_channels = ARRAY_SIZE(mt6577_auxadc_iio_channels);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	adc_dev->reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(adc_dev->reg_base)) {
+		dev_err(&pdev->dev, "failed to get auxadc base address\n");
+		return PTR_ERR(adc_dev->reg_base);
+	}
+
+	adc_dev->adc_clk = devm_clk_get(&pdev->dev, "main");
+	if (IS_ERR(adc_dev->adc_clk)) {
+		dev_err(&pdev->dev, "failed to get auxadc clock\n");
+		return PTR_ERR(adc_dev->adc_clk);
+	}
+
+	ret = clk_prepare_enable(adc_dev->adc_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable auxadc clock\n");
+		return ret;
+	}
+
+	adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
+	if (!adc_clk_rate) {
+		ret = -EINVAL;
+		dev_err(&pdev->dev, "null clock rate\n");
+		goto err_disable_clk;
+	}
+
+	mutex_init(&adc_dev->lock);
+
+	mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
+			      MT6577_AUXADC_PDN_EN, 0);
+	mdelay(MT6577_AUXADC_POWER_READY_MS);
+
+	platform_set_drvdata(pdev, indio_dev);
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to register iio device\n");
+		goto err_power_off;
+	}
+
+	return 0;
+
+err_power_off:
+	mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
+			      0, MT6577_AUXADC_PDN_EN);
+err_disable_clk:
+	clk_disable_unprepare(adc_dev->adc_clk);
+	return ret;
+}
+
+static int mt6577_auxadc_remove(struct platform_device *pdev)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+	struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+
+	mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
+			      0, MT6577_AUXADC_PDN_EN);
+
+	clk_disable_unprepare(adc_dev->adc_clk);
+
+	return 0;
+}
+
+static const struct of_device_id mt6577_auxadc_of_match[] = {
+	{ .compatible = "mediatek,mt2701-auxadc", },
+	{ .compatible = "mediatek,mt8173-auxadc", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, mt6577_auxadc_of_match);
+
+static struct platform_driver mt6577_auxadc_driver = {
+	.driver = {
+		.name   = "mt6577-auxadc",
+		.of_match_table = mt6577_auxadc_of_match,
+	},
+	.probe	= mt6577_auxadc_probe,
+	.remove	= mt6577_auxadc_remove,
+};
+module_platform_driver(mt6577_auxadc_driver);
+
+MODULE_AUTHOR("Zhiyong Tao <zhiyong.tao at mediatek.com>");
+MODULE_DESCRIPTION("MTK AUXADC Device Driver");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5



From p.zabel at pengutronix.de  Wed Jul 27 03:03:36 2016
From: p.zabel at pengutronix.de (Philipp Zabel)
Date: Wed, 27 Jul 2016 12:03:36 +0200
Subject: [PATCH v4 4/8] drm/mediatek: add support for Mediatek SoC MT2701
In-Reply-To: <1469529774.4678.34.camel@mtksdaap41>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
 <1468577274-6178-5-git-send-email-yt.shen@mediatek.com>
 <1468997599.11841.49.camel@mtksdaap41>
 <1469529774.4678.34.camel@mtksdaap41>
Message-ID: <1469613816.2470.50.camel@pengutronix.de>

Am Dienstag, den 26.07.2016, 18:42 +0800 schrieb YT Shen:
> Hi CK,
> 
> On Wed, 2016-07-20 at 14:53 +0800, CK Hu wrote:
> > Hi, YT:
> > 
> > Some comments inline.
> > 
> > On Fri, 2016-07-15 at 18:07 +0800, YT Shen wrote:
> > > This patch add support for the Mediatek MT2701 DISP subsystem.
> > > There is only one OVL engine in MT2701.
> > > 
> > > Signed-off-by: YT Shen <yt.shen at mediatek.com>
> > > ---
> > >  drivers/gpu/drm/mediatek/mtk_disp_ovl.c     |    6 ++++
> > >  drivers/gpu/drm/mediatek/mtk_disp_rdma.c    |    6 ++++
> > >  drivers/gpu/drm/mediatek/mtk_drm_ddp.c      |   41 +++++++++++++++++++++++++++
> > >  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |    7 +++++
> > >  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |    1 +
> > >  drivers/gpu/drm/mediatek/mtk_drm_drv.c      |   31 ++++++++++++++++++++
> > >  6 files changed, 92 insertions(+)
> > > 
> > 
> > [snip...]
> > 
> > >  
> > >  static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
> > > +	{ .compatible = "mediatek,mt2701-disp-ovl",   .data = (void *)MTK_DISP_OVL },
> > >  	{ .compatible = "mediatek,mt8173-disp-ovl",   .data = (void *)MTK_DISP_OVL },
> > > +	{ .compatible = "mediatek,mt2701-disp-rdma",  .data = (void *)MTK_DISP_RDMA },
> > >  	{ .compatible = "mediatek,mt8173-disp-rdma",  .data = (void *)MTK_DISP_RDMA },
> > > +	{ .compatible = "mediatek,mt2701-disp-wdma",  .data = (void *)MTK_DISP_WDMA },
> > 
> > Is WDMA different from MT8173 to MT2701. If they are the same, you need
> > not to add compatible of 'mediatek,mt2701-disp-wdma' because use
> > 'mediatek,mt8173-disp-wdma' is enough.
> Yes, the hardware has differences, so we need add new compatible
> 'mt2701-disp-wdma'

It would be nice if you could add a short paragraph to the patch
description about what the hardware differences are (probably just
changed register layout in most cases).

regards
Philipp



From broonie at kernel.org  Wed Jul 27 12:13:33 2016
From: broonie at kernel.org (Mark Brown)
Date: Wed, 27 Jul 2016 20:13:33 +0100
Subject: Applied "spi: mediatek: remove spi_master_put in mtk_spi_remove()" to
 the spi tree
In-Reply-To: <1469545010-32327-1-git-send-email-weiyj.lk@gmail.com>
Message-ID: <E1bSUGr-00051R-Fx@debutante>

The patch

   spi: mediatek: remove spi_master_put in mtk_spi_remove()

has been applied to the spi tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From c2b08cede727387a5e19b40fa8e1a1e3a53e8527 Mon Sep 17 00:00:00 2001
From: Wei Yongjun <weiyj.lk at gmail.com>
Date: Tue, 26 Jul 2016 14:56:50 +0000
Subject: [PATCH] spi: mediatek: remove spi_master_put in mtk_spi_remove()

The call to spi_master_put() in mtk_spi_remove() is redundant since
the master is registered using devm_spi_register_master() and no
reference hold by using spi_master_get() in mtk_spi_remove().

This is detected by Coccinelle semantic patch.

Signed-off-by: Wei Yongjun <weiyj.lk at gmail.com>
Signed-off-by: Mark Brown <broonie at kernel.org>
---
 drivers/spi/spi-mt65xx.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c
index 0be89e052428..899d7a8f0889 100644
--- a/drivers/spi/spi-mt65xx.c
+++ b/drivers/spi/spi-mt65xx.c
@@ -685,7 +685,6 @@ static int mtk_spi_remove(struct platform_device *pdev)
 	pm_runtime_disable(&pdev->dev);
 
 	mtk_spi_reset(mdata);
-	spi_master_put(master);
 
 	return 0;
 }
-- 
2.8.1



From ck.hu at mediatek.com  Wed Jul 27 19:07:35 2016
From: ck.hu at mediatek.com (CK Hu)
Date: Thu, 28 Jul 2016 10:07:35 +0800
Subject: [PATCH v4 4/8] drm/mediatek: add support for Mediatek SoC MT2701
In-Reply-To: <1469613816.2470.50.camel@pengutronix.de>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
 <1468577274-6178-5-git-send-email-yt.shen@mediatek.com>
 <1468997599.11841.49.camel@mtksdaap41>
 <1469529774.4678.34.camel@mtksdaap41>
 <1469613816.2470.50.camel@pengutronix.de>
Message-ID: <1469671655.11841.85.camel@mtksdaap41>

Hi, YT:

On Wed, 2016-07-27 at 12:03 +0200, Philipp Zabel wrote:
> Am Dienstag, den 26.07.2016, 18:42 +0800 schrieb YT Shen:
> > Hi CK,
> > 
> > On Wed, 2016-07-20 at 14:53 +0800, CK Hu wrote:
> > > Hi, YT:
> > > 
> > > Some comments inline.
> > > 
> > > On Fri, 2016-07-15 at 18:07 +0800, YT Shen wrote:
> > > > This patch add support for the Mediatek MT2701 DISP subsystem.
> > > > There is only one OVL engine in MT2701.
> > > > 
> > > > Signed-off-by: YT Shen <yt.shen at mediatek.com>
> > > > ---
> > > >  drivers/gpu/drm/mediatek/mtk_disp_ovl.c     |    6 ++++
> > > >  drivers/gpu/drm/mediatek/mtk_disp_rdma.c    |    6 ++++
> > > >  drivers/gpu/drm/mediatek/mtk_drm_ddp.c      |   41 +++++++++++++++++++++++++++
> > > >  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |    7 +++++
> > > >  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |    1 +
> > > >  drivers/gpu/drm/mediatek/mtk_drm_drv.c      |   31 ++++++++++++++++++++
> > > >  6 files changed, 92 insertions(+)
> > > > 
> > > 
> > > [snip...]
> > > 
> > > >  
> > > >  static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
> > > > +	{ .compatible = "mediatek,mt2701-disp-ovl",   .data = (void *)MTK_DISP_OVL },
> > > >  	{ .compatible = "mediatek,mt8173-disp-ovl",   .data = (void *)MTK_DISP_OVL },
> > > > +	{ .compatible = "mediatek,mt2701-disp-rdma",  .data = (void *)MTK_DISP_RDMA },
> > > >  	{ .compatible = "mediatek,mt8173-disp-rdma",  .data = (void *)MTK_DISP_RDMA },
> > > > +	{ .compatible = "mediatek,mt2701-disp-wdma",  .data = (void *)MTK_DISP_WDMA },
> > > 
> > > Is WDMA different from MT8173 to MT2701. If they are the same, you need
> > > not to add compatible of 'mediatek,mt2701-disp-wdma' because use
> > > 'mediatek,mt8173-disp-wdma' is enough.
> > Yes, the hardware has differences, so we need add new compatible
> > 'mt2701-disp-wdma'
> 
> It would be nice if you could add a short paragraph to the patch
> description about what the hardware differences are (probably just
> changed register layout in most cases).

If you don't want to add description, you may separate the modification
of OVL, RDMA, WDMA, PWM to different patch. And you send patch of OVL
and RDMA first because you have related code modification for these two.
You temporarily treat WDMA and PWM as MT8173 and it works. And one day
you need to modify code of WDMA and PWM for MT2701, then you send the
patch of WDMA and PWM and you need not to add any description because we
can find out the difference from source code.

> 
> regards
> Philipp
> 

Regards,
CK



From bibby.hsieh at mediatek.com  Wed Jul 27 19:22:51 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Thu, 28 Jul 2016 10:22:51 +0800
Subject: [PATCH v4 0/4] drm/mediatek: MT8173 gamma & dither support
Message-ID: <1469672575-5847-1-git-send-email-bibby.hsieh@mediatek.com>

This is MT8173 gamma & dither support PATCH v4, based on 4.7-rc1.

Changes since v3:
 -Split the GAMMA patch into 3 patches.
   --AAL engine basic function
   --GAMMA engine basic function
   --GAMMA correction config function
 -Align the all definition to 4 digits.
 -Remove HW constrain check from calculate bpc.
 -Use symbol to replace magic number.
 -Add a function "mtk_dither_set".

Changes since v2:
 -Modify defines to match the register field names in the MT8173 datasheet
 -Made dithering function support hardware mirroring well on two monitor.

Changes since v1:
 -According to the suggestion from Daniel,
  we used the new atomic color management.
 -Applied gamma function at GAMMA engine (path 2).
 -Made dithering function support hardware mirroring well.
 -Removed the bpc variable from mtk_drm_crtc struct.

Bibby Hsieh (4):
  drm/mediatek: Add AAL engine basic function
  drm/mediatek: Add GAMMA engine basic function
  drm/mediatek: Add gamma correction.
  drm/mediatek: set mt8173 dithering function

 drivers/gpu/drm/mediatek/mtk_disp_ovl.c     |    3 +-
 drivers/gpu/drm/mediatek/mtk_disp_rdma.c    |    3 +-
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c     |   29 ++++-
 drivers/gpu/drm/mediatek/mtk_drm_crtc.h     |    3 +
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |  151 +++++++++++++++++++++++++--
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |   18 +++-
 6 files changed, 189 insertions(+), 18 deletions(-)

-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Wed Jul 27 19:22:52 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Thu, 28 Jul 2016 10:22:52 +0800
Subject: [PATCH v4 1/4] drm/mediatek: Add AAL engine basic function
In-Reply-To: <1469672575-5847-1-git-send-email-bibby.hsieh@mediatek.com>
References: <1469672575-5847-1-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1469672575-5847-2-git-send-email-bibby.hsieh@mediatek.com>

In order to correct brightness values, we have
to support gamma funciton on MT8173. In MT8173,
we have two engines for supporting gamma function:
AAL and GAMMA. This patch add some AAL engine
basic function, include config, start and stop
function.

Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |   29 ++++++++++++++++++++++++++-
 1 file changed, 28 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
index 3970fcf..5fc9671 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
@@ -38,6 +38,9 @@
 #define DISP_COLOR_WIDTH			0x0c50
 #define DISP_COLOR_HEIGHT			0x0c54
 
+#define DISP_AAL_EN				0x0000
+#define DISP_AAL_SIZE				0x0030
+
 #define	OD_RELAY_MODE		BIT(0)
 
 #define	UFO_BYPASS		BIT(2)
@@ -45,6 +48,8 @@
 #define	COLOR_BYPASS_ALL	BIT(7)
 #define	COLOR_SEQ_SEL		BIT(13)
 
+#define AAL_EN			BIT(0)
+
 static void mtk_color_config(struct mtk_ddp_comp *comp, unsigned int w,
 			     unsigned int h, unsigned int vrefresh)
 {
@@ -76,6 +81,28 @@ static void mtk_ufoe_start(struct mtk_ddp_comp *comp)
 	writel(UFO_BYPASS, comp->regs + DISP_REG_UFO_START);
 }
 
+static void mtk_aal_config(struct mtk_ddp_comp *comp, unsigned int w,
+			   unsigned int h, unsigned int vrefresh)
+{
+	writel(h << 16 | w, comp->regs + DISP_AAL_SIZE);
+}
+
+static void mtk_aal_start(struct mtk_ddp_comp *comp)
+{
+	writel(AAL_EN, comp->regs + DISP_AAL_EN);
+}
+
+static void mtk_aal_stop(struct mtk_ddp_comp *comp)
+{
+	writel_relaxed(0x0, comp->regs + DISP_AAL_EN);
+}
+
+static const struct mtk_ddp_comp_funcs ddp_aal = {
+	.config = mtk_aal_config,
+	.start = mtk_aal_start,
+	.stop = mtk_aal_stop,
+};
+
 static const struct mtk_ddp_comp_funcs ddp_color = {
 	.config = mtk_color_config,
 	.start = mtk_color_start,
@@ -112,7 +139,7 @@ struct mtk_ddp_comp_match {
 };
 
 static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
-	[DDP_COMPONENT_AAL]	= { MTK_DISP_AAL,	0, NULL },
+	[DDP_COMPONENT_AAL]	= { MTK_DISP_AAL,	0, &ddp_aal },
 	[DDP_COMPONENT_COLOR0]	= { MTK_DISP_COLOR,	0, &ddp_color },
 	[DDP_COMPONENT_COLOR1]	= { MTK_DISP_COLOR,	1, &ddp_color },
 	[DDP_COMPONENT_DPI0]	= { MTK_DPI,		0, NULL },
-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Wed Jul 27 19:22:53 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Thu, 28 Jul 2016 10:22:53 +0800
Subject: [PATCH v4 2/4] drm/mediatek: Add GAMMA engine basic function
In-Reply-To: <1469672575-5847-1-git-send-email-bibby.hsieh@mediatek.com>
References: <1469672575-5847-1-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1469672575-5847-3-git-send-email-bibby.hsieh@mediatek.com>

In order to correct brightness values, we have
to support gamma funciton on MT8173. In MT8173,
we have two engines for supporting gamma function:
AAL and GAMMA. This patch add some GAMMA engine
basic function, include config, start and stop
function.

Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |   29 ++++++++++++++++++++++++++-
 1 file changed, 28 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
index 5fc9671..ba895c8 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
@@ -41,6 +41,9 @@
 #define DISP_AAL_EN				0x0000
 #define DISP_AAL_SIZE				0x0030
 
+#define DISP_GAMMA_EN				0x0000
+#define DISP_GAMMA_SIZE				0x0030
+
 #define	OD_RELAY_MODE		BIT(0)
 
 #define	UFO_BYPASS		BIT(2)
@@ -50,6 +53,8 @@
 
 #define AAL_EN			BIT(0)
 
+#define GAMMA_EN		BIT(0)
+
 static void mtk_color_config(struct mtk_ddp_comp *comp, unsigned int w,
 			     unsigned int h, unsigned int vrefresh)
 {
@@ -97,12 +102,34 @@ static void mtk_aal_stop(struct mtk_ddp_comp *comp)
 	writel_relaxed(0x0, comp->regs + DISP_AAL_EN);
 }
 
+static void mtk_gamma_config(struct mtk_ddp_comp *comp, unsigned int w,
+			     unsigned int h, unsigned int vrefresh)
+{
+	writel(h << 16 | w, comp->regs + DISP_GAMMA_SIZE);
+}
+
+static void mtk_gamma_start(struct mtk_ddp_comp *comp)
+{
+	writel(GAMMA_EN, comp->regs  + DISP_GAMMA_EN);
+}
+
+static void mtk_gamma_stop(struct mtk_ddp_comp *comp)
+{
+	writel_relaxed(0x0, comp->regs  + DISP_GAMMA_EN);
+}
+
 static const struct mtk_ddp_comp_funcs ddp_aal = {
 	.config = mtk_aal_config,
 	.start = mtk_aal_start,
 	.stop = mtk_aal_stop,
 };
 
+static const struct mtk_ddp_comp_funcs ddp_gamma = {
+	.config = mtk_gamma_config,
+	.start = mtk_gamma_start,
+	.stop = mtk_gamma_stop,
+};
+
 static const struct mtk_ddp_comp_funcs ddp_color = {
 	.config = mtk_color_config,
 	.start = mtk_color_start,
@@ -145,7 +172,7 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
 	[DDP_COMPONENT_DPI0]	= { MTK_DPI,		0, NULL },
 	[DDP_COMPONENT_DSI0]	= { MTK_DSI,		0, NULL },
 	[DDP_COMPONENT_DSI1]	= { MTK_DSI,		1, NULL },
-	[DDP_COMPONENT_GAMMA]	= { MTK_DISP_GAMMA,	0, NULL },
+	[DDP_COMPONENT_GAMMA]	= { MTK_DISP_GAMMA,	0, &ddp_gamma },
 	[DDP_COMPONENT_OD]	= { MTK_DISP_OD,	0, &ddp_od },
 	[DDP_COMPONENT_OVL0]	= { MTK_DISP_OVL,	0, NULL },
 	[DDP_COMPONENT_OVL1]	= { MTK_DISP_OVL,	1, NULL },
-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Wed Jul 27 19:22:54 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Thu, 28 Jul 2016 10:22:54 +0800
Subject: [PATCH v4 3/4] drm/mediatek: Add gamma correction.
In-Reply-To: <1469672575-5847-1-git-send-email-bibby.hsieh@mediatek.com>
References: <1469672575-5847-1-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1469672575-5847-4-git-send-email-bibby.hsieh@mediatek.com>

Add gamma set function to correct brightness values.
It applies arbitrary mapping curve to compensate the
incorrect transfer function of the panel.

Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c     |    8 ++++++-
 drivers/gpu/drm/mediatek/mtk_drm_crtc.h     |    1 +
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |   31 +++++++++++++++++++++++++++
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |   10 +++++++++
 4 files changed, 49 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index 24aa3ba..cbb460a5 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -409,6 +409,9 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
 	}
 	if (pending_planes)
 		mtk_crtc->pending_planes = true;
+	if (crtc->state->color_mgmt_changed)
+		for (i = 0; i < mtk_crtc->ddp_comp_nr; i++)
+			mtk_ddp_gamma_set(mtk_crtc->ddp_comp[i], crtc->state);
 }
 
 static const struct drm_crtc_funcs mtk_crtc_funcs = {
@@ -418,6 +421,7 @@ static const struct drm_crtc_funcs mtk_crtc_funcs = {
 	.reset			= mtk_drm_crtc_reset,
 	.atomic_duplicate_state	= mtk_drm_crtc_duplicate_state,
 	.atomic_destroy_state	= mtk_drm_crtc_destroy_state,
+	.gamma_set		= drm_atomic_helper_legacy_gamma_set,
 };
 
 static const struct drm_crtc_helper_funcs mtk_crtc_helper_funcs = {
@@ -568,7 +572,9 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
 				&mtk_crtc->planes[1].base, pipe);
 	if (ret < 0)
 		goto unprepare;
-
+	drm_mode_crtc_set_gamma_size(&mtk_crtc->base, MTK_LUT_SIZE);
+	drm_helper_crtc_enable_color_mgmt(&mtk_crtc->base, MTK_LUT_SIZE,
+					  MTK_LUT_SIZE);
 	priv->crtc[pipe] = &mtk_crtc->base;
 	priv->num_pipes++;
 
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.h b/drivers/gpu/drm/mediatek/mtk_drm_crtc.h
index 81e5566..d332564 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.h
@@ -19,6 +19,7 @@
 #include "mtk_drm_plane.h"
 
 #define OVL_LAYER_NR	4
+#define MTK_LUT_SIZE	512
 
 int mtk_drm_crtc_enable_vblank(struct drm_device *drm, unsigned int pipe);
 void mtk_drm_crtc_disable_vblank(struct drm_device *drm, unsigned int pipe);
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
index ba895c8..42cd587 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
@@ -24,6 +24,7 @@
 #include "mtk_drm_drv.h"
 #include "mtk_drm_plane.h"
 #include "mtk_drm_ddp_comp.h"
+#include "mtk_drm_crtc.h"
 
 #define DISP_OD_EN				0x0000
 #define DISP_OD_INTEN				0x0008
@@ -42,7 +43,11 @@
 #define DISP_AAL_SIZE				0x0030
 
 #define DISP_GAMMA_EN				0x0000
+#define DISP_GAMMA_CFG				0x0020
 #define DISP_GAMMA_SIZE				0x0030
+#define DISP_GAMMA_LUT				0x0700
+
+#define LUT_10BIT_MASK				0x03ff
 
 #define	OD_RELAY_MODE		BIT(0)
 
@@ -54,6 +59,7 @@
 #define AAL_EN			BIT(0)
 
 #define GAMMA_EN		BIT(0)
+#define GAMMA_LUT_EN		BIT(1)
 
 static void mtk_color_config(struct mtk_ddp_comp *comp, unsigned int w,
 			     unsigned int h, unsigned int vrefresh)
@@ -118,13 +124,38 @@ static void mtk_gamma_stop(struct mtk_ddp_comp *comp)
 	writel_relaxed(0x0, comp->regs  + DISP_GAMMA_EN);
 }
 
+static void mtk_gamma_set(struct mtk_ddp_comp *comp,
+			  struct drm_crtc_state *state)
+{
+	unsigned int i, reg;
+	struct drm_color_lut *lut;
+	void __iomem *lut_base;
+	u32 word;
+
+	if (state->gamma_lut) {
+		reg = readl(comp->regs + DISP_GAMMA_CFG);
+		reg = reg | GAMMA_LUT_EN;
+		writel(reg, comp->regs + DISP_GAMMA_CFG);
+		lut_base = comp->regs + DISP_GAMMA_LUT;
+		lut = (struct drm_color_lut *)state->gamma_lut->data;
+		for (i = 0; i < MTK_LUT_SIZE; i++) {
+			word = (((lut[i].red >> 6) & LUT_10BIT_MASK) << 20) +
+				(((lut[i].green >> 6) & LUT_10BIT_MASK) << 10) +
+				((lut[i].blue >> 6) & LUT_10BIT_MASK);
+			writel(word, (lut_base + i * 4));
+		}
+	}
+}
+
 static const struct mtk_ddp_comp_funcs ddp_aal = {
+	.gamma_set = mtk_gamma_set,
 	.config = mtk_aal_config,
 	.start = mtk_aal_start,
 	.stop = mtk_aal_stop,
 };
 
 static const struct mtk_ddp_comp_funcs ddp_gamma = {
+	.gamma_set = mtk_gamma_set,
 	.config = mtk_gamma_config,
 	.start = mtk_gamma_start,
 	.stop = mtk_gamma_stop,
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
index 6b13ba9..f4b7e0a 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
@@ -21,6 +21,7 @@ struct device_node;
 struct drm_crtc;
 struct drm_device;
 struct mtk_plane_state;
+struct drm_crtc_state;
 
 enum mtk_ddp_comp_type {
 	MTK_DISP_OVL,
@@ -73,6 +74,8 @@ struct mtk_ddp_comp_funcs {
 	void (*layer_off)(struct mtk_ddp_comp *comp, unsigned int idx);
 	void (*layer_config)(struct mtk_ddp_comp *comp, unsigned int idx,
 			     struct mtk_plane_state *state);
+	void (*gamma_set)(struct mtk_ddp_comp *comp,
+			  struct drm_crtc_state *state);
 };
 
 struct mtk_ddp_comp {
@@ -139,6 +142,13 @@ static inline void mtk_ddp_comp_layer_config(struct mtk_ddp_comp *comp,
 		comp->funcs->layer_config(comp, idx, state);
 }
 
+static inline void mtk_ddp_gamma_set(struct mtk_ddp_comp *comp,
+				     struct drm_crtc_state *state)
+{
+	if (comp->funcs && comp->funcs->gamma_set)
+		comp->funcs->gamma_set(comp, state);
+}
+
 int mtk_ddp_comp_get_id(struct device_node *node,
 			enum mtk_ddp_comp_type comp_type);
 int mtk_ddp_comp_init(struct device *dev, struct device_node *comp_node,
-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Wed Jul 27 19:22:55 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Thu, 28 Jul 2016 10:22:55 +0800
Subject: [PATCH v4 4/4] drm/mediatek: set mt8173 dithering function
In-Reply-To: <1469672575-5847-1-git-send-email-bibby.hsieh@mediatek.com>
References: <1469672575-5847-1-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1469672575-5847-5-git-send-email-bibby.hsieh@mediatek.com>

Some panels only accept bpc (bit per color) 6-bit.
But, the default bpc in mt8173 display data path is 8-bit.
If we didn't enable dithering function to convert bpc,
display cannot show the smooth grayscale image.

In mt8173, the dithering function in OD (OverDrive) and
GAMMA module, we have to config them with
connector->display_mode.bpc when CRTC initial.

1. Clear the default value at *_DITHER_5 and *_DITHER_7 register.
2. Calculate the LSB_ERR_SHIFT bits and ADD_LSHIFT bits two values.
i.e. Input bpc of OD is 10 bits, we assume the bpc of panel is 6-bit,
so, we need to set 4-bit to LSB_ERR_SHIFT and ADD_LSHIFT bits respectively.
3. Then, set the OD or GAMMA to dithering mode depends on path-1 or path-2.

Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c     |    3 +-
 drivers/gpu/drm/mediatek/mtk_disp_rdma.c    |    3 +-
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c     |   21 ++++++--
 drivers/gpu/drm/mediatek/mtk_drm_crtc.h     |    2 +
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |   72 ++++++++++++++++++++++-----
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |    8 +--
 6 files changed, 89 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index 8f62671f..019b7ca 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -103,7 +103,8 @@ static void mtk_ovl_stop(struct mtk_ddp_comp *comp)
 }
 
 static void mtk_ovl_config(struct mtk_ddp_comp *comp, unsigned int w,
-			   unsigned int h, unsigned int vrefresh)
+			   unsigned int h, unsigned int vrefresh,
+			   unsigned int bpc)
 {
 	if (w != 0 && h != 0)
 		writel_relaxed(h << 16 | w, comp->regs + DISP_REG_OVL_ROI_SIZE);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
index 5fb80cb..0df05f9 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
@@ -106,7 +106,8 @@ static void mtk_rdma_stop(struct mtk_ddp_comp *comp)
 }
 
 static void mtk_rdma_config(struct mtk_ddp_comp *comp, unsigned int width,
-			    unsigned int height, unsigned int vrefresh)
+			    unsigned int height, unsigned int vrefresh,
+			    unsigned int bpc)
 {
 	unsigned int threshold;
 	unsigned int reg;
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index cbb460a5..e51176e8 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -222,7 +222,9 @@ static void mtk_crtc_ddp_clk_disable(struct mtk_drm_crtc *mtk_crtc)
 static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
 {
 	struct drm_crtc *crtc = &mtk_crtc->base;
-	unsigned int width, height, vrefresh;
+	struct drm_connector *connector;
+	struct drm_encoder *encoder;
+	unsigned int width, height, vrefresh, bpc = MTK_MAX_BPC;
 	int ret;
 	int i;
 
@@ -234,6 +236,19 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
 	height = crtc->state->adjusted_mode.vdisplay;
 	vrefresh = crtc->state->adjusted_mode.vrefresh;
 
+	drm_for_each_encoder(encoder, crtc->dev) {
+		if (encoder->crtc != crtc)
+			continue;
+
+		drm_for_each_connector(connector, crtc->dev) {
+			if (connector->encoder != encoder)
+				continue;
+			if (connector->display_info.bpc != 0 &&
+			    bpc > connector->display_info.bpc)
+				bpc = connector->display_info.bpc;
+		}
+	}
+
 	ret = pm_runtime_get_sync(crtc->dev->dev);
 	if (ret < 0) {
 		DRM_ERROR("Failed to enable power domain: %d\n", ret);
@@ -266,7 +281,7 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
 	for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
 		struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[i];
 
-		mtk_ddp_comp_config(comp, width, height, vrefresh);
+		mtk_ddp_comp_config(comp, width, height, vrefresh, bpc);
 		mtk_ddp_comp_start(comp);
 	}
 
@@ -468,7 +483,7 @@ void mtk_crtc_ddp_irq(struct drm_crtc *crtc, struct mtk_ddp_comp *ovl)
 	if (state->pending_config) {
 		mtk_ddp_comp_config(ovl, state->pending_width,
 				    state->pending_height,
-				    state->pending_vrefresh);
+				    state->pending_vrefresh, 0);
 
 		state->pending_config = false;
 	}
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.h b/drivers/gpu/drm/mediatek/mtk_drm_crtc.h
index d332564..33f6ab6 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.h
@@ -20,6 +20,8 @@
 
 #define OVL_LAYER_NR	4
 #define MTK_LUT_SIZE	512
+#define MTK_MAX_BPC	10
+#define MTK_MIN_BPC	3
 
 int mtk_drm_crtc_enable_vblank(struct drm_device *drm, unsigned int pipe);
 void mtk_drm_crtc_disable_vblank(struct drm_device *drm, unsigned int pipe);
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
index 42cd587..df33b3c 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
@@ -31,6 +31,10 @@
 #define DISP_OD_INTSTA				0x000c
 #define DISP_OD_CFG				0x0020
 #define DISP_OD_SIZE				0x0030
+#define DISP_DITHER_5				0x0114
+#define DISP_DITHER_7				0x011c
+#define DISP_DITHER_15				0x013c
+#define DISP_DITHER_16				0x0140
 
 #define DISP_REG_UFO_START			0x0000
 
@@ -49,20 +53,59 @@
 
 #define LUT_10BIT_MASK				0x03ff
 
-#define	OD_RELAY_MODE		BIT(0)
+#define COLOR_BYPASS_ALL			BIT(7)
+#define COLOR_SEQ_SEL				BIT(13)
 
-#define	UFO_BYPASS		BIT(2)
+#define OD_RELAYMODE				BIT(0)
 
-#define	COLOR_BYPASS_ALL	BIT(7)
-#define	COLOR_SEQ_SEL		BIT(13)
+#define UFO_BYPASS				BIT(2)
 
-#define AAL_EN			BIT(0)
+#define AAL_EN					BIT(0)
 
-#define GAMMA_EN		BIT(0)
-#define GAMMA_LUT_EN		BIT(1)
+#define GAMMA_EN				BIT(0)
+#define GAMMA_LUT_EN				BIT(1)
+
+#define DISP_DITHERING				BIT(2)
+#define DITHER_LSB_ERR_SHIFT_R(x)		(((x) & 0x7) << 28)
+#define DITHER_OVFLW_BIT_R(x)			(((x) & 0x7) << 24)
+#define DITHER_ADD_LSHIFT_R(x)			(((x) & 0x7) << 20)
+#define DITHER_ADD_RSHIFT_R(x)			(((x) & 0x7) << 16)
+#define DITHER_NEW_BIT_MODE			BIT(0)
+#define DITHER_LSB_ERR_SHIFT_B(x)		(((x) & 0x7) << 28)
+#define DITHER_OVFLW_BIT_B(x)			(((x) & 0x7) << 24)
+#define DITHER_ADD_LSHIFT_B(x)			(((x) & 0x7) << 20)
+#define DITHER_ADD_RSHIFT_B(x)			(((x) & 0x7) << 16)
+#define DITHER_LSB_ERR_SHIFT_G(x)		(((x) & 0x7) << 12)
+#define DITHER_OVFLW_BIT_G(x)			(((x) & 0x7) << 8)
+#define DITHER_ADD_LSHIFT_G(x)			(((x) & 0x7) << 4)
+#define DITHER_ADD_RSHIFT_G(x)			(((x) & 0x7) << 0)
+
+void mtk_dither_set(struct mtk_ddp_comp *comp, unsigned int bpc,
+		    unsigned int CFG)
+{
+	/* If bpc equal to 0, the dithering function didn't be enabled */
+	if (bpc == 0)
+		return;
+
+	if (bpc >= MTK_MIN_BPC) {
+		writel(0, comp->regs + DISP_DITHER_5);
+		writel(0, comp->regs + DISP_DITHER_7);
+		writel(DITHER_LSB_ERR_SHIFT_R(MTK_MAX_BPC - bpc) |
+		       DITHER_ADD_LSHIFT_R(MTK_MAX_BPC - bpc) |
+		       DITHER_NEW_BIT_MODE,
+		       comp->regs + DISP_DITHER_15);
+		writel(DITHER_LSB_ERR_SHIFT_B(MTK_MAX_BPC - bpc) |
+		       DITHER_ADD_LSHIFT_B(MTK_MAX_BPC - bpc) |
+		       DITHER_LSB_ERR_SHIFT_G(MTK_MAX_BPC - bpc) |
+		       DITHER_ADD_LSHIFT_G(MTK_MAX_BPC - bpc),
+		       comp->regs + DISP_DITHER_16);
+		writel(DISP_DITHERING, comp->regs + CFG);
+	}
+}
 
 static void mtk_color_config(struct mtk_ddp_comp *comp, unsigned int w,
-			     unsigned int h, unsigned int vrefresh)
+			     unsigned int h, unsigned int vrefresh,
+			     unsigned int bpc)
 {
 	writel(w, comp->regs + DISP_COLOR_WIDTH);
 	writel(h, comp->regs + DISP_COLOR_HEIGHT);
@@ -76,14 +119,16 @@ static void mtk_color_start(struct mtk_ddp_comp *comp)
 }
 
 static void mtk_od_config(struct mtk_ddp_comp *comp, unsigned int w,
-			  unsigned int h, unsigned int vrefresh)
+			  unsigned int h, unsigned int vrefresh,
+			  unsigned int bpc)
 {
 	writel(w << 16 | h, comp->regs + DISP_OD_SIZE);
+	writel(OD_RELAYMODE, comp->regs + OD_RELAYMODE);
+	mtk_dither_set(comp, bpc, DISP_OD_CFG);
 }
 
 static void mtk_od_start(struct mtk_ddp_comp *comp)
 {
-	writel(OD_RELAY_MODE, comp->regs + DISP_OD_CFG);
 	writel(1, comp->regs + DISP_OD_EN);
 }
 
@@ -93,7 +138,8 @@ static void mtk_ufoe_start(struct mtk_ddp_comp *comp)
 }
 
 static void mtk_aal_config(struct mtk_ddp_comp *comp, unsigned int w,
-			   unsigned int h, unsigned int vrefresh)
+			   unsigned int h, unsigned int vrefresh,
+			   unsigned int bpc)
 {
 	writel(h << 16 | w, comp->regs + DISP_AAL_SIZE);
 }
@@ -109,9 +155,11 @@ static void mtk_aal_stop(struct mtk_ddp_comp *comp)
 }
 
 static void mtk_gamma_config(struct mtk_ddp_comp *comp, unsigned int w,
-			     unsigned int h, unsigned int vrefresh)
+			     unsigned int h, unsigned int vrefresh,
+			     unsigned int bpc)
 {
 	writel(h << 16 | w, comp->regs + DISP_GAMMA_SIZE);
+	mtk_dither_set(comp, bpc, DISP_GAMMA_CFG);
 }
 
 static void mtk_gamma_start(struct mtk_ddp_comp *comp)
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
index f4b7e0a..22a33ee 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
@@ -65,7 +65,7 @@ struct mtk_ddp_comp;
 
 struct mtk_ddp_comp_funcs {
 	void (*config)(struct mtk_ddp_comp *comp, unsigned int w,
-		       unsigned int h, unsigned int vrefresh);
+		       unsigned int h, unsigned int vrefresh, unsigned int bpc);
 	void (*start)(struct mtk_ddp_comp *comp);
 	void (*stop)(struct mtk_ddp_comp *comp);
 	void (*enable_vblank)(struct mtk_ddp_comp *comp, struct drm_crtc *crtc);
@@ -89,10 +89,10 @@ struct mtk_ddp_comp {
 
 static inline void mtk_ddp_comp_config(struct mtk_ddp_comp *comp,
 				       unsigned int w, unsigned int h,
-				       unsigned int vrefresh)
+				       unsigned int vrefresh, unsigned int bpc)
 {
 	if (comp->funcs && comp->funcs->config)
-		comp->funcs->config(comp, w, h, vrefresh);
+		comp->funcs->config(comp, w, h, vrefresh, bpc);
 }
 
 static inline void mtk_ddp_comp_start(struct mtk_ddp_comp *comp)
@@ -156,5 +156,7 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *comp_node,
 		      const struct mtk_ddp_comp_funcs *funcs);
 int mtk_ddp_comp_register(struct drm_device *drm, struct mtk_ddp_comp *comp);
 void mtk_ddp_comp_unregister(struct drm_device *drm, struct mtk_ddp_comp *comp);
+void mtk_dither_set(struct mtk_ddp_comp *comp, unsigned int bpc,
+		    unsigned int CFG);
 
 #endif /* MTK_DRM_DDP_COMP_H */
-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Wed Jul 27 19:47:17 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Thu, 28 Jul 2016 10:47:17 +0800
Subject: [PATCH v3] arm64: dts: mt8173: add mmsel clocks for 4K support
In-Reply-To: <1469611556.11841.77.camel@mtksdaap41>
References: <1469607914-64831-1-git-send-email-bibby.hsieh@mediatek.com>
 <1469611556.11841.77.camel@mtksdaap41>
Message-ID: <1469674037.29230.0.camel@mtksdaap41>

Hi, CK,

Thanks for your comments.

On Wed, 2016-07-27 at 17:25 +0800, CK Hu wrote:
> Hi, Bibby:
> 
> On Wed, 2016-07-27 at 16:25 +0800, Bibby Hsieh wrote:
> > If MT8173 can support HDMI 4K resoultion, the
> > VENCPLL should be configured to 800MHZ.
> > We didn't set VENCPLL directly, we set the
> > mm_sel to 400MHz statically in the board device tree.
> 
> You may rewrite the description as below:
> 
> 'To support HDMI 4K resolution, mmsys need clock mm_sel to be 400MHz.'
> 
> You need not to mention VENCPLL because it's controlled by clock driver.
> 
Ok, I will modify that.
> > 
> > Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> > ---
> > Changes since v2:
> >  - Align the clocks of dpi0 node.
> > 
> > Changes since v1:
> >  - Do not set the VENCPLL by clk_set_rate
> >    at display driver.
> >  - Configure the mm_sel to 400MHz statically
> >    in the board device tree.
> > ---
> >  arch/arm64/boot/dts/mediatek/mt8173.dtsi |    2 ++
> >  1 file changed, 2 insertions(+)
> > 
> > diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
> > index 78529e4..9c22204 100644
> > --- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
> > +++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
> > @@ -690,7 +690,9 @@
> >  			compatible = "mediatek,mt8173-mmsys", "syscon";
> >  			reg = <0 0x14000000 0 0x1000>;
> >  			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
> > +			clocks = <&topckgen CLK_TOP_MM_SEL>;
> >  			#clock-cells = <1>;
> > +			clock-frequency  = <400000000>;
> >  		};
> >  
> >  		ovl0: ovl at 1400c000 {
> 
> Regards,
> CK
> 


Bibby



From bibby.hsieh at mediatek.com  Wed Jul 27 19:49:25 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Thu, 28 Jul 2016 10:49:25 +0800
Subject: [PATCH v3] arm64: dts: mt8173: add mmsel clocks for 4K support
In-Reply-To: <1469611964.2470.30.camel@pengutronix.de>
References: <1469607914-64831-1-git-send-email-bibby.hsieh@mediatek.com>
 <1469611964.2470.30.camel@pengutronix.de>
Message-ID: <1469674165.29230.1.camel@mtksdaap41>

Hi, Philipp,

Thanks for your comments.

On Wed, 2016-07-27 at 11:32 +0200, Philipp Zabel wrote:
> Am Mittwoch, den 27.07.2016, 16:25 +0800 schrieb Bibby Hsieh:
> > If MT8173 can support HDMI 4K resoultion, the
> > VENCPLL should be configured to 800MHZ.
> > We didn't set VENCPLL directly, we set the
> > mm_sel to 400MHz statically in the board device tree.
> 
> Maybe add a comment that the board .dts file should override the clock
> rate property with the higher VENCPLL frequency the board supports HDMI
> 4K resolution.
> 
Ok, I will add that.
> > Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> > ---
> > Changes since v2:
> >  - Align the clocks of dpi0 node.
> > 
> > Changes since v1:
> >  - Do not set the VENCPLL by clk_set_rate
> >    at display driver.
> >  - Configure the mm_sel to 400MHz statically
> >    in the board device tree.
> > ---
> >  arch/arm64/boot/dts/mediatek/mt8173.dtsi |    2 ++
> >  1 file changed, 2 insertions(+)
> > 
> > diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
> > index 78529e4..9c22204 100644
> > --- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
> > +++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
> > @@ -690,7 +690,9 @@
> >  			compatible = "mediatek,mt8173-mmsys", "syscon";
> >  			reg = <0 0x14000000 0 0x1000>;
> >  			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
> > +			clocks = <&topckgen CLK_TOP_MM_SEL>;
> >  			#clock-cells = <1>;
> > +			clock-frequency  = <400000000>;
> 
> According to the "Assigned clock parents and rates" section in
> Documentation/devicetree/bindings/clock/clock-bindings.txt,
> this should be:
> 			assigned-clocks = <&topckgen CLK_TOP_MM_SEL>;
> 			assigned-clock-rates = <400000000>;
> 
Ok, will do.
> regards
> Philipp
> 

-- 
Bibby



From bibby.hsieh at mediatek.com  Wed Jul 27 20:34:30 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Thu, 28 Jul 2016 11:34:30 +0800
Subject: [PATCH v2 1/3] drm/mediatek: do mtk_hdmi_send_infoframe after
 HDMI clock enable
In-Reply-To: <1469611636.2470.24.camel@pengutronix.de>
References: <1469608292-6106-1-git-send-email-bibby.hsieh@mediatek.com>
 <1469608292-6106-2-git-send-email-bibby.hsieh@mediatek.com>
 <1469611636.2470.24.camel@pengutronix.de>
Message-ID: <1469676870.29230.3.camel@mtksdaap41>

Hi, Philipp,

Thanks for your review.

On Wed, 2016-07-27 at 11:27 +0200, Philipp Zabel wrote:
> Am Mittwoch, den 27.07.2016, 16:31 +0800 schrieb Bibby Hsieh:
> > From: Junzhi Zhao <junzhi.zhao at mediatek.com>
> > 
> > The mtk_hdmi_send_infoframe have to
> > be run after PLL and PIXEL clock of HDMI enable.
> > Make sure that HDMI inforframes can be sent
> > successfully.
> > 
> > Signed-off-by: Junzhi Zhao <junzhi.zhao at mediatek.com>
> > Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> > ---
> >  drivers/gpu/drm/mediatek/mtk_hdmi.c |   19 ++++++++++++-------
> >  1 file changed, 12 insertions(+), 7 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> > index ba812ef..d8609f5 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> > @@ -1133,12 +1133,6 @@ static int mtk_hdmi_output_set_display_mode(struct mtk_hdmi *hdmi,
> >  	phy_power_on(hdmi->phy);
> >  	mtk_hdmi_aud_output_config(hdmi, mode);
> >  
> > -	mtk_hdmi_setup_audio_infoframe(hdmi);
> > -	mtk_hdmi_setup_avi_infoframe(hdmi, mode);
> > -	mtk_hdmi_setup_spd_infoframe(hdmi, "mediatek", "On-chip HDMI");
> > -	if (mode->flags & DRM_MODE_FLAG_3D_MASK)
> > -		mtk_hdmi_setup_vendor_specific_infoframe(hdmi, mode);
> > -
> >  	mtk_hdmi_hw_vid_black(hdmi, false);
> >  	mtk_hdmi_hw_aud_unmute(hdmi);
> >  	mtk_hdmi_hw_send_av_unmute(hdmi);
> > @@ -1401,14 +1395,25 @@ static void mtk_hdmi_bridge_pre_enable(struct drm_bridge *bridge)
> >  	hdmi->powered = true;
> >  }
> >  
> > +static void mtk_hdmi_send_infoframe(struct mtk_hdmi *hdmi,
> > +				    struct drm_display_mode *mode)
> > +{
> > +	mtk_hdmi_setup_audio_infoframe(hdmi);
> > +	mtk_hdmi_setup_avi_infoframe(hdmi, mode);
> > +	mtk_hdmi_setup_spd_infoframe(hdmi, "mediatek", "On-chip HDMI");
> > +	if (mode->flags & DRM_MODE_FLAG_3D_MASK)
> > +		mtk_hdmi_setup_vendor_specific_infoframe(hdmi, mode);
> > +}
> > +
> >  static void mtk_hdmi_bridge_enable(struct drm_bridge *bridge)
> >  {
> >  	struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
> >  
> > +	phy_power_on(hdmi->phy);
> >  	mtk_hdmi_output_set_display_mode(hdmi, &hdmi->mode);
> >  	clk_prepare_enable(hdmi->clk[MTK_HDMI_CLK_HDMI_PLL]);
> >  	clk_prepare_enable(hdmi->clk[MTK_HDMI_CLK_HDMI_PIXEL]);
> > -	phy_power_on(hdmi->phy);
> 
> This change is not described in the patch description. Why is the phy
> power on moved after the pixel clock enable?
> 
Ok, will rollback it.
> > +	mtk_hdmi_send_infoframe(hdmi, &hdmi->mode);
> >  
> >  	hdmi->enabled = true;
> >  }
> 
> regards
> Philipp
> 

-- 
Bibby



From bibby.hsieh at mediatek.com  Wed Jul 27 20:35:16 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Thu, 28 Jul 2016 11:35:16 +0800
Subject: [PATCH v2 2/3] drm/mediatek: enhance the HDMI driving current
In-Reply-To: <1469611550.2470.22.camel@pengutronix.de>
References: <1469608292-6106-1-git-send-email-bibby.hsieh@mediatek.com>
 <1469608292-6106-3-git-send-email-bibby.hsieh@mediatek.com>
 <1469611550.2470.22.camel@pengutronix.de>
Message-ID: <1469676916.29230.4.camel@mtksdaap41>

Hi, Philipp,

Thanks for your review.

On Wed, 2016-07-27 at 11:25 +0200, Philipp Zabel wrote:
> Am Mittwoch, den 27.07.2016, 16:31 +0800 schrieb Bibby Hsieh:
> > From: Junzhi Zhao <junzhi.zhao at mediatek.com>
> > 
> > In order to improve 4K resolution performance,
> > we have to enhance the HDMI driving currend
>                                            ^
> Typo, s/currend/current/
> 
> Besides that, this patch looks good to me.
> 
Ok, I will fix that, thanks.
> regards
> Philipp
> 
> > when clock rate is greater than 165MHz.
> > 
> > Signed-off-by: Junzhi Zhao <junzhi.zhao at mediatek.com>
> > Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> > ---
> >  drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c |   42 +++++++++++++++++-------
> >  1 file changed, 30 insertions(+), 12 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
> > index 8a24754..51cb9cf 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
> > @@ -265,6 +265,9 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
> >  	struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
> >  	unsigned int pre_div;
> >  	unsigned int div;
> > +	unsigned int pre_ibias;
> > +	unsigned int hdmi_ibias;
> > +	unsigned int imp_en;
> >  
> >  	dev_dbg(hdmi_phy->dev, "%s: %lu Hz, parent: %lu Hz\n", __func__,
> >  		rate, parent_rate);
> > @@ -298,18 +301,31 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
> >  			  (0x1 << PLL_BR_SHIFT),
> >  			  RG_HDMITX_PLL_BP | RG_HDMITX_PLL_BC |
> >  			  RG_HDMITX_PLL_BR);
> > -	mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON3, RG_HDMITX_PRD_IMP_EN);
> > +	if (rate < 165000000) {
> > +		mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON3,
> > +					RG_HDMITX_PRD_IMP_EN);
> > +		pre_ibias = 0x3;
> > +		imp_en = 0x0;
> > +		hdmi_ibias = hdmi_phy->ibias;
> > +	} else {
> > +		mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON3,
> > +				      RG_HDMITX_PRD_IMP_EN);
> > +		pre_ibias = 0x6;
> > +		imp_en = 0xf;
> > +		hdmi_ibias = hdmi_phy->ibias_up;
> > +	}
> >  	mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON4,
> > -			  (0x3 << PRD_IBIAS_CLK_SHIFT) |
> > -			  (0x3 << PRD_IBIAS_D2_SHIFT) |
> > -			  (0x3 << PRD_IBIAS_D1_SHIFT) |
> > -			  (0x3 << PRD_IBIAS_D0_SHIFT),
> > +			  (pre_ibias << PRD_IBIAS_CLK_SHIFT) |
> > +			  (pre_ibias << PRD_IBIAS_D2_SHIFT) |
> > +			  (pre_ibias << PRD_IBIAS_D1_SHIFT) |
> > +			  (pre_ibias << PRD_IBIAS_D0_SHIFT),
> >  			  RG_HDMITX_PRD_IBIAS_CLK |
> >  			  RG_HDMITX_PRD_IBIAS_D2 |
> >  			  RG_HDMITX_PRD_IBIAS_D1 |
> >  			  RG_HDMITX_PRD_IBIAS_D0);
> >  	mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON3,
> > -			  (0x0 << DRV_IMP_EN_SHIFT), RG_HDMITX_DRV_IMP_EN);
> > +			  (imp_en << DRV_IMP_EN_SHIFT),
> > +			  RG_HDMITX_DRV_IMP_EN);
> >  	mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6,
> >  			  (hdmi_phy->drv_imp_clk << DRV_IMP_CLK_SHIFT) |
> >  			  (hdmi_phy->drv_imp_d2 << DRV_IMP_D2_SHIFT) |
> > @@ -318,12 +334,14 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
> >  			  RG_HDMITX_DRV_IMP_CLK | RG_HDMITX_DRV_IMP_D2 |
> >  			  RG_HDMITX_DRV_IMP_D1 | RG_HDMITX_DRV_IMP_D0);
> >  	mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON5,
> > -			  (hdmi_phy->ibias << DRV_IBIAS_CLK_SHIFT) |
> > -			  (hdmi_phy->ibias << DRV_IBIAS_D2_SHIFT) |
> > -			  (hdmi_phy->ibias << DRV_IBIAS_D1_SHIFT) |
> > -			  (hdmi_phy->ibias << DRV_IBIAS_D0_SHIFT),
> > -			  RG_HDMITX_DRV_IBIAS_CLK | RG_HDMITX_DRV_IBIAS_D2 |
> > -			  RG_HDMITX_DRV_IBIAS_D1 | RG_HDMITX_DRV_IBIAS_D0);
> > +			  (hdmi_ibias << DRV_IBIAS_CLK_SHIFT) |
> > +			  (hdmi_ibias << DRV_IBIAS_D2_SHIFT) |
> > +			  (hdmi_ibias << DRV_IBIAS_D1_SHIFT) |
> > +			  (hdmi_ibias << DRV_IBIAS_D0_SHIFT),
> > +			  RG_HDMITX_DRV_IBIAS_CLK |
> > +			  RG_HDMITX_DRV_IBIAS_D2 |
> > +			  RG_HDMITX_DRV_IBIAS_D1 |
> > +			  RG_HDMITX_DRV_IBIAS_D0);
> >  	return 0;
> >  }
> >  
> 
> 

-- 
Bibby



From bibby.hsieh at mediatek.com  Wed Jul 27 20:38:55 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Thu, 28 Jul 2016 11:38:55 +0800
Subject: [PATCH v2 3/3] drm/mediatek: fix the wrong pixel clock when
 resolution is 4K
In-Reply-To: <1469611430.2470.20.camel@pengutronix.de>
References: <1469608292-6106-1-git-send-email-bibby.hsieh@mediatek.com>
 <1469608292-6106-4-git-send-email-bibby.hsieh@mediatek.com>
 <1469611430.2470.20.camel@pengutronix.de>
Message-ID: <1469677135.29230.7.camel@mtksdaap41>

Hi, Philipp,

Thanks for your comments.

On Wed, 2016-07-27 at 11:23 +0200, Philipp Zabel wrote:
> Am Mittwoch, den 27.07.2016, 16:31 +0800 schrieb Bibby Hsieh:
> > From: Junzhi Zhao <junzhi.zhao at mediatek.com>
> > 
> > Pixel clock should be 297MHz when resolution is 4K.
> 
> This patch does two different things, please don't conflate them.
> 
> First, it adds support for 16*3 and 2*3 factors between PLL and pixel
> clock. This should be a separate patch and does what this patch
> description says.
> 
> The second part moves the clocks into an array and adds an indirection
> to clock registration depending on of_match_node. This should be a
> separate patch. I suppose this change is in preparation for mt2701
> support, but I'm not sure yet if it is needed at all.
> 

Ok, I will move the change for mt2701 to another patch and send it until
mt2701 start upstream.

> regards
> Philipp
> 
> > Signed-off-by: Junzhi Zhao <junzhi.zhao at mediatek.com>
> > Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> > ---
> >  drivers/gpu/drm/mediatek/mtk_dpi.c |  149 +++++++++++++++++++++++-------------
> >  1 file changed, 96 insertions(+), 53 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
> > index d05ca79..fa390e0 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_dpi.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
> > @@ -60,14 +60,25 @@ enum mtk_dpi_out_color_format {
> >  	MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL
> >  };
> >  
> > +enum mtk_dpi_clk_id {
> > +	MTK_DPI_CLK_DPI_ENGINE,
> > +	MTK_DPI_CLK_DPI_PIXEL,
> > +	MTK_DPI_CLK_TVD_PLL,
> > +	MTK_DPI_CLK_COUNT,
> > +};
> > +
> > +static const char * const mtk_dpi_clk_names[MTK_DPI_CLK_COUNT] = {
> > +	[MTK_DPI_CLK_DPI_ENGINE] = "engine",
> > +	[MTK_DPI_CLK_DPI_PIXEL] = "pixel",
> > +	[MTK_DPI_CLK_TVD_PLL] = "pll",
> > +};
> > +
> >  struct mtk_dpi {
> >  	struct mtk_ddp_comp ddp_comp;
> >  	struct drm_encoder encoder;
> >  	void __iomem *regs;
> >  	struct device *dev;
> > -	struct clk *engine_clk;
> > -	struct clk *pixel_clk;
> > -	struct clk *tvd_clk;
> > +	struct clk *clk[MTK_DPI_CLK_COUNT];
> >  	int irq;
> >  	struct drm_display_mode mode;
> >  	enum mtk_dpi_out_color_format color_format;
> > @@ -76,6 +87,7 @@ struct mtk_dpi {
> >  	enum mtk_dpi_out_channel_swap channel_swap;
> >  	bool power_sta;
> >  	u8 power_ctl;
> > +	void *data;
> >  };
> >  
> >  static inline struct mtk_dpi *mtk_dpi_from_encoder(struct drm_encoder *e)
> > @@ -114,6 +126,10 @@ struct mtk_dpi_yc_limit {
> >  	u16 c_bottom;
> >  };
> >  
> > +struct mtk_dpi_conf {
> > +	int (*clk_config)(struct mtk_dpi *dpi, struct drm_display_mode *mode);
> > +};
> > +
> >  static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask)
> >  {
> >  	u32 tmp = readl(dpi->regs + offset) & ~mask;
> > @@ -377,8 +393,8 @@ static void mtk_dpi_power_off(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl)
> >  		return;
> >  
> >  	mtk_dpi_disable(dpi);
> > -	clk_disable_unprepare(dpi->pixel_clk);
> > -	clk_disable_unprepare(dpi->engine_clk);
> > +	clk_disable_unprepare(dpi->clk[MTK_DPI_CLK_DPI_PIXEL]);
> > +	clk_disable_unprepare(dpi->clk[MTK_DPI_CLK_DPI_ENGINE]);
> >  	dpi->power_sta = false;
> >  }
> >  
> > @@ -395,13 +411,13 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl)
> >  	if (dpi->power_sta)
> >  		return 0;
> >  
> > -	ret = clk_prepare_enable(dpi->engine_clk);
> > +	ret = clk_prepare_enable(dpi->clk[MTK_DPI_CLK_DPI_ENGINE]);
> >  	if (ret) {
> >  		dev_err(dpi->dev, "Failed to enable engine clock: %d\n", ret);
> >  		goto err_eng;
> >  	}
> >  
> > -	ret = clk_prepare_enable(dpi->pixel_clk);
> > +	ret = clk_prepare_enable(dpi->clk[MTK_DPI_CLK_DPI_PIXEL]);
> >  	if (ret) {
> >  		dev_err(dpi->dev, "Failed to enable pixel clock: %d\n", ret);
> >  		goto err_pixel;
> > @@ -412,7 +428,7 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl)
> >  	return 0;
> >  
> >  err_pixel:
> > -	clk_disable_unprepare(dpi->engine_clk);
> > +	clk_disable_unprepare(dpi->clk[MTK_DPI_CLK_DPI_ENGINE]);
> >  err_eng:
> >  	dpi->power_ctl &= ~pctl;
> >  	return ret;
> > @@ -428,34 +444,18 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
> >  	struct mtk_dpi_sync_param vsync_leven = { 0 };
> >  	struct mtk_dpi_sync_param vsync_rodd = { 0 };
> >  	struct mtk_dpi_sync_param vsync_reven = { 0 };
> > -	unsigned long pix_rate;
> > -	unsigned long pll_rate;
> > -	unsigned int factor;
> > +	struct mtk_dpi_conf *conf;
> > +	int ret;
> >  
> >  	if (!dpi) {
> >  		dev_err(dpi->dev, "invalid argument\n");
> >  		return -EINVAL;
> >  	}
> >  
> > -	pix_rate = 1000UL * mode->clock;
> > -	if (mode->clock <= 74000)
> > -		factor = 8 * 3;
> > -	else
> > -		factor = 4 * 3;
> > -	pll_rate = pix_rate * factor;
> > -
> > -	dev_dbg(dpi->dev, "Want PLL %lu Hz, pixel clock %lu Hz\n",
> > -		pll_rate, pix_rate);
> > -
> > -	clk_set_rate(dpi->tvd_clk, pll_rate);
> > -	pll_rate = clk_get_rate(dpi->tvd_clk);
> > -
> > -	pix_rate = pll_rate / factor;
> > -	clk_set_rate(dpi->pixel_clk, pix_rate);
> > -	pix_rate = clk_get_rate(dpi->pixel_clk);
> > -
> > -	dev_dbg(dpi->dev, "Got  PLL %lu Hz, pixel clock %lu Hz\n",
> > -		pll_rate, pix_rate);
> > +	conf = (struct mtk_dpi_conf *)dpi->data;
> > +	ret = conf->clk_config(dpi, mode);
> > +	if (ret)
> > +		dev_err(dpi->dev, "dpi clk set fail\n");
> >  
> >  	limit.c_bottom = 0x0010;
> >  	limit.c_top = 0x0FE0;
> > @@ -656,20 +656,83 @@ static const struct component_ops mtk_dpi_component_ops = {
> >  	.unbind = mtk_dpi_unbind,
> >  };
> >  
> > +static int mtk_dpi_parse_clk_from_dt(struct mtk_dpi *dpi,
> > +				     struct device_node *np)
> > +{
> > +	int i;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(mtk_dpi_clk_names); i++) {
> > +		dpi->clk[i] = of_clk_get_by_name(np,
> > +						  mtk_dpi_clk_names[i]);
> > +		if (IS_ERR(dpi->clk[i]))
> > +			return PTR_ERR(dpi->clk[i]);
> > +	}
> > +	return 0;
> > +}
> > +
> > +static int mt8173_clk_config(struct mtk_dpi *dpi, struct drm_display_mode *mode)
> > +{
> > +	unsigned long pix_rate;
> > +	unsigned long pll_rate;
> > +	unsigned int factor;
> > +
> > +	pix_rate = 1000UL * mode->clock;
> > +	if (mode->clock <= 27000)
> > +		factor = 16 * 3;
> > +	else if (mode->clock <= 74250)
> > +		factor = 8 * 3;
> > +	else if (mode->clock <= 167000)
> > +		factor = 4 * 3;
> > +	else
> > +		factor = 2 * 3;
> > +	pll_rate = pix_rate * factor;
> > +
> > +	dev_dbg(dpi->dev, "Want PLL %lu Hz, pixel clock %lu Hz\n",
> > +		pll_rate, pix_rate);
> > +
> > +	pll_rate = clk_get_rate(dpi->clk[MTK_DPI_CLK_TVD_PLL]);
> > +	pix_rate = pll_rate / factor;
> > +	clk_set_rate(dpi->clk[MTK_DPI_CLK_DPI_PIXEL], pix_rate);
> > +	dev_dbg(dpi->dev, "Got  PLL %lu Hz, pixel clock %lu Hz\n",
> > +		pll_rate, pix_rate);
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct mtk_dpi_conf mt8173_conf = {
> > +	.clk_config = mt8173_clk_config,
> > +};
> > +
> > +static const struct of_device_id mtk_dpi_of_ids[] = {
> > +	{ .compatible = "mediatek,mt8173-dpi",
> > +		.data = &mt8173_conf,
> > +	},
> > +	{}
> > +};
> > +
> >  static int mtk_dpi_probe(struct platform_device *pdev)
> >  {
> >  	struct device *dev = &pdev->dev;
> >  	struct mtk_dpi *dpi;
> >  	struct resource *mem;
> > +	struct device_node *np = dev->of_node;
> >  	struct device_node *ep, *bridge_node = NULL;
> >  	int comp_id;
> > +	const struct of_device_id *match;
> > +	struct mtk_dpi_conf *conf;
> >  	int ret;
> >  
> > +	match = of_match_node(mtk_dpi_of_ids, dev->of_node);
> > +	if (!match)
> > +		return -ENODEV;
> > +
> >  	dpi = devm_kzalloc(dev, sizeof(*dpi), GFP_KERNEL);
> >  	if (!dpi)
> >  		return -ENOMEM;
> >  
> >  	dpi->dev = dev;
> > +	dpi->data = (void *)match->data;
> > +	conf = (struct mtk_dpi_conf *)match->data;
> >  
> >  	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >  	dpi->regs = devm_ioremap_resource(dev, mem);
> > @@ -679,24 +742,9 @@ static int mtk_dpi_probe(struct platform_device *pdev)
> >  		return ret;
> >  	}
> >  
> > -	dpi->engine_clk = devm_clk_get(dev, "engine");
> > -	if (IS_ERR(dpi->engine_clk)) {
> > -		ret = PTR_ERR(dpi->engine_clk);
> > -		dev_err(dev, "Failed to get engine clock: %d\n", ret);
> > -		return ret;
> > -	}
> > -
> > -	dpi->pixel_clk = devm_clk_get(dev, "pixel");
> > -	if (IS_ERR(dpi->pixel_clk)) {
> > -		ret = PTR_ERR(dpi->pixel_clk);
> > -		dev_err(dev, "Failed to get pixel clock: %d\n", ret);
> > -		return ret;
> > -	}
> > -
> > -	dpi->tvd_clk = devm_clk_get(dev, "pll");
> > -	if (IS_ERR(dpi->tvd_clk)) {
> > -		ret = PTR_ERR(dpi->tvd_clk);
> > -		dev_err(dev, "Failed to get tvdpll clock: %d\n", ret);
> > +	ret = mtk_dpi_parse_clk_from_dt(dpi, np);
> > +	if (ret) {
> > +		dev_err(dev, "parse tvd div clk failed!");
> >  		return ret;
> >  	}
> >  
> > @@ -754,11 +802,6 @@ static int mtk_dpi_remove(struct platform_device *pdev)
> >  	return 0;
> >  }
> >  
> > -static const struct of_device_id mtk_dpi_of_ids[] = {
> > -	{ .compatible = "mediatek,mt8173-dpi", },
> > -	{}
> > -};
> > -
> >  struct platform_driver mtk_dpi_driver = {
> >  	.probe = mtk_dpi_probe,
> >  	.remove = mtk_dpi_remove,
> 
> 

-- 
Bibby



From yt.shen at mediatek.com  Thu Jul 28 00:17:36 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Thu, 28 Jul 2016 15:17:36 +0800
Subject: [PATCH v4 4/8] drm/mediatek: add support for Mediatek SoC MT2701
In-Reply-To: <1469671655.11841.85.camel@mtksdaap41>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
 <1468577274-6178-5-git-send-email-yt.shen@mediatek.com>
 <1468997599.11841.49.camel@mtksdaap41>
 <1469529774.4678.34.camel@mtksdaap41>
 <1469613816.2470.50.camel@pengutronix.de>
 <1469671655.11841.85.camel@mtksdaap41>
Message-ID: <1469690256.28644.42.camel@mtksdaap41>

Hi Philipp, CK,

On Thu, 2016-07-28 at 10:07 +0800, CK Hu wrote:
> Hi, YT:
> 
> On Wed, 2016-07-27 at 12:03 +0200, Philipp Zabel wrote:
> > Am Dienstag, den 26.07.2016, 18:42 +0800 schrieb YT Shen:
> > > Hi CK,
> > > 
> > > On Wed, 2016-07-20 at 14:53 +0800, CK Hu wrote:
> > > > Hi, YT:
> > > > 
> > > > Some comments inline.
> > > > 
> > > > On Fri, 2016-07-15 at 18:07 +0800, YT Shen wrote:
> > > > > This patch add support for the Mediatek MT2701 DISP subsystem.
> > > > > There is only one OVL engine in MT2701.
> > > > > 
> > > > > Signed-off-by: YT Shen <yt.shen at mediatek.com>
> > > > > ---
> > > > >  drivers/gpu/drm/mediatek/mtk_disp_ovl.c     |    6 ++++
> > > > >  drivers/gpu/drm/mediatek/mtk_disp_rdma.c    |    6 ++++
> > > > >  drivers/gpu/drm/mediatek/mtk_drm_ddp.c      |   41 +++++++++++++++++++++++++++
> > > > >  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |    7 +++++
> > > > >  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |    1 +
> > > > >  drivers/gpu/drm/mediatek/mtk_drm_drv.c      |   31 ++++++++++++++++++++
> > > > >  6 files changed, 92 insertions(+)
> > > > > 
> > > > 
> > > > [snip...]
> > > > 
> > > > >  
> > > > >  static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
> > > > > +	{ .compatible = "mediatek,mt2701-disp-ovl",   .data = (void *)MTK_DISP_OVL },
> > > > >  	{ .compatible = "mediatek,mt8173-disp-ovl",   .data = (void *)MTK_DISP_OVL },
> > > > > +	{ .compatible = "mediatek,mt2701-disp-rdma",  .data = (void *)MTK_DISP_RDMA },
> > > > >  	{ .compatible = "mediatek,mt8173-disp-rdma",  .data = (void *)MTK_DISP_RDMA },
> > > > > +	{ .compatible = "mediatek,mt2701-disp-wdma",  .data = (void *)MTK_DISP_WDMA },
> > > > 
> > > > Is WDMA different from MT8173 to MT2701. If they are the same, you need
> > > > not to add compatible of 'mediatek,mt2701-disp-wdma' because use
> > > > 'mediatek,mt8173-disp-wdma' is enough.
> > > Yes, the hardware has differences, so we need add new compatible
> > > 'mt2701-disp-wdma'
> > 
> > It would be nice if you could add a short paragraph to the patch
> > description about what the hardware differences are (probably just
> > changed register layout in most cases).
Thanks for the suggestions, we will add more descriptions in the future.

> 
> If you don't want to add description, you may separate the modification
> of OVL, RDMA, WDMA, PWM to different patch. And you send patch of OVL
> and RDMA first because you have related code modification for these two.
> You temporarily treat WDMA and PWM as MT8173 and it works. And one day
> you need to modify code of WDMA and PWM for MT2701, then you send the
> patch of WDMA and PWM and you need not to add any description because we
> can find out the difference from source code.

The display module connections is shown in mt2701_mtk_ddp_main[] and
mt2701_mtk_ddp_ext[].
OVL -> RDMA -> COLOR -> BLS(pwm) -> DSI
RDMA -> DPI

This patch series mainly focus on DSI support for MT2701 SoC and the
basic functions.  The BLS(pwm) and DPI parts are not included here.

We will remove 'mt2701-disp-wdma'. We didn't implement its driver and it
is unused now.

For the pwm part, we need the device node to establish the display
module connections.  The pwm compatible string is described in
"dt-bindings: pwm: Add MediaTek display PWM bindings" [1] and the
control is implemented in "pwm: Add MediaTek MT2701 display PWM driver
support" [2].

For the dpi part, we need the device node to establish the display
module connections.  The dpi patch will be in another patch series,
split out from "drm/mediatek: fix the wrong pixel clock when resolution
is 4K" [3].


[1] https://patchwork.kernel.org/patch/9222997/
[2] https://patchwork.kernel.org/patch/9223001/
[3] https://patchwork.kernel.org/patch/9249471/ 

Regards,
yt.shen

> 
> > 
> > regards
> > Philipp
> > 
> 
> Regards,
> CK
> 




From yt.shen at mediatek.com  Thu Jul 28 02:27:54 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Thu, 28 Jul 2016 17:27:54 +0800
Subject: [PATCH v5 00/10] MT2701 DRM support
Message-ID: <1469698084-20185-1-git-send-email-yt.shen@mediatek.com>

This is MT2701 DRM support PATCH v5, based on 4.7-rc1.
We add DSI interrupt control, transfer function for MIPI DSI panel support.
Most codes are the same, except some register changed.

For example:
 - DISP_OVL address offset changed, color format definition changed.
 - DISP_RDMA fifo size changed.
 - DISP_COLOR offset changed.
 - MIPI_TX setting changed.

We add a new component DDP_COMPONENT_BLS, and the connections are updated.
OVL -> RDMA -> COLOR -> BLS -> DSI
RDMA -> DPI
And we have shadow register support in MT2701.

Changes since v4:
- Add messages when timeout in mtk_disp_mutex_acquire()
- Add descriptions for DISP_REG_MUTEX registers
- Move connection settings for display modules to a separate patch
- Remove 'mt2701-disp-wdma' because it is unused
- Move cleaning up and renaming to a separate patch
- Use wait_event_interruptible_timeout() to replace polling
- Remove irq_num from mtk_dsi structure
- Remove redundant and debug codes

Changes since v3:
- Add DSI support for MIPI DSI panels
- Update BLS binding to PWM nodes
- Remove ufoe device nodes
- Remove redundant parentheses
- Remove global variable initialization

Changes since v2:
- Rename mtk_ddp_mux_sel to mtk_ddp_sout_sel
- Update mt2701_mtk_ddp_ext components
- Changed to prefix naming
- Reorder the patch series
- Use of_device_get_match_data() to get driver private data
- Use iopoll macros to implement mtk_disp_mutex_acquire()
- Removed empty device tree nodes

Changes since v1:
- Removed BLS bindings and codes, which belong to pwm driver
- Moved mtk_disp_mutex_acquire() just before mtk_crtc_ddp_config()
- Split patch into smaller parts
- Added const keyword to constant structure
- Removed codes for special memory align

The PATCH depends on the following patch:
https://patchwork.kernel.org/patch/8832441/ ("dt-bindings: ARM: Mediatek: Document bindings for MT2701")
https://patchwork.kernel.org/patch/9222997/ ("dt-bindings: pwm: Add MediaTek display PWM bindings")
https://patchwork.kernel.org/patch/9164029/ ("dt-bindings: mediatek: add descriptions for mediatek mt2701 iommu and smi")
https://patchwork.kernel.org/patch/9164017/ ("iommu/mediatek: move the common struct into header file")
https://patchwork.kernel.org/patch/9164025/ ("memory/mediatek: add support for mt2701")
https://patchwork.kernel.org/patch/9164041/ ("iommu/mediatek: add support for mtk iommu generation one HW")
https://patchwork.kernel.org/patch/9164013/ ("ARM: dts: mt2701: add iommu/smi dtsi node for mt2701")

Thanks,
yt.shen

YT Shen (8):
  drm/mediatek: rename macros, add chip prefix
  drm/mediatek: add *driver_data for different hardware settings
  drm/mediatek: add shadow register support
  drm/mediatek: update display module connections
  drm/mediatek: cleaning up and refine
  drm/mediatek: update DSI sub driver flow
  drm/mediatek: add support for Mediatek SoC MT2701
  arm: dts: mt2701: Add display subsystem related nodes for MT2701

shaoming chen (2):
  drm/mediatek: add dsi interrupt control
  drm/mediatek: add dsi transfer function

 arch/arm/boot/dts/mt2701.dtsi               |  100 +++++
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c     |   32 +-
 drivers/gpu/drm/mediatek/mtk_disp_rdma.c    |   17 +-
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c     |   75 ++--
 drivers/gpu/drm/mediatek/mtk_drm_ddp.c      |  137 +++++--
 drivers/gpu/drm/mediatek/mtk_drm_ddp.h      |    2 +
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |   34 +-
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |   14 +
 drivers/gpu/drm/mediatek/mtk_drm_drv.c      |   55 ++-
 drivers/gpu/drm/mediatek/mtk_drm_drv.h      |    9 +
 drivers/gpu/drm/mediatek/mtk_dsi.c          |  548 ++++++++++++++++++++++++---
 drivers/gpu/drm/mediatek/mtk_mipi_tx.c      |   67 +++-
 12 files changed, 930 insertions(+), 160 deletions(-)

-- 
1.7.9.5



From yt.shen at mediatek.com  Thu Jul 28 02:27:55 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Thu, 28 Jul 2016 17:27:55 +0800
Subject: [PATCH v5 01/10] drm/mediatek: rename macros, add chip prefix
In-Reply-To: <1469698084-20185-1-git-send-email-yt.shen@mediatek.com>
References: <1469698084-20185-1-git-send-email-yt.shen@mediatek.com>
Message-ID: <1469698084-20185-2-git-send-email-yt.shen@mediatek.com>

Add MT8173 prefix for hardware related macros.

Signed-off-by: YT Shen <yt.shen at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_drm_ddp.c |   60 ++++++++++++++++----------------
 1 file changed, 30 insertions(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
index 17ba935..2fc4321 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
@@ -36,21 +36,21 @@
 #define DISP_REG_MUTEX_MOD(n)	(0x2c + 0x20 * (n))
 #define DISP_REG_MUTEX_SOF(n)	(0x30 + 0x20 * (n))
 
-#define MUTEX_MOD_DISP_OVL0		BIT(11)
-#define MUTEX_MOD_DISP_OVL1		BIT(12)
-#define MUTEX_MOD_DISP_RDMA0		BIT(13)
-#define MUTEX_MOD_DISP_RDMA1		BIT(14)
-#define MUTEX_MOD_DISP_RDMA2		BIT(15)
-#define MUTEX_MOD_DISP_WDMA0		BIT(16)
-#define MUTEX_MOD_DISP_WDMA1		BIT(17)
-#define MUTEX_MOD_DISP_COLOR0		BIT(18)
-#define MUTEX_MOD_DISP_COLOR1		BIT(19)
-#define MUTEX_MOD_DISP_AAL		BIT(20)
-#define MUTEX_MOD_DISP_GAMMA		BIT(21)
-#define MUTEX_MOD_DISP_UFOE		BIT(22)
-#define MUTEX_MOD_DISP_PWM0		BIT(23)
-#define MUTEX_MOD_DISP_PWM1		BIT(24)
-#define MUTEX_MOD_DISP_OD		BIT(25)
+#define MT8173_MUTEX_MOD_DISP_OVL0		BIT(11)
+#define MT8173_MUTEX_MOD_DISP_OVL1		BIT(12)
+#define MT8173_MUTEX_MOD_DISP_RDMA0		BIT(13)
+#define MT8173_MUTEX_MOD_DISP_RDMA1		BIT(14)
+#define MT8173_MUTEX_MOD_DISP_RDMA2		BIT(15)
+#define MT8173_MUTEX_MOD_DISP_WDMA0		BIT(16)
+#define MT8173_MUTEX_MOD_DISP_WDMA1		BIT(17)
+#define MT8173_MUTEX_MOD_DISP_COLOR0		BIT(18)
+#define MT8173_MUTEX_MOD_DISP_COLOR1		BIT(19)
+#define MT8173_MUTEX_MOD_DISP_AAL		BIT(20)
+#define MT8173_MUTEX_MOD_DISP_GAMMA		BIT(21)
+#define MT8173_MUTEX_MOD_DISP_UFOE		BIT(22)
+#define MT8173_MUTEX_MOD_DISP_PWM0		BIT(23)
+#define MT8173_MUTEX_MOD_DISP_PWM1		BIT(24)
+#define MT8173_MUTEX_MOD_DISP_OD		BIT(25)
 
 #define MUTEX_SOF_SINGLE_MODE		0
 #define MUTEX_SOF_DSI0			1
@@ -80,21 +80,21 @@ struct mtk_ddp {
 };
 
 static const unsigned int mutex_mod[DDP_COMPONENT_ID_MAX] = {
-	[DDP_COMPONENT_AAL] = MUTEX_MOD_DISP_AAL,
-	[DDP_COMPONENT_COLOR0] = MUTEX_MOD_DISP_COLOR0,
-	[DDP_COMPONENT_COLOR1] = MUTEX_MOD_DISP_COLOR1,
-	[DDP_COMPONENT_GAMMA] = MUTEX_MOD_DISP_GAMMA,
-	[DDP_COMPONENT_OD] = MUTEX_MOD_DISP_OD,
-	[DDP_COMPONENT_OVL0] = MUTEX_MOD_DISP_OVL0,
-	[DDP_COMPONENT_OVL1] = MUTEX_MOD_DISP_OVL1,
-	[DDP_COMPONENT_PWM0] = MUTEX_MOD_DISP_PWM0,
-	[DDP_COMPONENT_PWM1] = MUTEX_MOD_DISP_PWM1,
-	[DDP_COMPONENT_RDMA0] = MUTEX_MOD_DISP_RDMA0,
-	[DDP_COMPONENT_RDMA1] = MUTEX_MOD_DISP_RDMA1,
-	[DDP_COMPONENT_RDMA2] = MUTEX_MOD_DISP_RDMA2,
-	[DDP_COMPONENT_UFOE] = MUTEX_MOD_DISP_UFOE,
-	[DDP_COMPONENT_WDMA0] = MUTEX_MOD_DISP_WDMA0,
-	[DDP_COMPONENT_WDMA1] = MUTEX_MOD_DISP_WDMA1,
+	[DDP_COMPONENT_AAL] = MT8173_MUTEX_MOD_DISP_AAL,
+	[DDP_COMPONENT_COLOR0] = MT8173_MUTEX_MOD_DISP_COLOR0,
+	[DDP_COMPONENT_COLOR1] = MT8173_MUTEX_MOD_DISP_COLOR1,
+	[DDP_COMPONENT_GAMMA] = MT8173_MUTEX_MOD_DISP_GAMMA,
+	[DDP_COMPONENT_OD] = MT8173_MUTEX_MOD_DISP_OD,
+	[DDP_COMPONENT_OVL0] = MT8173_MUTEX_MOD_DISP_OVL0,
+	[DDP_COMPONENT_OVL1] = MT8173_MUTEX_MOD_DISP_OVL1,
+	[DDP_COMPONENT_PWM0] = MT8173_MUTEX_MOD_DISP_PWM0,
+	[DDP_COMPONENT_PWM1] = MT8173_MUTEX_MOD_DISP_PWM1,
+	[DDP_COMPONENT_RDMA0] = MT8173_MUTEX_MOD_DISP_RDMA0,
+	[DDP_COMPONENT_RDMA1] = MT8173_MUTEX_MOD_DISP_RDMA1,
+	[DDP_COMPONENT_RDMA2] = MT8173_MUTEX_MOD_DISP_RDMA2,
+	[DDP_COMPONENT_UFOE] = MT8173_MUTEX_MOD_DISP_UFOE,
+	[DDP_COMPONENT_WDMA0] = MT8173_MUTEX_MOD_DISP_WDMA0,
+	[DDP_COMPONENT_WDMA1] = MT8173_MUTEX_MOD_DISP_WDMA1,
 };
 
 static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur,
-- 
1.7.9.5



From yt.shen at mediatek.com  Thu Jul 28 02:27:56 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Thu, 28 Jul 2016 17:27:56 +0800
Subject: [PATCH v5 02/10] drm/mediatek: add *driver_data for different
 hardware settings
In-Reply-To: <1469698084-20185-1-git-send-email-yt.shen@mediatek.com>
References: <1469698084-20185-1-git-send-email-yt.shen@mediatek.com>
Message-ID: <1469698084-20185-3-git-send-email-yt.shen@mediatek.com>

There are some hardware settings changed, between MT8173 & MT2701:
DISP_OVL address offset changed, color format definition changed.
DISP_RDMA fifo size changed.
DISP_COLOR offset changed.
And add prefix for mtk_ddp_main & mtk_ddp_ext & mutex_mod.

Signed-off-by: YT Shen <yt.shen at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c     |   26 ++++++++++++++++----------
 drivers/gpu/drm/mediatek/mtk_disp_rdma.c    |   11 +++++++++--
 drivers/gpu/drm/mediatek/mtk_drm_ddp.c      |   11 +++++++----
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |   27 +++++++++++++++++++++------
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |   13 +++++++++++++
 drivers/gpu/drm/mediatek/mtk_drm_drv.c      |   25 ++++++++++++++++++-------
 drivers/gpu/drm/mediatek/mtk_drm_drv.h      |    8 ++++++++
 7 files changed, 92 insertions(+), 29 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index 8f62671f..eb5c05e 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -40,8 +40,6 @@
 #define	OVL_RDMA_MEM_GMC	0x40402020
 
 #define OVL_CON_BYTE_SWAP	BIT(24)
-#define OVL_CON_CLRFMT_RGB565	(0 << 12)
-#define OVL_CON_CLRFMT_RGB888	(1 << 12)
 #define OVL_CON_CLRFMT_RGBA8888	(2 << 12)
 #define OVL_CON_CLRFMT_ARGB8888	(3 << 12)
 #define	OVL_CON_AEN		BIT(8)
@@ -136,18 +134,18 @@ static void mtk_ovl_layer_off(struct mtk_ddp_comp *comp, unsigned int idx)
 	writel(0x0, comp->regs + DISP_REG_OVL_RDMA_CTRL(idx));
 }
 
-static unsigned int ovl_fmt_convert(unsigned int fmt)
+static unsigned int ovl_fmt_convert(struct mtk_ddp_comp *comp, unsigned int fmt)
 {
 	switch (fmt) {
 	default:
 	case DRM_FORMAT_RGB565:
-		return OVL_CON_CLRFMT_RGB565;
+		return comp->data->ovl.fmt_rgb565;
 	case DRM_FORMAT_BGR565:
-		return OVL_CON_CLRFMT_RGB565 | OVL_CON_BYTE_SWAP;
+		return comp->data->ovl.fmt_rgb565 | OVL_CON_BYTE_SWAP;
 	case DRM_FORMAT_RGB888:
-		return OVL_CON_CLRFMT_RGB888;
+		return comp->data->ovl.fmt_rgb888;
 	case DRM_FORMAT_BGR888:
-		return OVL_CON_CLRFMT_RGB888 | OVL_CON_BYTE_SWAP;
+		return comp->data->ovl.fmt_rgb888 | OVL_CON_BYTE_SWAP;
 	case DRM_FORMAT_RGBX8888:
 	case DRM_FORMAT_RGBA8888:
 		return OVL_CON_CLRFMT_ARGB8888;
@@ -177,7 +175,7 @@ static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx,
 	if (!pending->enable)
 		mtk_ovl_layer_off(comp, idx);
 
-	con = ovl_fmt_convert(fmt);
+	con = ovl_fmt_convert(comp, fmt);
 	if (idx != 0)
 		con |= OVL_CON_AEN | OVL_CON_ALPHA;
 
@@ -185,7 +183,8 @@ static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx,
 	writel_relaxed(pitch, comp->regs + DISP_REG_OVL_PITCH(idx));
 	writel_relaxed(src_size, comp->regs + DISP_REG_OVL_SRC_SIZE(idx));
 	writel_relaxed(offset, comp->regs + DISP_REG_OVL_OFFSET(idx));
-	writel_relaxed(addr, comp->regs + DISP_REG_OVL_ADDR(idx));
+	writel_relaxed(addr, comp->regs + comp->data->ovl.addr_offset
+					+ idx * 0x20);
 
 	if (pending->enable)
 		mtk_ovl_layer_on(comp, idx);
@@ -269,6 +268,8 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	priv->ddp_comp.data = of_device_get_match_data(dev);
+
 	platform_set_drvdata(pdev, priv);
 
 	ret = component_add(dev, &mtk_disp_ovl_component_ops);
@@ -285,8 +286,13 @@ static int mtk_disp_ovl_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct mtk_ddp_comp_driver_data mt8173_ovl_driver_data = {
+	.ovl = {0x0f40, 0, 1 << 12}
+};
+
 static const struct of_device_id mtk_disp_ovl_driver_dt_match[] = {
-	{ .compatible = "mediatek,mt8173-disp-ovl", },
+	{ .compatible = "mediatek,mt8173-disp-ovl",
+	  .data = &mt8173_ovl_driver_data},
 	{},
 };
 MODULE_DEVICE_TABLE(of, mtk_disp_ovl_driver_dt_match);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
index 5fb80cb..fb0db50 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
@@ -122,7 +122,7 @@ static void mtk_rdma_config(struct mtk_ddp_comp *comp, unsigned int width,
 	 */
 	threshold = width * height * vrefresh * 4 * 7 / 1000000;
 	reg = RDMA_FIFO_UNDERFLOW_EN |
-	      RDMA_FIFO_PSEUDO_SIZE(SZ_8K) |
+	      RDMA_FIFO_PSEUDO_SIZE(comp->data->rdma_fifo_pseudo_size) |
 	      RDMA_OUTPUT_VALID_FIFO_THRESHOLD(threshold);
 	writel(reg, comp->regs + DISP_REG_RDMA_FIFO_CON);
 }
@@ -207,6 +207,8 @@ static int mtk_disp_rdma_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	priv->ddp_comp.data = of_device_get_match_data(dev);
+
 	platform_set_drvdata(pdev, priv);
 
 	ret = component_add(dev, &mtk_disp_rdma_component_ops);
@@ -223,8 +225,13 @@ static int mtk_disp_rdma_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct mtk_ddp_comp_driver_data mt8173_rdma_driver_data = {
+	.rdma_fifo_pseudo_size = SZ_8K,
+};
+
 static const struct of_device_id mtk_disp_rdma_driver_dt_match[] = {
-	{ .compatible = "mediatek,mt8173-disp-rdma", },
+	{ .compatible = "mediatek,mt8173-disp-rdma",
+	  .data = &mt8173_rdma_driver_data},
 	{},
 };
 MODULE_DEVICE_TABLE(of, mtk_disp_rdma_driver_dt_match);
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
index 2fc4321..8030769 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
@@ -77,9 +77,10 @@ struct mtk_ddp {
 	struct clk			*clk;
 	void __iomem			*regs;
 	struct mtk_disp_mutex		mutex[10];
+	const unsigned int		*mutex_mod;
 };
 
-static const unsigned int mutex_mod[DDP_COMPONENT_ID_MAX] = {
+static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = {
 	[DDP_COMPONENT_AAL] = MT8173_MUTEX_MOD_DISP_AAL,
 	[DDP_COMPONENT_COLOR0] = MT8173_MUTEX_MOD_DISP_COLOR0,
 	[DDP_COMPONENT_COLOR1] = MT8173_MUTEX_MOD_DISP_COLOR1,
@@ -247,7 +248,7 @@ void mtk_disp_mutex_add_comp(struct mtk_disp_mutex *mutex,
 		break;
 	default:
 		reg = readl_relaxed(ddp->regs + DISP_REG_MUTEX_MOD(mutex->id));
-		reg |= mutex_mod[id];
+		reg |= ddp->mutex_mod[id];
 		writel_relaxed(reg, ddp->regs + DISP_REG_MUTEX_MOD(mutex->id));
 		return;
 	}
@@ -273,7 +274,7 @@ void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex,
 		break;
 	default:
 		reg = readl_relaxed(ddp->regs + DISP_REG_MUTEX_MOD(mutex->id));
-		reg &= ~mutex_mod[id];
+		reg &= ~(ddp->mutex_mod[id]);
 		writel_relaxed(reg, ddp->regs + DISP_REG_MUTEX_MOD(mutex->id));
 		break;
 	}
@@ -326,6 +327,8 @@ static int mtk_ddp_probe(struct platform_device *pdev)
 		return PTR_ERR(ddp->regs);
 	}
 
+	ddp->mutex_mod = of_device_get_match_data(dev);
+
 	platform_set_drvdata(pdev, ddp);
 
 	return 0;
@@ -337,7 +340,7 @@ static int mtk_ddp_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id ddp_driver_dt_match[] = {
-	{ .compatible = "mediatek,mt8173-disp-mutex" },
+	{ .compatible = "mediatek,mt8173-disp-mutex", .data = mt8173_mutex_mod},
 	{},
 };
 MODULE_DEVICE_TABLE(of, ddp_driver_dt_match);
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
index 3970fcf..4b4e449 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
@@ -34,9 +34,8 @@
 #define DISP_REG_UFO_START			0x0000
 
 #define DISP_COLOR_CFG_MAIN			0x0400
-#define DISP_COLOR_START			0x0c00
-#define DISP_COLOR_WIDTH			0x0c50
-#define DISP_COLOR_HEIGHT			0x0c54
+#define DISP_COLOR_WIDTH			0x50
+#define DISP_COLOR_HEIGHT			0x54
 
 #define	OD_RELAY_MODE		BIT(0)
 
@@ -48,15 +47,15 @@
 static void mtk_color_config(struct mtk_ddp_comp *comp, unsigned int w,
 			     unsigned int h, unsigned int vrefresh)
 {
-	writel(w, comp->regs + DISP_COLOR_WIDTH);
-	writel(h, comp->regs + DISP_COLOR_HEIGHT);
+	writel(w, comp->regs + comp->data->color_offset + DISP_COLOR_WIDTH);
+	writel(h, comp->regs + comp->data->color_offset + DISP_COLOR_HEIGHT);
 }
 
 static void mtk_color_start(struct mtk_ddp_comp *comp)
 {
 	writel(COLOR_BYPASS_ALL | COLOR_SEQ_SEL,
 	       comp->regs + DISP_COLOR_CFG_MAIN);
-	writel(0x1, comp->regs + DISP_COLOR_START);
+	writel(0x1, comp->regs + comp->data->color_offset);
 }
 
 static void mtk_od_config(struct mtk_ddp_comp *comp, unsigned int w,
@@ -131,6 +130,16 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
 	[DDP_COMPONENT_WDMA1]	= { MTK_DISP_WDMA,	1, NULL },
 };
 
+static const struct mtk_ddp_comp_driver_data mt8173_color_driver_data = {
+	.color_offset = 0x0c00,
+};
+
+static const struct of_device_id mtk_disp_color_driver_dt_match[] = {
+	{ .compatible = "mediatek,mt8173-disp-color",
+	  .data = &mt8173_color_driver_data},
+	{},
+};
+
 int mtk_ddp_comp_get_id(struct device_node *node,
 			enum mtk_ddp_comp_type comp_type)
 {
@@ -153,6 +162,7 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
 	enum mtk_ddp_comp_type type;
 	struct device_node *larb_node;
 	struct platform_device *larb_pdev;
+	const struct of_device_id *match;
 
 	if (comp_id < 0 || comp_id >= DDP_COMPONENT_ID_MAX)
 		return -EINVAL;
@@ -177,6 +187,11 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
 
 	type = mtk_ddp_matches[comp_id].type;
 
+	if (type == MTK_DISP_COLOR) {
+		match = of_match_node(mtk_disp_color_driver_dt_match, node);
+		comp->data = match->data;
+	}
+
 	/* Only DMA capable components need the LARB property */
 	comp->larb_dev = NULL;
 	if (type != MTK_DISP_OVL &&
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
index 6b13ba9..53065c7 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
@@ -75,6 +75,18 @@ struct mtk_ddp_comp_funcs {
 			     struct mtk_plane_state *state);
 };
 
+struct mtk_ddp_comp_driver_data {
+	union {
+		struct ovl {
+			unsigned int addr_offset;
+			unsigned int fmt_rgb565;
+			unsigned int fmt_rgb888;
+		} ovl;
+		unsigned int rdma_fifo_pseudo_size;
+		unsigned int color_offset;
+	};
+};
+
 struct mtk_ddp_comp {
 	struct clk *clk;
 	void __iomem *regs;
@@ -82,6 +94,7 @@ struct mtk_ddp_comp {
 	struct device *larb_dev;
 	enum mtk_ddp_comp_id id;
 	const struct mtk_ddp_comp_funcs *funcs;
+	const struct mtk_ddp_comp_driver_data *data;
 };
 
 static inline void mtk_ddp_comp_config(struct mtk_ddp_comp *comp,
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index b1223d5..80b4f54 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -109,7 +109,7 @@ static const struct drm_mode_config_funcs mtk_drm_mode_config_funcs = {
 	.atomic_commit = mtk_atomic_commit,
 };
 
-static const enum mtk_ddp_comp_id mtk_ddp_main[] = {
+static const enum mtk_ddp_comp_id mt8173_mtk_ddp_main[] = {
 	DDP_COMPONENT_OVL0,
 	DDP_COMPONENT_COLOR0,
 	DDP_COMPONENT_AAL,
@@ -120,7 +120,7 @@ static const enum mtk_ddp_comp_id mtk_ddp_main[] = {
 	DDP_COMPONENT_PWM0,
 };
 
-static const enum mtk_ddp_comp_id mtk_ddp_ext[] = {
+static const enum mtk_ddp_comp_id mt8173_mtk_ddp_ext[] = {
 	DDP_COMPONENT_OVL1,
 	DDP_COMPONENT_COLOR1,
 	DDP_COMPONENT_GAMMA,
@@ -128,6 +128,13 @@ static const enum mtk_ddp_comp_id mtk_ddp_ext[] = {
 	DDP_COMPONENT_DPI0,
 };
 
+static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = {
+	.main_path = mt8173_mtk_ddp_main,
+	.main_len = ARRAY_SIZE(mt8173_mtk_ddp_main),
+	.ext_path = mt8173_mtk_ddp_ext,
+	.ext_len = ARRAY_SIZE(mt8173_mtk_ddp_ext),
+};
+
 static int mtk_drm_kms_init(struct drm_device *drm)
 {
 	struct mtk_drm_private *private = drm->dev_private;
@@ -170,17 +177,19 @@ static int mtk_drm_kms_init(struct drm_device *drm)
 	 * and each statically assigned to a crtc:
 	 * OVL0 -> COLOR0 -> AAL -> OD -> RDMA0 -> UFOE -> DSI0 ...
 	 */
-	ret = mtk_drm_crtc_create(drm, mtk_ddp_main, ARRAY_SIZE(mtk_ddp_main));
+	ret = mtk_drm_crtc_create(drm, private->data->main_path,
+				  private->data->main_len);
 	if (ret < 0)
 		goto err_component_unbind;
 	/* ... and OVL1 -> COLOR1 -> GAMMA -> RDMA1 -> DPI0. */
-	ret = mtk_drm_crtc_create(drm, mtk_ddp_ext, ARRAY_SIZE(mtk_ddp_ext));
+	ret = mtk_drm_crtc_create(drm, private->data->ext_path,
+				  private->data->ext_len);
 	if (ret < 0)
 		goto err_component_unbind;
 
 	/* Use OVL device for all DMA memory allocations */
-	np = private->comp_node[mtk_ddp_main[0]] ?:
-	     private->comp_node[mtk_ddp_ext[0]];
+	np = private->comp_node[private->data->main_path[0]] ?:
+	     private->comp_node[private->data->ext_path[0]];
 	pdev = of_find_device_by_node(np);
 	if (!pdev) {
 		ret = -ENODEV;
@@ -353,6 +362,7 @@ static int mtk_drm_probe(struct platform_device *pdev)
 
 	mutex_init(&private->commit.lock);
 	INIT_WORK(&private->commit.work, mtk_atomic_work);
+	private->data = of_device_get_match_data(dev);
 
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	private->config_regs = devm_ioremap_resource(dev, mem);
@@ -504,7 +514,8 @@ static SIMPLE_DEV_PM_OPS(mtk_drm_pm_ops, mtk_drm_sys_suspend,
 			 mtk_drm_sys_resume);
 
 static const struct of_device_id mtk_drm_of_ids[] = {
-	{ .compatible = "mediatek,mt8173-mmsys", },
+	{ .compatible = "mediatek,mt8173-mmsys",
+	  .data = &mt8173_mmsys_driver_data},
 	{ }
 };
 
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
index aa93894..fa0b106 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
@@ -28,6 +28,13 @@ struct drm_fb_helper;
 struct drm_property;
 struct regmap;
 
+struct mtk_mmsys_driver_data {
+	const enum mtk_ddp_comp_id *main_path;
+	unsigned int main_len;
+	const enum mtk_ddp_comp_id *ext_path;
+	unsigned int ext_len;
+};
+
 struct mtk_drm_private {
 	struct drm_device *drm;
 	struct device *dma_dev;
@@ -40,6 +47,7 @@ struct mtk_drm_private {
 	void __iomem *config_regs;
 	struct device_node *comp_node[DDP_COMPONENT_ID_MAX];
 	struct mtk_ddp_comp *ddp_comp[DDP_COMPONENT_ID_MAX];
+	const struct mtk_mmsys_driver_data *data;
 
 	struct {
 		struct drm_atomic_state *state;
-- 
1.7.9.5



From yt.shen at mediatek.com  Thu Jul 28 02:27:57 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Thu, 28 Jul 2016 17:27:57 +0800
Subject: [PATCH v5 03/10] drm/mediatek: add shadow register support
In-Reply-To: <1469698084-20185-1-git-send-email-yt.shen@mediatek.com>
References: <1469698084-20185-1-git-send-email-yt.shen@mediatek.com>
Message-ID: <1469698084-20185-4-git-send-email-yt.shen@mediatek.com>

We need to acquire mutex before using the resources,
and need to release it after finished.
So we don't need to write registers in the blanking period.

Signed-off-by: YT Shen <yt.shen at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c |   75 +++++++++++++++++++------------
 drivers/gpu/drm/mediatek/mtk_drm_ddp.c  |   25 +++++++++++
 drivers/gpu/drm/mediatek/mtk_drm_ddp.h  |    2 +
 drivers/gpu/drm/mediatek/mtk_drm_drv.h  |    1 +
 4 files changed, 74 insertions(+), 29 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index 24aa3ba..80d9641 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -315,6 +315,42 @@ static void mtk_crtc_ddp_hw_fini(struct mtk_drm_crtc *mtk_crtc)
 	pm_runtime_put(drm->dev);
 }
 
+static void mtk_crtc_ddp_config(struct drm_crtc *crtc)
+{
+	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
+	struct mtk_crtc_state *state = to_mtk_crtc_state(mtk_crtc->base.state);
+	struct mtk_ddp_comp *ovl = mtk_crtc->ddp_comp[0];
+	unsigned int i;
+
+	/*
+	 * TODO: instead of updating the registers here, we should prepare
+	 * working registers in atomic_commit and let the hardware command
+	 * queue update module registers on vblank.
+	 */
+	if (state->pending_config) {
+		mtk_ddp_comp_config(ovl, state->pending_width,
+				    state->pending_height,
+				    state->pending_vrefresh);
+
+		state->pending_config = false;
+	}
+
+	if (mtk_crtc->pending_planes) {
+		for (i = 0; i < OVL_LAYER_NR; i++) {
+			struct drm_plane *plane = &mtk_crtc->planes[i].base;
+			struct mtk_plane_state *plane_state;
+
+			plane_state = to_mtk_plane_state(plane->state);
+
+			if (plane_state->pending.config) {
+				mtk_ddp_comp_layer_config(ovl, i, plane_state);
+				plane_state->pending.config = false;
+			}
+		}
+		mtk_crtc->pending_planes = false;
+	}
+}
+
 static void mtk_drm_crtc_enable(struct drm_crtc *crtc)
 {
 	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
@@ -391,6 +427,7 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
 				      struct drm_crtc_state *old_crtc_state)
 {
 	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
+	struct mtk_drm_private *priv = crtc->dev->dev_private;
 	unsigned int pending_planes = 0;
 	int i;
 
@@ -409,6 +446,12 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
 	}
 	if (pending_planes)
 		mtk_crtc->pending_planes = true;
+
+	if (priv->data->shadow_register) {
+		mtk_disp_mutex_acquire(mtk_crtc->mutex);
+		mtk_crtc_ddp_config(crtc);
+		mtk_disp_mutex_release(mtk_crtc->mutex);
+	}
 }
 
 static const struct drm_crtc_funcs mtk_crtc_funcs = {
@@ -453,36 +496,10 @@ err_cleanup_crtc:
 void mtk_crtc_ddp_irq(struct drm_crtc *crtc, struct mtk_ddp_comp *ovl)
 {
 	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
-	struct mtk_crtc_state *state = to_mtk_crtc_state(mtk_crtc->base.state);
-	unsigned int i;
+	struct mtk_drm_private *priv = crtc->dev->dev_private;
 
-	/*
-	 * TODO: instead of updating the registers here, we should prepare
-	 * working registers in atomic_commit and let the hardware command
-	 * queue update module registers on vblank.
-	 */
-	if (state->pending_config) {
-		mtk_ddp_comp_config(ovl, state->pending_width,
-				    state->pending_height,
-				    state->pending_vrefresh);
-
-		state->pending_config = false;
-	}
-
-	if (mtk_crtc->pending_planes) {
-		for (i = 0; i < OVL_LAYER_NR; i++) {
-			struct drm_plane *plane = &mtk_crtc->planes[i].base;
-			struct mtk_plane_state *plane_state;
-
-			plane_state = to_mtk_plane_state(plane->state);
-
-			if (plane_state->pending.config) {
-				mtk_ddp_comp_layer_config(ovl, i, plane_state);
-				plane_state->pending.config = false;
-			}
-		}
-		mtk_crtc->pending_planes = false;
-	}
+	if (!priv->data->shadow_register)
+		mtk_crtc_ddp_config(crtc);
 
 	mtk_drm_finish_page_flip(mtk_crtc);
 }
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
index 8030769..b77d456 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
@@ -12,6 +12,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
@@ -32,10 +33,13 @@
 #define DISP_REG_CONFIG_MMSYS_CG_CON0		0x100
 
 #define DISP_REG_MUTEX_EN(n)	(0x20 + 0x20 * (n))
+#define DISP_REG_MUTEX(n)	(0x24 + 0x20 * (n))
 #define DISP_REG_MUTEX_RST(n)	(0x28 + 0x20 * (n))
 #define DISP_REG_MUTEX_MOD(n)	(0x2c + 0x20 * (n))
 #define DISP_REG_MUTEX_SOF(n)	(0x30 + 0x20 * (n))
 
+#define INT_MUTEX				BIT(1)
+
 #define MT8173_MUTEX_MOD_DISP_OVL0		BIT(11)
 #define MT8173_MUTEX_MOD_DISP_OVL1		BIT(12)
 #define MT8173_MUTEX_MOD_DISP_RDMA0		BIT(13)
@@ -300,6 +304,27 @@ void mtk_disp_mutex_disable(struct mtk_disp_mutex *mutex)
 	writel(0, ddp->regs + DISP_REG_MUTEX_EN(mutex->id));
 }
 
+void mtk_disp_mutex_acquire(struct mtk_disp_mutex *mutex)
+{
+	struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
+					   mutex[mutex->id]);
+	u32 tmp;
+
+	writel(1, ddp->regs + DISP_REG_MUTEX_EN(mutex->id));
+	writel(1, ddp->regs + DISP_REG_MUTEX(mutex->id));
+	if (readl_poll_timeout_atomic(ddp->regs + DISP_REG_MUTEX(mutex->id),
+				      tmp, tmp & INT_MUTEX, 1, 10000))
+		pr_err("could not acquire mutex %d\n", mutex->id);
+}
+
+void mtk_disp_mutex_release(struct mtk_disp_mutex *mutex)
+{
+	struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
+					   mutex[mutex->id]);
+
+	writel(0, ddp->regs + DISP_REG_MUTEX(mutex->id));
+}
+
 static int mtk_ddp_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp.h
index 92c1175..f9a7991 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.h
@@ -37,5 +37,7 @@ void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex,
 				enum mtk_ddp_comp_id id);
 void mtk_disp_mutex_unprepare(struct mtk_disp_mutex *mutex);
 void mtk_disp_mutex_put(struct mtk_disp_mutex *mutex);
+void mtk_disp_mutex_acquire(struct mtk_disp_mutex *mutex);
+void mtk_disp_mutex_release(struct mtk_disp_mutex *mutex);
 
 #endif /* MTK_DRM_DDP_H */
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
index fa0b106..94f8b66 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
@@ -33,6 +33,7 @@ struct mtk_mmsys_driver_data {
 	unsigned int main_len;
 	const enum mtk_ddp_comp_id *ext_path;
 	unsigned int ext_len;
+	bool shadow_register;
 };
 
 struct mtk_drm_private {
-- 
1.7.9.5



From yt.shen at mediatek.com  Thu Jul 28 02:27:58 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Thu, 28 Jul 2016 17:27:58 +0800
Subject: [PATCH v5 04/10] drm/mediatek: update display module connections
In-Reply-To: <1469698084-20185-1-git-send-email-yt.shen@mediatek.com>
References: <1469698084-20185-1-git-send-email-yt.shen@mediatek.com>
Message-ID: <1469698084-20185-5-git-send-email-yt.shen@mediatek.com>

update connections for OVL, RDMA, BLS, DSI

Signed-off-by: YT Shen <yt.shen at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_drm_ddp.c |   24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
index b77d456..329da541 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
@@ -32,6 +32,10 @@
 #define DISP_REG_CONFIG_DISP_RDMA1_MOUT_EN	0x0c8
 #define DISP_REG_CONFIG_MMSYS_CG_CON0		0x100
 
+#define DISP_REG_CONFIG_DISP_OVL_MOUT_EN	0x030
+#define DISP_REG_CONFIG_OUT_SEL			0x04c
+#define DISP_REG_CONFIG_DSI_SEL			0x050
+
 #define DISP_REG_MUTEX_EN(n)	(0x20 + 0x20 * (n))
 #define DISP_REG_MUTEX(n)	(0x24 + 0x20 * (n))
 #define DISP_REG_MUTEX_RST(n)	(0x28 + 0x20 * (n))
@@ -71,6 +75,10 @@
 #define DPI0_SEL_IN_RDMA1		0x1
 #define COLOR1_SEL_IN_OVL1		0x1
 
+#define OVL_MOUT_EN_RDMA		0x1
+#define BLS_TO_DSI_RDMA1_TO_DPI1	0x8
+#define DSI_SEL_IN_BLS			0x0
+
 struct mtk_disp_mutex {
 	int id;
 	bool claimed;
@@ -111,6 +119,9 @@ static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur,
 	if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_COLOR0) {
 		*addr = DISP_REG_CONFIG_DISP_OVL0_MOUT_EN;
 		value = OVL0_MOUT_EN_COLOR0;
+	} else if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_RDMA0) {
+		*addr = DISP_REG_CONFIG_DISP_OVL_MOUT_EN;
+		value = OVL_MOUT_EN_RDMA;
 	} else if (cur == DDP_COMPONENT_OD && next == DDP_COMPONENT_RDMA0) {
 		*addr = DISP_REG_CONFIG_DISP_OD_MOUT_EN;
 		value = OD_MOUT_EN_RDMA0;
@@ -148,6 +159,9 @@ static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur,
 	} else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) {
 		*addr = DISP_REG_CONFIG_DISP_COLOR1_SEL_IN;
 		value = COLOR1_SEL_IN_OVL1;
+	} else if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0) {
+		*addr = DISP_REG_CONFIG_DSI_SEL;
+		value = DSI_SEL_IN_BLS;
 	} else {
 		value = 0;
 	}
@@ -155,6 +169,14 @@ static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur,
 	return value;
 }
 
+static void mtk_ddp_sout_sel(void __iomem *config_regs,
+			    enum mtk_ddp_comp_id cur, enum mtk_ddp_comp_id next)
+{
+	if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0)
+		writel_relaxed(BLS_TO_DSI_RDMA1_TO_DPI1,
+			       config_regs + DISP_REG_CONFIG_OUT_SEL);
+}
+
 void mtk_ddp_add_comp_to_path(void __iomem *config_regs,
 			      enum mtk_ddp_comp_id cur,
 			      enum mtk_ddp_comp_id next)
@@ -167,6 +189,8 @@ void mtk_ddp_add_comp_to_path(void __iomem *config_regs,
 		writel_relaxed(reg, config_regs + addr);
 	}
 
+	mtk_ddp_sout_sel(config_regs, cur, next);
+
 	value = mtk_ddp_sel_in(cur, next, &addr);
 	if (value) {
 		reg = readl_relaxed(config_regs + addr) | value;
-- 
1.7.9.5



From yt.shen at mediatek.com  Thu Jul 28 02:27:59 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Thu, 28 Jul 2016 17:27:59 +0800
Subject: [PATCH v5 05/10] drm/mediatek: cleaning up and refine
In-Reply-To: <1469698084-20185-1-git-send-email-yt.shen@mediatek.com>
References: <1469698084-20185-1-git-send-email-yt.shen@mediatek.com>
Message-ID: <1469698084-20185-6-git-send-email-yt.shen@mediatek.com>

cleaning up unused define and refine function name and variable

Signed-off-by: shaoming chen <shaoming.chen at mediatek.com>
Signed-off-by: YT Shen <yt.shen at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_dsi.c     |   77 +++++++++++++++-----------------
 drivers/gpu/drm/mediatek/mtk_mipi_tx.c |    8 ++--
 2 files changed, 41 insertions(+), 44 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index 2d808e5..a9cf5a1 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -27,9 +27,6 @@
 
 #include "mtk_drm_ddp_comp.h"
 
-#define DSI_VIDEO_FIFO_DEPTH	(1920 / 4)
-#define DSI_HOST_FIFO_DEPTH	64
-
 #define DSI_START		0x00
 
 #define DSI_CON_CTRL		0x10
@@ -46,7 +43,7 @@
 #define MIX_MODE			BIT(17)
 
 #define DSI_TXRX_CTRL		0x18
-#define VC_NUM				(2 << 0)
+#define VC_NUM				BIT(1)
 #define LANE_NUM			(0xf << 2)
 #define DIS_EOT				BIT(6)
 #define NULL_EN				BIT(7)
@@ -158,11 +155,11 @@ static void mtk_dsi_mask(struct mtk_dsi *dsi, u32 offset, u32 mask, u32 data)
 	writel((temp & ~mask) | (data & mask), dsi->regs + offset);
 }
 
-static void dsi_phy_timconfig(struct mtk_dsi *dsi)
+static void mtk_dsi_phy_timconfig(struct mtk_dsi *dsi)
 {
 	u32 timcon0, timcon1, timcon2, timcon3;
-	unsigned int ui, cycle_time;
-	unsigned int lpx;
+	u32 ui, cycle_time;
+	u32 lpx;
 
 	ui = 1000 / dsi->data_rate + 0x01;
 	cycle_time = 8000 / dsi->data_rate + 0x01;
@@ -192,7 +189,7 @@ static void mtk_dsi_disable(struct mtk_dsi *dsi)
 	mtk_dsi_mask(dsi, DSI_CON_CTRL, DSI_EN, 0);
 }
 
-static void mtk_dsi_reset(struct mtk_dsi *dsi)
+static void mtk_dsi_reset_engine(struct mtk_dsi *dsi)
 {
 	mtk_dsi_mask(dsi, DSI_CON_CTRL, DSI_RESET, DSI_RESET);
 	mtk_dsi_mask(dsi, DSI_CON_CTRL, DSI_RESET, 0);
@@ -235,8 +232,8 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi)
 	}
 
 	mtk_dsi_enable(dsi);
-	mtk_dsi_reset(dsi);
-	dsi_phy_timconfig(dsi);
+	mtk_dsi_reset_engine(dsi);
+	mtk_dsi_phy_timconfig(dsi);
 
 	return 0;
 
@@ -249,33 +246,33 @@ err_refcount:
 	return ret;
 }
 
-static void dsi_clk_ulp_mode_enter(struct mtk_dsi *dsi)
+static void mtk_dsi_clk_ulp_mode_enter(struct mtk_dsi *dsi)
 {
 	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, 0);
 	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_ULPM_EN, 0);
 }
 
-static void dsi_clk_ulp_mode_leave(struct mtk_dsi *dsi)
+static void mtk_dsi_clk_ulp_mode_leave(struct mtk_dsi *dsi)
 {
 	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_ULPM_EN, 0);
 	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_WAKEUP_EN, LC_WAKEUP_EN);
 	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_WAKEUP_EN, 0);
 }
 
-static void dsi_lane0_ulp_mode_enter(struct mtk_dsi *dsi)
+static void mtk_dsi_lane0_ulp_mode_enter(struct mtk_dsi *dsi)
 {
 	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_HS_TX_EN, 0);
 	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_ULPM_EN, 0);
 }
 
-static void dsi_lane0_ulp_mode_leave(struct mtk_dsi *dsi)
+static void mtk_dsi_lane0_ulp_mode_leave(struct mtk_dsi *dsi)
 {
 	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_ULPM_EN, 0);
 	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_WAKEUP_EN, LD0_WAKEUP_EN);
 	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_WAKEUP_EN, 0);
 }
 
-static bool dsi_clk_hs_state(struct mtk_dsi *dsi)
+static bool mtk_dsi_clk_hs_state(struct mtk_dsi *dsi)
 {
 	u32 tmp_reg1;
 
@@ -283,15 +280,15 @@ static bool dsi_clk_hs_state(struct mtk_dsi *dsi)
 	return ((tmp_reg1 & LC_HS_TX_EN) == 1) ? true : false;
 }
 
-static void dsi_clk_hs_mode(struct mtk_dsi *dsi, bool enter)
+static void mtk_dsi_clk_hs_mode(struct mtk_dsi *dsi, bool enter)
 {
-	if (enter && !dsi_clk_hs_state(dsi))
+	if (enter && !mtk_dsi_clk_hs_state(dsi))
 		mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, LC_HS_TX_EN);
-	else if (!enter && dsi_clk_hs_state(dsi))
+	else if (!enter && mtk_dsi_clk_hs_state(dsi))
 		mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, 0);
 }
 
-static void dsi_set_mode(struct mtk_dsi *dsi)
+static void mtk_dsi_set_mode(struct mtk_dsi *dsi)
 {
 	u32 vid_mode = CMD_MODE;
 
@@ -306,7 +303,7 @@ static void dsi_set_mode(struct mtk_dsi *dsi)
 	writel(vid_mode, dsi->regs + DSI_MODE_CTRL);
 }
 
-static void dsi_ps_control_vact(struct mtk_dsi *dsi)
+static void mtk_dsi_ps_control_vact(struct mtk_dsi *dsi)
 {
 	struct videomode *vm = &dsi->vm;
 	u32 dsi_buf_bpp, ps_wc;
@@ -340,7 +337,7 @@ static void dsi_ps_control_vact(struct mtk_dsi *dsi)
 	writel(ps_wc, dsi->regs + DSI_HSTX_CKL_WC);
 }
 
-static void dsi_rxtx_control(struct mtk_dsi *dsi)
+static void mtk_dsi_rxtx_control(struct mtk_dsi *dsi)
 {
 	u32 tmp_reg;
 
@@ -365,9 +362,9 @@ static void dsi_rxtx_control(struct mtk_dsi *dsi)
 	writel(tmp_reg, dsi->regs + DSI_TXRX_CTRL);
 }
 
-static void dsi_ps_control(struct mtk_dsi *dsi)
+static void mtk_dsi_ps_control(struct mtk_dsi *dsi)
 {
-	unsigned int dsi_tmp_buf_bpp;
+	u32 dsi_tmp_buf_bpp;
 	u32 tmp_reg;
 
 	switch (dsi->format) {
@@ -397,12 +394,12 @@ static void dsi_ps_control(struct mtk_dsi *dsi)
 	writel(tmp_reg, dsi->regs + DSI_PSCTRL);
 }
 
-static void dsi_config_vdo_timing(struct mtk_dsi *dsi)
+static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi)
 {
-	unsigned int horizontal_sync_active_byte;
-	unsigned int horizontal_backporch_byte;
-	unsigned int horizontal_frontporch_byte;
-	unsigned int dsi_tmp_buf_bpp;
+	u32 horizontal_sync_active_byte;
+	u32 horizontal_backporch_byte;
+	u32 horizontal_frontporch_byte;
+	u32 dsi_tmp_buf_bpp;
 
 	struct videomode *vm = &dsi->vm;
 
@@ -431,7 +428,7 @@ static void dsi_config_vdo_timing(struct mtk_dsi *dsi)
 	writel(horizontal_backporch_byte, dsi->regs + DSI_HBP_WC);
 	writel(horizontal_frontporch_byte, dsi->regs + DSI_HFP_WC);
 
-	dsi_ps_control(dsi);
+	mtk_dsi_ps_control(dsi);
 }
 
 static void mtk_dsi_start(struct mtk_dsi *dsi)
@@ -448,8 +445,8 @@ static void mtk_dsi_poweroff(struct mtk_dsi *dsi)
 	if (--dsi->refcount != 0)
 		return;
 
-	dsi_lane0_ulp_mode_enter(dsi);
-	dsi_clk_ulp_mode_enter(dsi);
+	mtk_dsi_lane0_ulp_mode_enter(dsi);
+	mtk_dsi_clk_ulp_mode_enter(dsi);
 
 	mtk_dsi_disable(dsi);
 
@@ -479,18 +476,18 @@ static void mtk_output_dsi_enable(struct mtk_dsi *dsi)
 		return;
 	}
 
-	dsi_rxtx_control(dsi);
+	mtk_dsi_rxtx_control(dsi);
 
-	dsi_clk_ulp_mode_leave(dsi);
-	dsi_lane0_ulp_mode_leave(dsi);
-	dsi_clk_hs_mode(dsi, 0);
-	dsi_set_mode(dsi);
+	mtk_dsi_clk_ulp_mode_leave(dsi);
+	mtk_dsi_lane0_ulp_mode_leave(dsi);
+	mtk_dsi_clk_hs_mode(dsi, 0);
+	mtk_dsi_set_mode(dsi);
 
-	dsi_ps_control_vact(dsi);
-	dsi_config_vdo_timing(dsi);
+	mtk_dsi_ps_control_vact(dsi);
+	mtk_dsi_config_vdo_timing(dsi);
 
-	dsi_set_mode(dsi);
-	dsi_clk_hs_mode(dsi, 1);
+	mtk_dsi_set_mode(dsi);
+	mtk_dsi_clk_hs_mode(dsi, 1);
 
 	mtk_dsi_start(dsi);
 
diff --git a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
index cf8f38d..19481c7 100644
--- a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
+++ b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
@@ -126,7 +126,7 @@
 struct mtk_mipi_tx {
 	struct device *dev;
 	void __iomem *regs;
-	unsigned int data_rate;
+	u32 data_rate;
 	struct clk_hw pll_hw;
 	struct clk *pll;
 };
@@ -163,7 +163,7 @@ static void mtk_mipi_tx_update_bits(struct mtk_mipi_tx *mipi_tx, u32 offset,
 static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw)
 {
 	struct mtk_mipi_tx *mipi_tx = mtk_mipi_tx_from_clk_hw(hw);
-	unsigned int txdiv, txdiv0, txdiv1;
+	u8 txdiv, txdiv0, txdiv1;
 	u64 pcw;
 
 	dev_dbg(mipi_tx->dev, "prepare: %u Hz\n", mipi_tx->data_rate);
@@ -310,7 +310,7 @@ static const struct clk_ops mtk_mipi_tx_pll_ops = {
 static int mtk_mipi_tx_power_on_signal(struct phy *phy)
 {
 	struct mtk_mipi_tx *mipi_tx = phy_get_drvdata(phy);
-	unsigned int reg;
+	u32 reg;
 
 	for (reg = MIPITX_DSI_CLOCK_LANE;
 	     reg <= MIPITX_DSI_DATA_LANE3; reg += 4)
@@ -341,7 +341,7 @@ static int mtk_mipi_tx_power_on(struct phy *phy)
 static void mtk_mipi_tx_power_off_signal(struct phy *phy)
 {
 	struct mtk_mipi_tx *mipi_tx = phy_get_drvdata(phy);
-	unsigned int reg;
+	u32 reg;
 
 	mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_TOP_CON,
 			     RG_DSI_PAD_TIE_LOW_EN);
-- 
1.7.9.5



From yt.shen at mediatek.com  Thu Jul 28 02:28:00 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Thu, 28 Jul 2016 17:28:00 +0800
Subject: [PATCH v5 06/10] drm/mediatek: add dsi interrupt control
In-Reply-To: <1469698084-20185-1-git-send-email-yt.shen@mediatek.com>
References: <1469698084-20185-1-git-send-email-yt.shen@mediatek.com>
Message-ID: <1469698084-20185-7-git-send-email-yt.shen@mediatek.com>

From: shaoming chen <shaoming.chen at mediatek.com>

add dsi interrupt control

Signed-off-by: shaoming chen <shaoming.chen at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_dsi.c |   92 ++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index a9cf5a1..553443a 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -18,6 +18,7 @@
 #include <drm/drm_panel.h>
 #include <linux/clk.h>
 #include <linux/component.h>
+#include <linux/irq.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/of_graph.h>
@@ -29,6 +30,17 @@
 
 #define DSI_START		0x00
 
+#define DSI_INTEN		0x08
+
+#define DSI_INTSTA		0x0c
+#define LPRX_RD_RDY_INT_FLAG		BIT(0)
+#define CMD_DONE_INT_FLAG		BIT(1)
+#define TE_RDY_INT_FLAG			BIT(2)
+#define VM_DONE_INT_FLAG		BIT(3)
+#define EXT_TE_RDY_INT_FLAG		BIT(4)
+#define DSI_INT_ALL_BITS		0x7f
+#define DSI_BUSY			BIT(31)
+
 #define DSI_CON_CTRL		0x10
 #define DSI_RESET			BIT(0)
 #define DSI_EN				BIT(1)
@@ -71,6 +83,9 @@
 
 #define DSI_HSTX_CKL_WC		0x64
 
+#define DSI_RACK		0x84
+#define RACK				BIT(0)
+
 #define DSI_PHY_LCCON		0x104
 #define LC_HS_TX_EN			BIT(0)
 #define LC_ULPM_EN			BIT(1)
@@ -131,8 +146,13 @@ struct mtk_dsi {
 	struct videomode vm;
 	int refcount;
 	bool enabled;
+	int irq_data;
 };
 
+static wait_queue_head_t _dsi_cmd_done_wait_queue;
+static wait_queue_head_t _dsi_dcs_read_wait_queue;
+static wait_queue_head_t _dsi_wait_vm_done_queue;
+
 static inline struct mtk_dsi *encoder_to_dsi(struct drm_encoder *e)
 {
 	return container_of(e, struct mtk_dsi, encoder);
@@ -437,6 +457,55 @@ static void mtk_dsi_start(struct mtk_dsi *dsi)
 	writel(1, dsi->regs + DSI_START);
 }
 
+static void mtk_dsi_set_interrupt_enable(struct mtk_dsi *dsi)
+{
+	u32 inten = DSI_INT_ALL_BITS;
+
+	if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO)
+		inten &= ~(TE_RDY_INT_FLAG | EXT_TE_RDY_INT_FLAG);
+
+	writel(inten, dsi->regs + DSI_INTEN);
+}
+
+static void mtk_dsi_irq_wakeup(struct mtk_dsi *dsi, u32 irq_bit)
+{
+	dsi->irq_data |= irq_bit;
+}
+
+static irqreturn_t mtk_dsi_irq(int irq, void *dev_id)
+{
+	struct mtk_dsi *dsi = dev_id;
+
+	u32 status, tmp;
+
+	status = readl(dsi->regs + DSI_INTSTA);
+
+	if (status & LPRX_RD_RDY_INT_FLAG) {
+		do {
+			mtk_dsi_mask(dsi, DSI_RACK, RACK, RACK);
+			tmp = readl(dsi->regs + DSI_INTSTA);
+		} while (tmp & DSI_BUSY);
+
+		mtk_dsi_mask(dsi, DSI_INTSTA, LPRX_RD_RDY_INT_FLAG, 0);
+		mtk_dsi_irq_wakeup(dsi, LPRX_RD_RDY_INT_FLAG);
+		wake_up_interruptible(&_dsi_dcs_read_wait_queue);
+	}
+
+	if (status & CMD_DONE_INT_FLAG) {
+		mtk_dsi_mask(dsi, DSI_INTSTA, CMD_DONE_INT_FLAG, 0);
+		mtk_dsi_irq_wakeup(dsi, CMD_DONE_INT_FLAG);
+		wake_up_interruptible(&_dsi_cmd_done_wait_queue);
+	}
+
+	if (status & VM_DONE_INT_FLAG) {
+		mtk_dsi_mask(dsi, DSI_INTSTA, VM_DONE_INT_FLAG, 0);
+		mtk_dsi_irq_wakeup(dsi, VM_DONE_INT_FLAG);
+		wake_up_interruptible(&_dsi_wait_vm_done_queue);
+	}
+
+	return IRQ_HANDLED;
+}
+
 static void mtk_dsi_poweroff(struct mtk_dsi *dsi)
 {
 	if (WARN_ON(dsi->refcount == 0))
@@ -485,6 +554,7 @@ static void mtk_output_dsi_enable(struct mtk_dsi *dsi)
 
 	mtk_dsi_ps_control_vact(dsi);
 	mtk_dsi_config_vdo_timing(dsi);
+	mtk_dsi_set_interrupt_enable(dsi);
 
 	mtk_dsi_set_mode(dsi);
 	mtk_dsi_clk_hs_mode(dsi, 1);
@@ -804,6 +874,7 @@ static int mtk_dsi_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct device_node *remote_node, *endpoint;
 	struct resource *regs;
+	int irq_num;
 	int comp_id;
 	int ret;
 
@@ -880,8 +951,29 @@ static int mtk_dsi_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	irq_num = platform_get_irq(pdev, 0);
+	if (irq_num < 0) {
+		dev_err(&pdev->dev, "failed to request dsi irq resource\n");
+		return -EPROBE_DEFER;
+	}
+
+	irq_set_status_flags(irq_num, IRQ_TYPE_LEVEL_LOW);
+	ret = devm_request_irq(&pdev->dev, irq_num, mtk_dsi_irq,
+			       IRQF_TRIGGER_LOW, dev_name(&pdev->dev), dsi);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to request mediatek dsi irq\n");
+		return -EPROBE_DEFER;
+	}
+
+	dsi->irq_data = 0;
+	dev_info(dev, "dsi irq num is 0x%x\n", irq_num);
+
 	platform_set_drvdata(pdev, dsi);
 
+	init_waitqueue_head(&_dsi_cmd_done_wait_queue);
+	init_waitqueue_head(&_dsi_dcs_read_wait_queue);
+	init_waitqueue_head(&_dsi_wait_vm_done_queue);
+
 	return component_add(&pdev->dev, &mtk_dsi_component_ops);
 }
 
-- 
1.7.9.5



From yt.shen at mediatek.com  Thu Jul 28 02:28:01 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Thu, 28 Jul 2016 17:28:01 +0800
Subject: [PATCH v5 07/10] drm/mediatek: add dsi transfer function
In-Reply-To: <1469698084-20185-1-git-send-email-yt.shen@mediatek.com>
References: <1469698084-20185-1-git-send-email-yt.shen@mediatek.com>
Message-ID: <1469698084-20185-8-git-send-email-yt.shen@mediatek.com>

From: shaoming chen <shaoming.chen at mediatek.com>

add dsi read/write commands for transfer function

Signed-off-by: shaoming chen <shaoming.chen at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_dsi.c |  286 ++++++++++++++++++++++++++++++++++++
 1 file changed, 286 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index 553443a..1d36524 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -24,6 +24,7 @@
 #include <linux/of_graph.h>
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
+#include <video/mipi_display.h>
 #include <video/videomode.h>
 
 #include "mtk_drm_ddp_comp.h"
@@ -81,8 +82,16 @@
 #define DSI_HBP_WC		0x54
 #define DSI_HFP_WC		0x58
 
+#define DSI_CMDQ_SIZE		0x60
+#define CMDQ_SIZE		0x3f
+
 #define DSI_HSTX_CKL_WC		0x64
 
+#define DSI_RX_DATA0		0x74
+#define DSI_RX_DATA1		0x78
+#define DSI_RX_DATA2		0x7c
+#define DSI_RX_DATA3		0x80
+
 #define DSI_RACK		0x84
 #define RACK				BIT(0)
 
@@ -118,8 +127,25 @@
 #define CLK_HS_POST			(0xff << 8)
 #define CLK_HS_EXIT			(0xff << 16)
 
+#define DSI_CMDQ0		0x180
+
 #define NS_TO_CYCLE(n, c)    ((n) / (c) + (((n) % (c)) ? 1 : 0))
 
+#define MTK_DSI_HOST_IS_READ(type) \
+	((type == MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM) || \
+	(type == MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM) || \
+	(type == MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM) || \
+	(type == MIPI_DSI_DCS_READ))
+
+#define MTK_DSI_HOST_IS_WRITE(type) \
+	((type == MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM) || \
+	(type == MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM) || \
+	(type == MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM) || \
+	(type == MIPI_DSI_DCS_SHORT_WRITE) || \
+	(type == MIPI_DSI_DCS_SHORT_WRITE_PARAM) || \
+	(type == MIPI_DSI_GENERIC_LONG_WRITE) || \
+	(type == MIPI_DSI_DCS_LONG_WRITE))
+
 struct phy;
 
 struct mtk_dsi {
@@ -149,6 +175,17 @@ struct mtk_dsi {
 	int irq_data;
 };
 
+struct dsi_rxtx_data {
+	u8 byte0;
+	u8 byte1;
+	u8 byte2;
+	u8 byte3;
+};
+
+struct dsi_tx_cmdq_regs {
+	struct dsi_rxtx_data data[128];
+};
+
 static wait_queue_head_t _dsi_cmd_done_wait_queue;
 static wait_queue_head_t _dsi_dcs_read_wait_queue;
 static wait_queue_head_t _dsi_wait_vm_done_queue;
@@ -813,9 +850,258 @@ static int mtk_dsi_host_detach(struct mipi_dsi_host *host,
 	return 0;
 }
 
+static void mtk_dsi_set_cmdq(void __iomem *reg, u32 mask, u32 data)
+{
+	u32 temp = readl(reg);
+
+	writel((temp & ~mask) | (data & mask), reg);
+}
+
+static void mtk_dsi_wait_for_idle(struct mtk_dsi *dsi)
+{
+	u32 timeout_ms = 500000; /* total 1s ~ 2s timeout */
+
+	while (timeout_ms--) {
+		if (!(readl(dsi->regs + DSI_INTSTA) & DSI_BUSY))
+			break;
+
+		usleep_range(2, 4);
+	}
+
+	if (timeout_ms == 0) {
+		dev_info(dsi->dev, "polling dsi wait not busy timeout!\n");
+
+		mtk_dsi_enable(dsi);
+		mtk_dsi_reset_engine(dsi);
+	}
+}
+
+static void mtk_dsi_wait_for_cmd_done(struct mtk_dsi *dsi)
+{
+	s32 ret = 0;
+	unsigned long timeout = msecs_to_jiffies(500);
+
+	ret = wait_event_interruptible_timeout(_dsi_cmd_done_wait_queue,
+			dsi->irq_data & CMD_DONE_INT_FLAG, timeout);
+	if (ret == 0) {
+		dev_info(dsi->dev, "dsi wait engine cmd done fail\n");
+		mtk_dsi_enable(dsi);
+		mtk_dsi_reset_engine(dsi);
+		return;
+	}
+
+	dsi->irq_data &= ~CMD_DONE_INT_FLAG;
+}
+
+static ssize_t mtk_dsi_host_read_cmd(struct mtk_dsi *dsi,
+				     const struct mipi_dsi_msg *msg)
+{
+	u8 max_try_count = 5;
+	u32 recv_cnt, tmp_val;
+	struct dsi_rxtx_data read_data0, read_data1, read_data2, read_data3;
+	u8 config, type, data0, data1;
+	s32 ret;
+
+	u8 *buffer = msg->rx_buf;
+	u8 buffer_size = msg->rx_len;
+
+	if (readl(dsi->regs + DSI_MODE_CTRL) & 0x03) {
+		dev_info(dsi->dev, "dsi engine is not command mode\n");
+		return -1;
+	}
+
+	if (!buffer) {
+		dev_info(dsi->dev, "dsi receive buffer size may be NULL\n");
+		return -1;
+	}
+
+	do {
+		if (max_try_count == 0) {
+			dev_info(dsi->dev, "dsi engine read counter has been maxinum\n");
+			return -1;
+		}
+
+		max_try_count--;
+		recv_cnt = 0;
+
+		mtk_dsi_wait_for_idle(dsi);
+
+		config = 0x04;
+		data0 = *((u8 *)(msg->tx_buf));
+
+		if (buffer_size < 3)
+			type = MIPI_DSI_DCS_READ;
+		else
+			type = MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM;
+
+		data1 = 0;
+
+		tmp_val = (data1 << 24) | (data0 << 16) | (type << 8) | config;
+
+		writel(tmp_val, dsi->regs + DSI_CMDQ0);
+		mtk_dsi_mask(dsi, DSI_CMDQ_SIZE, CMDQ_SIZE, 1);
+
+		mtk_dsi_start(dsi);
+
+		/* 2s timeout*/
+		ret = wait_event_interruptible_timeout(_dsi_dcs_read_wait_queue,
+				dsi->irq_data & LPRX_RD_RDY_INT_FLAG, timeout);
+		if (ret == 0) {
+			dev_info(dsi->dev, "Wait DSI read ready timeout!!!\n");
+
+			mtk_dsi_enable(dsi);
+			mtk_dsi_reset_engine(dsi);
+
+			return ret;
+		}
+
+		dsi->irq_data &= ~LPRX_RD_RDY_INT_FLAG;
+
+		*(u32 *)(&read_data0) = readl(dsi->regs + DSI_RX_DATA0);
+		*(u32 *)(&read_data1) = readl(dsi->regs + DSI_RX_DATA1);
+		*(u32 *)(&read_data2) = readl(dsi->regs + DSI_RX_DATA2);
+		*(u32 *)(&read_data3) = readl(dsi->regs + DSI_RX_DATA3);
+
+		type = read_data0.byte0;
+
+		if (type == MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE ||
+		    type == MIPI_DSI_RX_DCS_LONG_READ_RESPONSE) {
+
+			/*
+			 * Data ID(1 byte) + Word Count(2 bytes) + ECC(1 byte) +
+			 * data 0 + ...+ data WC-1 + CHECKSUM (2 bytes)
+			 */
+			recv_cnt = read_data0.byte1 + read_data0.byte2 * 16;
+			dev_info(dsi->dev, "long packet size: %d\n", recv_cnt);
+
+			/*
+			 * the buffer size is 16 bytes once, so the data payload
+			 * is, 16 - bytes(data ID + WC + ECC + CHECKSUM), if
+			 * over 10 bytes, it will be read again
+			 */
+			if (recv_cnt > 10)
+				recv_cnt = 10;
+
+			if (recv_cnt > buffer_size)
+				recv_cnt = buffer_size;
+
+			if (recv_cnt <= 4) {
+				memcpy(buffer, &read_data1, recv_cnt);
+			} else if (recv_cnt <= 8) {
+				memcpy(buffer, &read_data1, 4);
+				memcpy(buffer + 4, &read_data2, recv_cnt - 4);
+			} else {
+				memcpy(buffer, &read_data1, 4);
+				memcpy(buffer + 4, &read_data2, 4);
+				memcpy(buffer + 8, &read_data3, recv_cnt - 8);
+			}
+		} else if (type == MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE ||
+			   type == MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE ||
+			   type == MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE ||
+			   type == MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE) {
+
+			if (type == MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE ||
+			    type == MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE)
+				recv_cnt = 1;
+			else
+				recv_cnt = 2;
+
+			if (recv_cnt > buffer_size)
+				recv_cnt = buffer_size;
+
+			memcpy(buffer, &read_data0.byte1, recv_cnt);
+		} else if (type == MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT) {
+			dev_info(dsi->dev, "packet type is 0x02, try again\n");
+		} else {
+			dev_info(dsi->dev, "packet type(0x%x) cannot be non-recognize\n",
+				 type);
+
+			return 0;
+		}
+	} while (type == MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT);
+
+	dev_info(dsi->dev, "dsi get %d byte data from the panel address(0x%x)\n",
+		 recv_cnt, *((u8 *)(msg->tx_buf)));
+
+	return recv_cnt;
+}
+
+static ssize_t mtk_dsi_host_write_cmd(struct mtk_dsi *dsi,
+				      const struct mipi_dsi_msg *msg)
+{
+	u32 i;
+	u32 goto_addr, mask_para, set_para, reg_val;
+	void __iomem *cmdq_reg;
+	u8 config, type, data0, data1;
+	u16 wc16;
+	const char *tx_buf = msg->tx_buf;
+	struct dsi_tx_cmdq_regs *dsi_cmd_reg;
+
+	dsi_cmd_reg = (struct dsi_tx_cmdq_regs *)(dsi->regs + DSI_CMDQ0);
+
+	mtk_dsi_wait_for_idle(dsi);
+
+	if (msg->tx_len > 2) {
+		config = 2;
+		type = msg->type;
+		wc16 = msg->tx_len;
+
+		reg_val = (wc16 << 16) | (type << 8) | config;
+
+		writel(reg_val, &dsi_cmd_reg->data[0]);
+
+		for (i = 0; i < msg->tx_len; i++) {
+			goto_addr = (u32)(&dsi_cmd_reg->data[1].byte0) + i;
+			mask_para = (0xff << ((goto_addr & 0x3) * 8));
+			set_para = (tx_buf[i] << ((goto_addr & 0x3) * 8));
+			cmdq_reg = (void __iomem *)(goto_addr & (~0x3));
+			mtk_dsi_set_cmdq(cmdq_reg, mask_para, set_para);
+		}
+
+		mtk_dsi_mask(dsi, DSI_CMDQ_SIZE, CMDQ_SIZE,
+			     1 + (msg->tx_len + 3) / 4);
+	} else {
+		config = 0;
+		data0 = tx_buf[0];
+		if (msg->tx_len == 2) {
+			type = MIPI_DSI_DCS_SHORT_WRITE_PARAM;
+			data1 = tx_buf[1];
+		} else {
+			type = MIPI_DSI_DCS_SHORT_WRITE;
+			data1 = 0;
+		}
+
+		reg_val = (data1 << 24) | (data0 << 16) | (type << 8) | config;
+
+		writel(reg_val, &dsi_cmd_reg->data[0]);
+		mtk_dsi_mask(dsi, DSI_CMDQ_SIZE, CMDQ_SIZE, 1);
+	}
+
+	mtk_dsi_start(dsi);
+	mtk_dsi_wait_for_cmd_done(dsi);
+
+	return 0;
+}
+
+static ssize_t mtk_dsi_host_transfer(struct mipi_dsi_host *host,
+				     const struct mipi_dsi_msg *msg)
+{
+	struct mtk_dsi *dsi = host_to_dsi(host);
+	u8 type = msg->type;
+	ssize_t ret = 0;
+
+	if (MTK_DSI_HOST_IS_READ(type))
+		ret = mtk_dsi_host_read_cmd(dsi, msg);
+	else if (MTK_DSI_HOST_IS_WRITE(type))
+		ret = mtk_dsi_host_write_cmd(dsi, msg);
+
+	return ret;
+}
+
 static const struct mipi_dsi_host_ops mtk_dsi_ops = {
 	.attach = mtk_dsi_host_attach,
 	.detach = mtk_dsi_host_detach,
+	.transfer = mtk_dsi_host_transfer,
 };
 
 static int mtk_dsi_bind(struct device *dev, struct device *master, void *data)
-- 
1.7.9.5



From yt.shen at mediatek.com  Thu Jul 28 02:28:02 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Thu, 28 Jul 2016 17:28:02 +0800
Subject: [PATCH v5 08/10] drm/mediatek: update DSI sub driver flow
In-Reply-To: <1469698084-20185-1-git-send-email-yt.shen@mediatek.com>
References: <1469698084-20185-1-git-send-email-yt.shen@mediatek.com>
Message-ID: <1469698084-20185-9-git-send-email-yt.shen@mediatek.com>

This patch update enable/disable flow of DSI module and MIPI TX module

Signed-off-by: shaoming chen <shaoming.chen at mediatek.com>
Signed-off-by: YT Shen <yt.shen at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_dsi.c     |  104 ++++++++++++++++++++++++++------
 drivers/gpu/drm/mediatek/mtk_mipi_tx.c |   32 +++++-----
 2 files changed, 103 insertions(+), 33 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index 1d36524..2646f83 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -95,6 +95,8 @@
 #define DSI_RACK		0x84
 #define RACK				BIT(0)
 
+#define DSI_MEM_CONTI		0x90
+
 #define DSI_PHY_LCCON		0x104
 #define LC_HS_TX_EN			BIT(0)
 #define LC_ULPM_EN			BIT(1)
@@ -127,6 +129,10 @@
 #define CLK_HS_POST			(0xff << 8)
 #define CLK_HS_EXIT			(0xff << 16)
 
+#define DSI_VM_CMD_CON		0x130
+#define VM_CMD_EN			BIT(0)
+#define TS_VFP_EN			BIT(5)
+
 #define DSI_CMDQ0		0x180
 
 #define NS_TO_CYCLE(n, c)    ((n) / (c) + (((n) % (c)) ? 1 : 0))
@@ -266,7 +272,9 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi)
 	 * mipi_ratio is mipi clk coefficient for balance the pixel clk in mipi.
 	 * we set mipi_ratio is 1.05.
 	 */
-	dsi->data_rate = dsi->vm.pixelclock * 3 * 21 / (1 * 1000 * 10);
+	dsi->data_rate = dsi->vm.pixelclock * 12 * 21;
+	dsi->data_rate /= (dsi->lanes * 1000 * 10);
+	dev_info(dev, "set mipitx's data rate: %dMHz\n", dsi->data_rate);
 
 	ret = clk_set_rate(dsi->hs_clk, dsi->data_rate * 1000000);
 	if (ret < 0) {
@@ -288,10 +296,6 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi)
 		goto err_disable_engine_clk;
 	}
 
-	mtk_dsi_enable(dsi);
-	mtk_dsi_reset_engine(dsi);
-	mtk_dsi_phy_timconfig(dsi);
-
 	return 0;
 
 err_disable_engine_clk:
@@ -306,7 +310,7 @@ err_refcount:
 static void mtk_dsi_clk_ulp_mode_enter(struct mtk_dsi *dsi)
 {
 	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, 0);
-	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_ULPM_EN, 0);
+	mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_ULPM_EN, LC_ULPM_EN);
 }
 
 static void mtk_dsi_clk_ulp_mode_leave(struct mtk_dsi *dsi)
@@ -319,7 +323,7 @@ static void mtk_dsi_clk_ulp_mode_leave(struct mtk_dsi *dsi)
 static void mtk_dsi_lane0_ulp_mode_enter(struct mtk_dsi *dsi)
 {
 	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_HS_TX_EN, 0);
-	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_ULPM_EN, 0);
+	mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_ULPM_EN, LD0_ULPM_EN);
 }
 
 static void mtk_dsi_lane0_ulp_mode_leave(struct mtk_dsi *dsi)
@@ -355,11 +359,21 @@ static void mtk_dsi_set_mode(struct mtk_dsi *dsi)
 		if ((dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) &&
 		    !(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE))
 			vid_mode = BURST_MODE;
+		else
+			vid_mode = SYNC_EVENT_MODE;
 	}
 
 	writel(vid_mode, dsi->regs + DSI_MODE_CTRL);
 }
 
+static void mtk_dsi_set_vm_cmd(struct mtk_dsi *dsi)
+{
+	writel(0x3c, dsi->regs + DSI_MEM_CONTI);
+
+	mtk_dsi_mask(dsi, DSI_VM_CMD_CON, VM_CMD_EN, VM_CMD_EN);
+	mtk_dsi_mask(dsi, DSI_VM_CMD_CON, TS_VFP_EN, TS_VFP_EN);
+}
+
 static void mtk_dsi_ps_control_vact(struct mtk_dsi *dsi)
 {
 	struct videomode *vm = &dsi->vm;
@@ -416,6 +430,9 @@ static void mtk_dsi_rxtx_control(struct mtk_dsi *dsi)
 		break;
 	}
 
+	tmp_reg |= (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) << 6;
+	tmp_reg |= (dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET) >> 3;
+
 	writel(tmp_reg, dsi->regs + DSI_TXRX_CTRL);
 }
 
@@ -494,6 +511,16 @@ static void mtk_dsi_start(struct mtk_dsi *dsi)
 	writel(1, dsi->regs + DSI_START);
 }
 
+static void mtk_dsi_stop(struct mtk_dsi *dsi)
+{
+	writel(0, dsi->regs + DSI_START);
+}
+
+static void mtk_dsi_set_cmd_mode(struct mtk_dsi *dsi)
+{
+	writel(CMD_MODE, dsi->regs + DSI_MODE_CTRL);
+}
+
 static void mtk_dsi_set_interrupt_enable(struct mtk_dsi *dsi)
 {
 	u32 inten = DSI_INT_ALL_BITS;
@@ -543,6 +570,27 @@ static irqreturn_t mtk_dsi_irq(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+static void mtk_dsi_switch_to_cmd_mode(struct mtk_dsi *dsi)
+{
+	s32 ret = 0;
+	unsigned long timeout = msecs_to_jiffies(500);
+
+	mtk_dsi_set_cmd_mode(dsi);
+
+	ret = wait_event_interruptible_timeout(_dsi_wait_vm_done_queue,
+				dsi->irq_data & VM_DONE_INT_FLAG, timeout);
+	if (ret == 0) {
+		dev_info(dsi->dev, "dsi wait engine idle timeout\n");
+
+		mtk_dsi_enable(dsi);
+		mtk_dsi_reset_engine(dsi);
+
+		return;
+	}
+
+	dsi->irq_data &= ~VM_DONE_INT_FLAG;
+}
+
 static void mtk_dsi_poweroff(struct mtk_dsi *dsi)
 {
 	if (WARN_ON(dsi->refcount == 0))
@@ -551,6 +599,17 @@ static void mtk_dsi_poweroff(struct mtk_dsi *dsi)
 	if (--dsi->refcount != 0)
 		return;
 
+	mtk_dsi_switch_to_cmd_mode(dsi);
+
+	if (dsi->panel) {
+		if (drm_panel_unprepare(dsi->panel)) {
+			DRM_ERROR("failed to unprepare the panel\n");
+			return;
+		}
+	}
+
+	mtk_dsi_reset_engine(dsi);
+
 	mtk_dsi_lane0_ulp_mode_enter(dsi);
 	mtk_dsi_clk_ulp_mode_enter(dsi);
 
@@ -569,29 +628,37 @@ static void mtk_output_dsi_enable(struct mtk_dsi *dsi)
 	if (dsi->enabled)
 		return;
 
-	if (dsi->panel) {
-		if (drm_panel_prepare(dsi->panel)) {
-			DRM_ERROR("failed to setup the panel\n");
-			return;
-		}
-	}
-
 	ret = mtk_dsi_poweron(dsi);
 	if (ret < 0) {
 		DRM_ERROR("failed to power on dsi\n");
 		return;
 	}
 
+	usleep_range(20000, 21000);
+
 	mtk_dsi_rxtx_control(dsi);
+	mtk_dsi_phy_timconfig(dsi);
+	mtk_dsi_ps_control_vact(dsi);
+	mtk_dsi_set_vm_cmd(dsi);
+	mtk_dsi_config_vdo_timing(dsi);
+	mtk_dsi_set_interrupt_enable(dsi);
 
+	mtk_dsi_enable(dsi);
 	mtk_dsi_clk_ulp_mode_leave(dsi);
 	mtk_dsi_lane0_ulp_mode_leave(dsi);
 	mtk_dsi_clk_hs_mode(dsi, 0);
-	mtk_dsi_set_mode(dsi);
 
-	mtk_dsi_ps_control_vact(dsi);
-	mtk_dsi_config_vdo_timing(dsi);
-	mtk_dsi_set_interrupt_enable(dsi);
+	if (dsi->panel) {
+		if (drm_panel_prepare(dsi->panel)) {
+			DRM_ERROR("failed to prepare the panel\n");
+			return;
+		}
+
+		if (drm_panel_enable(dsi->panel)) {
+			DRM_ERROR("failed to enable the panel\n");
+			return;
+		}
+	}
 
 	mtk_dsi_set_mode(dsi);
 	mtk_dsi_clk_hs_mode(dsi, 1);
@@ -613,6 +680,7 @@ static void mtk_output_dsi_disable(struct mtk_dsi *dsi)
 		}
 	}
 
+	mtk_dsi_stop(dsi);
 	mtk_dsi_poweroff(dsi);
 
 	dsi->enabled = false;
diff --git a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
index 19481c7..0666f15 100644
--- a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
+++ b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
@@ -168,7 +168,9 @@ static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw)
 
 	dev_dbg(mipi_tx->dev, "prepare: %u Hz\n", mipi_tx->data_rate);
 
-	if (mipi_tx->data_rate >= 500000000) {
+	if (mipi_tx->data_rate > 1250000000) {
+		return -EINVAL;
+	} else if (mipi_tx->data_rate >= 500000000) {
 		txdiv = 1;
 		txdiv0 = 0;
 		txdiv1 = 0;
@@ -192,6 +194,10 @@ static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw)
 		return -EINVAL;
 	}
 
+	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_TOP_CON,
+				RG_DSI_LNT_IMP_CAL_CODE | RG_DSI_LNT_HS_BIAS_EN,
+				(8 << 4) | RG_DSI_LNT_HS_BIAS_EN);
+
 	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_BG_CON,
 				RG_DSI_VOUT_MSK |
 				RG_DSI_BG_CKEN | RG_DSI_BG_CORE_EN,
@@ -201,24 +207,18 @@ static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw)
 
 	usleep_range(30, 100);
 
-	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_TOP_CON,
-				RG_DSI_LNT_IMP_CAL_CODE | RG_DSI_LNT_HS_BIAS_EN,
-				(8 << 4) | RG_DSI_LNT_HS_BIAS_EN);
-
-	mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_CON,
-			     RG_DSI_CKG_LDOOUT_EN | RG_DSI_LDOCORE_EN);
+	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_CON,
+				RG_DSI_CKG_LDOOUT_EN | RG_DSI_LDOCORE_EN,
+				RG_DSI_CKG_LDOOUT_EN | RG_DSI_LDOCORE_EN);
 
 	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_PWR,
 				RG_DSI_MPPLL_SDM_PWR_ON |
 				RG_DSI_MPPLL_SDM_ISO_EN,
 				RG_DSI_MPPLL_SDM_PWR_ON);
 
-	mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON0,
-			       RG_DSI_MPPLL_PLL_EN);
-
 	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_CON0,
-				RG_DSI_MPPLL_TXDIV0 | RG_DSI_MPPLL_TXDIV1 |
-				RG_DSI_MPPLL_PREDIV,
+				RG_DSI_MPPLL_PREDIV | RG_DSI_MPPLL_TXDIV0 |
+				RG_DSI_MPPLL_TXDIV1 | RG_DSI_MPPLL_POSDIV,
 				(txdiv0 << 3) | (txdiv1 << 5));
 
 	/*
@@ -233,10 +233,12 @@ static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw)
 		      26000000);
 	writel(pcw, mipi_tx->regs + MIPITX_DSI_PLL_CON2);
 
-	mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_PLL_CON1,
-			     RG_DSI_MPPLL_SDM_FRA_EN);
+	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_CON1,
+				RG_DSI_MPPLL_SDM_FRA_EN,
+				RG_DSI_MPPLL_SDM_FRA_EN);
 
-	mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_PLL_CON0, RG_DSI_MPPLL_PLL_EN);
+	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_CON0,
+				RG_DSI_MPPLL_PLL_EN, RG_DSI_MPPLL_PLL_EN);
 
 	usleep_range(20, 100);
 
-- 
1.7.9.5



From yt.shen at mediatek.com  Thu Jul 28 02:28:03 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Thu, 28 Jul 2016 17:28:03 +0800
Subject: [PATCH v5 09/10] drm/mediatek: add support for Mediatek SoC MT2701
In-Reply-To: <1469698084-20185-1-git-send-email-yt.shen@mediatek.com>
References: <1469698084-20185-1-git-send-email-yt.shen@mediatek.com>
Message-ID: <1469698084-20185-10-git-send-email-yt.shen@mediatek.com>

This patch add support for the Mediatek MT2701 DISP subsystem.
There is only one OVL engine in MT2701.

Signed-off-by: YT Shen <yt.shen at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c     |    6 ++++++
 drivers/gpu/drm/mediatek/mtk_disp_rdma.c    |    6 ++++++
 drivers/gpu/drm/mediatek/mtk_drm_ddp.c      |   17 +++++++++++++++
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |    7 +++++++
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |    1 +
 drivers/gpu/drm/mediatek/mtk_drm_drv.c      |   30 +++++++++++++++++++++++++++
 drivers/gpu/drm/mediatek/mtk_dsi.c          |    1 +
 drivers/gpu/drm/mediatek/mtk_mipi_tx.c      |   27 +++++++++++++++++++++++-
 8 files changed, 94 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index eb5c05e..1da0a71 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -286,11 +286,17 @@ static int mtk_disp_ovl_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct mtk_ddp_comp_driver_data mt2701_ovl_driver_data = {
+	.ovl = {0x0040, 1 << 12, 0}
+};
+
 static const struct mtk_ddp_comp_driver_data mt8173_ovl_driver_data = {
 	.ovl = {0x0f40, 0, 1 << 12}
 };
 
 static const struct of_device_id mtk_disp_ovl_driver_dt_match[] = {
+	{ .compatible = "mediatek,mt2701-disp-ovl",
+	  .data = &mt2701_ovl_driver_data},
 	{ .compatible = "mediatek,mt8173-disp-ovl",
 	  .data = &mt8173_ovl_driver_data},
 	{},
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
index fb0db50..506a353 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
@@ -225,11 +225,17 @@ static int mtk_disp_rdma_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct mtk_ddp_comp_driver_data mt2701_rdma_driver_data = {
+	.rdma_fifo_pseudo_size = SZ_4K,
+};
+
 static const struct mtk_ddp_comp_driver_data mt8173_rdma_driver_data = {
 	.rdma_fifo_pseudo_size = SZ_8K,
 };
 
 static const struct of_device_id mtk_disp_rdma_driver_dt_match[] = {
+	{ .compatible = "mediatek,mt2701-disp-rdma",
+	  .data = &mt2701_rdma_driver_data},
 	{ .compatible = "mediatek,mt8173-disp-rdma",
 	  .data = &mt8173_rdma_driver_data},
 	{},
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
index 329da541..7678ac0 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
@@ -60,6 +60,13 @@
 #define MT8173_MUTEX_MOD_DISP_PWM1		BIT(24)
 #define MT8173_MUTEX_MOD_DISP_OD		BIT(25)
 
+#define MT2701_MUTEX_MOD_DISP_OVL		BIT(3)
+#define MT2701_MUTEX_MOD_DISP_WDMA		BIT(6)
+#define MT2701_MUTEX_MOD_DISP_COLOR		BIT(7)
+#define MT2701_MUTEX_MOD_DISP_BLS		BIT(9)
+#define MT2701_MUTEX_MOD_DISP_RDMA0		BIT(10)
+#define MT2701_MUTEX_MOD_DISP_RDMA1		BIT(12)
+
 #define MUTEX_SOF_SINGLE_MODE		0
 #define MUTEX_SOF_DSI0			1
 #define MUTEX_SOF_DSI1			2
@@ -92,6 +99,15 @@ struct mtk_ddp {
 	const unsigned int		*mutex_mod;
 };
 
+static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+	[DDP_COMPONENT_BLS] = MT2701_MUTEX_MOD_DISP_BLS,
+	[DDP_COMPONENT_COLOR0] = MT2701_MUTEX_MOD_DISP_COLOR,
+	[DDP_COMPONENT_OVL0] = MT2701_MUTEX_MOD_DISP_OVL,
+	[DDP_COMPONENT_RDMA0] = MT2701_MUTEX_MOD_DISP_RDMA0,
+	[DDP_COMPONENT_RDMA1] = MT2701_MUTEX_MOD_DISP_RDMA1,
+	[DDP_COMPONENT_WDMA0] = MT2701_MUTEX_MOD_DISP_WDMA,
+};
+
 static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = {
 	[DDP_COMPONENT_AAL] = MT8173_MUTEX_MOD_DISP_AAL,
 	[DDP_COMPONENT_COLOR0] = MT8173_MUTEX_MOD_DISP_COLOR0,
@@ -389,6 +405,7 @@ static int mtk_ddp_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id ddp_driver_dt_match[] = {
+	{ .compatible = "mediatek,mt2701-disp-mutex", .data = mt2701_mutex_mod},
 	{ .compatible = "mediatek,mt8173-disp-mutex", .data = mt8173_mutex_mod},
 	{},
 };
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
index 4b4e449..465819b 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
@@ -112,6 +112,7 @@ struct mtk_ddp_comp_match {
 
 static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
 	[DDP_COMPONENT_AAL]	= { MTK_DISP_AAL,	0, NULL },
+	[DDP_COMPONENT_BLS]	= { MTK_DISP_PWM,	0, NULL },
 	[DDP_COMPONENT_COLOR0]	= { MTK_DISP_COLOR,	0, &ddp_color },
 	[DDP_COMPONENT_COLOR1]	= { MTK_DISP_COLOR,	1, &ddp_color },
 	[DDP_COMPONENT_DPI0]	= { MTK_DPI,		0, NULL },
@@ -130,11 +131,17 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
 	[DDP_COMPONENT_WDMA1]	= { MTK_DISP_WDMA,	1, NULL },
 };
 
+static const struct mtk_ddp_comp_driver_data mt2701_color_driver_data = {
+	.color_offset = 0x0f00,
+};
+
 static const struct mtk_ddp_comp_driver_data mt8173_color_driver_data = {
 	.color_offset = 0x0c00,
 };
 
 static const struct of_device_id mtk_disp_color_driver_dt_match[] = {
+	{ .compatible = "mediatek,mt2701-disp-color",
+	  .data = &mt2701_color_driver_data},
 	{ .compatible = "mediatek,mt8173-disp-color",
 	  .data = &mt8173_color_driver_data},
 	{},
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
index 53065c7..0850aa4 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
@@ -40,6 +40,7 @@ enum mtk_ddp_comp_type {
 
 enum mtk_ddp_comp_id {
 	DDP_COMPONENT_AAL,
+	DDP_COMPONENT_BLS,
 	DDP_COMPONENT_COLOR0,
 	DDP_COMPONENT_COLOR1,
 	DDP_COMPONENT_DPI0,
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index 80b4f54..ebaa08a 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -109,6 +109,19 @@ static const struct drm_mode_config_funcs mtk_drm_mode_config_funcs = {
 	.atomic_commit = mtk_atomic_commit,
 };
 
+static const enum mtk_ddp_comp_id mt2701_mtk_ddp_main[] = {
+	DDP_COMPONENT_OVL0,
+	DDP_COMPONENT_RDMA0,
+	DDP_COMPONENT_COLOR0,
+	DDP_COMPONENT_BLS,
+	DDP_COMPONENT_DSI0,
+};
+
+static const enum mtk_ddp_comp_id mt2701_mtk_ddp_ext[] = {
+	DDP_COMPONENT_RDMA1,
+	DDP_COMPONENT_DPI0,
+};
+
 static const enum mtk_ddp_comp_id mt8173_mtk_ddp_main[] = {
 	DDP_COMPONENT_OVL0,
 	DDP_COMPONENT_COLOR0,
@@ -128,6 +141,14 @@ static const enum mtk_ddp_comp_id mt8173_mtk_ddp_ext[] = {
 	DDP_COMPONENT_DPI0,
 };
 
+static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = {
+	.main_path = mt2701_mtk_ddp_main,
+	.main_len = ARRAY_SIZE(mt2701_mtk_ddp_main),
+	.ext_path = mt2701_mtk_ddp_ext,
+	.ext_len = ARRAY_SIZE(mt2701_mtk_ddp_ext),
+	.shadow_register = true,
+};
+
 static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = {
 	.main_path = mt8173_mtk_ddp_main,
 	.main_len = ARRAY_SIZE(mt8173_mtk_ddp_main),
@@ -331,16 +352,23 @@ static const struct component_master_ops mtk_drm_ops = {
 };
 
 static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
+	{ .compatible = "mediatek,mt2701-disp-ovl",   .data = (void *)MTK_DISP_OVL },
 	{ .compatible = "mediatek,mt8173-disp-ovl",   .data = (void *)MTK_DISP_OVL },
+	{ .compatible = "mediatek,mt2701-disp-rdma",  .data = (void *)MTK_DISP_RDMA },
 	{ .compatible = "mediatek,mt8173-disp-rdma",  .data = (void *)MTK_DISP_RDMA },
 	{ .compatible = "mediatek,mt8173-disp-wdma",  .data = (void *)MTK_DISP_WDMA },
+	{ .compatible = "mediatek,mt2701-disp-color", .data = (void *)MTK_DISP_COLOR },
 	{ .compatible = "mediatek,mt8173-disp-color", .data = (void *)MTK_DISP_COLOR },
 	{ .compatible = "mediatek,mt8173-disp-aal",   .data = (void *)MTK_DISP_AAL},
 	{ .compatible = "mediatek,mt8173-disp-gamma", .data = (void *)MTK_DISP_GAMMA, },
 	{ .compatible = "mediatek,mt8173-disp-ufoe",  .data = (void *)MTK_DISP_UFOE },
+	{ .compatible = "mediatek,mt2701-dsi",	      .data = (void *)MTK_DSI },
 	{ .compatible = "mediatek,mt8173-dsi",        .data = (void *)MTK_DSI },
+	{ .compatible = "mediatek,mt2701-dpi",	      .data = (void *)MTK_DPI },
 	{ .compatible = "mediatek,mt8173-dpi",        .data = (void *)MTK_DPI },
+	{ .compatible = "mediatek,mt2701-disp-mutex", .data = (void *)MTK_DISP_MUTEX },
 	{ .compatible = "mediatek,mt8173-disp-mutex", .data = (void *)MTK_DISP_MUTEX },
+	{ .compatible = "mediatek,mt2701-disp-pwm",   .data = (void *)MTK_DISP_PWM },
 	{ .compatible = "mediatek,mt8173-disp-pwm",   .data = (void *)MTK_DISP_PWM },
 	{ .compatible = "mediatek,mt8173-disp-od",    .data = (void *)MTK_DISP_OD },
 	{ }
@@ -514,6 +542,8 @@ static SIMPLE_DEV_PM_OPS(mtk_drm_pm_ops, mtk_drm_sys_suspend,
 			 mtk_drm_sys_resume);
 
 static const struct of_device_id mtk_drm_of_ids[] = {
+	{ .compatible = "mediatek,mt2701-mmsys",
+	  .data = &mt2701_mmsys_driver_data},
 	{ .compatible = "mediatek,mt8173-mmsys",
 	  .data = &mt8173_mmsys_driver_data},
 	{ }
diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index 2646f83..0d7e6ba 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -1342,6 +1342,7 @@ static int mtk_dsi_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id mtk_dsi_of_match[] = {
+	{ .compatible = "mediatek,mt2701-dsi" },
 	{ .compatible = "mediatek,mt8173-dsi" },
 	{ },
 };
diff --git a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
index 0666f15..083d3fd 100644
--- a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
+++ b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
@@ -16,6 +16,7 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/phy/phy.h>
 
@@ -87,6 +88,9 @@
 
 #define MIPITX_DSI_PLL_CON2	0x58
 
+#define MIPITX_DSI_PLL_TOP	0x64
+#define RG_DSI_MPPLL_PRESERVE		(0xff << 8)
+
 #define MIPITX_DSI_PLL_PWR	0x68
 #define RG_DSI_MPPLL_SDM_PWR_ON		BIT(0)
 #define RG_DSI_MPPLL_SDM_ISO_EN		BIT(1)
@@ -127,6 +131,8 @@ struct mtk_mipi_tx {
 	struct device *dev;
 	void __iomem *regs;
 	u32 data_rate;
+	const struct mtk_mipitx_data *driver_data;
+
 	struct clk_hw pll_hw;
 	struct clk *pll;
 };
@@ -245,6 +251,10 @@ static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw)
 	mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON1,
 			       RG_DSI_MPPLL_SDM_SSC_EN);
 
+	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_TOP,
+				RG_DSI_MPPLL_PRESERVE,
+				mipi_tx->driver_data->data);
+
 	return 0;
 }
 
@@ -257,6 +267,9 @@ static void mtk_mipi_tx_pll_unprepare(struct clk_hw *hw)
 	mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON0,
 			       RG_DSI_MPPLL_PLL_EN);
 
+	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_TOP,
+				RG_DSI_MPPLL_PRESERVE, 0);
+
 	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_PWR,
 				RG_DSI_MPPLL_SDM_ISO_EN |
 				RG_DSI_MPPLL_SDM_PWR_ON,
@@ -393,6 +406,7 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev)
 	if (!mipi_tx)
 		return -ENOMEM;
 
+	mipi_tx->driver_data = of_device_get_match_data(dev);
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	mipi_tx->regs = devm_ioremap_resource(dev, mem);
 	if (IS_ERR(mipi_tx->regs)) {
@@ -450,8 +464,19 @@ static int mtk_mipi_tx_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct mtk_mipitx_data mt2701_mipitx_data = {
+	.data = (3 << 8)
+};
+
+static const struct mtk_mipitx_data mt8173_mipitx_data = {
+	.data = (0 << 8)
+};
+
 static const struct of_device_id mtk_mipi_tx_match[] = {
-	{ .compatible = "mediatek,mt8173-mipi-tx", },
+	{ .compatible = "mediatek,mt2701-mipi-tx",
+	  .data = &mt2701_mipitx_data },
+	{ .compatible = "mediatek,mt8173-mipi-tx",
+	  .data = &mt8173_mipitx_data },
 	{},
 };
 
-- 
1.7.9.5



From yt.shen at mediatek.com  Thu Jul 28 02:28:04 2016
From: yt.shen at mediatek.com (YT Shen)
Date: Thu, 28 Jul 2016 17:28:04 +0800
Subject: [PATCH v5 10/10] arm: dts: mt2701: Add display subsystem related
 nodes for MT2701
In-Reply-To: <1469698084-20185-1-git-send-email-yt.shen@mediatek.com>
References: <1469698084-20185-1-git-send-email-yt.shen@mediatek.com>
Message-ID: <1469698084-20185-11-git-send-email-yt.shen@mediatek.com>

This patch adds the device nodes for the DISP function blocks for MT2701

Signed-off-by: YT Shen <yt.shen at mediatek.com>
---
 arch/arm/boot/dts/mt2701.dtsi |  100 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 100 insertions(+)

diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
index 363de0d..7da9310 100644
--- a/arch/arm/boot/dts/mt2701.dtsi
+++ b/arch/arm/boot/dts/mt2701.dtsi
@@ -24,6 +24,11 @@
 	compatible = "mediatek,mt2701";
 	interrupt-parent = <&sysirq>;
 
+	aliases {
+		rdma0 = &rdma0;
+		rdma1 = &rdma1;
+	};
+
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -171,6 +176,16 @@
 		power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>;
 	};
 
+	mipi_tx0: mipi-dphy at 10010000 {
+		compatible = "mediatek,mt2701-mipi-tx";
+		reg = <0 0x10010000 0 0x90>;
+		clocks = <&clk26m>;
+		clock-output-names = "mipi_tx0_pll";
+		#clock-cells = <0>;
+		#phy-cells = <0>;
+		status = "disabled";
+	};
+
 	sysirq: interrupt-controller at 10200100 {
 		compatible = "mediatek,mt2701-sysirq",
 			     "mediatek,mt6577-sysirq";
@@ -255,6 +270,68 @@
 		status = "disabled";
 	};
 
+	ovl at 14007000 {
+		compatible = "mediatek,mt2701-disp-ovl";
+		reg = <0 0x14007000 0 0x1000>;
+		interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&mmsys CLK_MM_DISP_OVL>;
+		iommus = <&iommu MT2701_M4U_PORT_DISP_OVL_0>;
+		mediatek,larb = <&larb0>;
+	};
+
+	rdma0: rdma at 14008000 {
+		compatible = "mediatek,mt2701-disp-rdma";
+		reg = <0 0x14008000 0 0x1000>;
+		interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&mmsys CLK_MM_DISP_RDMA>;
+		iommus = <&iommu MT2701_M4U_PORT_DISP_RDMA>;
+		mediatek,larb = <&larb0>;
+	};
+
+	wdma at 14009000 {
+		compatible = "mediatek,mt2701-disp-wdma";
+		reg = <0 0x14009000 0 0x1000>;
+		interrupts = <GIC_SPI 154 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&mmsys CLK_MM_DISP_WDMA>;
+		iommus = <&iommu MT2701_M4U_PORT_DISP_WDMA>;
+		mediatek,larb = <&larb0>;
+	};
+
+	bls at 1400a000 {
+		compatible = "mediatek,mt2701-disp-pwm";
+		reg = <0 0x1400a000 0 0x1000>;
+		interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&mmsys CLK_MM_DISP_BLS>;
+	};
+
+	color at 1400b000 {
+		compatible = "mediatek,mt2701-disp-color";
+		reg = <0 0x1400b000 0 0x1000>;
+		interrupts = <GIC_SPI 156 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&mmsys CLK_MM_DISP_COLOR>;
+	};
+
+	dsi0: dsi at 1400c000 {
+		compatible = "mediatek,mt2701-dsi";
+		reg = <0 0x1400c000 0 0x1000>;
+		interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&mmsys CLK_MM_DSI_ENGINE>, <&mmsys CLK_MM_DSI_DIG>,
+			 <&mipi_tx0>;
+		clock-names = "engine", "digital", "hs";
+		mediatek,syscon-dsi = <&mmsys 0x138>;
+		mediatek,ssc-range = <5>;
+		phys = <&mipi_tx0>;
+		phy-names = "dphy";
+		status = "disabled";
+	};
+
+	mutex: mutex at 1400e000 {
+		compatible = "mediatek,mt2701-disp-mutex";
+		reg = <0 0x1400e000 0 0x1000>;
+		interrupts = <GIC_SPI 161 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&mmsys CLK_MM_MUTEX_32K>;
+	};
+
 	larb0: larb at 14010000 {
 		compatible = "mediatek,mt2701-smi-larb";
 		reg = <0 0x14010000 0 0x1000>;
@@ -265,6 +342,29 @@
 		power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>;
 	};
 
+	rdma1: rdma at 14012000 {
+		compatible = "mediatek,mt2701-disp-rdma";
+		reg = <0 0x14012000 0 0x1000>;
+		interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&mmsys CLK_MM_DISP_RDMA1>;
+		iommus = <&iommu MT2701_M4U_PORT_DISP_RDMA1>;
+		mediatek,larb = <&larb0>;
+	};
+
+	dpi0: dpi at 14014000 {
+		compatible = "mediatek,mt2701-dpi";
+		reg = <0 0x14014000 0 0x1000>;
+		interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&mmsys CLK_MM_DPI1_DIGL>,
+			 <&mmsys CLK_MM_DPI1_ENGINE>,
+			 <&topckgen CLK_TOP_DPI1_SEL>,
+			 <&topckgen CLK_TOP_TVDPLL>,
+			 <&topckgen CLK_TOP_TVDPLL_D2>,
+			 <&topckgen CLK_TOP_TVDPLL_D4>;
+		clock-names = "pixel", "engine", "sel","div1","div2","div4";
+		status = "disabled";
+	};
+
 	imgsys: syscon at 15000000 {
 		compatible = "mediatek,mt2701-imgsys", "syscon";
 		reg = <0 0x15000000 0 0x1000>;
-- 
1.7.9.5



From ck.hu at mediatek.com  Thu Jul 28 02:41:05 2016
From: ck.hu at mediatek.com (CK Hu)
Date: Thu, 28 Jul 2016 17:41:05 +0800
Subject: [PATCH v4 4/8] drm/mediatek: add support for Mediatek SoC MT2701
In-Reply-To: <1469690256.28644.42.camel@mtksdaap41>
References: <1468577274-6178-1-git-send-email-yt.shen@mediatek.com>
 <1468577274-6178-5-git-send-email-yt.shen@mediatek.com>
 <1468997599.11841.49.camel@mtksdaap41>
 <1469529774.4678.34.camel@mtksdaap41>
 <1469613816.2470.50.camel@pengutronix.de>
 <1469671655.11841.85.camel@mtksdaap41>
 <1469690256.28644.42.camel@mtksdaap41>
Message-ID: <1469698865.11841.94.camel@mtksdaap41>

Hi, YT:


On Thu, 2016-07-28 at 15:17 +0800, YT Shen wrote:
> Hi Philipp, CK,
> 
> On Thu, 2016-07-28 at 10:07 +0800, CK Hu wrote:
> > Hi, YT:
> > 
> > On Wed, 2016-07-27 at 12:03 +0200, Philipp Zabel wrote:
> > > Am Dienstag, den 26.07.2016, 18:42 +0800 schrieb YT Shen:
> > > > Hi CK,
> > > > 
> > > > On Wed, 2016-07-20 at 14:53 +0800, CK Hu wrote:
> > > > > Hi, YT:
> > > > > 
> > > > > Some comments inline.
> > > > > 
> > > > > On Fri, 2016-07-15 at 18:07 +0800, YT Shen wrote:
> > > > > > This patch add support for the Mediatek MT2701 DISP subsystem.
> > > > > > There is only one OVL engine in MT2701.
> > > > > > 
> > > > > > Signed-off-by: YT Shen <yt.shen at mediatek.com>
> > > > > > ---
> > > > > >  drivers/gpu/drm/mediatek/mtk_disp_ovl.c     |    6 ++++
> > > > > >  drivers/gpu/drm/mediatek/mtk_disp_rdma.c    |    6 ++++
> > > > > >  drivers/gpu/drm/mediatek/mtk_drm_ddp.c      |   41 +++++++++++++++++++++++++++
> > > > > >  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |    7 +++++
> > > > > >  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |    1 +
> > > > > >  drivers/gpu/drm/mediatek/mtk_drm_drv.c      |   31 ++++++++++++++++++++
> > > > > >  6 files changed, 92 insertions(+)
> > > > > > 
> > > > > 
> > > > > [snip...]
> > > > > 
> > > > > >  
> > > > > >  static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
> > > > > > +	{ .compatible = "mediatek,mt2701-disp-ovl",   .data = (void *)MTK_DISP_OVL },
> > > > > >  	{ .compatible = "mediatek,mt8173-disp-ovl",   .data = (void *)MTK_DISP_OVL },
> > > > > > +	{ .compatible = "mediatek,mt2701-disp-rdma",  .data = (void *)MTK_DISP_RDMA },
> > > > > >  	{ .compatible = "mediatek,mt8173-disp-rdma",  .data = (void *)MTK_DISP_RDMA },
> > > > > > +	{ .compatible = "mediatek,mt2701-disp-wdma",  .data = (void *)MTK_DISP_WDMA },
> > > > > 
> > > > > Is WDMA different from MT8173 to MT2701. If they are the same, you need
> > > > > not to add compatible of 'mediatek,mt2701-disp-wdma' because use
> > > > > 'mediatek,mt8173-disp-wdma' is enough.
> > > > Yes, the hardware has differences, so we need add new compatible
> > > > 'mt2701-disp-wdma'
> > > 
> > > It would be nice if you could add a short paragraph to the patch
> > > description about what the hardware differences are (probably just
> > > changed register layout in most cases).
> Thanks for the suggestions, we will add more descriptions in the future.
> 
> > 
> > If you don't want to add description, you may separate the modification
> > of OVL, RDMA, WDMA, PWM to different patch. And you send patch of OVL
> > and RDMA first because you have related code modification for these two.
> > You temporarily treat WDMA and PWM as MT8173 and it works. And one day
> > you need to modify code of WDMA and PWM for MT2701, then you send the
> > patch of WDMA and PWM and you need not to add any description because we
> > can find out the difference from source code.
> 
> The display module connections is shown in mt2701_mtk_ddp_main[] and
> mt2701_mtk_ddp_ext[].
> OVL -> RDMA -> COLOR -> BLS(pwm) -> DSI
> RDMA -> DPI
> 
> This patch series mainly focus on DSI support for MT2701 SoC and the
> basic functions.  The BLS(pwm) and DPI parts are not included here.
> 
> We will remove 'mt2701-disp-wdma'. We didn't implement its driver and it
> is unused now.
> 
> For the pwm part, we need the device node to establish the display
> module connections.  The pwm compatible string is described in
> "dt-bindings: pwm: Add MediaTek display PWM bindings" [1] and the
> control is implemented in "pwm: Add MediaTek MT2701 display PWM driver
> support" [2].
> 
> For the dpi part, we need the device node to establish the display
> module connections.  The dpi patch will be in another patch series,
> split out from "drm/mediatek: fix the wrong pixel clock when resolution
> is 4K" [3].

For dpi part, I think you need not to include it in this patch. You can
send it with the MT2701 DPI patch. For module connection, you can use
"mediatek,mt8173-dpi" and it works. If you want to add it in this patch,
please describe the difference of mt8173-dpi and mt2701-dpi in this
patch.

> 
> 
> [1] https://patchwork.kernel.org/patch/9222997/
> [2] https://patchwork.kernel.org/patch/9223001/
> [3] https://patchwork.kernel.org/patch/9249471/ 
> 
> Regards,
> yt.shen
> 
> > 
> > > 
> > > regards
> > > Philipp
> > > 
> > 
> > Regards,
> > CK
> > 
> 
> 

Regards,
CK



From robh at kernel.org  Thu Jul 28 08:55:05 2016
From: robh at kernel.org (Rob Herring)
Date: Thu, 28 Jul 2016 10:55:05 -0500
Subject: [PATCH v2 2/4] dt-bindings: Add a binding for Mediatek MDP
In-Reply-To: <1469583886.27630.18.camel@mtksdaap41>
References: <1469176383-35210-1-git-send-email-minghsiu.tsai@mediatek.com>
 <1469176383-35210-3-git-send-email-minghsiu.tsai@mediatek.com>
 <20160726185433.GA14609@rob-hp-laptop> <1469583886.27630.18.camel@mtksdaap41>
Message-ID: <CAL_JsqK4Lz9mSJ+EXAY1g9L-CzBmbsed+MfCjkf_545y1Ov0iw@mail.gmail.com>

On Tue, Jul 26, 2016 at 8:44 PM, Minghsiu Tsai
<minghsiu.tsai at mediatek.com> wrote:
> On Tue, 2016-07-26 at 13:54 -0500, Rob Herring wrote:
>> On Fri, Jul 22, 2016 at 04:33:01PM +0800, Minghsiu Tsai wrote:
>> > Add a DT binding documentation of MDP for the MT8173 SoC
>> > from Mediatek
>> >
>> > Signed-off-by: Minghsiu Tsai <minghsiu.tsai at mediatek.com>
>> > ---
>> >  .../devicetree/bindings/media/mediatek-mdp.txt     |   96 ++++++++++++++++++++
>> >  1 file changed, 96 insertions(+)
>> >  create mode 100644 Documentation/devicetree/bindings/media/mediatek-mdp.txt
>> >
>> > diff --git a/Documentation/devicetree/bindings/media/mediatek-mdp.txt b/Documentation/devicetree/bindings/media/mediatek-mdp.txt
>> > new file mode 100644
>> > index 0000000..2dad031
>> > --- /dev/null
>> > +++ b/Documentation/devicetree/bindings/media/mediatek-mdp.txt
>> > @@ -0,0 +1,96 @@
>> > +* Mediatek Media Data Path
>> > +
>> > +Media Data Path is used for scaling and color space conversion.
>> > +
>> > +Required properties (all function blocks):
>> > +- compatible: "mediatek,<chip>-mdp"
>>
>> What is this, ...
>>
>
> It is used to match platform driver.

Would structuring things like this work instead:

{
  compatible = "mediatek,<chip>-mdp";
  ranges = ...;
  {
    compatible = "mediatek,<chip>-mdp-rdma";
    ...
  };
  {
    compatible = "mediatek,<chip>-mdp-wdma";
    ...
  };
  ...
};

>
>
>> > +        "mediatek,<chip>-mdp-<function>", one of
>>
>> and this?
>>
>
> It is string format of HW block. <chip> could be "mt8173", and
> <function> are "rdma", "rsz", "wdma", and "wrot".
>
>
>> > +        "mediatek,<chip>-mdp-rdma"  - read DMA
>> > +        "mediatek,<chip>-mdp-rsz"   - resizer
>> > +        "mediatek,<chip>-mdp-wdma"  - write DMA
>> > +        "mediatek,<chip>-mdp-wrot"  - write DMA with rotation
>>
>> List what are valid values of <chip>.
>>
>
> <chip> - mt8173. There should be other chip added in future.
> I will change the property as blow:
>
> - compatible: "mediatek,<chip>-mdp"
>         Should be one of
>         "mediatek,<chip>-mdp-rdma"  - read DMA
>         "mediatek,<chip>-mdp-rsz"   - resizer
>         "mediatek,<chip>-mdp-wdma"  - write DMA
>         "mediatek,<chip>-mdp-wrot"  - write DMA with rotation
>         <chip> - could be 8173
>
>
> If don't need <chip>, I also can change it as below. It is more clear.

Up to you. Depends on how many different chips you will have.

> - compatible: "mediatek,mt8173-mdp"
>         Should be one of
>         "mediatek,mt8173-mdp-rdma"  - read DMA
>         "mediatek,mt8173-mdp-rsz"   - resizer
>         "mediatek,mt8173-mdp-wdma"  - write DMA
>         "mediatek,mt8173-mdp-wrot"  - write DMA with rotation
>
>
>> > +- reg: Physical base address and length of the function block register space
>> > +- clocks: device clocks
>> > +- power-domains: a phandle to the power domain.
>> > +- mediatek,vpu: the node of video processor unit
>> > +
>> > +Required properties (DMA function blocks):
>> > +- compatible: Should be one of
>> > +        "mediatek,<chip>-mdp-rdma"
>> > +        "mediatek,<chip>-mdp-wdma"
>> > +        "mediatek,<chip>-mdp-wrot"
>> > +- iommus: should point to the respective IOMMU block with master port as
>> > +  argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
>> > +  for details.
>> > +- mediatek,larb: must contain the local arbiters in the current Socs.
>>
>> It is still not clear which properties apply to which compatible
>> strings.
>>
>
> I found out the document for larb.
> I will change the property as below:
>
> - mediatek,larb: must contain the local arbiters in the current Socs,
> see
> Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
>   for details.

That's good, but not what I meant. You still have properties which
only apply to certain blocks, but are listed for all blocks like
mediatek,vpu for example.

Rob


From josh at joshtriplett.org  Thu Jul 28 19:16:58 2016
From: josh at joshtriplett.org (Josh Triplett)
Date: Thu, 28 Jul 2016 19:16:58 -0700
Subject: Automated autobuilder emails.
Message-ID: <20160729021658.GA15676@x>

Hi,

I'm sending this to you because you're the two @mediatek.com folks
listed in the kernel MAINTAINERS file, and other mediatek addresses I've
tried have bounced.  I'm hoping you know the right people to contact and
can forward this mail if needed.

It looks like mediatek has an internal autobuilder,
adm_jenkins at mediatek.com , sending automated mails about kernel builds
outside of Mediatek, to various people at Samsung, @google.com,
@chromium.org, and myself.  Based on that selection of addresses, I'm
guessing you're trying to run an autobuilder related to Chrome OS?

The autobuilder mails (sample below) include links to servers within
mediatek, making them unhelpful for people outside of mediatek.  Could
you please not send such mails to people outside your company?

If you're trying to run a build-checking service for people outside your
company, you'd need to make the documentation and build logs accessible
to people outside your company.  And if you're running an entirely
internal autobuilder, it shouldn't be sending mails outside your
company.

Thanks,
Josh Triplett

On Fri, Jul 29, 2016 at 02:56:44AM +0800, adm_jenkins at mediatek.com wrote:
> Dear pals,
> linux-apollo-golden-1501-1620-7-001 - Build # 2016-07-28_14-22-08 - Failure:
> Check console output at
>  http://mtksdtbm24:8080/job/linux-apollo-golden-1501-1620-7-001/325/ to view
>  the results
>
> Build Tag:
> t-linux-apollo-golden-1501-1620-7-001-autobuild-fail-20160728142208
> Clean Build:  true
> Image Location:
> https://share.mediatek.inc/browse/shares/8?path=%2Fdtv_release1%2Fautobuild_image%2Fdtv_git
>  (\\mtksfs19\dtv_release1\autobuild_image\dtv_git)
> Full Log:
> \\mtksfs19\dtv_release1\autobuild_log\dtv_git\apollo-golden-1501-1620-7-001\2016-07-28_14-22-08


From bibby.hsieh at mediatek.com  Fri Jul 29 02:04:07 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Fri, 29 Jul 2016 17:04:07 +0800
Subject: [PATCH 0/7] drm/mediatek: cleaning up and refine
Message-ID: <1469783054-54567-1-git-send-email-bibby.hsieh@mediatek.com>

These patches based on 4.7-rc1 to clean up unused function & variable
and use drm core function instead.

The following patches are needed to cleanly apply on top of v4.7-rc1:
 - https://patchwork.kernel.org/patch/8044001/
   (drm: Deal with rotation in drm_plane_helper_check_update())
 - https://patchwork.kernel.org/patch/9248373/
   (drm: Warn about negative sizes when calculating scale factor)
 - https://patchwork.kernel.org/patch/9248371/
   (drm: Store clipped src/dst coordinatee in drm_plane_state)
 - https://patchwork.kernel.org/patch/9248363/
   (drm/plane-helper: Add drm_plane_helper_check_state())
 - https://patchwork.kernel.org/patch/9248361/
   (drm/mediatek: Use drm_plane_helper_check_state())

Bibby Hsieh (2):
  drm/mediatek: Use drm_atomic destroy_state helpers
  drm/mediatek: Fix mtk_atomic_complete for runtime_pm

Daniel Kurtz (5):
  drm/mediatek: Remove mtk_drm_crtc_check_flush
  drm/mediatek: plane: Remove plane zpos/index
  drm/mediatek: Remove mtk_drm_plane
  drm/mediatek: plane: Merge mtk_plane_enable into
    mtk_plane_atomic_update
  drm/mediatek: plane: Use FB's format's cpp to compute x offset

 drivers/gpu/drm/mediatek/mtk_drm_crtc.c  |   21 ++++----
 drivers/gpu/drm/mediatek/mtk_drm_crtc.h  |    1 -
 drivers/gpu/drm/mediatek/mtk_drm_drv.c   |   17 ++++++-
 drivers/gpu/drm/mediatek/mtk_drm_plane.c |   80 +++++++++++-------------------
 drivers/gpu/drm/mediatek/mtk_drm_plane.h |   15 +-----
 5 files changed, 56 insertions(+), 78 deletions(-)

-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Fri Jul 29 02:04:09 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Fri, 29 Jul 2016 17:04:09 +0800
Subject: [PATCH 2/7] drm/mediatek: plane: Remove plane zpos/index
In-Reply-To: <1469783054-54567-1-git-send-email-bibby.hsieh@mediatek.com>
References: <1469783054-54567-1-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1469783054-54567-3-git-send-email-bibby.hsieh@mediatek.com>

From: Daniel Kurtz <djkurtz at chromium.org>

It is not actually useful to a mtk plane to know its zpos/index, so just
remove this field.

This let's us completely remove struct mtk_drm_plane in a follow up patch.

Signed-off-by: Daniel Kurtz <djkurtz at chromium.org>
Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c  |    2 +-
 drivers/gpu/drm/mediatek/mtk_drm_plane.c |    4 +---
 drivers/gpu/drm/mediatek/mtk_drm_plane.h |    4 +---
 3 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index 24aa3ba..18211ab 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -559,7 +559,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
 				(zpos == 1) ? DRM_PLANE_TYPE_CURSOR :
 						DRM_PLANE_TYPE_OVERLAY;
 		ret = mtk_plane_init(drm_dev, &mtk_crtc->planes[zpos],
-				     BIT(pipe), type, zpos);
+				     BIT(pipe), type);
 		if (ret)
 			goto unprepare;
 	}
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
index 093db07..d28db57 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
@@ -189,8 +189,7 @@ static const struct drm_plane_helper_funcs mtk_plane_helper_funcs = {
 };
 
 int mtk_plane_init(struct drm_device *dev, struct mtk_drm_plane *mtk_plane,
-		   unsigned long possible_crtcs, enum drm_plane_type type,
-		   unsigned int zpos)
+		   unsigned long possible_crtcs, enum drm_plane_type type)
 {
 	int err;
 
@@ -203,7 +202,6 @@ int mtk_plane_init(struct drm_device *dev, struct mtk_drm_plane *mtk_plane,
 	}
 
 	drm_plane_helper_add(&mtk_plane->base, &mtk_plane_helper_funcs);
-	mtk_plane->idx = zpos;
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.h b/drivers/gpu/drm/mediatek/mtk_drm_plane.h
index 72a7b3e..74dbeda 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_plane.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.h
@@ -20,7 +20,6 @@
 
 struct mtk_drm_plane {
 	struct drm_plane		base;
-	unsigned int			idx;
 };
 
 struct mtk_plane_pending_state {
@@ -53,7 +52,6 @@ to_mtk_plane_state(struct drm_plane_state *state)
 }
 
 int mtk_plane_init(struct drm_device *dev, struct mtk_drm_plane *mtk_plane,
-		   unsigned long possible_crtcs, enum drm_plane_type type,
-		   unsigned int zpos);
+		   unsigned long possible_crtcs, enum drm_plane_type type);
 
 #endif
-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Fri Jul 29 02:04:08 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Fri, 29 Jul 2016 17:04:08 +0800
Subject: [PATCH 1/7] drm/mediatek: Remove mtk_drm_crtc_check_flush
In-Reply-To: <1469783054-54567-1-git-send-email-bibby.hsieh@mediatek.com>
References: <1469783054-54567-1-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1469783054-54567-2-git-send-email-bibby.hsieh@mediatek.com>

From: Daniel Kurtz <djkurtz at chromium.org>

This function no longer exists.

Signed-off-by: Daniel Kurtz <djkurtz at chromium.org>
Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_drm_crtc.h |    1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.h b/drivers/gpu/drm/mediatek/mtk_drm_crtc.h
index 81e5566..4d32cf1 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.h
@@ -22,7 +22,6 @@
 
 int mtk_drm_crtc_enable_vblank(struct drm_device *drm, unsigned int pipe);
 void mtk_drm_crtc_disable_vblank(struct drm_device *drm, unsigned int pipe);
-void mtk_drm_crtc_check_flush(struct drm_crtc *crtc);
 void mtk_drm_crtc_commit(struct drm_crtc *crtc);
 void mtk_crtc_ddp_irq(struct drm_crtc *crtc, struct mtk_ddp_comp *ovl);
 int mtk_drm_crtc_create(struct drm_device *drm_dev,
-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Fri Jul 29 02:04:13 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Fri, 29 Jul 2016 17:04:13 +0800
Subject: [PATCH 6/7] drm/mediatek: plane: Use FB's format's cpp to compute x
 offset
In-Reply-To: <1469783054-54567-1-git-send-email-bibby.hsieh@mediatek.com>
References: <1469783054-54567-1-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1469783054-54567-7-git-send-email-bibby.hsieh@mediatek.com>

From: Daniel Kurtz <djkurtz at chromium.org>

Use the framebuffer's format to compute its cpp, and use it when
calculating the address shift value.

Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_drm_plane.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
index b3ddb20..c461a23 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
@@ -135,7 +135,7 @@ static void mtk_plane_atomic_update(struct drm_plane *plane,
 	pitch = fb->pitches[0];
 	format = fb->pixel_format;
 
-	addr += (plane->state->src.x1 >> 16) * 4;
+	addr += (plane->state->src.x1 >> 16) * drm_format_plane_cpp(format, 0);
 	addr += (plane->state->src.y1 >> 16) * pitch;
 
 	state->pending.enable = true;
-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Fri Jul 29 02:04:11 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Fri, 29 Jul 2016 17:04:11 +0800
Subject: [PATCH 4/7] drm/mediatek: Use drm_atomic destroy_state helpers
In-Reply-To: <1469783054-54567-1-git-send-email-bibby.hsieh@mediatek.com>
References: <1469783054-54567-1-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1469783054-54567-5-git-send-email-bibby.hsieh@mediatek.com>

Use the core destroy_state helpers to destroy core state to ensure we don't
leak if/when more fields get added later.

Signed-off-by: Daniel Kurtz <djkurtz at chromium.org>
Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c  |    3 +--
 drivers/gpu/drm/mediatek/mtk_drm_plane.c |    3 +--
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index d6fbefa..733b2a3 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -112,8 +112,7 @@ static void mtk_drm_crtc_reset(struct drm_crtc *crtc)
 	struct mtk_crtc_state *state;
 
 	if (crtc->state) {
-		if (crtc->state->mode_blob)
-			drm_property_unreference_blob(crtc->state->mode_blob);
+		__drm_atomic_helper_crtc_destroy_state(crtc->state);
 
 		state = to_mtk_crtc_state(crtc->state);
 		memset(state, 0, sizeof(*state));
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
index 86b7aed..17172ba 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
@@ -73,8 +73,7 @@ static void mtk_plane_reset(struct drm_plane *plane)
 	struct mtk_plane_state *state;
 
 	if (plane->state) {
-		if (plane->state->fb)
-			drm_framebuffer_unreference(plane->state->fb);
+		__drm_atomic_helper_plane_destroy_state(plane->state);
 
 		state = to_mtk_plane_state(plane->state);
 		memset(state, 0, sizeof(*state));
-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Fri Jul 29 02:04:12 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Fri, 29 Jul 2016 17:04:12 +0800
Subject: [PATCH 5/7] drm/mediatek: plane: Merge mtk_plane_enable into
 mtk_plane_atomic_update
In-Reply-To: <1469783054-54567-1-git-send-email-bibby.hsieh@mediatek.com>
References: <1469783054-54567-1-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1469783054-54567-6-git-send-email-bibby.hsieh@mediatek.com>

From: Daniel Kurtz <djkurtz at chromium.org>

The mtk_plane_enable is just called once by mtk_plane_atomic_update.
So, merge mtk_plane_enable into mtk_plane_atomic_update.

While we are here, also clean up the function a bit by using an fb local
variables.

Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
Signed-off-by: Daniel Kurtz <djkurtz at chromium.org>
---
 drivers/gpu/drm/mediatek/mtk_drm_plane.c |   65 +++++++++++-------------------
 1 file changed, 23 insertions(+), 42 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
index 17172ba..b3ddb20 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
@@ -30,44 +30,6 @@ static const u32 formats[] = {
 	DRM_FORMAT_RGB565,
 };
 
-static void mtk_plane_enable(struct drm_plane *plane,
-			     dma_addr_t addr)
-{
-	struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
-	unsigned int pitch, format;
-	bool enable;
-
-	if (WARN_ON(!plane->state))
-		return;
-
-	enable = state->base.visible;
-
-	if (WARN_ON(enable && !plane->state->fb))
-		return;
-
-	if (plane->state->fb) {
-		pitch = plane->state->fb->pitches[0];
-		format = plane->state->fb->pixel_format;
-	} else {
-		pitch = 0;
-		format = DRM_FORMAT_RGBA8888;
-	}
-
-	addr += (state->base.src.x1 >> 16) * 4;
-	addr += (state->base.src.y1 >> 16) * pitch;
-
-	state->pending.enable = enable;
-	state->pending.pitch = pitch;
-	state->pending.format = format;
-	state->pending.addr = addr;
-	state->pending.x = state->base.dst.x1;
-	state->pending.y = state->base.dst.y1;
-	state->pending.width = drm_rect_width(&state->base.dst);
-	state->pending.height = drm_rect_height(&state->base.dst);
-	wmb(); /* Make sure the above parameters are set before update */
-	state->pending.dirty = true;
-}
-
 static void mtk_plane_reset(struct drm_plane *plane)
 {
 	struct mtk_plane_state *state;
@@ -157,16 +119,35 @@ static void mtk_plane_atomic_update(struct drm_plane *plane,
 				    struct drm_plane_state *old_state)
 {
 	struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
-	struct drm_crtc *crtc = state->base.crtc;
+	struct drm_crtc *crtc = plane->state->crtc;
+	struct drm_framebuffer *fb = plane->state->fb;
 	struct drm_gem_object *gem;
 	struct mtk_drm_gem_obj *mtk_gem;
+	unsigned int pitch, format;
+	dma_addr_t addr;
 
-	if (!crtc)
+	if (!crtc || WARN_ON(!fb))
 		return;
 
-	gem = mtk_fb_get_gem_obj(state->base.fb);
+	gem = mtk_fb_get_gem_obj(fb);
 	mtk_gem = to_mtk_gem_obj(gem);
-	mtk_plane_enable(plane, mtk_gem->dma_addr);
+	addr = mtk_gem->dma_addr;
+	pitch = fb->pitches[0];
+	format = fb->pixel_format;
+
+	addr += (plane->state->src.x1 >> 16) * 4;
+	addr += (plane->state->src.y1 >> 16) * pitch;
+
+	state->pending.enable = true;
+	state->pending.pitch = pitch;
+	state->pending.format = format;
+	state->pending.addr = addr;
+	state->pending.x = plane->state->dst.x1;
+	state->pending.y = plane->state->dst.y1;
+	state->pending.width = drm_rect_width(&plane->state->dst);
+	state->pending.height = drm_rect_height(&plane->state->dst);
+	wmb(); /* Make sure the above parameters are set before update */
+	state->pending.dirty = true;
 }
 
 static void mtk_plane_atomic_disable(struct drm_plane *plane,
-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Fri Jul 29 02:04:14 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Fri, 29 Jul 2016 17:04:14 +0800
Subject: [PATCH 7/7] drm/mediatek: Fix mtk_atomic_complete for runtime_pm
In-Reply-To: <1469783054-54567-1-git-send-email-bibby.hsieh@mediatek.com>
References: <1469783054-54567-1-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1469783054-54567-8-git-send-email-bibby.hsieh@mediatek.com>

To properly implement atomic w/ runtime pm, we move
drm_atomic_helper_commit_modeset_enables() above
drm_atomic_helper_commit_planes() to ensure CRTCs are enabled before
modifying plane registers, and set active_only to true to filter out
plane update notifications when the CRTC is disabled.

According to the document from linux kernel:
Set the active_only parameters to true in order not to receive plane
update notifications related to a disabled CRTC. This avoids the need
to manually ignore plane updates in driver code when the driver and/or
hardware can't or just don't need to deal with updates on disabled
CRTCs, for example when supporting runtime PM.

Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
Signed-off-by: Daniel Kurtz <djkurtz at chromium.org>
---
 drivers/gpu/drm/mediatek/mtk_drm_drv.c |   17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index b1223d5..507392a 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -61,10 +61,25 @@ static void mtk_atomic_complete(struct mtk_drm_private *private,
 
 	mtk_atomic_wait_for_fences(state);
 
+	/*
+	 * Mediatek drm supports runtime PM, so plane registers cannot be
+	 * written when their crtc is disabled.
+	 *
+	 * The comment for drm_atomic_helper_commit states:
+	 *     For drivers supporting runtime PM the recommended sequence is
+	 *
+	 *     drm_atomic_helper_commit_modeset_disables(dev, state);
+	 *     drm_atomic_helper_commit_modeset_enables(dev, state);
+	 *     drm_atomic_helper_commit_planes(dev, state, true);
+	 *
+	 * See the kerneldoc entries for these three functions for more details.
+	 */
 	drm_atomic_helper_commit_modeset_disables(drm, state);
-	drm_atomic_helper_commit_planes(drm, state, false);
 	drm_atomic_helper_commit_modeset_enables(drm, state);
+	drm_atomic_helper_commit_planes(drm, state, true);
+
 	drm_atomic_helper_wait_for_vblanks(drm, state);
+
 	drm_atomic_helper_cleanup_planes(drm, state);
 	drm_atomic_state_free(state);
 }
-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Fri Jul 29 02:04:10 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Fri, 29 Jul 2016 17:04:10 +0800
Subject: [PATCH 3/7] drm/mediatek: Remove mtk_drm_plane
In-Reply-To: <1469783054-54567-1-git-send-email-bibby.hsieh@mediatek.com>
References: <1469783054-54567-1-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1469783054-54567-4-git-send-email-bibby.hsieh@mediatek.com>

From: Daniel Kurtz <djkurtz at chromium.org>

Now that mtk_drm_plane just contains its base struct drm_plane, we can
just remove it and use struct drm_plane everywhere.

Signed-off-by: Daniel Kurtz <djkurtz at chromium.org>
Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c  |   16 ++++++++--------
 drivers/gpu/drm/mediatek/mtk_drm_plane.c |   10 ++++------
 drivers/gpu/drm/mediatek/mtk_drm_plane.h |   11 +----------
 3 files changed, 13 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index 18211ab..d6fbefa 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -31,7 +31,7 @@
  * struct mtk_drm_crtc - MediaTek specific crtc structure.
  * @base: crtc object.
  * @enabled: records whether crtc_enable succeeded
- * @planes: array of 4 mtk_drm_plane structures, one for each overlay plane
+ * @planes: array of 4 drm_plane structures, one for each overlay plane
  * @pending_planes: whether any plane has pending changes to be applied
  * @config_regs: memory mapped mmsys configuration register space
  * @mutex: handle to one of the ten disp_mutex streams
@@ -45,7 +45,7 @@ struct mtk_drm_crtc {
 	bool				pending_needs_vblank;
 	struct drm_pending_vblank_event	*event;
 
-	struct mtk_drm_plane		planes[OVL_LAYER_NR];
+	struct drm_plane		planes[OVL_LAYER_NR];
 	bool				pending_planes;
 
 	void __iomem			*config_regs;
@@ -272,7 +272,7 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
 
 	/* Initially configure all planes */
 	for (i = 0; i < OVL_LAYER_NR; i++) {
-		struct drm_plane *plane = &mtk_crtc->planes[i].base;
+		struct drm_plane *plane = &mtk_crtc->planes[i];
 		struct mtk_plane_state *plane_state;
 
 		plane_state = to_mtk_plane_state(plane->state);
@@ -351,7 +351,7 @@ static void mtk_drm_crtc_disable(struct drm_crtc *crtc)
 
 	/* Set all pending plane state to disabled */
 	for (i = 0; i < OVL_LAYER_NR; i++) {
-		struct drm_plane *plane = &mtk_crtc->planes[i].base;
+		struct drm_plane *plane = &mtk_crtc->planes[i];
 		struct mtk_plane_state *plane_state;
 
 		plane_state = to_mtk_plane_state(plane->state);
@@ -397,7 +397,7 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
 	if (mtk_crtc->event)
 		mtk_crtc->pending_needs_vblank = true;
 	for (i = 0; i < OVL_LAYER_NR; i++) {
-		struct drm_plane *plane = &mtk_crtc->planes[i].base;
+		struct drm_plane *plane = &mtk_crtc->planes[i];
 		struct mtk_plane_state *plane_state;
 
 		plane_state = to_mtk_plane_state(plane->state);
@@ -471,7 +471,7 @@ void mtk_crtc_ddp_irq(struct drm_crtc *crtc, struct mtk_ddp_comp *ovl)
 
 	if (mtk_crtc->pending_planes) {
 		for (i = 0; i < OVL_LAYER_NR; i++) {
-			struct drm_plane *plane = &mtk_crtc->planes[i].base;
+			struct drm_plane *plane = &mtk_crtc->planes[i];
 			struct mtk_plane_state *plane_state;
 
 			plane_state = to_mtk_plane_state(plane->state);
@@ -564,8 +564,8 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
 			goto unprepare;
 	}
 
-	ret = mtk_drm_crtc_init(drm_dev, mtk_crtc, &mtk_crtc->planes[0].base,
-				&mtk_crtc->planes[1].base, pipe);
+	ret = mtk_drm_crtc_init(drm_dev, mtk_crtc, &mtk_crtc->planes[0],
+				&mtk_crtc->planes[1], pipe);
 	if (ret < 0)
 		goto unprepare;
 
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
index d28db57..86b7aed 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
@@ -33,7 +33,6 @@ static const u32 formats[] = {
 static void mtk_plane_enable(struct drm_plane *plane,
 			     dma_addr_t addr)
 {
-	struct drm_plane *plane = &mtk_plane->base;
 	struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
 	unsigned int pitch, format;
 	bool enable;
@@ -162,14 +161,13 @@ static void mtk_plane_atomic_update(struct drm_plane *plane,
 	struct drm_crtc *crtc = state->base.crtc;
 	struct drm_gem_object *gem;
 	struct mtk_drm_gem_obj *mtk_gem;
-	struct mtk_drm_plane *mtk_plane = to_mtk_plane(plane);
 
 	if (!crtc)
 		return;
 
 	gem = mtk_fb_get_gem_obj(state->base.fb);
 	mtk_gem = to_mtk_gem_obj(gem);
-	mtk_plane_enable(mtk_plane, mtk_gem->dma_addr);
+	mtk_plane_enable(plane, mtk_gem->dma_addr);
 }
 
 static void mtk_plane_atomic_disable(struct drm_plane *plane,
@@ -188,12 +186,12 @@ static const struct drm_plane_helper_funcs mtk_plane_helper_funcs = {
 	.atomic_disable = mtk_plane_atomic_disable,
 };
 
-int mtk_plane_init(struct drm_device *dev, struct mtk_drm_plane *mtk_plane,
+int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane,
 		   unsigned long possible_crtcs, enum drm_plane_type type)
 {
 	int err;
 
-	err = drm_universal_plane_init(dev, &mtk_plane->base, possible_crtcs,
+	err = drm_universal_plane_init(dev, plane, possible_crtcs,
 				       &mtk_plane_funcs, formats,
 				       ARRAY_SIZE(formats), type, NULL);
 	if (err) {
@@ -201,7 +199,7 @@ int mtk_plane_init(struct drm_device *dev, struct mtk_drm_plane *mtk_plane,
 		return err;
 	}
 
-	drm_plane_helper_add(&mtk_plane->base, &mtk_plane_helper_funcs);
+	drm_plane_helper_add(plane, &mtk_plane_helper_funcs);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.h b/drivers/gpu/drm/mediatek/mtk_drm_plane.h
index 74dbeda..6a20b49 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_plane.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.h
@@ -18,10 +18,6 @@
 #include <drm/drm_crtc.h>
 #include <linux/types.h>
 
-struct mtk_drm_plane {
-	struct drm_plane		base;
-};
-
 struct mtk_plane_pending_state {
 	bool				config;
 	bool				enable;
@@ -40,18 +36,13 @@ struct mtk_plane_state {
 	struct mtk_plane_pending_state	pending;
 };
 
-static inline struct mtk_drm_plane *to_mtk_plane(struct drm_plane *plane)
-{
-	return container_of(plane, struct mtk_drm_plane, base);
-}
-
 static inline struct mtk_plane_state *
 to_mtk_plane_state(struct drm_plane_state *state)
 {
 	return container_of(state, struct mtk_plane_state, base);
 }
 
-int mtk_plane_init(struct drm_device *dev, struct mtk_drm_plane *mtk_plane,
+int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane,
 		   unsigned long possible_crtcs, enum drm_plane_type type);
 
 #endif
-- 
1.7.9.5



From bibby.hsieh at mediatek.com  Fri Jul 29 02:09:48 2016
From: bibby.hsieh at mediatek.com (Bibby Hsieh)
Date: Fri, 29 Jul 2016 17:09:48 +0800
Subject: [PATCH v4] arm64: dts: mt8173: add mmsel clocks for 4K support
Message-ID: <1469783388-56804-1-git-send-email-bibby.hsieh@mediatek.com>

To support HDMI 4K resolution, mmsys need clcok
mm_sel to be 400MHz.

The board .dts file should override the clock rate
property with the higher VENCPLL frequency the board
supports HDMI 4K resolution.

Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
---
 arch/arm64/boot/dts/mediatek/mt8173.dtsi |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
index 78529e4..93d4d17 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -690,6 +690,8 @@
 			compatible = "mediatek,mt8173-mmsys", "syscon";
 			reg = <0 0x14000000 0 0x1000>;
 			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+			clocks = <&topckgen CLK_TOP_MM_SEL>;
+			clock-frequency  = <400000000>;
 			#clock-cells = <1>;
 		};
 
-- 
1.7.9.5



From eddie.huang at mediatek.com  Fri Jul 29 02:24:27 2016
From: eddie.huang at mediatek.com (Eddie Huang)
Date: Fri, 29 Jul 2016 17:24:27 +0800
Subject: Automated autobuilder emails.
In-Reply-To: <20160729021658.GA15676@x>
References: <20160729021658.GA15676@x>
Message-ID: <1469784267.12040.3.camel@mtksdaap41>

Hi,

On Thu, 2016-07-28 at 19:16 -0700, Josh Triplett wrote:
> Hi,
> 
> I'm sending this to you because you're the two @mediatek.com folks
> listed in the kernel MAINTAINERS file, and other mediatek addresses I've
> tried have bounced.  I'm hoping you know the right people to contact and
> can forward this mail if needed.
> 
> It looks like mediatek has an internal autobuilder,
> adm_jenkins at mediatek.com , sending automated mails about kernel builds
> outside of Mediatek, to various people at Samsung, @google.com,
> @chromium.org, and myself.  Based on that selection of addresses, I'm
> guessing you're trying to run an autobuilder related to Chrome OS?
> 
> The autobuilder mails (sample below) include links to servers within
> mediatek, making them unhelpful for people outside of mediatek.  Could
> you please not send such mails to people outside your company?
> 
> If you're trying to run a build-checking service for people outside your
> company, you'd need to make the documentation and build logs accessible
> to people outside your company.  And if you're running an entirely
> internal autobuilder, it shouldn't be sending mails outside your
> company.
> 
> Thanks,
> Josh Triplett
> 

We already suspend our Jenkins auto build, and will modify mailing rule
to avoid sending mail outside Mediatek company.Sorry for your
inconvenience.

Eddie
Thanks




From josh at joshtriplett.org  Fri Jul 29 02:50:45 2016
From: josh at joshtriplett.org (Josh Triplett)
Date: Fri, 29 Jul 2016 02:50:45 -0700
Subject: Automated autobuilder emails.
In-Reply-To: <1469784267.12040.3.camel@mtksdaap41>
References: <20160729021658.GA15676@x>
 <1469784267.12040.3.camel@mtksdaap41>
Message-ID: <20160729095045.GA1435@x>

On Fri, Jul 29, 2016 at 05:24:27PM +0800, Eddie Huang wrote:
> On Thu, 2016-07-28 at 19:16 -0700, Josh Triplett wrote:
> > I'm sending this to you because you're the two @mediatek.com folks
> > listed in the kernel MAINTAINERS file, and other mediatek addresses I've
> > tried have bounced.  I'm hoping you know the right people to contact and
> > can forward this mail if needed.
> > 
> > It looks like mediatek has an internal autobuilder,
> > adm_jenkins at mediatek.com , sending automated mails about kernel builds
> > outside of Mediatek, to various people at Samsung, @google.com,
> > @chromium.org, and myself.  Based on that selection of addresses, I'm
> > guessing you're trying to run an autobuilder related to Chrome OS?
> > 
> > The autobuilder mails (sample below) include links to servers within
> > mediatek, making them unhelpful for people outside of mediatek.  Could
> > you please not send such mails to people outside your company?
> > 
> > If you're trying to run a build-checking service for people outside your
> > company, you'd need to make the documentation and build logs accessible
> > to people outside your company.  And if you're running an entirely
> > internal autobuilder, it shouldn't be sending mails outside your
> > company.
> > 
> > Thanks,
> > Josh Triplett
> > 
> 
> We already suspend our Jenkins auto build, and will modify mailing rule
> to avoid sending mail outside Mediatek company.Sorry for your
> inconvenience.

Thanks.  Not a problem; accidents happen. :)


From tiffany.lin at mediatek.com  Fri Jul 29 02:50:58 2016
From: tiffany.lin at mediatek.com (Tiffany Lin)
Date: Fri, 29 Jul 2016 17:50:58 +0800
Subject: [PATCH v2] vcodec: mediatek: Add g/s_selection support for V4L2
 Encoder
Message-ID: <1469785858-44115-1-git-send-email-tiffany.lin@mediatek.com>

Signed-off-by: Tiffany Lin <tiffany.lin at mediatek.com>
---
 drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c |   83 ++++++++++++++++++--
 1 file changed, 78 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
index 3ed3f2d..8f09dd3 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
@@ -487,7 +487,6 @@ static int vidioc_venc_s_fmt_out(struct file *file, void *priv,
 	struct mtk_q_data *q_data;
 	int ret, i;
 	struct mtk_video_fmt *fmt;
-	unsigned int pitch_w_div16;
 	struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
 
 	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
@@ -530,13 +529,12 @@ static int vidioc_venc_s_fmt_out(struct file *file, void *priv,
 	q_data->coded_width = f->fmt.pix_mp.width;
 	q_data->coded_height = f->fmt.pix_mp.height;
 
-	pitch_w_div16 = DIV_ROUND_UP(q_data->visible_width, 16);
-	if (pitch_w_div16 % 8 != 0) {
+	if (q_data->visible_width % 16) {
 		/* Adjust returned width/height, so application could correctly
 		 * allocate hw required memory
 		 */
-		q_data->visible_height += 32;
-		vidioc_try_fmt(f, q_data->fmt);
+		q_data->coded_height += 32;
+		f->fmt.pix_mp.height += 32;
 	}
 
 	q_data->field = f->fmt.pix_mp.field;
@@ -631,6 +629,78 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
 	return vidioc_try_fmt(f, fmt);
 }
 
+static int vidioc_venc_g_selection(struct file *file, void *priv,
+				     struct v4l2_selection *s)
+{
+	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+	struct mtk_q_data *q_data;
+
+	if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+		mtk_v4l2_err("Invalid s->type = %d", s->type);
+		return -EINVAL;
+	}
+
+	q_data = mtk_venc_get_q_data(ctx, s->type);
+	if (!q_data)
+		return -EINVAL;
+
+	/* crop means compose for output devices */
+	switch (s->target) {
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		s->r.top = 0;
+		s->r.left = 0;
+		s->r.width = q_data->coded_width;
+		s->r.height = q_data->coded_height;
+		break;
+	case V4L2_SEL_TGT_CROP:
+		s->r.top = 0;
+		s->r.left = 0;
+		s->r.width = q_data->visible_width;
+		s->r.height = q_data->visible_height;
+		break;
+	default:
+		mtk_v4l2_err("Invalid s->target = %d", s->target);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int vidioc_venc_s_selection(struct file *file, void *priv,
+				     struct v4l2_selection *s)
+{
+	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+	struct mtk_q_data *q_data;
+
+	if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+		mtk_v4l2_err("Invalid s->type = %d", s->type);
+		return -EINVAL;
+	}
+
+	q_data = mtk_venc_get_q_data(ctx, s->type);
+	if (!q_data)
+		return -EINVAL;
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_CROP:
+		/* Only support crop from (0,0) */
+		if ((s->r.width > q_data->coded_width) ||
+			(s->r.height > q_data->coded_height)) {
+			return -ERANGE;
+		}
+		s->r.top = 0;
+		s->r.left = 0;
+		q_data->visible_width = s->r.width;
+		q_data->visible_height = s->r.height;
+		break;
+	default:
+		mtk_v4l2_err("Invalid s->target = %d", s->target);
+		return -EINVAL;
+	}
+	return 0;
+}
+
 static int vidioc_venc_qbuf(struct file *file, void *priv,
 			    struct v4l2_buffer *buf)
 {
@@ -689,6 +759,9 @@ const struct v4l2_ioctl_ops mtk_venc_ioctl_ops = {
 
 	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,
 	.vidioc_prepare_buf		= v4l2_m2m_ioctl_prepare_buf,
+
+	.vidioc_g_selection		= vidioc_venc_g_selection,
+	.vidioc_s_selection		= vidioc_venc_s_selection,
 };
 
 static int vb2ops_venc_queue_setup(struct vb2_queue *vq,
-- 
1.7.9.5



From p.zabel at pengutronix.de  Fri Jul 29 02:53:10 2016
From: p.zabel at pengutronix.de (Philipp Zabel)
Date: Fri, 29 Jul 2016 11:53:10 +0200
Subject: [PATCH v4] arm64: dts: mt8173: add mmsel clocks for 4K support
In-Reply-To: <1469783388-56804-1-git-send-email-bibby.hsieh@mediatek.com>
References: <1469783388-56804-1-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1469785990.3012.35.camel@pengutronix.de>

Hi Bibby,

Am Freitag, den 29.07.2016, 17:09 +0800 schrieb Bibby Hsieh:
> To support HDMI 4K resolution, mmsys need clcok
> mm_sel to be 400MHz.
> 
> The board .dts file should override the clock rate
> property with the higher VENCPLL frequency the board
> supports HDMI 4K resolution.
> 
> Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> ---
>  arch/arm64/boot/dts/mediatek/mt8173.dtsi |    2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
> index 78529e4..93d4d17 100644
> --- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
> +++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
> @@ -690,6 +690,8 @@
>  			compatible = "mediatek,mt8173-mmsys", "syscon";
>  			reg = <0 0x14000000 0 0x1000>;
>  			power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
> +			clocks = <&topckgen CLK_TOP_MM_SEL>;
> +			clock-frequency  = <400000000>;

This is unchanged compared to v3, I suggest to use assigned-clocks /
assigned-clock-rates properties instead.

best regards
Philipp



From ck.hu at mediatek.com  Fri Jul 29 03:14:45 2016
From: ck.hu at mediatek.com (CK Hu)
Date: Fri, 29 Jul 2016 18:14:45 +0800
Subject: [PATCH 2/7] drm/mediatek: plane: Remove plane zpos/index
In-Reply-To: <1469783054-54567-3-git-send-email-bibby.hsieh@mediatek.com>
References: <1469783054-54567-1-git-send-email-bibby.hsieh@mediatek.com>
 <1469783054-54567-3-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <1469787285.11841.97.camel@mtksdaap41>

Hi, Bibby:

On Fri, 2016-07-29 at 17:04 +0800, Bibby Hsieh wrote:
> From: Daniel Kurtz <djkurtz at chromium.org>
> 
> It is not actually useful to a mtk plane to know its zpos/index, so just
> remove this field.
> 
> This let's us completely remove struct mtk_drm_plane in a follow up patch.

'let's us'? My English is not as good as native English speaker.
Otherwise, this patch looks good to me.

> 
> Signed-off-by: Daniel Kurtz <djkurtz at chromium.org>
> Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_drm_crtc.c  |    2 +-
>  drivers/gpu/drm/mediatek/mtk_drm_plane.c |    4 +---
>  drivers/gpu/drm/mediatek/mtk_drm_plane.h |    4 +---
>  3 files changed, 3 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> index 24aa3ba..18211ab 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> @@ -559,7 +559,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
>  				(zpos == 1) ? DRM_PLANE_TYPE_CURSOR :
>  						DRM_PLANE_TYPE_OVERLAY;
>  		ret = mtk_plane_init(drm_dev, &mtk_crtc->planes[zpos],
> -				     BIT(pipe), type, zpos);
> +				     BIT(pipe), type);
>  		if (ret)
>  			goto unprepare;
>  	}
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
> index 093db07..d28db57 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
> @@ -189,8 +189,7 @@ static const struct drm_plane_helper_funcs mtk_plane_helper_funcs = {
>  };
>  
>  int mtk_plane_init(struct drm_device *dev, struct mtk_drm_plane *mtk_plane,
> -		   unsigned long possible_crtcs, enum drm_plane_type type,
> -		   unsigned int zpos)
> +		   unsigned long possible_crtcs, enum drm_plane_type type)
>  {
>  	int err;
>  
> @@ -203,7 +202,6 @@ int mtk_plane_init(struct drm_device *dev, struct mtk_drm_plane *mtk_plane,
>  	}
>  
>  	drm_plane_helper_add(&mtk_plane->base, &mtk_plane_helper_funcs);
> -	mtk_plane->idx = zpos;
>  
>  	return 0;
>  }
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.h b/drivers/gpu/drm/mediatek/mtk_drm_plane.h
> index 72a7b3e..74dbeda 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_plane.h
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.h
> @@ -20,7 +20,6 @@
>  
>  struct mtk_drm_plane {
>  	struct drm_plane		base;
> -	unsigned int			idx;
>  };
>  
>  struct mtk_plane_pending_state {
> @@ -53,7 +52,6 @@ to_mtk_plane_state(struct drm_plane_state *state)
>  }
>  
>  int mtk_plane_init(struct drm_device *dev, struct mtk_drm_plane *mtk_plane,
> -		   unsigned long possible_crtcs, enum drm_plane_type type,
> -		   unsigned int zpos);
> +		   unsigned long possible_crtcs, enum drm_plane_type type);
>  
>  #endif

Regards,
CK




From thierry.reding at gmail.com  Fri Jul 29 07:45:02 2016
From: thierry.reding at gmail.com (Thierry Reding)
Date: Fri, 29 Jul 2016 16:45:02 +0200
Subject: [PATCH v2 3/3] drm/mediatek: fix the wrong pixel clock when
 resolution is 4K
In-Reply-To: <1469608292-6106-4-git-send-email-bibby.hsieh@mediatek.com>
References: <1469608292-6106-1-git-send-email-bibby.hsieh@mediatek.com>
 <1469608292-6106-4-git-send-email-bibby.hsieh@mediatek.com>
Message-ID: <20160729144502.GC3864@ulmo.ba.sec>

On Wed, Jul 27, 2016 at 04:31:32PM +0800, Bibby Hsieh wrote:
> From: Junzhi Zhao <junzhi.zhao at mediatek.com>
> 
> Pixel clock should be 297MHz when resolution is 4K.
> 
> Signed-off-by: Junzhi Zhao <junzhi.zhao at mediatek.com>
> Signed-off-by: Bibby Hsieh <bibby.hsieh at mediatek.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_dpi.c |  149 +++++++++++++++++++++++-------------
>  1 file changed, 96 insertions(+), 53 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
> index d05ca79..fa390e0 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dpi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
> @@ -60,14 +60,25 @@ enum mtk_dpi_out_color_format {
>  	MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL
>  };
>  
> +enum mtk_dpi_clk_id {
> +	MTK_DPI_CLK_DPI_ENGINE,
> +	MTK_DPI_CLK_DPI_PIXEL,
> +	MTK_DPI_CLK_TVD_PLL,
> +	MTK_DPI_CLK_COUNT,
> +};
> +
> +static const char * const mtk_dpi_clk_names[MTK_DPI_CLK_COUNT] = {
> +	[MTK_DPI_CLK_DPI_ENGINE] = "engine",
> +	[MTK_DPI_CLK_DPI_PIXEL] = "pixel",
> +	[MTK_DPI_CLK_TVD_PLL] = "pll",
> +};
> +
>  struct mtk_dpi {
>  	struct mtk_ddp_comp ddp_comp;
>  	struct drm_encoder encoder;
>  	void __iomem *regs;
>  	struct device *dev;
> -	struct clk *engine_clk;
> -	struct clk *pixel_clk;
> -	struct clk *tvd_clk;
> +	struct clk *clk[MTK_DPI_CLK_COUNT];

This looks to me like a step backwards. All accesses to these clocks are
now very clumsy and I don't see any advantage in using this array rather
than individually named clocks.

Also, that change seems completely unrelated to the description in the
commit message.

>  	int irq;
>  	struct drm_display_mode mode;
>  	enum mtk_dpi_out_color_format color_format;
> @@ -76,6 +87,7 @@ struct mtk_dpi {
>  	enum mtk_dpi_out_channel_swap channel_swap;
>  	bool power_sta;
>  	u8 power_ctl;
> +	void *data;

This should probably be const. It's a bad idea to cast away the const
from the of_device_id.data that this is assigned from.

> +static const struct of_device_id mtk_dpi_of_ids[] = {
> +	{ .compatible = "mediatek,mt8173-dpi",
> +		.data = &mt8173_conf,
> +	},

Please align this in some standard way. It all fits on one line, so the
most obvious choice would've been:

	{ .compatible = "mediatek,mt8173-dpi", .data = &mt8173_conf },

> +	{}
> +};
> +
>  static int mtk_dpi_probe(struct platform_device *pdev)
>  {
>  	struct device *dev = &pdev->dev;
>  	struct mtk_dpi *dpi;
>  	struct resource *mem;
> +	struct device_node *np = dev->of_node;
>  	struct device_node *ep, *bridge_node = NULL;
>  	int comp_id;
> +	const struct of_device_id *match;
> +	struct mtk_dpi_conf *conf;
>  	int ret;
>  
> +	match = of_match_node(mtk_dpi_of_ids, dev->of_node);
> +	if (!match)
> +		return -ENODEV;

You introduce a variable np = dev->of_node above, but then you add code
that uses dev->of_node directly?

That said, you should use of_device_get_match_data() anyway, so that you
can omit...

> +
>  	dpi = devm_kzalloc(dev, sizeof(*dpi), GFP_KERNEL);
>  	if (!dpi)
>  		return -ENOMEM;
>  
>  	dpi->dev = dev;
> +	dpi->data = (void *)match->data;
> +	conf = (struct mtk_dpi_conf *)match->data;

... the dereferences here. Also, like I said before you should make
dpi->data and conf both const to avoid casting away the constness of the
data. If you do that you can even drop the casts because you'd be
casting from a const void * to a const foo *, which gets casted
automatically.

> @@ -754,11 +802,6 @@ static int mtk_dpi_remove(struct platform_device *pdev)
>  	return 0;
>  }
>  
> -static const struct of_device_id mtk_dpi_of_ids[] = {
> -	{ .compatible = "mediatek,mt8173-dpi", },
> -	{}
> -};

Another advantage of using of_device_get_match_data() is that it doesn't
need direct access to the of_device_id table (it'll obtain it via an
indirect dev->driver->of_match_table), so you don't have to move this
around and make this patch overall less churn.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mediatek/attachments/20160729/de5bab71/attachment.sig>

From lkp at intel.com  Sat Jul 30 19:02:54 2016
From: lkp at intel.com (kbuild test robot)
Date: Sun, 31 Jul 2016 10:02:54 +0800
Subject: [PATCH v6 3/3] arm: dts: mt2701: Add auxadc node.
In-Reply-To: <1469613781-1296-4-git-send-email-zhiyong.tao@mediatek.com>
Message-ID: <201607311038.2PkrZMqq%fengguang.wu@intel.com>

Hi,

[auto build test ERROR on robh/for-next]
[also build test ERROR on v4.7 next-20160729]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Zhiyong-Tao/AUXADC-Mediatek-auxadc-driver/20160727-180722
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: arm-at91_dt_defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 5.4.0-6) 5.4.0 20160609
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm 

All errors (new ones prefixed by >>):

>> Error: arch/arm/boot/dts/mt2701.dtsi:145.22-23 syntax error
   FATAL ERROR: Unable to parse input tree

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/octet-stream
Size: 21319 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mediatek/attachments/20160731/9f214972/attachment-0001.obj>

