Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/4] arm64/mm: migrate swapper_pg_dir
From: Greg KH @ 2018-05-30  9:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180530091259.9386-2-yaojun8558363@gmail.com>

On Wed, May 30, 2018 at 05:12:56PM +0800, YaoJun wrote:
> Introduce __pa_swapper_pg_dir to save physical address
> of swapper_pg_dir. And pass it as an argument to
> __enable_mmu().
> 
> Signed-off-by: YaoJun <yaojun8558363@gmail.com>

This is better, but your subject line is still identical for all 4
patches (which doesn't make sense as they do different things), and I
think you need to put a space in your name somewhere, right?

thanks,

greg k-h

^ permalink raw reply

* [RFT v3 1/4] perf cs-etm: Generate branch sample for missed packets
From: Robert Walker @ 2018-05-30  9:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180528221347.GA4109@xps15>



On 28/05/18 23:13, Mathieu Poirier wrote:
> Leo and/or Robert,
> 
> On Mon, May 28, 2018 at 04:45:00PM +0800, Leo Yan wrote:
>> Commit e573e978fb12 ("perf cs-etm: Inject capabilitity for CoreSight
>> traces") reworks the samples generation flow from CoreSight trace to
>> match the correct format so Perf report tool can display the samples
>> properly.
>>
>> But the change has side effect for branch packet handling, it only
>> generate branch samples by checking previous packet flag
>> 'last_instr_taken_branch' is true, this results in below three kinds
>> packets are missed to generate branch samples:
>>
>> - The start tracing packet at the beginning of tracing data;
>> - The exception handling packet;
>> - If one CS_ETM_TRACE_ON packet is inserted, we also miss to handle it
>>    for branch samples.  CS_ETM_TRACE_ON packet itself can give the info
>>    that there have a discontinuity in the trace, on the other hand we
>>    also miss to generate proper branch sample for packets before and
>>    after CS_ETM_TRACE_ON packet.
>>
>> This patch is to add branch sample handling for up three kinds packets:
>>
>> - In function cs_etm__sample(), check if 'prev_packet->sample_type' is
>>    zero and in this case it generates branch sample for the start tracing
>>    packet; furthermore, we also need to handle the condition for
>>    prev_packet::end_addr is zero in the cs_etm__last_executed_instr();
>>
>> - In function cs_etm__sample(), check if 'prev_packet->exc' is true and
>>    generate branch sample for exception handling packet;
>>
>> - If there has one CS_ETM_TRACE_ON packet is coming, we firstly generate
>>    branch sample in the function cs_etm__flush(), this can save complete
>>    info for the previous CS_ETM_RANGE packet just before CS_ETM_TRACE_ON
>>    packet.  We also generate branch sample for the new CS_ETM_RANGE
>>    packet after CS_ETM_TRACE_ON packet, this have two purposes, the
>>    first one purpose is to save the info for the new CS_ETM_RANGE packet,
>>    the second purpose is to save CS_ETM_TRACE_ON packet info so we can
>>    have hint for a discontinuity in the trace.
>>
>>    For CS_ETM_TRACE_ON packet, its fields 'packet->start_addr' and
>>    'packet->end_addr' equal to 0xdeadbeefdeadbeefUL which are emitted in
>>    the decoder layer as dummy value.  This patch is to convert these
>>    values to zeros for more readable; this is accomplished by functions
>>    cs_etm__last_executed_instr() and cs_etm__first_executed_instr().  The
>>    later one is a new function introduced by this patch.
>>
>> Reviewed-by: Robert Walker <robert.walker@arm.com>
>> Fixes: e573e978fb12 ("perf cs-etm: Inject capabilitity for CoreSight traces")
>> Signed-off-by: Leo Yan <leo.yan@linaro.org>
>> ---
>>   tools/perf/util/cs-etm.c | 93 +++++++++++++++++++++++++++++++++++++-----------
>>   1 file changed, 73 insertions(+), 20 deletions(-)
>>
>> diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
>> index 822ba91..8418173 100644
>> --- a/tools/perf/util/cs-etm.c
>> +++ b/tools/perf/util/cs-etm.c
>> @@ -495,6 +495,20 @@ static inline void cs_etm__reset_last_branch_rb(struct cs_etm_queue *etmq)
>>   static inline u64 cs_etm__last_executed_instr(struct cs_etm_packet *packet)
>>   {
>>   	/*
>> +	 * The packet is the start tracing packet if the end_addr is zero,
>> +	 * returns 0 for this case.
>> +	 */
>> +	if (!packet->end_addr)
>> +		return 0;
> 
> What is considered to be the "start tracing packet"?  Right now the only two
> kind of packets inserted in the decoder packet buffer queue are INST_RANGE and
> TRACE_ON.  How can we hit a condition where packet->end-addr == 0?
> 
> 
>> +
>> +	/*
>> +	 * The packet is the CS_ETM_TRACE_ON packet if the end_addr is
>> +	 * magic number 0xdeadbeefdeadbeefUL, returns 0 for this case.
>> +	 */
>> +	if (packet->end_addr == 0xdeadbeefdeadbeefUL)
>> +		return 0;
> 
> As it is with the above, I find triggering on addresses to be brittle and hard
> to maintain on the long run.  Packets all have a sample_type field that should
> be used in cases like this one.  That way we know exactly the condition that is
> targeted.
> 
> While working on this set, please spin-off another patch that defines
> CS_ETM_INVAL_ADDR 0xdeadbeefdeadbeefUL and replace all the cases where the
> numeral is used.  That way we stop using the hard coded value.
> 
>> +
>> +	/*
>>   	 * The packet records the execution range with an exclusive end address
>>   	 *
>>   	 * A64 instructions are constant size, so the last executed
>> @@ -505,6 +519,18 @@ static inline u64 cs_etm__last_executed_instr(struct cs_etm_packet *packet)
>>   	return packet->end_addr - A64_INSTR_SIZE;
>>   }
>>   
>> +static inline u64 cs_etm__first_executed_instr(struct cs_etm_packet *packet)
>> +{
>> +	/*
>> +	 * The packet is the CS_ETM_TRACE_ON packet if the start_addr is
>> +	 * magic number 0xdeadbeefdeadbeefUL, returns 0 for this case.
>> +	 */
>> +	if (packet->start_addr == 0xdeadbeefdeadbeefUL)
>> +		return 0;
> 
> Same comment as above.
> 
>> +
>> +	return packet->start_addr;
>> +}
>> +
>>   static inline u64 cs_etm__instr_count(const struct cs_etm_packet *packet)
>>   {
>>   	/*
>> @@ -546,7 +572,7 @@ static void cs_etm__update_last_branch_rb(struct cs_etm_queue *etmq)
>>   
>>   	be       = &bs->entries[etmq->last_branch_pos];
>>   	be->from = cs_etm__last_executed_instr(etmq->prev_packet);
>> -	be->to	 = etmq->packet->start_addr;
>> +	be->to	 = cs_etm__first_executed_instr(etmq->packet);
>>   	/* No support for mispredict */
>>   	be->flags.mispred = 0;
>>   	be->flags.predicted = 1;
>> @@ -701,7 +727,7 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq)
>>   	sample.ip = cs_etm__last_executed_instr(etmq->prev_packet);
>>   	sample.pid = etmq->pid;
>>   	sample.tid = etmq->tid;
>> -	sample.addr = etmq->packet->start_addr;
>> +	sample.addr = cs_etm__first_executed_instr(etmq->packet);
>>   	sample.id = etmq->etm->branches_id;
>>   	sample.stream_id = etmq->etm->branches_id;
>>   	sample.period = 1;
>> @@ -897,13 +923,28 @@ static int cs_etm__sample(struct cs_etm_queue *etmq)
>>   		etmq->period_instructions = instrs_over;
>>   	}
>>   
>> -	if (etm->sample_branches &&
>> -	    etmq->prev_packet &&
>> -	    etmq->prev_packet->sample_type == CS_ETM_RANGE &&
>> -	    etmq->prev_packet->last_instr_taken_branch) {
>> -		ret = cs_etm__synth_branch_sample(etmq);
>> -		if (ret)
>> -			return ret;
>> +	if (etm->sample_branches && etmq->prev_packet) {
>> +		bool generate_sample = false;
>> +
>> +		/* Generate sample for start tracing packet */
>> +		if (etmq->prev_packet->sample_type == 0 ||
> 
> What kind of packet is sample_type == 0 ?
> 
>> +		    etmq->prev_packet->sample_type == CS_ETM_TRACE_ON)
>> +			generate_sample = true;
>> +
>> +		/* Generate sample for exception packet */
>> +		if (etmq->prev_packet->exc == true)
>> +			generate_sample = true;
> 
> Please don't do that.  Exception packets have a type of their own and can be
> added to the decoder packet queue the same way INST_RANGE and TRACE_ON packets
> are.  Moreover exception packet containt an address that, if I'm reading the
> documenation properly, can be used to keep track of instructions that were
> executed between the last address of the previous range packet and the address
> executed just before the exception occurred.  Mike and Rob will have to confirm
> this as the decoder may be doing all that hard work for us.
> 
>> +
>> +		/* Generate sample for normal branch packet */
>> +		if (etmq->prev_packet->sample_type == CS_ETM_RANGE &&
>> +		    etmq->prev_packet->last_instr_taken_branch)
>> +			generate_sample = true;
>> +
>> +		if (generate_sample) {
>> +			ret = cs_etm__synth_branch_sample(etmq);
>> +			if (ret)
>> +				return ret;
>> +		}
>>   	}
>>   
>>   	if (etm->sample_branches || etm->synth_opts.last_branch) {
>> @@ -922,11 +963,16 @@ static int cs_etm__sample(struct cs_etm_queue *etmq)
>>   static int cs_etm__flush(struct cs_etm_queue *etmq)
>>   {
>>   	int err = 0;
>> +	struct cs_etm_auxtrace *etm = etmq->etm;
>>   	struct cs_etm_packet *tmp;
>>   
>> -	if (etmq->etm->synth_opts.last_branch &&
>> -	    etmq->prev_packet &&
>> -	    etmq->prev_packet->sample_type == CS_ETM_RANGE) {
>> +	if (!etmq->prev_packet)
>> +		return 0;
>> +
>> +	if (etmq->prev_packet->sample_type != CS_ETM_RANGE)
>> +		return 0;
>> +
>> +	if (etmq->etm->synth_opts.last_branch) {
> 
> If you add:
> 
>          if (!etmq->etm->synth_opts.last_branch)
>                  return 0;
> 
> You can avoid indenting the whole block.
> 
>>   		/*
>>   		 * Generate a last branch event for the branches left in the
>>   		 * circular buffer at the end of the trace.
>> @@ -939,18 +985,25 @@ static int cs_etm__flush(struct cs_etm_queue *etmq)
>>   		err = cs_etm__synth_instruction_sample(
>>   			etmq, addr,
>>   			etmq->period_instructions);
>> +		if (err)
>> +			return err;
>>   		etmq->period_instructions = 0;
>> +	}
>>   
>> -		/*
>> -		 * Swap PACKET with PREV_PACKET: PACKET becomes PREV_PACKET for
>> -		 * the next incoming packet.
>> -		 */
>> -		tmp = etmq->packet;
>> -		etmq->packet = etmq->prev_packet;
>> -		etmq->prev_packet = tmp;
>> +	if (etm->sample_branches) {
>> +		err = cs_etm__synth_branch_sample(etmq);
>> +		if (err)
>> +			return err;
>>   	}
>>   
>> -	return err;
>> +	/*
>> +	 * Swap PACKET with PREV_PACKET: PACKET becomes PREV_PACKET for
>> +	 * the next incoming packet.
>> +	 */
>> +	tmp = etmq->packet;
>> +	etmq->packet = etmq->prev_packet;
>> +	etmq->prev_packet = tmp;
> 
> Robert, I remember noticing that when you first submitted the code but forgot to
> go back to it.  What is the point of swapping the packets?  I understand
> 
> etmq->prev_packet = etmq->packet;
> 
> But not
> 
> etmq->packet = tmp;
> 
> After all etmq->packet will be clobbered as soon as cs_etm_decoder__get_packet()
> is called, which is alwasy right after either cs_etm__sample() or
> cs_etm__flush().
>

This is code I inherited from the original versions of these patches, 
but it works because:
- etmq->packet and etmq->prev_packet are pointers to struct 
cs_etm_packet allocated by zalloc() in cs_etm__alloc_queue()
- cs_etm_decoder__get_packet() takes a pointer to struct cs_etm_packet 
and copies the contents of the first packet from the queue into the 
passed location with:
    *packet = decoder->packet_buffer[decoder->head]

So the swap code is only swapping the pointers over, not the contents of 
the packets.

Regards

Rob


> Thanks,
> Mathieu
>
> 
> 
>> +	return 0;
>>   }
>>   
>>   static int cs_etm__run_decoder(struct cs_etm_queue *etmq)
>> -- 
>> 2.7.4
>>

^ permalink raw reply

* [PATCH] drm/bridge/synopsys: dw-hdmi: fix dw_hdmi_setup_rx_sense
From: Neil Armstrong @ 2018-05-30  9:43 UTC (permalink / raw)
  To: linux-arm-kernel

The dw_hdmi_setup_rx_sense exported function should not use struct device
to recover the dw-hdmi context using drvdata, but take struct dw_hdmi
directly like other exported functions.

This caused a regression using Meson DRM on S905X since v4.17-rc1 :

Internal error: Oops: 96000007 [#1] PREEMPT SMP
[...]
CPU: 0 PID: 124 Comm: irq/32-dw_hdmi_ Not tainted 4.17.0-rc7 #2
Hardware name: Libre Technology CC (DT)
[...]
pc : osq_lock+0x54/0x188
lr : __mutex_lock.isra.0+0x74/0x530
[...]
Process irq/32-dw_hdmi_ (pid: 124, stack limit = 0x00000000adf418cb)
Call trace:
  osq_lock+0x54/0x188
  __mutex_lock_slowpath+0x10/0x18
  mutex_lock+0x30/0x38
  __dw_hdmi_setup_rx_sense+0x28/0x98
  dw_hdmi_setup_rx_sense+0x10/0x18
  dw_hdmi_top_thread_irq+0x2c/0x50
  irq_thread_fn+0x28/0x68
  irq_thread+0x10c/0x1a0
  kthread+0x128/0x130
  ret_from_fork+0x10/0x18
 Code: 34000964 d00050a2 51000484 9135c042 (f864d844)
 ---[ end trace 945641e1fbbc07da ]---
 note: irq/32-dw_hdmi_[124] exited with preempt_count 1
 genirq: exiting task "irq/32-dw_hdmi_" (124) is an active IRQ thread (irq 32)

Fixes: eea034af90c6 ("drm/bridge/synopsys: dw-hdmi: don't clobber drvdata")
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Tested-by: Koen Kooi <koen@dominion.thruhere.net>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 15 ++++-----------
 drivers/gpu/drm/meson/meson_dw_hdmi.c     |  2 +-
 include/drm/bridge/dw_hdmi.h              |  2 +-
 3 files changed, 6 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index ec8d000..3c136f2b 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -2077,7 +2077,7 @@ static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id)
 	return ret;
 }
 
-void __dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense)
+void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense)
 {
 	mutex_lock(&hdmi->mutex);
 
@@ -2103,13 +2103,6 @@ void __dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense)
 	}
 	mutex_unlock(&hdmi->mutex);
 }
-
-void dw_hdmi_setup_rx_sense(struct device *dev, bool hpd, bool rx_sense)
-{
-	struct dw_hdmi *hdmi = dev_get_drvdata(dev);
-
-	__dw_hdmi_setup_rx_sense(hdmi, hpd, rx_sense);
-}
 EXPORT_SYMBOL_GPL(dw_hdmi_setup_rx_sense);
 
 static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
@@ -2145,9 +2138,9 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
 	 */
 	if (intr_stat &
 	    (HDMI_IH_PHY_STAT0_RX_SENSE | HDMI_IH_PHY_STAT0_HPD)) {
-		__dw_hdmi_setup_rx_sense(hdmi,
-					 phy_stat & HDMI_PHY_HPD,
-					 phy_stat & HDMI_PHY_RX_SENSE);
+		dw_hdmi_setup_rx_sense(hdmi,
+				       phy_stat & HDMI_PHY_HPD,
+				       phy_stat & HDMI_PHY_RX_SENSE);
 
 		if ((phy_stat & (HDMI_PHY_RX_SENSE | HDMI_PHY_HPD)) == 0)
 			cec_notifier_set_phys_addr(hdmi->cec_notifier,
diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
index a393095..c9ad456 100644
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
@@ -529,7 +529,7 @@ static irqreturn_t dw_hdmi_top_thread_irq(int irq, void *dev_id)
 		if (stat & HDMITX_TOP_INTR_HPD_RISE)
 			hpd_connected = true;
 
-		dw_hdmi_setup_rx_sense(dw_hdmi->dev, hpd_connected,
+		dw_hdmi_setup_rx_sense(dw_hdmi->hdmi, hpd_connected,
 				       hpd_connected);
 
 		drm_helper_hpd_irq_event(dw_hdmi->encoder.dev);
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index dd2a8cf..ccb5aa8 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -151,7 +151,7 @@ struct dw_hdmi *dw_hdmi_bind(struct platform_device *pdev,
 			     struct drm_encoder *encoder,
 			     const struct dw_hdmi_plat_data *plat_data);
 
-void dw_hdmi_setup_rx_sense(struct device *dev, bool hpd, bool rx_sense);
+void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense);
 
 void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate);
 void dw_hdmi_audio_enable(struct dw_hdmi *hdmi);
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 9/9] drm/mediatek: Add support for mediatek SOC MT2712
From: kbuild test robot @ 2018-05-30  9:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1527489507-24453-10-git-send-email-stu.hsieh@mediatek.com>

Hi Stu,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on drm/drm-next]
[also build test ERROR on v4.17-rc7 next-20180529]
[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/Stu-Hsieh/Add-support-for-mediatek-SOC-MT2712/20180530-032344
base:   git://people.freedesktop.org/~airlied/linux.git drm-next
config: arm-allmodconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/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 >>):

>> drivers/gpu//drm/mediatek/mtk_drm_drv.c:165:2: error: 'DDP_COMPONENT_DPI1' undeclared here (not in a function); did you mean 'DDP_COMPONENT_DSI1'?
     DDP_COMPONENT_DPI1,
     ^~~~~~~~~~~~~~~~~~
     DDP_COMPONENT_DSI1
>> drivers/gpu//drm/mediatek/mtk_drm_drv.c:171:2: error: 'DDP_COMPONENT_DSI2' undeclared here (not in a function); did you mean 'DDP_COMPONENT_DSI1'?
     DDP_COMPONENT_DSI2,
     ^~~~~~~~~~~~~~~~~~
     DDP_COMPONENT_DSI1
>> drivers/gpu//drm/mediatek/mtk_drm_drv.c:171:2: error: incompatible types when initializing type 'enum mtk_ddp_comp_id' using type 'const enum mtk_ddp_comp_id *'

vim +165 drivers/gpu//drm/mediatek/mtk_drm_drv.c

   158	
   159	static const enum mtk_ddp_comp_id mt2712_mtk_ddp_ext[] = {
   160		DDP_COMPONENT_OVL1,
   161		DDP_COMPONENT_COLOR1,
   162		DDP_COMPONENT_AAL1,
   163		DDP_COMPONENT_OD1,
   164		DDP_COMPONENT_RDMA1,
 > 165		DDP_COMPONENT_DPI1,
   166		DDP_COMPONENT_PWM1,
   167	};
   168	
   169	static const enum mtk_ddp_comp_id mt2712_mtk_ddp_third[] = {
   170		DDP_COMPONENT_RDMA2,
 > 171		DDP_COMPONENT_DSI2,
   172		DDP_COMPONENT_PWM2,
   173	};
   174	

---
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/gzip
Size: 65217 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180530/15cd8e25/attachment-0001.gz>

^ permalink raw reply

* [PATCH v3 1/2] regulator: dt-bindings: add QCOM RPMh regulator bindings
From: Mark Brown @ 2018-05-30  9:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAD=FV=W4aDxWbcaJ9GZ1KkvyiTPAPR-oUoTFzJfS+LftU5ZP=Q@mail.gmail.com>

On Tue, May 29, 2018 at 10:30:33PM -0700, Doug Anderson wrote:
> On Wed, May 23, 2018 at 8:56 AM, Mark Brown <broonie@kernel.org> wrote:

> > Yes, that's definitely not what's expected but it's unfortunately what
> > the firmware chose to implement so we may well be stuck with it
> > unfortunately.

> We're not really stuck with it if we do what I was suggesting.  I was
> suggesting that every time we disable the regulator in Linux we have
> Linux vote for the lowest voltage it's comfortable with.  Linux keeps
> track of the true voltage that the driver wants and will always change
> its vote back to that before enabling.  Thus (assuming Linux is OK
> with 1.2 V - 1.4 V for a rail):

That's pretty much what it should do anyway with normally designed
hardware.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180530/9b330fe7/attachment.sig>

^ permalink raw reply

* [PATCH 2/2] arm64: dts: renesas: condor: add I2C0 support
From: Simon Horman @ 2018-05-30  9:35 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <9bc27b57-cf26-3b03-6ec4-1e9788a46426@cogentembedded.com>

On Tue, May 29, 2018 at 06:46:10PM +0300, Sergei Shtylyov wrote:
> Hello!
> 
> On 05/29/2018 04:10 PM, Simon Horman wrote:
> 
> >> Define the Condor board dependent part of the I2C0 device node.
> >>
> >> The I2C0 bus is populated by 2 ON Semiconductor PCA9654 I/O expanders
> >> and Analog Devices  ADV7511W HDMI transmitter (but we're only describing
> >> the former chips now).
> >>
> >> Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
> >>
> >> ---
> >>  arch/arm64/boot/dts/renesas/r8a77980-condor.dts |   27 ++++++++++++++++++++++++
> >>  1 file changed, 27 insertions(+)
> >>
> >> Index: renesas/arch/arm64/boot/dts/renesas/r8a77980-condor.dts
> >> ===================================================================
> >> --- renesas.orig/arch/arm64/boot/dts/renesas/r8a77980-condor.dts
> >> +++ renesas/arch/arm64/boot/dts/renesas/r8a77980-condor.dts
> >> @@ -80,6 +80,28 @@
> >>  	clock-frequency = <32768>;
> >>  };
> >>  
> >> +&i2c0 {
> >> +	pinctrl-0 = <&i2c0_pins>;
> >> +	pinctrl-names = "default";
> >> +
> >> +	status = "okay";
> >> +	clock-frequency = <400000>;
> >> +
> >> +	io_expander0: gpio at 20 {
> > 
> > Hi Sergei,
> > 
> > I'm a little confused about where 0x20 and 0x21 are derived from.
> > Could you explain a little?
> 
>    r-carv3h_system_evaluation_board_rev020.pdf, pp. 16-17, lower left corners.
> The schematics gives the 8-bit read/write addresses but we use uniform 7-bit
> I2C address in DTs.

Thanks, this patch looks fine to me.
However, I'd like to give others a chance to review it,
and it is dependent on patch 1/2 where I have a different review question.

Reviewed-by: Simon Horman <horms+renesas@verge.net.au>

> >> +		compatible = "onnn,pca9654";
> >> +		reg = <0x20>;
> >> +		gpio-controller;
> >> +		#gpio-cells = <2>;
> >> +	};
> >> +
> >> +	io_expander1: gpio at 21 {
> >> +		compatible = "onnn,pca9654";
> >> +		reg = <0x21>;
> >> +		gpio-controller;
> >> +		#gpio-cells = <2>;
> >> +	};
> >> +};
> >> +
> >>  &mmc0 {
> >>  	pinctrl-0 = <&mmc_pins>;
> >>  	pinctrl-1 = <&mmc_pins_uhs>;
> 

^ permalink raw reply

* [PATCH v2 0/9] PM / Domains: Add support for multi PM domains per device
From: Rafael J. Wysocki @ 2018-05-30  9:30 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180529100421.31022-1-ulf.hansson@linaro.org>

On Tue, May 29, 2018 at 12:04 PM, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> Changes in v2:
>         - Addressed comments from Geert around DT doc.
>         - Addressed comments from Jon around clarification of how to use this
>         and changes to returned error codes.
>         - Fixed build error in case CONFIG_PM was unset.
>
> There are devices that are partitioned across multiple PM domains. Currently
> these can't be supported well by the available PM infrastructures we have in
> the kernel. This series is an attempt to address this.
>
> The interesting parts happens from patch 5 an onwards, including a minor DT
> update to the existing power-domain bindings, the 4 earlier are just trivial
> clean-ups of some related code in genpd, which I happened to stumble over.
>
> Some additional background:
>
> One existing case where devices are partitioned across multiple PM domains, is
> the Nvida Tegra 124/210 X-USB subsystem. A while ago Jon Hunter (Nvidia) sent a
> series, trying to address these issues, however this is a new approach, while
> it re-uses the same concepts from DT point of view.
>
> The Tegra 124/210 X-USB subsystem contains of a host controller and a device
> controller. Each controller have its own independent PM domain, but are being
> partitioned across another shared PM domain for the USB super-speed logic.
>
> Currently to make the drivers work, either the related PM domains needs to stay
> powered on always or the PM domain topology needs to be in-correctly modelled
> through sub-domains. In both cases PM domains may be powered on while they
> don't need to be, so in the end this means - wasting power -.
>
> As stated above, this series intends to address these problem from a PM
> infrastructure point of view. More details are available in each changelog.
>
> It should be noted that this series has been tested on HW, however only by using
> a home-cooked test PM domain driver for genpd and together with a test driver.
> This allowed me to play with PM domain (genpd), runtime PM and device links.
>
> Any further deployment for real use cases are greatly appreciated. I am happy to
> to help, if needed!
>
> Kind regards
> Ulf Hansson
>
>
> Ulf Hansson (9):
>   PM / Domains: Drop extern declarations of functions in pm_domain.h
>   PM / Domains: Drop __pm_genpd_add_device()
>   PM / Domains: Drop genpd as in-param for pm_genpd_remove_device()
>   PM / Domains: Drop unused parameter in genpd_allocate_dev_data()
>   PM / Domains: dt: Allow power-domain property to be a list of
>     specifiers
>   PM / Domains: Don't attach devices in genpd with multi PM domains
>   PM / Domains: Split genpd_dev_pm_attach()
>   PM / Domains: Add support for multi PM domains per device to genpd
>   PM / Domains: Add dev_pm_domain_attach_by_id() to manage multi PM
>     domains
>
>  .../bindings/power/power_domain.txt           |  19 ++-
>  drivers/base/power/common.c                   |  39 ++++-
>  drivers/base/power/domain.c                   | 155 ++++++++++++++----
>  drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c       |   2 +-
>  include/linux/pm_domain.h                     |  79 ++++-----
>  5 files changed, 216 insertions(+), 78 deletions(-)

I can take patches [1-4/9] from this series for 4.18.

I need an ACK from Rob on the bindings change.

The rest of the series doesn't seem to be ready yet.

Thanks,
Rafael

^ permalink raw reply

* [PATCH v10 0/2] Initial Allwinner V3s CSI Support
From: Sakari Ailus @ 2018-05-30  9:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180529095757.qkz7jyuxza7movbc@flea.home>

On Tue, May 29, 2018 at 11:57:57AM +0200, Maxime Ripard wrote:
> On Thu, May 17, 2018 at 11:02:24AM +0200, Maxime Ripard wrote:
> > On Fri, May 04, 2018 at 02:44:08PM +0800, Yong Deng wrote:
> > > This patchset add initial support for Allwinner V3s CSI.
> > > 
> > > Allwinner V3s SoC features two CSI module. CSI0 is used for MIPI CSI-2
> > > interface and CSI1 is used for parallel interface. This is not
> > > documented in datasheet but by test and guess.
> > > 
> > > This patchset implement a v4l2 framework driver and add a binding 
> > > documentation for it. 
> > > 
> > > Currently, the driver only support the parallel interface. And has been
> > > tested with a BT1120 signal which generating from FPGA. The following
> > > fetures are not support with this patchset:
> > >   - ISP 
> > >   - MIPI-CSI2
> > >   - Master clock for camera sensor
> > >   - Power regulator for the front end IC
> > 
> > I tested it on my H3 with a parallel camera, and it still works. Thanks!
> > 
> > Hans, Sakari, any chance this might land in 4.18?
> 
> Ping?

I'll try to look into this soonish but it seems to be too late for 4.18.
Sorry about that.

-- 
Sakari Ailus
sakari.ailus at linux.intel.com

^ permalink raw reply

* [PATCH v2 9/9] PM / Domains: Add dev_pm_domain_attach_by_id() to manage multi PM domains
From: Jon Hunter @ 2018-05-30  9:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180529100421.31022-10-ulf.hansson@linaro.org>

Hi Ulf,

On 29/05/18 11:04, Ulf Hansson wrote:
> The existing dev_pm_domain_attach() function, allows a single PM domain to
> be attached per device. To be able to support devices that are partitioned
> across multiple PM domains, let's introduce a new interface,
> dev_pm_domain_attach_by_id().
> 
> The dev_pm_domain_attach_by_id() returns a new allocated struct device with
> the corresponding attached PM domain. This enables for example a driver to
> operate on the new device from a power management point of view. The driver
> may then also benefit from using the received device, to set up so called
> device-links towards its original device. Depending on the situation, these
> links may then be dynamically changed.

I have given this series a go with Tegra updating the XHCI driver to make
use of these new APIs. Good news it does appear to work fine for Tegra,
however, initially when looking at the device_link_add() API ...

/**
 * device_link_add - Create a link between two devices.
 * @consumer: Consumer end of the link.
 * @supplier: Supplier end of the link.
 * @flags: Link flags.

 ... I had assumed that the 'consumer' device would be the actual XHCI 
device (in the case of Tegra) and the 'supplier' device would be the new
genpd device. However, this did not work and I got the following WARN on
boot ...

[    2.050929] ---[ end trace eff0b5265e530c92 ]---
[    2.055567] WARNING: CPU: 2 PID: 1 at drivers/base/core.c:446 device_links_driver_bound+0xc0/0xd0
[    2.064422] Modules linked in:
[    2.067471] CPU: 2 PID: 1 Comm: swapper/0 Tainted: G        W         4.17.0-rc7-next-20180529-00011-g4faf0dc0ebf3-dirty #32
[    2.078667] Hardware name: Google Pixel C (DT)
[    2.083101] pstate: 80000005 (Nzcv daif -PAN -UAO)
[    2.087881] pc : device_links_driver_bound+0xc0/0xd0
[    2.092832] lr : device_links_driver_bound+0x20/0xd0

Switching the Tegra XHCI device to be the 'supplier' and genpd device to
be the 'consumer' does work, but is this correct? Seems to be opposite to
what I expected. Maybe I am missing something?

> The new interface is typically called by drivers during their probe phase,
> in case they manages devices which uses multiple PM domains. If that is the
> case, the driver also becomes responsible of managing the detaching of the
> PM domains, which typically should be done at the remove phase. Detaching
> is done by calling the existing dev_pm_domain_detach() function and for
> each of the received devices from dev_pm_domain_attach_by_id().
> 
> Note, currently its only genpd that supports multiple PM domains per
> device, but dev_pm_domain_attach_by_id() can easily by extended to cover
> other PM domain types, if/when needed.
> 
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> ---
> 
> Changes in v2:
> 	- Fixed comments from Jon. Clarified function descriptions/changelog and
> 	return ERR_PTR(-EEXIST) in case a PM domain is already assigned.
> 	- Fix build error when CONFIG_PM is unset.
> 
> ---
>  drivers/base/power/common.c | 43 ++++++++++++++++++++++++++++++++++---
>  include/linux/pm_domain.h   |  7 ++++++
>  2 files changed, 47 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c
> index 7ae62b6355b8..5e5ea0c239de 100644
> --- a/drivers/base/power/common.c
> +++ b/drivers/base/power/common.c
> @@ -116,14 +116,51 @@ int dev_pm_domain_attach(struct device *dev, bool power_on)
>  }
>  EXPORT_SYMBOL_GPL(dev_pm_domain_attach);
>  
> +/**
> + * dev_pm_domain_attach_by_id - Attach a device to one of its PM domains.
> + * @dev: Device to attach.

Nit ... I still don't think this is the device we are attaching to, but the
device the PM domains are associated with. IOW we are using this device to
lookup the PM domains.

> + * @index: The index of the PM domain.
> + *
> + * As @dev may only be attached to a single PM domain, the backend PM domain
> + * provider creates a virtual device to attach instead. If attachment succeeds,
> + * the ->detach() callback in the struct dev_pm_domain are assigned by the
> + * corresponding backend attach function, as to deal with detaching of the
> + * created virtual device.
> + *
> + * This function should typically be invoked by a driver during the probe phase,
> + * in case its device requires power management through multiple PM domains. The
> + * driver may benefit from using the received device, to configure device-links
> + * towards its original device. Depending on the use-case and if needed, the
> + * links may be dynamically changed by the driver, which allows it to control
> + * the power to the PM domains independently from each other.
> + *
> + * Callers must ensure proper synchronization of this function with power
> + * management callbacks.
> + *
> + * Returns the virtual created device when successfully attached to its PM
> + * domain, NULL in case @dev don't need a PM domain, else an ERR_PTR().
> + * Note that, to detach the returned virtual device, the driver shall call
> + * dev_pm_domain_detach() on it, typically during the remove phase.
> + */
> +struct device *dev_pm_domain_attach_by_id(struct device *dev,
> +					  unsigned int index)
> +{
> +	if (dev->pm_domain)
> +		return ERR_PTR(-EEXIST);
> +
> +	return genpd_dev_pm_attach_by_id(dev, index);
> +}
> +EXPORT_SYMBOL_GPL(dev_pm_domain_attach_by_id);
> +
>  /**
>   * dev_pm_domain_detach - Detach a device from its PM domain.
>   * @dev: Device to detach.
>   * @power_off: Used to indicate whether we should power off the device.
>   *
> - * This functions will reverse the actions from dev_pm_domain_attach() and thus
> - * try to detach the @dev from its PM domain. Typically it should be invoked
> - * from subsystem level code during the remove phase.
> + * This functions will reverse the actions from dev_pm_domain_attach() and
> + * dev_pm_domain_attach_by_id(), thus it detaches @dev from its PM domain.
> + * Typically it should be invoked during the remove phase, either from
> + * subsystem level code or from drivers.
>   *
>   * Callers must ensure proper synchronization of this function with power
>   * management callbacks.
> diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
> index 82458e8e2e01..9206a4fef9ac 100644
> --- a/include/linux/pm_domain.h
> +++ b/include/linux/pm_domain.h
> @@ -299,6 +299,8 @@ struct generic_pm_domain *of_genpd_remove_last(struct device_node *np)
>  
>  #ifdef CONFIG_PM
>  int dev_pm_domain_attach(struct device *dev, bool power_on);
> +struct device *dev_pm_domain_attach_by_id(struct device *dev,
> +					  unsigned int index);
>  void dev_pm_domain_detach(struct device *dev, bool power_off);
>  void dev_pm_domain_set(struct device *dev, struct dev_pm_domain *pd);
>  #else
> @@ -306,6 +308,11 @@ static inline int dev_pm_domain_attach(struct device *dev, bool power_on)
>  {
>  	return 0;
>  }
> +static inline struct device *dev_pm_domain_attach_by_id(struct device *dev,
> +							unsigned int index)
> +{
> +	return NULL;
> +}
>  static inline void dev_pm_domain_detach(struct device *dev, bool power_off) {}
>  static inline void dev_pm_domain_set(struct device *dev,
>  				     struct dev_pm_domain *pd) {}
> 

My only other comments on this series are ...

1. I think it would be nice to have an dev_pm_domain_attach_by_name() and 
   that the DT binding has a 'power-domain-names' property.
2. I am wondering if there could be value in having a
   dev_pm_domain_attach_link_all() helper which would attach and link all
   PM domains at once. 

Cheers
Jon

-- 
nvpublic

^ permalink raw reply

* [PATCH] arm64: mm: mark tramp_pg_dir read-only
From: Will Deacon @ 2018-05-30  9:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180530044806.18449-1-yaojun8558363@gmail.com>

On Wed, May 30, 2018 at 12:48:06PM +0800, YaoJun wrote:
> To protect against KSMA(Kernel Space Mirroring Attack), make
> tramp_pg_dir read-only. The principle of KSMA is to insert a
> carefully constructed PGD entry into the translation table.
> The type of this entry is block, which maps the kernel text
> and its access permissions bits are 01. The user process can
> then modify kernel text directly through this mapping. In this
> way, an arbitrary write can be converted to multiple arbitrary
> writes.
> 
> Signed-off-by: YaoJun <yaojun8558363@gmail.com>
> ---
>  arch/arm64/mm/mmu.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 2dbb2c9f1ec1..ac4b22c7e435 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -551,6 +551,10 @@ static int __init map_entry_trampoline(void)
>  	__create_pgd_mapping(tramp_pg_dir, pa_start, TRAMP_VALIAS, PAGE_SIZE,
>  			     prot, pgd_pgtable_alloc, 0);
>  
> +	update_mapping_prot(__pa_symbol(tramp_pg_dir),
> +				(unsigned long)tramp_pg_dir,
> +				PGD_SIZE, PAGE_KERNEL_RO);

Hmm, I like the idea but is there a risk that the page table has been mapped
as part of a block entry, which we can't safely split at this point (i.e.
we'll run into one of the BUG_ONs in the mapping code)?

Will

^ permalink raw reply

* Regression in Linux next again
From: Mark Brown @ 2018-05-30  9:13 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180529221501.GJ5702@atomide.com>

On Tue, May 29, 2018 at 03:15:01PM -0700, Tony Lindgren wrote:

> I think I bisected this same issue for the second time now
> but for a different merge window. What's up with that?

Last time we just reverted it as Maciej was unable to reproduce your
problem, he's tried again with some alterations.

> Reverting both patches fixes the issue for me. I could
> not debug it further because of the compile error(s).

OK, unless this gets fixed really quickly I'll revert again.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180530/89c8cec3/attachment.sig>

^ permalink raw reply

* [PATCH 4/4] arm64/mm: migrate swapper_pg_dir
From: YaoJun @ 2018-05-30  9:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180530091259.9386-1-yaojun8558363@gmail.com>

Migrate swapper_pg_dir and tramp_pg_dir. And its placement in
the virtual address space does not correlate with the placement
of the kernel.

Signed-off-by: YaoJun <yaojun8558363@gmail.com>
---
 arch/arm64/mm/mmu.c | 67 +++++++++++++++++++++++++++++++--------------
 1 file changed, 46 insertions(+), 21 deletions(-)

diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 26ba3e70a91c..b508de2cc6c4 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -57,6 +57,9 @@ EXPORT_SYMBOL(kimage_voffset);
 
 phys_addr_t __pa_swapper_pg_dir;
 pgd_t *new_swapper_pg_dir = swapper_pg_dir;
+#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+pgd_t *new_tramp_pg_dir;
+#endif
 
 /*
  * Empty_zero_page is a special page that is used for zero-initialized data
@@ -105,6 +108,25 @@ static phys_addr_t __init early_pgtable_alloc(void)
 	return phys;
 }
 
+#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+static phys_addr_t __init early_pgtables_alloc(int num)
+{
+	int i;
+	phys_addr_t phys;
+	void *ptr;
+
+	phys = memblock_alloc(PAGE_SIZE * num, PAGE_SIZE);
+
+	for (i = 0; i < num; i++) {
+		ptr = pte_set_fixmap(phys + i * PAGE_SIZE);
+		memset(ptr, 0, PAGE_SIZE);
+		pte_clear_fixmap();
+	}
+
+	return phys;
+}
+#endif
+
 static bool pgattr_change_is_safe(u64 old, u64 new)
 {
 	/*
@@ -554,6 +576,10 @@ static int __init map_entry_trampoline(void)
 	__create_pgd_mapping(tramp_pg_dir, pa_start, TRAMP_VALIAS, PAGE_SIZE,
 			     prot, pgd_pgtable_alloc, 0);
 
+	memcpy(new_tramp_pg_dir, tramp_pg_dir, PGD_SIZE);
+	memblock_free(__pa_symbol(tramp_pg_dir),
+		__pa_symbol(swapper_pg_dir) - __pa_symbol(tramp_pg_dir));
+
 	/* Map both the text and data into the kernel page table */
 	__set_fixmap(FIX_ENTRY_TRAMP_TEXT, pa_start, prot);
 	if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
@@ -631,36 +657,35 @@ static void __init map_kernel(pgd_t *pgdp)
  */
 void __init paging_init(void)
 {
-	phys_addr_t pgd_phys = early_pgtable_alloc();
-	pgd_t *pgdp = pgd_set_fixmap(pgd_phys);
+	phys_addr_t pgd_phys;
+	pgd_t *pgdp;
+
+#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+	int pages;
+
+	pages = (__pa_symbol(swapper_pg_dir) - __pa_symbol(tramp_pg_dir) +
+			PAGE_SIZE) >> PAGE_SHIFT;
+	pgd_phys = early_pgtables_alloc(pages);
+	new_tramp_pg_dir = __va(pgd_phys);
+	__pa_swapper_pg_dir = pgd_phys + PAGE_SIZE;
+#else
+	pgd_phys = early_pgtable_alloc();
+	__pa_swapper_pg_dir = pgd_phys;
+#endif
+	new_swapper_pg_dir = __va(__pa_swapper_pg_dir);
 
-	__pa_swapper_pg_dir = __pa_symbol(swapper_pg_dir);
+	pgdp = pgd_set_fixmap(__pa_swapper_pg_dir);
 
 	map_kernel(pgdp);
 	map_mem(pgdp);
 
-	/*
-	 * We want to reuse the original swapper_pg_dir so we don't have to
-	 * communicate the new address to non-coherent secondaries in
-	 * secondary_entry, and so cpu_switch_mm can generate the address with
-	 * adrp+add rather than a load from some global variable.
-	 *
-	 * To do this we need to go via a temporary pgd.
-	 */
-	cpu_replace_ttbr1(pgd_phys);
-	memcpy(swapper_pg_dir, pgdp, PGD_SIZE);
 	cpu_replace_ttbr1(__pa_swapper_pg_dir);
+	init_mm.pgd = new_swapper_pg_dir;
 
 	pgd_clear_fixmap();
-	memblock_free(pgd_phys, PAGE_SIZE);
 
-	/*
-	 * We only reuse the PGD from the swapper_pg_dir, not the pud + pmd
-	 * allocated with it.
-	 */
-	memblock_free(__pa_symbol(swapper_pg_dir) + PAGE_SIZE,
-		      __pa_symbol(swapper_pg_end) - __pa_symbol(swapper_pg_dir)
-		      - PAGE_SIZE);
+	memblock_free(__pa_symbol(swapper_pg_dir),
+		__pa_symbol(swapper_pg_end) - __pa_symbol(swapper_pg_dir));
 }
 
 /*
-- 
2.17.0

^ permalink raw reply related

* [PATCH 3/4] arm64/mm: migrate swapper_pg_dir
From: YaoJun @ 2018-05-30  9:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180530091259.9386-1-yaojun8558363@gmail.com>

Make tramp_pg_dir and swapper_pg_dir adjacent. So we can migrate
them together.

Signed-off-by: YaoJun <yaojun8558363@gmail.com>
---
 arch/arm64/kernel/entry.S       |  4 ++--
 arch/arm64/kernel/vmlinux.lds.S | 10 +++++-----
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index ec2ee720e33e..b35425feaf56 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -1004,7 +1004,7 @@ __ni_sys_trace:
 
 	.macro tramp_map_kernel, tmp
 	mrs	\tmp, ttbr1_el1
-	add	\tmp, \tmp, #(PAGE_SIZE + RESERVED_TTBR0_SIZE)
+	add	\tmp, \tmp, #(PAGE_SIZE)
 	bic	\tmp, \tmp, #USER_ASID_FLAG
 	msr	ttbr1_el1, \tmp
 #ifdef CONFIG_QCOM_FALKOR_ERRATUM_1003
@@ -1023,7 +1023,7 @@ alternative_else_nop_endif
 
 	.macro tramp_unmap_kernel, tmp
 	mrs	\tmp, ttbr1_el1
-	sub	\tmp, \tmp, #(PAGE_SIZE + RESERVED_TTBR0_SIZE)
+	sub	\tmp, \tmp, #(PAGE_SIZE)
 	orr	\tmp, \tmp, #USER_ASID_FLAG
 	msr	ttbr1_el1, \tmp
 	/*
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index 0221aca6493d..a094156e05a4 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -219,15 +219,15 @@ SECTIONS
 	idmap_pg_dir = .;
 	. += IDMAP_DIR_SIZE;
 
-#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
-	tramp_pg_dir = .;
-	. += PAGE_SIZE;
-#endif
-
 #ifdef CONFIG_ARM64_SW_TTBR0_PAN
 	reserved_ttbr0 = .;
 	. += RESERVED_TTBR0_SIZE;
 #endif
+
+#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+	tramp_pg_dir = .;
+	. += PAGE_SIZE;
+#endif
 	swapper_pg_dir = .;
 	. += SWAPPER_DIR_SIZE;
 	swapper_pg_end = .;
-- 
2.17.0

^ permalink raw reply related

* [PATCH 2/4] arm64/mm: migrate swapper_pg_dir
From: YaoJun @ 2018-05-30  9:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180530091259.9386-1-yaojun8558363@gmail.com>

Introduce new_swapper_pg_dir to save virtual address of
 new swapper_pg_dir.

Signed-off-by: YaoJun <yaojun8558363@gmail.com>
---
 arch/arm64/include/asm/mmu_context.h | 2 +-
 arch/arm64/include/asm/pgtable.h     | 1 +
 arch/arm64/mm/kasan_init.c           | 2 +-
 arch/arm64/mm/mmu.c                  | 1 +
 4 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h
index 3eddb871f251..481c2d16adeb 100644
--- a/arch/arm64/include/asm/mmu_context.h
+++ b/arch/arm64/include/asm/mmu_context.h
@@ -57,7 +57,7 @@ static inline void cpu_set_reserved_ttbr0(void)
 
 static inline void cpu_switch_mm(pgd_t *pgd, struct mm_struct *mm)
 {
-	BUG_ON(pgd == swapper_pg_dir);
+	BUG_ON(pgd == new_swapper_pg_dir);
 	cpu_set_reserved_ttbr0();
 	cpu_do_switch_mm(virt_to_phys(pgd),mm);
 }
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 14ba344b1af7..7abec25cedd2 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -723,6 +723,7 @@ extern pgd_t swapper_pg_end[];
 extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
 extern pgd_t tramp_pg_dir[PTRS_PER_PGD];
 extern phys_addr_t __pa_swapper_pg_dir;
+extern pgd_t *new_swapper_pg_dir;
 
 /*
  * Encode and decode a swap entry:
diff --git a/arch/arm64/mm/kasan_init.c b/arch/arm64/mm/kasan_init.c
index dd4f28c19165..08bcaae4725e 100644
--- a/arch/arm64/mm/kasan_init.c
+++ b/arch/arm64/mm/kasan_init.c
@@ -197,7 +197,7 @@ void __init kasan_init(void)
 	 * tmp_pg_dir used to keep early shadow mapped until full shadow
 	 * setup will be finished.
 	 */
-	memcpy(tmp_pg_dir, swapper_pg_dir, sizeof(tmp_pg_dir));
+	memcpy(tmp_pg_dir, new_swapper_pg_dir, sizeof(tmp_pg_dir));
 	dsb(ishst);
 	cpu_replace_ttbr1(__pa_symbol(tmp_pg_dir));
 
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 41eee333f91a..26ba3e70a91c 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -56,6 +56,7 @@ u64 kimage_voffset __ro_after_init;
 EXPORT_SYMBOL(kimage_voffset);
 
 phys_addr_t __pa_swapper_pg_dir;
+pgd_t *new_swapper_pg_dir = swapper_pg_dir;
 
 /*
  * Empty_zero_page is a special page that is used for zero-initialized data
-- 
2.17.0

^ permalink raw reply related

* [PATCH 1/4] arm64/mm: migrate swapper_pg_dir
From: YaoJun @ 2018-05-30  9:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180530091259.9386-1-yaojun8558363@gmail.com>

Introduce __pa_swapper_pg_dir to save physical address
of swapper_pg_dir. And pass it as an argument to
__enable_mmu().

Signed-off-by: YaoJun <yaojun8558363@gmail.com>
---
 arch/arm64/include/asm/mmu_context.h |  4 +---
 arch/arm64/include/asm/pgtable.h     |  1 +
 arch/arm64/kernel/cpufeature.c       |  2 +-
 arch/arm64/kernel/head.S             | 10 ++++++----
 arch/arm64/kernel/hibernate.c        |  2 +-
 arch/arm64/kernel/sleep.S            |  2 ++
 arch/arm64/mm/kasan_init.c           |  4 ++--
 arch/arm64/mm/mmu.c                  |  8 ++++++--
 8 files changed, 20 insertions(+), 13 deletions(-)

diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h
index 39ec0b8a689e..3eddb871f251 100644
--- a/arch/arm64/include/asm/mmu_context.h
+++ b/arch/arm64/include/asm/mmu_context.h
@@ -141,14 +141,12 @@ static inline void cpu_install_idmap(void)
  * Atomically replaces the active TTBR1_EL1 PGD with a new VA-compatible PGD,
  * avoiding the possibility of conflicting TLB entries being allocated.
  */
-static inline void cpu_replace_ttbr1(pgd_t *pgdp)
+static inline void cpu_replace_ttbr1(phys_addr_t pgd_phys)
 {
 	typedef void (ttbr_replace_func)(phys_addr_t);
 	extern ttbr_replace_func idmap_cpu_replace_ttbr1;
 	ttbr_replace_func *replace_phys;
 
-	phys_addr_t pgd_phys = virt_to_phys(pgdp);
-
 	replace_phys = (void *)__pa_symbol(idmap_cpu_replace_ttbr1);
 
 	cpu_install_idmap();
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 7c4c8f318ba9..14ba344b1af7 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -722,6 +722,7 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 extern pgd_t swapper_pg_end[];
 extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
 extern pgd_t tramp_pg_dir[PTRS_PER_PGD];
+extern phys_addr_t __pa_swapper_pg_dir;
 
 /*
  * Encode and decode a swap entry:
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 9d1b06d67c53..5b9448688d80 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -917,7 +917,7 @@ kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused)
 	remap_fn = (void *)__pa_symbol(idmap_kpti_install_ng_mappings);
 
 	cpu_install_idmap();
-	remap_fn(cpu, num_online_cpus(), __pa_symbol(swapper_pg_dir));
+	remap_fn(cpu, num_online_cpus(), __pa_swapper_pg_dir);
 	cpu_uninstall_idmap();
 
 	if (!cpu)
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index b0853069702f..e3bb44b4b6c6 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -706,6 +706,8 @@ secondary_startup:
 	 * Common entry point for secondary CPUs.
 	 */
 	bl	__cpu_setup			// initialise processor
+	adrp    x25, idmap_pg_dir
+	ldr_l   x26, __pa_swapper_pg_dir
 	bl	__enable_mmu
 	ldr	x8, =__secondary_switched
 	br	x8
@@ -761,10 +763,8 @@ ENTRY(__enable_mmu)
 	cmp	x2, #ID_AA64MMFR0_TGRAN_SUPPORTED
 	b.ne	__no_granule_support
 	update_early_cpu_boot_status 0, x1, x2
-	adrp	x1, idmap_pg_dir
-	adrp	x2, swapper_pg_dir
-	phys_to_ttbr x3, x1
-	phys_to_ttbr x4, x2
+	phys_to_ttbr x3, x25
+	phys_to_ttbr x4, x26
 	msr	ttbr0_el1, x3			// load TTBR0
 	msr	ttbr1_el1, x4			// load TTBR1
 	isb
@@ -823,6 +823,8 @@ __primary_switch:
 	mrs	x20, sctlr_el1			// preserve old SCTLR_EL1 value
 #endif
 
+	adrp    x25, idmap_pg_dir
+	adrp    x26, swapper_pg_dir
 	bl	__enable_mmu
 #ifdef CONFIG_RELOCATABLE
 	bl	__relocate_kernel
diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c
index 1ec5f28c39fc..12948949202c 100644
--- a/arch/arm64/kernel/hibernate.c
+++ b/arch/arm64/kernel/hibernate.c
@@ -125,7 +125,7 @@ int arch_hibernation_header_save(void *addr, unsigned int max_size)
 		return -EOVERFLOW;
 
 	arch_hdr_invariants(&hdr->invariants);
-	hdr->ttbr1_el1		= __pa_symbol(swapper_pg_dir);
+	hdr->ttbr1_el1          = __pa_swapper_pg_dir;
 	hdr->reenter_kernel	= _cpu_resume;
 
 	/* We can't use __hyp_get_vectors() because kvm may still be loaded */
diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S
index bebec8ef9372..860d46395be1 100644
--- a/arch/arm64/kernel/sleep.S
+++ b/arch/arm64/kernel/sleep.S
@@ -101,6 +101,8 @@ ENTRY(cpu_resume)
 	bl	el2_setup		// if in EL2 drop to EL1 cleanly
 	bl	__cpu_setup
 	/* enable the MMU early - so we can access sleep_save_stash by va */
+	adrp    x25, idmap_pg_dir
+	ldr_l   x26, __pa_swapper_pg_dir
 	bl	__enable_mmu
 	ldr	x8, =_cpu_resume
 	br	x8
diff --git a/arch/arm64/mm/kasan_init.c b/arch/arm64/mm/kasan_init.c
index 12145874c02b..dd4f28c19165 100644
--- a/arch/arm64/mm/kasan_init.c
+++ b/arch/arm64/mm/kasan_init.c
@@ -199,7 +199,7 @@ void __init kasan_init(void)
 	 */
 	memcpy(tmp_pg_dir, swapper_pg_dir, sizeof(tmp_pg_dir));
 	dsb(ishst);
-	cpu_replace_ttbr1(lm_alias(tmp_pg_dir));
+	cpu_replace_ttbr1(__pa_symbol(tmp_pg_dir));
 
 	clear_pgds(KASAN_SHADOW_START, KASAN_SHADOW_END);
 
@@ -236,7 +236,7 @@ void __init kasan_init(void)
 			pfn_pte(sym_to_pfn(kasan_zero_page), PAGE_KERNEL_RO));
 
 	memset(kasan_zero_page, 0, PAGE_SIZE);
-	cpu_replace_ttbr1(lm_alias(swapper_pg_dir));
+	cpu_replace_ttbr1(__pa_swapper_pg_dir);
 
 	/* At this point kasan is fully initialized. Enable error messages */
 	init_task.kasan_depth = 0;
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 2dbb2c9f1ec1..41eee333f91a 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -55,6 +55,8 @@ u64 idmap_ptrs_per_pgd = PTRS_PER_PGD;
 u64 kimage_voffset __ro_after_init;
 EXPORT_SYMBOL(kimage_voffset);
 
+phys_addr_t __pa_swapper_pg_dir;
+
 /*
  * Empty_zero_page is a special page that is used for zero-initialized data
  * and COW.
@@ -631,6 +633,8 @@ void __init paging_init(void)
 	phys_addr_t pgd_phys = early_pgtable_alloc();
 	pgd_t *pgdp = pgd_set_fixmap(pgd_phys);
 
+	__pa_swapper_pg_dir = __pa_symbol(swapper_pg_dir);
+
 	map_kernel(pgdp);
 	map_mem(pgdp);
 
@@ -642,9 +646,9 @@ void __init paging_init(void)
 	 *
 	 * To do this we need to go via a temporary pgd.
 	 */
-	cpu_replace_ttbr1(__va(pgd_phys));
+	cpu_replace_ttbr1(pgd_phys);
 	memcpy(swapper_pg_dir, pgdp, PGD_SIZE);
-	cpu_replace_ttbr1(lm_alias(swapper_pg_dir));
+	cpu_replace_ttbr1(__pa_swapper_pg_dir);
 
 	pgd_clear_fixmap();
 	memblock_free(pgd_phys, PAGE_SIZE);
-- 
2.17.0

^ permalink raw reply related

* [PATCH 0/4] arm64/mm: migrate swapper_pg_dir
From: YaoJun @ 2018-05-30  9:12 UTC (permalink / raw)
  To: linux-arm-kernel

Currently, The offset between swapper_pg_dir and _text is
fixed. When attackers know the address of _text(no KASLR or
breaking KASLR), they can caculate the address of
swapper_pg_dir. Then KSMA(Kernel Space Mirroring Attack) can
be applied.

The principle of KSMA is to insert a carefully constructed PGD
entry into the translation table. The type of this entry is
block, which maps the kernel text and its access permissions
bits are 01. The user process can then modify kernel text
directly through this mapping.

To protect against KSMA, these patches migrate swapper_pg_dir
to new place, which is dynamically allocated. Since it is
allocated during the kernel boot process and the address is
relatively fixed, further randomization may be required.

YaoJun (4):
  arm64/mm: Introduce __pa_swapper_pg_dir to save physical
	    address of swapper_pg_dir. And pass it as an
	    argument to __enable_mmu().
  arm64/mm: Introduce new_swapper_pg_dir to save virtual
	    address of new swapper_pg_dir.
  arm64/mm: Make tramp_pg_dir and swapper_pg_dir adjacent.
  arm64/mm: Migrate swapper_pg_dir and tramp_pg_dir.

 arch/arm64/include/asm/mmu_context.h |  6 +--
 arch/arm64/include/asm/pgtable.h     |  2 +
 arch/arm64/kernel/cpufeature.c       |  2 +-
 arch/arm64/kernel/entry.S            |  4 +-
 arch/arm64/kernel/head.S             | 10 ++--
 arch/arm64/kernel/hibernate.c        |  2 +-
 arch/arm64/kernel/sleep.S            |  2 +
 arch/arm64/kernel/vmlinux.lds.S      | 10 ++--
 arch/arm64/mm/kasan_init.c           |  6 +--
 arch/arm64/mm/mmu.c                  | 72 ++++++++++++++++++++--------
 10 files changed, 75 insertions(+), 41 deletions(-)

-- 
2.17.0

^ permalink raw reply

* [PATCH 8/8] media: uniphier: add LD20 adapter driver for ISDB
From: Katsuhiro Suzuki @ 2018-05-30  9:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180530090946.1635-1-suzuki.katsuhiro@socionext.com>

This patch adds UniPhier LD20 DVB adapter driver for ISDB-S/T
that equipments SONY SUT-PJ series using CXD2858 tuner and Socionext
MN884434 demodulator.

Signed-off-by: Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>
---
 drivers/media/platform/uniphier/Kconfig       |  10 +
 drivers/media/platform/uniphier/Makefile      |   1 +
 .../platform/uniphier/ld20-mn884434-helene.c  | 274 ++++++++++++++++++
 3 files changed, 285 insertions(+)
 create mode 100644 drivers/media/platform/uniphier/ld20-mn884434-helene.c

diff --git a/drivers/media/platform/uniphier/Kconfig b/drivers/media/platform/uniphier/Kconfig
index 0fc9bbfc170b..1ad2b0f2716c 100644
--- a/drivers/media/platform/uniphier/Kconfig
+++ b/drivers/media/platform/uniphier/Kconfig
@@ -25,3 +25,13 @@ config DVB_UNIPHIER_LD11_ISDB
 	  Demod: Socionext MN884433
 	  Tuner: SONY HELENE (CXD2858ER)
 	  Say Y when you want to support this adapters.
+
+config DVB_UNIPHIER_LD20_ISDB
+	bool "Support UniPhier LD20 ISDB adapters"
+	depends on DVB_UNIPHIER
+	help
+	  Driver for LD20 ISDB-S/T adapters which use
+	  Demux: Socionext LD20 HSC
+	  Demod: Socionext MN884434
+	  Tuner: SONY HELENE (CXD2858ER)
+	  Say Y when you want to support this adapters.
diff --git a/drivers/media/platform/uniphier/Makefile b/drivers/media/platform/uniphier/Makefile
index e4b06f8a37b5..9c12456748f9 100644
--- a/drivers/media/platform/uniphier/Makefile
+++ b/drivers/media/platform/uniphier/Makefile
@@ -9,3 +9,4 @@ ccflags-y += -Idrivers/media/tuners/
 
 uniphier-dvb-y += uniphier-adapter.o
 uniphier-dvb-$(CONFIG_DVB_UNIPHIER_LD11_ISDB) += ld11-mn884433-helene.o
+uniphier-dvb-$(CONFIG_DVB_UNIPHIER_LD20_ISDB) += ld20-mn884434-helene.o
diff --git a/drivers/media/platform/uniphier/ld20-mn884434-helene.c b/drivers/media/platform/uniphier/ld20-mn884434-helene.c
new file mode 100644
index 000000000000..7ccbe52a50fb
--- /dev/null
+++ b/drivers/media/platform/uniphier/ld20-mn884434-helene.c
@@ -0,0 +1,274 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Socionext UniPhier LD20 adapter driver for ISDB.
+// Using Socionext MN884434 ISDB-S/ISDB-T demodulator and
+// SONY HELENE tuner.
+//
+// Copyright (c) 2018 Socionext Inc.
+
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/reset.h>
+
+#include "sc1501a.h"
+#include "helene.h"
+#include "hsc.h"
+#include "uniphier-adapter.h"
+
+static struct sc1501a_config mn884434_conf[] = {
+	{ .if_freq = LOW_IF_4MHZ, },
+	{ .if_freq = LOW_IF_4MHZ, },
+};
+
+static int uniphier_adapter_demod_probe(struct uniphier_adapter_priv *priv)
+{
+	const struct uniphier_adapter_spec *spec = priv->spec;
+	struct device *dev = &priv->pdev->dev;
+	struct device_node *node;
+	int ret, i;
+
+	priv->demod_mclk = devm_clk_get(dev, "demod-mclk");
+	if (IS_ERR(priv->demod_mclk)) {
+		dev_err(dev, "Failed to request demod-mclk: %ld\n",
+			PTR_ERR(priv->demod_mclk));
+		return PTR_ERR(priv->demod_mclk);
+	}
+
+	priv->demod_gpio = devm_gpiod_get_optional(dev, "reset-demod",
+						   GPIOD_OUT_HIGH);
+	if (IS_ERR(priv->demod_gpio)) {
+		dev_err(dev, "Failed to request demod_gpio: %ld\n",
+			PTR_ERR(priv->demod_gpio));
+		return PTR_ERR(priv->demod_gpio);
+	}
+
+	node = of_parse_phandle(dev->of_node, "demod-i2c-bus", 0);
+	if (!node) {
+		dev_err(dev, "Failed to parse demod-i2c-bus\n");
+		return -ENODEV;
+	}
+
+	priv->demod_i2c_adapter = of_find_i2c_adapter_by_node(node);
+	if (!priv->demod_i2c_adapter) {
+		dev_err(dev, "Failed to find demod i2c adapter\n");
+		of_node_put(node);
+		return -ENODEV;
+	}
+	of_node_put(node);
+
+	mn884434_conf[0].reset_gpio = priv->demod_gpio;
+	for (i = 0; i < spec->adapters; i++) {
+		struct i2c_client *c;
+
+		mn884434_conf[i].mclk = priv->demod_mclk;
+		mn884434_conf[i].fe = &priv->fe[i].fe;
+
+		c = dvb_module_probe(spec->demod_i2c_info[i].type, NULL,
+				     priv->demod_i2c_adapter,
+				     spec->demod_i2c_info[i].addr,
+				     &mn884434_conf[i]);
+		if (!c) {
+			dev_err(dev, "Failed to probe demod\n");
+			ret = -ENODEV;
+			goto err_out;
+		}
+		priv->fe[i].demod_i2c = c;
+	}
+
+	return 0;
+
+err_out:
+	for (i = 0; i < spec->adapters; i++)
+		dvb_module_release(priv->fe[i].demod_i2c);
+
+	return ret;
+}
+
+static struct helene_config helene_conf[] = {
+	{ .xtal = SONY_HELENE_XTAL_16000, },
+	{ .xtal = SONY_HELENE_XTAL_16000, },
+	{ .xtal = SONY_HELENE_XTAL_16000, },
+};
+
+static int uniphier_adapter_tuner_probe(struct uniphier_adapter_priv *priv)
+{
+	const struct uniphier_adapter_spec *spec = priv->spec;
+	struct device *dev = &priv->pdev->dev;
+	struct device_node *node;
+	int ret, i;
+
+	priv->tuner_gpio = devm_gpiod_get_optional(dev, "reset-tuner",
+						   GPIOD_OUT_HIGH);
+	if (IS_ERR(priv->tuner_gpio)) {
+		dev_err(dev, "Failed to request tuner_gpio: %ld\n",
+			PTR_ERR(priv->tuner_gpio));
+		return PTR_ERR(priv->tuner_gpio);
+	}
+	gpiod_set_value_cansleep(priv->tuner_gpio, 0);
+
+	node = of_parse_phandle(dev->of_node, "tuner-i2c-bus", 0);
+	if (!node) {
+		dev_err(dev, "Failed to parse tuner-i2c-bus\n");
+		return -ENODEV;
+	}
+
+	priv->tuner_i2c_adapter = of_find_i2c_adapter_by_node(node);
+	if (!priv->tuner_i2c_adapter) {
+		dev_err(dev, "Failed to find tuner i2c adapter\n");
+		of_node_put(node);
+		return -ENODEV;
+	}
+	of_node_put(node);
+
+	for (i = 0; i < priv->spec->adapters; i++) {
+		struct i2c_client *c;
+
+		helene_conf[i].fe = priv->fe[i].fe;
+
+		c = dvb_module_probe(spec->tuner_i2c_info[i].type, NULL,
+				     priv->tuner_i2c_adapter,
+				     spec->tuner_i2c_info[i].addr,
+				     &helene_conf[i]);
+		if (!c) {
+			dev_err(dev, "Failed to probe tuner\n");
+			ret = -ENODEV;
+			goto err_out;
+		}
+		priv->fe[i].tuner_i2c = c;
+	}
+
+	return 0;
+
+err_out:
+	for (i = 0; i < spec->adapters; i++)
+		dvb_module_release(priv->fe[i].tuner_i2c);
+
+	return ret;
+}
+
+static int uniphier_adapter_probe(struct platform_device *pdev)
+{
+	struct uniphier_adapter_priv *priv;
+	struct device *dev = &pdev->dev;
+	int i, ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	priv->pdev = pdev;
+
+	priv->spec = of_device_get_match_data(dev);
+	if (!priv->spec)
+		return -EINVAL;
+
+	priv->fe = devm_kzalloc(dev, sizeof(*priv->fe) * priv->spec->adapters,
+				GFP_KERNEL);
+	if (!priv->fe)
+		return -ENOMEM;
+
+	ret = uniphier_adapter_demux_probe(priv);
+	if (ret)
+		return ret;
+
+	ret = uniphier_adapter_demod_probe(priv);
+	if (ret)
+		return ret;
+
+	ret = uniphier_adapter_tuner_probe(priv);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, priv);
+
+	for (i = 0; i < priv->spec->adapters; i++) {
+		priv->chip->tsif[i].fe = priv->fe[i].fe;
+
+		ret = hsc_register_dvb(&priv->chip->tsif[i]);
+		if (ret) {
+			dev_err(dev, "Failed to register adapter\n");
+			goto err_out_if;
+		}
+	}
+
+	return 0;
+
+err_out_if:
+	for (i = 0; i < priv->spec->adapters; i++)
+		hsc_unregister_dvb(&priv->chip->tsif[i]);
+
+	return ret;
+}
+
+static int uniphier_adapter_remove(struct platform_device *pdev)
+{
+	struct uniphier_adapter_priv *priv = platform_get_drvdata(pdev);
+	int i;
+
+	for (i = 0; i < priv->spec->adapters; i++) {
+		hsc_dmaif_release(&priv->chip->dmaif[i]);
+		hsc_tsif_release(&priv->chip->tsif[i]);
+		hsc_unregister_dvb(&priv->chip->tsif[i]);
+		dvb_module_release(priv->fe[i].tuner_i2c);
+		dvb_module_release(priv->fe[i].demod_i2c);
+	}
+
+	return 0;
+}
+
+static const struct hsc_conf ld20_hsc_conf[] = {
+	{
+		.css_in = HSC_CSS_IN_SRLTS2,
+		.css_out = HSC_CSS_OUT_TSI0,
+		.dpll = HSC_DPLL0,
+		.dma_out = HSC_DMA_OUT0,
+	},
+	{
+		.css_in = HSC_CSS_IN_SRLTS3,
+		.css_out = HSC_CSS_OUT_TSI1,
+		.dpll = HSC_DPLL1,
+		.dma_out = HSC_DMA_OUT1,
+	},
+};
+
+static const struct i2c_board_info mn884434_i2c_info[] = {
+	{ .type = "mn884434-0", .addr = 0x68, },
+	{ .type = "mn884434-1", .addr = 0x6a, },
+};
+
+static const struct i2c_board_info helene_i2c_info[] = {
+	{ .type = "helene", .addr = 0x60, },
+	{ .type = "helene", .addr = 0x61, },
+};
+
+static const struct uniphier_adapter_spec ld20_mn884434_helene_spec = {
+	.adapters = 2,
+	.hsc_conf = ld20_hsc_conf,
+	.demod_i2c_info = mn884434_i2c_info,
+	.tuner_i2c_info = helene_i2c_info,
+};
+
+static const struct of_device_id uniphier_hsc_adapter_of_match[] = {
+	{
+		.compatible = "socionext,uniphier-ld20-mn884434-helene",
+		.data = &ld20_mn884434_helene_spec,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, uniphier_hsc_adapter_of_match);
+
+static struct platform_driver uniphier_hsc_adapter_driver = {
+	.driver = {
+		.name = "uniphier-ld20-isdb",
+		.of_match_table = of_match_ptr(uniphier_hsc_adapter_of_match),
+	},
+	.probe  = uniphier_adapter_probe,
+	.remove = uniphier_adapter_remove,
+};
+module_platform_driver(uniphier_hsc_adapter_driver);
+
+MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
+MODULE_DESCRIPTION("UniPhier LD20 adapter driver for ISDB.");
+MODULE_LICENSE("GPL v2");
-- 
2.17.0

^ permalink raw reply related

* [PATCH 7/8] media: uniphier: add LD11 adapter driver for ISDB
From: Katsuhiro Suzuki @ 2018-05-30  9:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180530090946.1635-1-suzuki.katsuhiro@socionext.com>

This patch adds UniPhier LD11 DVB adapter driver for ISDB-S/T
that equipments SONY SUT-PJ series using CXD2858 tuner and Socionext
MN884433 demodulator.

Signed-off-by: Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>
---
 drivers/media/platform/uniphier/Kconfig       |  10 +
 drivers/media/platform/uniphier/Makefile      |   1 +
 .../platform/uniphier/ld11-mn884433-helene.c  | 265 ++++++++++++++++++
 3 files changed, 276 insertions(+)
 create mode 100644 drivers/media/platform/uniphier/ld11-mn884433-helene.c

diff --git a/drivers/media/platform/uniphier/Kconfig b/drivers/media/platform/uniphier/Kconfig
index 8f3a662a391c..0fc9bbfc170b 100644
--- a/drivers/media/platform/uniphier/Kconfig
+++ b/drivers/media/platform/uniphier/Kconfig
@@ -15,3 +15,13 @@ config DVB_UNIPHIER_LD11
 	  Driver for the HSC (High speed Stream Controller) for
 	  UniPhier LD11/LD20.
 	  Say Y when you want to support this hardware.
+
+config DVB_UNIPHIER_LD11_ISDB
+	bool "Support UniPhier LD11 ISDB adapters"
+	depends on DVB_UNIPHIER
+	help
+	  Driver for LD11 ISDB-S/T adapters which use
+	  Demux: Socionext LD11 HSC
+	  Demod: Socionext MN884433
+	  Tuner: SONY HELENE (CXD2858ER)
+	  Say Y when you want to support this adapters.
diff --git a/drivers/media/platform/uniphier/Makefile b/drivers/media/platform/uniphier/Makefile
index 9e75ad081b77..e4b06f8a37b5 100644
--- a/drivers/media/platform/uniphier/Makefile
+++ b/drivers/media/platform/uniphier/Makefile
@@ -8,3 +8,4 @@ ccflags-y += -Idrivers/media/dvb-frontends/
 ccflags-y += -Idrivers/media/tuners/
 
 uniphier-dvb-y += uniphier-adapter.o
+uniphier-dvb-$(CONFIG_DVB_UNIPHIER_LD11_ISDB) += ld11-mn884433-helene.o
diff --git a/drivers/media/platform/uniphier/ld11-mn884433-helene.c b/drivers/media/platform/uniphier/ld11-mn884433-helene.c
new file mode 100644
index 000000000000..f4f48b6a0211
--- /dev/null
+++ b/drivers/media/platform/uniphier/ld11-mn884433-helene.c
@@ -0,0 +1,265 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Socionext UniPhier LD11 adapter driver for ISDB.
+// Using Socionext MN884433 ISDB-S/ISDB-T demodulator and
+// SONY HELENE tuner.
+//
+// Copyright (c) 2018 Socionext Inc.
+
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/reset.h>
+
+#include "sc1501a.h"
+#include "cxd2858.h"
+#include "helene.h"
+#include "hsc.h"
+#include "uniphier-adapter.h"
+
+static struct sc1501a_config mn884433_conf[] = {
+	{ .if_freq = LOW_IF_4MHZ, },
+};
+
+static int uniphier_adapter_demod_probe(struct uniphier_adapter_priv *priv)
+{
+	const struct uniphier_adapter_spec *spec = priv->spec;
+	struct device *dev = &priv->pdev->dev;
+	struct device_node *node;
+	int ret, i;
+
+	priv->demod_mclk = devm_clk_get(dev, "demod-mclk");
+	if (IS_ERR(priv->demod_mclk)) {
+		dev_err(dev, "Failed to request demod-mclk: %ld\n",
+			PTR_ERR(priv->demod_mclk));
+		return PTR_ERR(priv->demod_mclk);
+	}
+
+	priv->demod_gpio = devm_gpiod_get_optional(dev, "reset-demod",
+						   GPIOD_OUT_HIGH);
+	if (IS_ERR(priv->demod_gpio)) {
+		dev_err(dev, "Failed to request demod_gpio: %ld\n",
+			PTR_ERR(priv->demod_gpio));
+		return PTR_ERR(priv->demod_gpio);
+	}
+
+	node = of_parse_phandle(dev->of_node, "demod-i2c-bus", 0);
+	if (!node) {
+		dev_err(dev, "Failed to parse demod-i2c-bus\n");
+		return -ENODEV;
+	}
+
+	priv->demod_i2c_adapter = of_find_i2c_adapter_by_node(node);
+	if (!priv->demod_i2c_adapter) {
+		dev_err(dev, "Failed to find demod i2c adapter\n");
+		of_node_put(node);
+		return -ENODEV;
+	}
+	of_node_put(node);
+
+	mn884433_conf[0].reset_gpio = priv->demod_gpio;
+	for (i = 0; i < spec->adapters; i++) {
+		struct i2c_client *c;
+
+		mn884433_conf[i].mclk = priv->demod_mclk;
+		mn884433_conf[i].fe = &priv->fe[i].fe;
+
+		c = dvb_module_probe(spec->demod_i2c_info[i].type, NULL,
+				     priv->demod_i2c_adapter,
+				     spec->demod_i2c_info[i].addr,
+				     &mn884433_conf[i]);
+		if (!c) {
+			dev_err(dev, "Failed to probe demod\n");
+			ret = -ENODEV;
+			goto err_out;
+		}
+		priv->fe[i].demod_i2c = c;
+	}
+
+	return 0;
+
+err_out:
+	for (i = 0; i < spec->adapters; i++)
+		dvb_module_release(priv->fe[i].demod_i2c);
+
+	return ret;
+}
+
+static struct helene_config helene_conf[] = {
+	{ .xtal = SONY_HELENE_XTAL_16000, },
+	{ .xtal = SONY_HELENE_XTAL_16000, },
+};
+
+static int uniphier_adapter_tuner_probe(struct uniphier_adapter_priv *priv)
+{
+	const struct uniphier_adapter_spec *spec = priv->spec;
+	struct device *dev = &priv->pdev->dev;
+	struct device_node *node;
+	int ret, i;
+
+	priv->tuner_gpio = devm_gpiod_get_optional(dev, "reset-tuner",
+						   GPIOD_OUT_HIGH);
+	if (IS_ERR(priv->tuner_gpio)) {
+		dev_err(dev, "Failed to request tuner_gpio: %ld\n",
+			PTR_ERR(priv->tuner_gpio));
+		return PTR_ERR(priv->tuner_gpio);
+	}
+	gpiod_set_value_cansleep(priv->tuner_gpio, 0);
+
+	node = of_parse_phandle(dev->of_node, "tuner-i2c-bus", 0);
+	if (!node) {
+		dev_err(dev, "Failed to parse tuner-i2c-bus\n");
+		return -ENODEV;
+	}
+
+	priv->tuner_i2c_adapter = of_find_i2c_adapter_by_node(node);
+	if (!priv->tuner_i2c_adapter) {
+		dev_err(dev, "Failed to find tuner i2c adapter\n");
+		of_node_put(node);
+		return -ENODEV;
+	}
+	of_node_put(node);
+
+	for (i = 0; i < priv->spec->adapters; i++) {
+		struct i2c_client *c;
+
+		helene_conf[i].fe = priv->fe[i].fe;
+
+		c = dvb_module_probe(spec->tuner_i2c_info[i].type, NULL,
+				     priv->tuner_i2c_adapter,
+				     spec->tuner_i2c_info[i].addr,
+				     &helene_conf[i]);
+		if (!c) {
+			dev_err(dev, "Failed to probe tuner\n");
+			ret = -ENODEV;
+			goto err_out;
+		}
+		priv->fe[i].tuner_i2c = c;
+	}
+
+	return 0;
+
+err_out:
+	for (i = 0; i < spec->adapters; i++)
+		dvb_module_release(priv->fe[i].tuner_i2c);
+
+	return ret;
+}
+
+static int uniphier_adapter_probe(struct platform_device *pdev)
+{
+	struct uniphier_adapter_priv *priv;
+	struct device *dev = &pdev->dev;
+	int i, ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	priv->pdev = pdev;
+
+	priv->spec = of_device_get_match_data(dev);
+	if (!priv->spec)
+		return -EINVAL;
+
+	priv->fe = devm_kzalloc(dev, sizeof(*priv->fe) * priv->spec->adapters,
+				GFP_KERNEL);
+	if (!priv->fe)
+		return -ENOMEM;
+
+	ret = uniphier_adapter_demux_probe(priv);
+	if (ret)
+		return ret;
+
+	ret = uniphier_adapter_demod_probe(priv);
+	if (ret)
+		return ret;
+
+	ret = uniphier_adapter_tuner_probe(priv);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, priv);
+
+	for (i = 0; i < priv->spec->adapters; i++) {
+		priv->chip->tsif[i].fe = priv->fe[i].fe;
+
+		ret = hsc_register_dvb(&priv->chip->tsif[i]);
+		if (ret) {
+			dev_err(dev, "Failed to register adapter\n");
+			goto err_out_if;
+		}
+	}
+
+	return 0;
+
+err_out_if:
+	for (i = 0; i < priv->spec->adapters; i++)
+		hsc_unregister_dvb(&priv->chip->tsif[i]);
+
+	return ret;
+}
+
+static int uniphier_adapter_remove(struct platform_device *pdev)
+{
+	struct uniphier_adapter_priv *priv = platform_get_drvdata(pdev);
+	int i;
+
+	for (i = 0; i < priv->spec->adapters; i++) {
+		hsc_dmaif_release(&priv->chip->dmaif[i]);
+		hsc_tsif_release(&priv->chip->tsif[i]);
+		hsc_unregister_dvb(&priv->chip->tsif[i]);
+		dvb_module_release(priv->fe[i].tuner_i2c);
+		dvb_module_release(priv->fe[i].demod_i2c);
+	}
+
+	return 0;
+}
+
+static const struct hsc_conf ld11_hsc_conf[] = {
+	{
+		.css_in = HSC_CSS_IN_SRLTS0,
+		.css_out = HSC_CSS_OUT_TSI0,
+		.dpll = HSC_DPLL0,
+		.dma_out = HSC_DMA_OUT0,
+	},
+};
+
+static const struct i2c_board_info mn884433_i2c_info[] = {
+	{ .type = "mn884433", .addr = 0x68, },
+};
+
+static const struct i2c_board_info helene_i2c_info[] = {
+	{ .type = "helene", .addr = 0x61, },
+};
+
+static const struct uniphier_adapter_spec ld11_mn884433_helene_spec = {
+	.adapters = 1,
+	.hsc_conf = ld11_hsc_conf,
+	.demod_i2c_info = mn884433_i2c_info,
+	.tuner_i2c_info = helene_i2c_info,
+};
+
+static const struct of_device_id uniphier_hsc_adapter_of_match[] = {
+	{
+		.compatible = "socionext,uniphier-ld11-mn884433-helene",
+		.data = &ld11_mn884433_helene_spec,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, uniphier_hsc_adapter_of_match);
+
+static struct platform_driver uniphier_hsc_adapter_driver = {
+	.driver = {
+		.name = "uniphier-ld11-isdb",
+		.of_match_table = of_match_ptr(uniphier_hsc_adapter_of_match),
+	},
+	.probe  = uniphier_adapter_probe,
+	.remove = uniphier_adapter_remove,
+};
+module_platform_driver(uniphier_hsc_adapter_driver);
+
+MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
+MODULE_DESCRIPTION("UniPhier LD11 adapter driver for ISDB.");
+MODULE_LICENSE("GPL v2");
-- 
2.17.0

^ permalink raw reply related

* [PATCH 6/8] media: uniphier: add common module of DVB adapter drivers
From: Katsuhiro Suzuki @ 2018-05-30  9:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180530090946.1635-1-suzuki.katsuhiro@socionext.com>

This patch adds common module for UniPhier DVB adapter drivers
that equipments tuners and demod that connected by I2C and
UniPhier demux.

Signed-off-by: Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>
---
 drivers/media/platform/uniphier/Makefile      |  5 ++
 drivers/media/platform/uniphier/hsc-core.c    |  8 ---
 .../platform/uniphier/uniphier-adapter.c      | 54 +++++++++++++++++++
 .../platform/uniphier/uniphier-adapter.h      | 42 +++++++++++++++
 4 files changed, 101 insertions(+), 8 deletions(-)
 create mode 100644 drivers/media/platform/uniphier/uniphier-adapter.c
 create mode 100644 drivers/media/platform/uniphier/uniphier-adapter.h

diff --git a/drivers/media/platform/uniphier/Makefile b/drivers/media/platform/uniphier/Makefile
index 0622f04d9e68..9e75ad081b77 100644
--- a/drivers/media/platform/uniphier/Makefile
+++ b/drivers/media/platform/uniphier/Makefile
@@ -3,3 +3,8 @@ uniphier-dvb-y += hsc-core.o hsc-ucode.o hsc-css.o hsc-ts.o hsc-dma.o
 uniphier-dvb-$(CONFIG_DVB_UNIPHIER_LD11) += hsc-ld11.o
 
 obj-$(CONFIG_DVB_UNIPHIER) += uniphier-dvb.o
+
+ccflags-y += -Idrivers/media/dvb-frontends/
+ccflags-y += -Idrivers/media/tuners/
+
+uniphier-dvb-y += uniphier-adapter.o
diff --git a/drivers/media/platform/uniphier/hsc-core.c b/drivers/media/platform/uniphier/hsc-core.c
index cdb488e4df8c..a8d247cfd302 100644
--- a/drivers/media/platform/uniphier/hsc-core.c
+++ b/drivers/media/platform/uniphier/hsc-core.c
@@ -256,14 +256,6 @@ static void hsc_dmaif_feed_worker(struct work_struct *work)
 	dma_sync_single_for_cpu(dev, dmapos, cnt, DMA_FROM_DEVICE);
 	for (i = 0; i < cnt; i += SZ_M2TS_PKT) {
 		pkt = buf->virt + buf->rd_offs + i;
-
-		if (pkt[4] == 0x47 && pkt[5] == 0x1f && pkt[6] == 0xff)
-			continue;
-		if (pkt[5] & 0x80)
-			continue;
-		if (pkt[7] & 0xc0)
-			continue;
-
 		dvb_dmx_swfilter_packets(&tsif->demux, &pkt[4], 1);
 	}
 	dma_sync_single_for_device(dev, dmapos, cnt, DMA_FROM_DEVICE);
diff --git a/drivers/media/platform/uniphier/uniphier-adapter.c b/drivers/media/platform/uniphier/uniphier-adapter.c
new file mode 100644
index 000000000000..c895bbd9988e
--- /dev/null
+++ b/drivers/media/platform/uniphier/uniphier-adapter.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Socionext UniPhier LD20 adapter driver for ISDB.
+// Using Socionext MN884434 ISDB-S/ISDB-T demodulator and
+// SONY HELENE tuner.
+//
+// Copyright (c) 2018 Socionext Inc.
+
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+
+#include "hsc.h"
+#include "uniphier-adapter.h"
+
+int uniphier_adapter_demux_probe(struct uniphier_adapter_priv *priv)
+{
+	const struct uniphier_adapter_spec *spec = priv->spec;
+	struct device *dev = &priv->pdev->dev;
+	struct device_node *node;
+	int ret, i;
+
+	node = of_parse_phandle(dev->of_node, "demux", 0);
+	if (!node) {
+		dev_err(dev, "Failed to parse demux\n");
+		return -ENODEV;
+	}
+
+	priv->pdev_demux = of_find_device_by_node(node);
+	if (!priv->pdev_demux) {
+		dev_err(dev, "Failed to find demux device\n");
+		of_node_put(node);
+		return -ENODEV;
+	}
+	of_node_put(node);
+
+	priv->chip = platform_get_drvdata(priv->pdev_demux);
+
+	for (i = 0; i < spec->adapters; i++) {
+		ret = hsc_tsif_init(&priv->chip->tsif[i], &spec->hsc_conf[i]);
+		if (ret) {
+			dev_err(dev, "Failed to init TS I/F\n");
+			return ret;
+		}
+
+		ret = hsc_dmaif_init(&priv->chip->dmaif[i], &spec->hsc_conf[i]);
+		if (ret) {
+			dev_err(dev, "Failed to init DMA I/F\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
diff --git a/drivers/media/platform/uniphier/uniphier-adapter.h b/drivers/media/platform/uniphier/uniphier-adapter.h
new file mode 100644
index 000000000000..1faada3fd378
--- /dev/null
+++ b/drivers/media/platform/uniphier/uniphier-adapter.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Socionext UniPhier DVB driver for High-speed Stream Controller (HSC).
+ *
+ * Copyright (c) 2018 Socionext Inc.
+ */
+
+#ifndef DVB_UNIPHIER_ADAPTER_H__
+#define DVB_UNIPHIER_ADAPTER_H__
+
+struct uniphier_adapter_spec {
+	int adapters;
+	const struct hsc_conf *hsc_conf;
+	const struct i2c_board_info *demod_i2c_info;
+	const struct i2c_board_info *tuner_i2c_info;
+};
+
+struct uniphier_adapter_fe {
+	struct i2c_client *demod_i2c;
+	struct i2c_client *tuner_i2c;
+	struct dvb_frontend *fe;
+};
+
+struct uniphier_adapter_priv {
+	const struct uniphier_adapter_spec *spec;
+
+	struct platform_device *pdev;
+	struct hsc_chip *chip;
+
+	struct platform_device *pdev_demux;
+	struct clk *demod_mclk;
+	struct gpio_desc *demod_gpio;
+	struct i2c_adapter *demod_i2c_adapter;
+	struct gpio_desc *tuner_gpio;
+	struct i2c_adapter *tuner_i2c_adapter;
+
+	struct uniphier_adapter_fe *fe;
+};
+
+int uniphier_adapter_demux_probe(struct uniphier_adapter_priv *priv);
+
+#endif /* DVB_UNIPHIER_ADAPTER_H__ */
-- 
2.17.0

^ permalink raw reply related

* [PATCH 5/8] media: uniphier: add LD11/LD20 HSC support
From: Katsuhiro Suzuki @ 2018-05-30  9:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180530090946.1635-1-suzuki.katsuhiro@socionext.com>

This patch adds definition of registers specs to support of HSC
MPEG2-TS I/O driver for UniPhier LD11/LD20 SoCs.

Signed-off-by: Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>
---
 drivers/media/platform/uniphier/Kconfig    |   8 +
 drivers/media/platform/uniphier/Makefile   |   1 +
 drivers/media/platform/uniphier/hsc-ld11.c | 219 +++++++++++++++++++++
 3 files changed, 228 insertions(+)
 create mode 100644 drivers/media/platform/uniphier/hsc-ld11.c

diff --git a/drivers/media/platform/uniphier/Kconfig b/drivers/media/platform/uniphier/Kconfig
index 1b4543ec1e3c..8f3a662a391c 100644
--- a/drivers/media/platform/uniphier/Kconfig
+++ b/drivers/media/platform/uniphier/Kconfig
@@ -7,3 +7,11 @@ config DVB_UNIPHIER
 	  Driver for UniPhier frontend for MPEG2-TS input/output,
 	  demux and descramble.
 	  Say Y when you want to support this frontend.
+
+config DVB_UNIPHIER_LD11
+	bool "Support UniPhier LD11/LD20 HSC Device Driver"
+	depends on DVB_UNIPHIER
+	help
+	  Driver for the HSC (High speed Stream Controller) for
+	  UniPhier LD11/LD20.
+	  Say Y when you want to support this hardware.
diff --git a/drivers/media/platform/uniphier/Makefile b/drivers/media/platform/uniphier/Makefile
index 88bc860b391f..0622f04d9e68 100644
--- a/drivers/media/platform/uniphier/Makefile
+++ b/drivers/media/platform/uniphier/Makefile
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
 uniphier-dvb-y += hsc-core.o hsc-ucode.o hsc-css.o hsc-ts.o hsc-dma.o
+uniphier-dvb-$(CONFIG_DVB_UNIPHIER_LD11) += hsc-ld11.o
 
 obj-$(CONFIG_DVB_UNIPHIER) += uniphier-dvb.o
diff --git a/drivers/media/platform/uniphier/hsc-ld11.c b/drivers/media/platform/uniphier/hsc-ld11.c
new file mode 100644
index 000000000000..df3cc85ac525
--- /dev/null
+++ b/drivers/media/platform/uniphier/hsc-ld11.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Socionext UniPhier DVB driver for High-speed Stream Controller (HSC).
+// For UniPhier LD11/LD20.
+//
+// Copyright (c) 2018 Socionext Inc.
+
+#include "hsc.h"
+#include "hsc-reg.h"
+
+static const struct hsc_spec_init_ram uniphier_hsc_ld11_init_rams[] = {
+	{ FLT_PATN_RAM_TOP_ADDR, FLT_PATN_RAM_SIZE, ~0, },
+	{ FLT_MASK_RAM_TOP_ADDR, FLT_MASK_RAM_SIZE, 0, },
+	/* FLT_PID Pattern */
+	{ SHARE_MEMORY_0_NORMAL, FLT_PIDPATTERN_SIZE, ~0, },
+	/* FLT_PID Table */
+	{ SHARE_MEMORY_0_NORMAL + FLT_PIDPATTERN_SIZE,
+	  SHARE_MEMORY_0_SIZE - FLT_PIDPATTERN_SIZE, 0, },
+	{ SHARE_MEMORY_1_NORMAL, SHARE_MEMORY_1_SIZE, 0, },
+	{ SHARE_MEMORY_2_NORMAL, SHARE_MEMORY_2_SIZE, 0, },
+	{ SHARE_MEMORY_3_NORMAL, SHARE_MEMORY_3_SIZE, 0, },
+	{ SHARE_MEMORY_4_NORMAL, SHARE_MEMORY_4_SIZE, 0, },
+	{ SHARE_MEMORY_5_NORMAL, SHARE_MEMORY_5_SIZE, 0, },
+};
+
+static const struct hsc_spec_init_ram uniphier_hsc_ld20_init_rams[] = {
+	{ FLT_PATN_RAM_TOP_ADDR, FLT_PATN_RAM_SIZE, ~0, },
+	{ FLT_MASK_RAM_TOP_ADDR, FLT_MASK_RAM_SIZE, 0, },
+	/* FLT_PID Pattern */
+	{ SHARE_MEMORY_0_NORMAL, FLT_PIDPATTERN_SIZE, ~0, },
+	/* FLT_PID Table */
+	{ SHARE_MEMORY_0_NORMAL + FLT_PIDPATTERN_SIZE,
+	  SHARE_MEMORY_0_SIZE - FLT_PIDPATTERN_SIZE, 0, },
+	{ SHARE_MEMORY_1_NORMAL, SHARE_MEMORY_1_SIZE, 0, },
+	{ SHARE_MEMORY_2_NORMAL, SHARE_MEMORY_2_SIZE, 0, },
+	{ SHARE_MEMORY_3_NORMAL, SHARE_MEMORY_3_SIZE, 0, },
+	{ SHARE_MEMORY_4_NORMAL, SHARE_MEMORY_4_SIZE, 0, },
+	{ SHARE_MEMORY_5_NORMAL, SHARE_MEMORY_5_SIZE, 0, },
+	{ SHARE_MEMORY_6_NORMAL, SHARE_MEMORY_6_SIZE, 0, },
+	{ SHARE_MEMORY_7_NORMAL, SHARE_MEMORY_7_SIZE, 0, },
+};
+
+static const struct hsc_spec_css_in uniphier_hsc_ld11_css_in[] = {
+	[HSC_CSS_IN_SRLTS0] = {
+		.pol = { true, CSS_SIGNALPOLCH(0), -1,  3,  0, },
+	},
+	[HSC_CSS_IN_SRLTS1] = {
+		.pol = { true, CSS_SIGNALPOLCH(0), -1, 11,  8, },
+	},
+	[HSC_CSS_IN_SRLTS2] = {
+		.pol = { true, CSS_SIGNALPOLCH(0), -1, 19, 16, },
+	},
+	[HSC_CSS_IN_SRLTS3] = {
+		.pol = { true, CSS_SIGNALPOLCH(0), -1, 27, 24, },
+	},
+	[HSC_CSS_IN_SRLTS4] = {
+		.pol = { true, CSS_SIGNALPOLCH(1), -1,  3,  0, },
+	},
+	[HSC_CSS_IN_PARTS0] = {
+		.pol = { true, CSS_PTSISIGNALPOL,  -1, -1,  0, },
+	},
+	[HSC_CSS_IN_PARTS1] = {
+		.pol = { true, CSS_PTSISIGNALPOL,  -1, -1,  8, },
+	},
+	[HSC_CSS_IN_DMD0]   = {
+		.pol = { true, CSS_DMDSIGNALPOL,   -1, -1, 16, },
+	},
+};
+
+static const struct hsc_spec_css_out uniphier_hsc_ld11_css_out[] = {
+	[HSC_CSS_OUT_SRLTS0] = {
+		.pol = { true, CSS_STSOSIGNALPOL,   6, -1,  0, },
+		.sel = { true, CSS_OUTPUTCTRL(0), GENMASK(4,  0), },
+	},
+	[HSC_CSS_OUT_SRLTS1] = {
+		.pol = { true, CSS_STSOSIGNALPOL,  14, -1,  8, },
+		.sel = { true, CSS_OUTPUTCTRL(0), GENMASK(12,  8), },
+	},
+	[HSC_CSS_OUT_TSI0] = {
+		.sel = { true, CSS_OUTPUTCTRL(1), GENMASK(4,  0), },
+	},
+	[HSC_CSS_OUT_TSI1] = {
+		.sel = { true, CSS_OUTPUTCTRL(1), GENMASK(12,  8), },
+	},
+	[HSC_CSS_OUT_TSI2] = {
+		.sel = { true, CSS_OUTPUTCTRL(1), GENMASK(20, 16), },
+	},
+	[HSC_CSS_OUT_TSI3] = {
+		.sel = { true, CSS_OUTPUTCTRL(1), GENMASK(28, 24), },
+	},
+	[HSC_CSS_OUT_TSI4] = {
+		.sel = { true, CSS_OUTPUTCTRL(2), GENMASK(4,  0), },
+	},
+	[HSC_CSS_OUT_PARTS0] = {
+		.pol = { true, CSS_PTSOSIGNALPOL,  -1, -1,  0, },
+		.sel = { true, CSS_OUTPUTCTRL(4), GENMASK(4,  0), },
+	},
+	[HSC_CSS_OUT_PKTFF0] = {
+		.sel = { true, CSS_OUTPUTCTRL(5), GENMASK(4,  0), },
+	},
+};
+
+static const struct hsc_spec_ts uniphier_hsc_ld11_ts_in[] = {
+	[HSC_TSI0] = {
+		.intr = { true, IOB_INTREN0, 13 },
+	},
+	[HSC_TSI1] = {
+		.intr = { true, IOB_INTREN0, 14 },
+	},
+	[HSC_TSI2] = {
+		.intr = { true, IOB_INTREN0, 15 },
+	},
+	[HSC_TSI3] = {
+		.intr = { true, IOB_INTREN0, 16 },
+	},
+	[HSC_TSI4] = {
+		.intr = { true, IOB_INTREN0, 17 },
+	},
+};
+
+static const struct hsc_spec_dma uniphier_hsc_ld11_dma_in[] = {
+	[HSC_DMA_IN0] = {
+		.dma_ch = 5,
+		.en     = { true, CDMBC_TDSTRT, 5 },
+		.intr   = { true, IOB_INTREN1, 1 },
+	},
+	[HSC_DMA_IN1] = {
+		.dma_ch = 6,
+		.en     = { true, CDMBC_TDSTRT, 6 },
+		.intr   = { true, IOB_INTREN1, 2 },
+	},
+	[HSC_DMA_IN2] = {
+		.dma_ch = 7,
+		.en     = { true, CDMBC_TDSTRT, 7 },
+		.intr   = { true, IOB_INTREN1, 3 },
+	},
+	[HSC_DMA_IN3] = {
+		.dma_ch = 22,
+		.en     = { true, CDMBC_TDSTRT, 13 },
+		.intr   = { true, IOB_INTREN1, 4 },
+	},
+	[HSC_DMA_IN4] = {
+		.dma_ch = 23,
+		.en     = { true, CDMBC_TDSTRT, 14 },
+		.intr   = { true, IOB_INTREN1, 5 },
+	},
+	[HSC_DMA_IN5] = {
+		.dma_ch = 24,
+		.en     = { true, CDMBC_TDSTRT, 15 },
+		.intr   = { true, IOB_INTREN1, 6 },
+	},
+};
+
+static const struct hsc_spec_dma uniphier_hsc_ld11_dma_out[] = {
+	[HSC_DMA_OUT0] = {
+		.dma_ch = 1,
+		.en     = { true, CDMBC_TDSTRT, 1 },
+		.intr   = { true, IOB_INTREN1, 13 },
+	},
+	[HSC_DMA_OUT1] = {
+		.dma_ch = 2,
+		.en     = { true, CDMBC_TDSTRT, 2 },
+		.intr   = { true, IOB_INTREN1, 14 },
+	},
+	[HSC_DMA_OUT2] = {
+		.dma_ch = 3,
+		.en     = { true, CDMBC_TDSTRT, 3 },
+		.intr   = { true, IOB_INTREN1, 15 },
+	},
+	[HSC_DMA_OUT3] = {
+		.dma_ch = 19,
+		.en     = { true, CDMBC_TDSTRT, 9 },
+		.intr   = { true, IOB_INTREN1, 16 },
+	},
+	[HSC_DMA_OUT4] = {
+		.dma_ch = 20,
+		.en     = { true, CDMBC_TDSTRT, 10 },
+		.intr   = { true, IOB_INTREN1, 17 },
+	},
+	[HSC_DMA_OUT5] = {
+		.dma_ch = 21,
+		.en     = { true, CDMBC_TDSTRT, 11 },
+		.intr   = { true, IOB_INTREN1, 18 },
+	},
+};
+
+const struct hsc_spec uniphier_hsc_ld11_spec = {
+	.ucode_spu     = { "hsc_spu_code_ld11.bin", "hsc_spu_data_ld11.bin" },
+	.ucode_ace     = { "hsc_ace_code_ld11.bin", "hsc_ace_data_ld11.bin" },
+	.init_rams     = uniphier_hsc_ld11_init_rams,
+	.num_init_rams = ARRAY_SIZE(uniphier_hsc_ld11_init_rams),
+	.css_in        = uniphier_hsc_ld11_css_in,
+	.num_css_in    = ARRAY_SIZE(uniphier_hsc_ld11_css_in),
+	.css_out       = uniphier_hsc_ld11_css_out,
+	.num_css_out   = ARRAY_SIZE(uniphier_hsc_ld11_css_out),
+	.ts_in         = uniphier_hsc_ld11_ts_in,
+	.num_ts_in     = ARRAY_SIZE(uniphier_hsc_ld11_ts_in),
+	.dma_in        = uniphier_hsc_ld11_dma_in,
+	.num_dma_in    = ARRAY_SIZE(uniphier_hsc_ld11_dma_in),
+	.dma_out       = uniphier_hsc_ld11_dma_out,
+	.num_dma_out   = ARRAY_SIZE(uniphier_hsc_ld11_dma_out),
+};
+
+const struct hsc_spec uniphier_hsc_ld20_spec = {
+	.ucode_spu     = { "hsc_spu_code_ld11.bin", "hsc_spu_data_ld11.bin" },
+	.ucode_ace     = { "hsc_ace_code_ld11.bin", "hsc_ace_data_ld11.bin" },
+	.init_rams     = uniphier_hsc_ld20_init_rams,
+	.num_init_rams = ARRAY_SIZE(uniphier_hsc_ld20_init_rams),
+	.css_in        = uniphier_hsc_ld11_css_in,
+	.num_css_in    = ARRAY_SIZE(uniphier_hsc_ld11_css_in),
+	.css_out       = uniphier_hsc_ld11_css_out,
+	.num_css_out   = ARRAY_SIZE(uniphier_hsc_ld11_css_out),
+	.ts_in         = uniphier_hsc_ld11_ts_in,
+	.num_ts_in     = ARRAY_SIZE(uniphier_hsc_ld11_ts_in),
+	.dma_in        = uniphier_hsc_ld11_dma_in,
+	.num_dma_in    = ARRAY_SIZE(uniphier_hsc_ld11_dma_in),
+	.dma_out       = uniphier_hsc_ld11_dma_out,
+	.num_dma_out   = ARRAY_SIZE(uniphier_hsc_ld11_dma_out),
+};
-- 
2.17.0

^ permalink raw reply related

* [PATCH 4/8] media: uniphier: add common module of HSC MPEG2-TS I/O driver
From: Katsuhiro Suzuki @ 2018-05-30  9:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180530090946.1635-1-suzuki.katsuhiro@socionext.com>

This patch adds common module of HSC (High speed Stream Controller)
driver for Socionext UniPhier SoCs.

Signed-off-by: Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>
---
 drivers/media/platform/uniphier/Makefile   |   2 +-
 drivers/media/platform/uniphier/hsc-core.c | 514 +++++++++++++++++++++
 2 files changed, 515 insertions(+), 1 deletion(-)
 create mode 100644 drivers/media/platform/uniphier/hsc-core.c

diff --git a/drivers/media/platform/uniphier/Makefile b/drivers/media/platform/uniphier/Makefile
index 92536bc56b31..88bc860b391f 100644
--- a/drivers/media/platform/uniphier/Makefile
+++ b/drivers/media/platform/uniphier/Makefile
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
-uniphier-dvb-y += hsc-ucode.o hsc-css.o hsc-ts.o hsc-dma.o
+uniphier-dvb-y += hsc-core.o hsc-ucode.o hsc-css.o hsc-ts.o hsc-dma.o
 
 obj-$(CONFIG_DVB_UNIPHIER) += uniphier-dvb.o
diff --git a/drivers/media/platform/uniphier/hsc-core.c b/drivers/media/platform/uniphier/hsc-core.c
new file mode 100644
index 000000000000..cdb488e4df8c
--- /dev/null
+++ b/drivers/media/platform/uniphier/hsc-core.c
@@ -0,0 +1,514 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Socionext UniPhier DVB driver for High-speed Stream Controller (HSC).
+//
+// Copyright (c) 2018 Socionext Inc.
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/reset.h>
+
+#include "hsc.h"
+#include "hsc-reg.h"
+
+#define SZ_TS_PKT      188
+#define SZ_M2TS_PKT    192
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nums);
+
+static int hsc_start_feed(struct dvb_demux_feed *feed)
+{
+	struct hsc_tsif *tsif = feed->demux->priv;
+	struct hsc_dmaif *dmaif = tsif->dmaif;
+	struct hsc_chip *chip = tsif->chip;
+
+	tsif->running = true;
+	dmaif->running = true;
+
+	hsc_ts_in_set_enable(chip, tsif->tsi, true);
+
+	hsc_dma_out_set_src_ts_in(&dmaif->dma_out, tsif->tsi);
+	hsc_dma_out_start(&dmaif->dma_out, true);
+
+	return 0;
+}
+
+static int hsc_stop_feed(struct dvb_demux_feed *feed)
+{
+	struct hsc_tsif *tsif = feed->demux->priv;
+	struct hsc_dmaif *dmaif = tsif->dmaif;
+	struct hsc_chip *chip = tsif->chip;
+
+	hsc_ts_in_set_enable(chip, tsif->tsi, false);
+
+	hsc_dma_out_start(&dmaif->dma_out, false);
+
+	tsif->running = false;
+	dmaif->running = false;
+
+	return 0;
+}
+
+int hsc_register_dvb(struct hsc_tsif *tsif)
+{
+	struct device *dev = &tsif->chip->pdev->dev;
+	int ret;
+
+	tsif->adapter.priv = tsif;
+	ret = dvb_register_adapter(&tsif->adapter, "uniphier-hsc",
+				   THIS_MODULE, dev, adapter_nums);
+	if (ret < 0) {
+		dev_err(dev, "Failed to register DVB adapter: %d\n", ret);
+		return ret;
+	}
+	tsif->valid_adapter = true;
+
+	tsif->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+	tsif->demux.priv = tsif;
+	tsif->demux.feednum = 256;
+	tsif->demux.filternum = 256;
+	tsif->demux.start_feed = hsc_start_feed;
+	tsif->demux.stop_feed = hsc_stop_feed;
+	tsif->demux.write_to_decoder = NULL;
+	ret = dvb_dmx_init(&tsif->demux);
+	if (ret) {
+		dev_err(dev, "Failed to register demux: %d\n", ret);
+		goto err_out_adapter;
+	}
+	tsif->valid_demux = true;
+
+	tsif->dmxdev.filternum = 256;
+	tsif->dmxdev.demux = &tsif->demux.dmx;
+	tsif->dmxdev.capabilities = 0;
+	ret = dvb_dmxdev_init(&tsif->dmxdev, &tsif->adapter);
+	if (ret) {
+		dev_err(dev, "Failed to register demux dev: %d\n", ret);
+		goto err_out_dmx;
+	}
+	tsif->valid_dmxdev = true;
+
+	ret = dvb_register_frontend(&tsif->adapter, tsif->fe);
+	if (ret) {
+		dev_err(dev, "Failed to register adapter: %d\n", ret);
+		goto err_out_dmxdev;
+	}
+	tsif->valid_fe = true;
+
+	return 0;
+
+err_out_dmxdev:
+	dvb_dmxdev_release(&tsif->dmxdev);
+
+err_out_dmx:
+	dvb_dmx_release(&tsif->demux);
+
+err_out_adapter:
+	dvb_unregister_adapter(&tsif->adapter);
+
+	return ret;
+}
+
+void hsc_unregister_dvb(struct hsc_tsif *tsif)
+{
+	if (tsif->valid_fe) {
+		dvb_frontend_detach(tsif->fe);
+		dvb_unregister_frontend(tsif->fe);
+	}
+	if (tsif->valid_dmxdev)
+		dvb_dmxdev_release(&tsif->dmxdev);
+	if (tsif->valid_demux)
+		dvb_dmx_release(&tsif->demux);
+	if (tsif->valid_adapter)
+		dvb_unregister_adapter(&tsif->adapter);
+}
+
+static bool is_tsi_error(struct hsc_tsif *tsif, u32 status)
+{
+	if (status & (TSI_INTR_SERR | TSI_INTR_SOF | TSI_INTR_TOF))
+		return true;
+
+	return false;
+}
+
+static void hsc_tsif_recover_worker(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct hsc_tsif *tsif = container_of(dwork,
+		struct hsc_tsif, recover_work);
+	struct hsc_chip *chip = tsif->chip;
+
+	if (!tsif->running)
+		return;
+
+	hsc_ts_in_set_enable(chip, tsif->tsi, true);
+}
+
+static irqreturn_t hsc_tsif_irq(int irq, void *p)
+{
+	struct platform_device *pdev = p;
+	struct device *dev = &pdev->dev;
+	struct hsc_chip *chip = platform_get_drvdata(pdev);
+	struct regmap *r = chip->regmap;
+	int i, ret = IRQ_NONE;
+
+	for (i = 0; i < ARRAY_SIZE(chip->tsif); i++) {
+		struct hsc_tsif *tsif = &chip->tsif[i];
+		u32 st;
+
+		if (!tsif->running)
+			continue;
+
+		regmap_read(r, TSI_SYNCSTATUS(tsif->tsi), &st);
+		if (!st)
+			continue;
+
+		regmap_write(r, TSI_SYNCSTATUS(tsif->tsi), 0xffff);
+
+		if (is_tsi_error(tsif, st)) {
+			/* Recovery */
+			dev_info(dev, "TS %d Sync lost, try recovery.\n",
+				 tsif->tsi);
+			schedule_delayed_work(&tsif->recover_work,
+					      tsif->recover_delay);
+		}
+
+		ret = IRQ_HANDLED;
+	}
+
+	return ret;
+}
+
+int hsc_tsif_init(struct hsc_tsif *tsif, const struct hsc_conf *conf)
+{
+	struct hsc_chip *chip = tsif->chip;
+	int ret;
+
+	if (!conf)
+		return -EINVAL;
+
+	tsif->css_in = conf->css_in;
+	tsif->css_out = conf->css_out;
+	tsif->dpll = conf->dpll;
+
+	tsif->tsi = hsc_css_out_to_ts_in(tsif->css_out);
+	if (tsif->tsi == -1)
+		return -EINVAL;
+
+	tsif->dpll_src = hsc_css_out_to_dpll_src(tsif->css_out);
+	if (tsif->dpll_src == -1)
+		return -EINVAL;
+
+	ret = hsc_css_out_set_src(chip, tsif->css_in, tsif->css_out, true);
+	if (ret)
+		return ret;
+
+	ret = hsc_css_in_set_polarity(chip, tsif->css_in, false, false, false);
+	if (ret)
+		return ret;
+
+	ret = hsc_ts_in_set_dmaparam(chip, tsif->tsi, HSC_TSIF_MPEG2_TS_ATS);
+	if (ret)
+		return ret;
+
+	ret = hsc_dpll_set_src(chip, tsif->dpll, tsif->dpll_src);
+	if (ret)
+		return ret;
+
+	INIT_DELAYED_WORK(&tsif->recover_work, hsc_tsif_recover_worker);
+	tsif->recover_delay = HZ / 10;
+
+	return 0;
+}
+
+void hsc_tsif_release(struct hsc_tsif *tsif)
+{
+	cancel_delayed_work(&tsif->recover_work);
+}
+
+static void hsc_dmaif_feed_worker(struct work_struct *work)
+{
+	struct hsc_dmaif *dmaif = container_of(work,
+		struct hsc_dmaif, feed_work);
+	struct hsc_tsif *tsif = dmaif->tsif;
+	struct hsc_dma_buf *buf = &dmaif->buf_out;
+	struct device *dev = &dmaif->chip->pdev->dev;
+	dma_addr_t dmapos;
+	u8 *pkt;
+	u64 cnt, i;
+	int wrap = 0;
+
+	if (!dmaif->running)
+		return;
+
+retry:
+	spin_lock(&dmaif->lock);
+	hsc_dma_out_sync(&dmaif->dma_out);
+	spin_unlock(&dmaif->lock);
+
+	dmapos = buf->phys + buf->rd_offs;
+	cnt = hsc_rb_cnt_to_end(buf);
+	cnt = DIV_ROUND_DOWN_ULL(cnt, SZ_M2TS_PKT) * SZ_M2TS_PKT;
+
+	dma_sync_single_for_cpu(dev, dmapos, cnt, DMA_FROM_DEVICE);
+	for (i = 0; i < cnt; i += SZ_M2TS_PKT) {
+		pkt = buf->virt + buf->rd_offs + i;
+
+		if (pkt[4] == 0x47 && pkt[5] == 0x1f && pkt[6] == 0xff)
+			continue;
+		if (pkt[5] & 0x80)
+			continue;
+		if (pkt[7] & 0xc0)
+			continue;
+
+		dvb_dmx_swfilter_packets(&tsif->demux, &pkt[4], 1);
+	}
+	dma_sync_single_for_device(dev, dmapos, cnt, DMA_FROM_DEVICE);
+
+	spin_lock(&dmaif->lock);
+
+	buf->rd_offs += cnt;
+	if (buf->rd_offs >= buf->size)
+		buf->rd_offs -= buf->size;
+
+	buf->chk_offs = buf->wr_offs + buf->size_chk;
+	if (buf->chk_offs >= buf->size)
+		buf->chk_offs -= buf->size;
+
+	if (!wrap && hsc_rb_cnt(buf) >= buf->size_chk / 2) {
+		wrap = 1;
+		spin_unlock(&dmaif->lock);
+		goto retry;
+	}
+
+	hsc_dma_out_sync(&dmaif->dma_out);
+
+	spin_unlock(&dmaif->lock);
+}
+
+static irqreturn_t hsc_dmaif_irq(int irq, void *p)
+{
+	struct platform_device *pdev = p;
+	struct hsc_chip *chip = platform_get_drvdata(pdev);
+	int i, ret = IRQ_NONE;
+	u32 st;
+
+	for (i = 0; i < ARRAY_SIZE(chip->tsif); i++) {
+		struct hsc_dmaif *dmaif = &chip->dmaif[i];
+
+		if (!dmaif->running)
+			continue;
+
+		hsc_dma_out_get_intr(&dmaif->dma_out, &st);
+		if (!st)
+			continue;
+
+		hsc_dma_out_clear_intr(&dmaif->dma_out, 0xffff);
+
+		spin_lock(&dmaif->lock);
+		hsc_dma_out_sync(&dmaif->dma_out);
+		spin_unlock(&dmaif->lock);
+
+		schedule_work(&dmaif->feed_work);
+
+		ret = IRQ_HANDLED;
+	}
+
+	return ret;
+}
+
+int hsc_dmaif_init(struct hsc_dmaif *dmaif, const struct hsc_conf *conf)
+{
+	struct hsc_chip *chip = dmaif->chip;
+	struct hsc_dma_buf *buf = &dmaif->buf_out;
+	struct device *dev = &chip->pdev->dev;
+	int ret;
+
+	if (!conf)
+		return -EINVAL;
+
+	ret = hsc_dma_out_init(&dmaif->dma_out, chip, conf->dma_out, buf);
+	if (ret)
+		return ret;
+
+	buf->size = HSC_DMAIF_TS_BUFSIZE;
+	buf->size_chk = HSC_DMAIF_TS_BUFSIZE / 4;
+	buf->virt = dma_alloc_coherent(dev, buf->size, &buf->phys, GFP_KERNEL);
+	if (!buf->virt)
+		return -ENOMEM;
+
+	spin_lock_init(&dmaif->lock);
+	INIT_WORK(&dmaif->feed_work, hsc_dmaif_feed_worker);
+
+	return 0;
+}
+
+void hsc_dmaif_release(struct hsc_dmaif *dmaif)
+{
+	struct hsc_chip *chip = dmaif->chip;
+	struct device *dev = &chip->pdev->dev;
+
+	flush_scheduled_work();
+
+	dma_free_coherent(dev, dmaif->buf_out.size, dmaif->buf_out.virt,
+			  dmaif->buf_out.phys);
+}
+
+static const struct regmap_config hsc_regmap_config = {
+	.reg_bits      = 32,
+	.reg_stride    = 4,
+	.val_bits      = 32,
+	.max_register  = 0xffffc,
+	.cache_type    = REGCACHE_NONE,
+};
+
+static int hsc_probe(struct platform_device *pdev)
+{
+	struct hsc_chip *chip;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	void __iomem *preg;
+	int irq, ret, i;
+
+	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+	chip->pdev = pdev;
+
+	chip->spec = of_device_get_match_data(dev);
+	if (!chip->spec)
+		return -EINVAL;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	preg = devm_ioremap_resource(dev, res);
+	if (IS_ERR(preg))
+		return PTR_ERR(preg);
+
+	chip->regmap = devm_regmap_init_mmio(dev, preg,
+					     &hsc_regmap_config);
+	if (IS_ERR(chip->regmap))
+		return PTR_ERR(chip->regmap);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(dev, "Could not get irq for TS I/F\n");
+		return irq;
+	}
+
+	ret = devm_request_irq(dev, irq, hsc_tsif_irq, IRQF_SHARED,
+			       dev_name(dev), pdev);
+	if (ret)
+		return ret;
+
+	irq = platform_get_irq(pdev, 1);
+	if (irq < 0) {
+		dev_err(dev, "Could not get irq for DMA I/F\n");
+		return irq;
+	}
+
+	ret = devm_request_irq(dev, irq, hsc_dmaif_irq, IRQF_SHARED,
+			       dev_name(dev), pdev);
+	if (ret)
+		return ret;
+
+	chip->clk_stdmac = devm_clk_get(dev, "stdmac");
+	if (IS_ERR(chip->clk_stdmac))
+		return PTR_ERR(chip->clk_stdmac);
+
+	chip->clk_hsc = devm_clk_get(dev, "hsc");
+	if (IS_ERR(chip->clk_hsc))
+		return PTR_ERR(chip->clk_hsc);
+
+	chip->rst_stdmac = devm_reset_control_get_shared(dev, "stdmac");
+	if (IS_ERR(chip->rst_stdmac))
+		return PTR_ERR(chip->rst_stdmac);
+
+	chip->rst_hsc = devm_reset_control_get_shared(dev, "hsc");
+	if (IS_ERR(chip->rst_hsc))
+		return PTR_ERR(chip->rst_hsc);
+
+	ret = clk_prepare_enable(chip->clk_stdmac);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare_enable(chip->clk_hsc);
+	if (ret)
+		goto err_out_clk_stdmac;
+
+	ret = reset_control_deassert(chip->rst_stdmac);
+	if (ret)
+		goto err_out_clk_hsc;
+
+	ret = reset_control_deassert(chip->rst_hsc);
+	if (ret)
+		goto err_out_rst_stdmac;
+
+	ret = hsc_ucode_load_all(chip);
+	if (ret)
+		goto err_out_rst_hsc;
+
+	for (i = 0; i < HSC_STREAM_IF_NUM; i++) {
+		chip->dmaif[i].chip = chip;
+		chip->dmaif[i].tsif = &chip->tsif[i];
+		chip->tsif[i].chip = chip;
+		chip->tsif[i].dmaif = &chip->dmaif[i];
+	}
+
+	platform_set_drvdata(pdev, chip);
+
+	return 0;
+
+err_out_rst_hsc:
+	reset_control_assert(chip->rst_hsc);
+
+err_out_rst_stdmac:
+	reset_control_assert(chip->rst_stdmac);
+
+err_out_clk_hsc:
+	clk_disable_unprepare(chip->clk_hsc);
+
+err_out_clk_stdmac:
+	clk_disable_unprepare(chip->clk_stdmac);
+
+	return ret;
+}
+
+static int hsc_remove(struct platform_device *pdev)
+{
+	struct hsc_chip *chip = platform_get_drvdata(pdev);
+
+	hsc_ucode_unload_all(chip);
+
+	reset_control_assert(chip->rst_hsc);
+	reset_control_assert(chip->rst_stdmac);
+	clk_disable_unprepare(chip->clk_hsc);
+	clk_disable_unprepare(chip->clk_stdmac);
+
+	return 0;
+}
+
+static const struct of_device_id uniphier_hsc_of_match[] = {
+	{
+		.compatible = "socionext,uniphier-ld11-hsc",
+		.data = &uniphier_hsc_ld11_spec,
+	},
+	{
+		.compatible = "socionext,uniphier-ld20-hsc",
+		.data = &uniphier_hsc_ld20_spec,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, uniphier_hsc_of_match);
+
+static struct platform_driver uniphier_hsc_driver = {
+	.driver = {
+		.name = "uniphier-hsc",
+		.of_match_table = of_match_ptr(uniphier_hsc_of_match),
+	},
+	.probe  = hsc_probe,
+	.remove = hsc_remove,
+};
+module_platform_driver(uniphier_hsc_driver);
-- 
2.17.0

^ permalink raw reply related

* [PATCH 3/8] media: uniphier: add submodules of HSC MPEG2-TS I/O driver
From: Katsuhiro Suzuki @ 2018-05-30  9:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180530090946.1635-1-suzuki.katsuhiro@socionext.com>

This patch adds submodules of HSC for UniPhier SoCs.
These work as follows:
  ucode: Load uCode and start subsystems
  css  : Switch stream path
  ts   : Receive MPEG2-TS clock and signal
  dma  : Transfer MPEG2-TS data bytes to main memory

Signed-off-by: Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>
---
 drivers/media/platform/uniphier/Makefile    |   3 +
 drivers/media/platform/uniphier/hsc-css.c   | 258 ++++++++++++
 drivers/media/platform/uniphier/hsc-dma.c   | 302 ++++++++++++++
 drivers/media/platform/uniphier/hsc-ts.c    |  99 +++++
 drivers/media/platform/uniphier/hsc-ucode.c | 436 ++++++++++++++++++++
 5 files changed, 1098 insertions(+)
 create mode 100644 drivers/media/platform/uniphier/hsc-css.c
 create mode 100644 drivers/media/platform/uniphier/hsc-dma.c
 create mode 100644 drivers/media/platform/uniphier/hsc-ts.c
 create mode 100644 drivers/media/platform/uniphier/hsc-ucode.c

diff --git a/drivers/media/platform/uniphier/Makefile b/drivers/media/platform/uniphier/Makefile
index f66554cd5c45..92536bc56b31 100644
--- a/drivers/media/platform/uniphier/Makefile
+++ b/drivers/media/platform/uniphier/Makefile
@@ -1 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
+uniphier-dvb-y += hsc-ucode.o hsc-css.o hsc-ts.o hsc-dma.o
+
+obj-$(CONFIG_DVB_UNIPHIER) += uniphier-dvb.o
diff --git a/drivers/media/platform/uniphier/hsc-css.c b/drivers/media/platform/uniphier/hsc-css.c
new file mode 100644
index 000000000000..baa0a15ca98e
--- /dev/null
+++ b/drivers/media/platform/uniphier/hsc-css.c
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Socionext UniPhier DVB driver for High-speed Stream Controller (HSC).
+// CSS (Cross Stream Switch) connects MPEG2-TS input port and output port.
+//
+// Copyright (c) 2018 Socionext Inc.
+
+#include <linux/bitfield.h>
+#include <linux/kernel.h>
+
+#include "hsc.h"
+#include "hsc-reg.h"
+
+enum HSC_TS_IN hsc_css_out_to_ts_in(enum HSC_CSS_OUT out)
+{
+	if (out >= HSC_CSS_OUT_TSI0 && out <= HSC_CSS_OUT_TSI9)
+		return HSC_TSI0 + (out - HSC_CSS_OUT_TSI0);
+
+	return -1;
+}
+
+enum HSC_DPLL_SRC hsc_css_out_to_dpll_src(enum HSC_CSS_OUT out)
+{
+	if (out >= HSC_CSS_OUT_TSI0 && out <= HSC_CSS_OUT_TSI9)
+		return HSC_DPLL_SRC_TSI0 + (out - HSC_CSS_OUT_TSI0);
+
+	return -1;
+}
+
+static bool css_in_is_valid(struct hsc_chip *chip, enum HSC_CSS_IN in)
+{
+	if (in >= chip->spec->num_css_in)
+		return false;
+
+	return true;
+}
+
+static bool css_out_is_valid(struct hsc_chip *chip, enum HSC_CSS_OUT out)
+{
+	if (out >= chip->spec->num_css_out)
+		return false;
+
+	return true;
+}
+
+static const struct hsc_spec_css_in *css_in_get_spec(struct hsc_chip *chip,
+						     enum HSC_CSS_IN in)
+{
+	const struct hsc_spec_css_in *spec = chip->spec->css_in;
+
+	if (!css_in_is_valid(chip, in))
+		return NULL;
+
+	return &spec[in];
+}
+
+static const struct hsc_spec_css_out *css_out_get_spec(struct hsc_chip *chip,
+						       enum HSC_CSS_OUT out)
+{
+	const struct hsc_spec_css_out *spec = chip->spec->css_out;
+
+	if (!css_out_is_valid(chip, out))
+		return NULL;
+
+	return &spec[out];
+}
+
+int hsc_dpll_get_src(struct hsc_chip *chip, enum HSC_DPLL dpll,
+		     enum HSC_DPLL_SRC *src)
+{
+	struct regmap *r = chip->regmap;
+	u32 v;
+
+	if (!src || dpll >= HSC_DPLL_NUM)
+		return -EINVAL;
+
+	regmap_read(r, CSS_DPCTRL(dpll), &v);
+	*src = ffs(v & CSS_DPCTRL_DPSEL_MASK) - 1;
+
+	return 0;
+}
+
+/**
+ * Select source clock of DPLL.
+ *
+ * @dpll: ID of DPLL
+ * @src : ID of clock source or HSC_DPLL_SRC_NONE to disconnect
+ */
+int hsc_dpll_set_src(struct hsc_chip *chip, enum HSC_DPLL dpll,
+		     enum HSC_DPLL_SRC src)
+{
+	struct regmap *r = chip->regmap;
+	u32 v = 0;
+
+	if (dpll >= HSC_DPLL_NUM || src >= HSC_DPLL_SRC_NUM)
+		return -EINVAL;
+
+	if (src != HSC_DPLL_SRC_NONE)
+		v = 1 << src;
+
+	regmap_write(r, CSS_DPCTRL(dpll), v);
+
+	return 0;
+}
+
+static int hsc_css_get_polarity(struct hsc_chip *chip,
+				const struct hsc_css_pol *pol,
+				bool *sync_bit, bool *val_bit, bool *clk_fall)
+{
+	struct regmap *r = chip->regmap;
+	u32 v;
+
+	if (!sync_bit || !val_bit || !clk_fall || !pol->valid)
+		return -EINVAL;
+
+	regmap_read(r, pol->reg, &v);
+
+	*sync_bit = !!(v & BIT(pol->sft_sync));
+	*val_bit = !!(v & BIT(pol->sft_val));
+	*clk_fall = !!(v & BIT(pol->sft_clk));
+
+	return 0;
+}
+
+/**
+ * Setup signal polarity of TS signals.
+ *
+ * @sync_bit : true : The sync signal keeps only 1bit period.
+ *             false: The sync signal keeps during 8bits period.
+ * @valid_bit: true : The valid signal does not keep during 8bits period.
+ *             false: The valid signal keeps during 8bits period.
+ * @clk_fall : true : Latch the data at falling edge of clock signal.
+ *             false: Latch the data at rising edge of clock signal.
+ */
+static int hsc_css_set_polarity(struct hsc_chip *chip,
+				const struct hsc_css_pol *pol,
+				bool sync_bit, bool val_bit, bool clk_fall)
+{
+	struct regmap *r = chip->regmap;
+	u32 m = 0, v = 0;
+
+	if (!pol->valid)
+		return -EINVAL;
+
+	if (pol->sft_sync != -1) {
+		m |= BIT(pol->sft_sync);
+		if (sync_bit)
+			v |= BIT(pol->sft_sync);
+	}
+
+	if (pol->sft_val != -1) {
+		m |= BIT(pol->sft_val);
+		if (val_bit)
+			v |= BIT(pol->sft_val);
+	}
+
+	if (pol->sft_clk != -1) {
+		m |= BIT(pol->sft_clk);
+		if (clk_fall)
+			v |= BIT(pol->sft_clk);
+	}
+
+	regmap_update_bits(r, pol->reg, m, v);
+
+	return 0;
+}
+
+int hsc_css_in_get_polarity(struct hsc_chip *chip, enum HSC_CSS_IN in,
+			    bool *sync_bit, bool *val_bit, bool *clk_fall)
+{
+	const struct hsc_spec_css_in *speci = css_in_get_spec(chip, in);
+
+	if (!speci)
+		return -EINVAL;
+
+	return hsc_css_get_polarity(chip, &speci->pol,
+				    sync_bit, val_bit, clk_fall);
+}
+
+int hsc_css_in_set_polarity(struct hsc_chip *chip, enum HSC_CSS_IN in,
+			    bool sync_bit, bool val_bit, bool clk_fall)
+{
+	const struct hsc_spec_css_in *speci = css_in_get_spec(chip, in);
+
+	if (!speci)
+		return -EINVAL;
+
+	return hsc_css_set_polarity(chip, &speci->pol,
+				    sync_bit, val_bit, clk_fall);
+}
+
+int hsc_css_out_get_polarity(struct hsc_chip *chip, enum HSC_CSS_OUT out,
+			     bool *sync_bit, bool *val_bit, bool *clk_fall)
+{
+	const struct hsc_spec_css_out *speco = css_out_get_spec(chip, out);
+
+	if (!speco)
+		return -EINVAL;
+
+	return hsc_css_get_polarity(chip, &speco->pol,
+				    sync_bit, val_bit, clk_fall);
+}
+
+int hsc_css_out_set_polarity(struct hsc_chip *chip, enum HSC_CSS_OUT out,
+			     bool sync_bit, bool val_bit, bool clk_fall)
+{
+	const struct hsc_spec_css_out *speco = css_out_get_spec(chip, out);
+
+	if (!speco)
+		return -EINVAL;
+
+	return hsc_css_set_polarity(chip, &speco->pol,
+				    sync_bit, val_bit, clk_fall);
+}
+
+int hsc_css_out_get_src(struct hsc_chip *chip, enum HSC_CSS_IN *in,
+			enum HSC_CSS_OUT out, bool *en)
+{
+	struct regmap *r = chip->regmap;
+	const struct hsc_spec_css_out *speco = css_out_get_spec(chip, out);
+	u32 v;
+
+	if (!in || !en || !speco || !speco->sel.valid)
+		return -EINVAL;
+
+	regmap_read(r, speco->sel.reg, &v);
+	*in = field_get(speco->sel.mask, v);
+
+	regmap_read(r, CSS_OUTPUTENABLE, &v);
+	*en = !!(v & BIT(out));
+
+	return 0;
+}
+
+/**
+ * Connect the input port and output port using CSS (Cross Stream Switch).
+ *
+ * @in   : Input port number.
+ * @out  : Output port number.
+ * @en   : false: Disable this path.
+ *         true : Enable this path.
+ */
+int hsc_css_out_set_src(struct hsc_chip *chip, enum HSC_CSS_IN in,
+			enum HSC_CSS_OUT out, bool en)
+{
+	struct regmap *r = chip->regmap;
+	const struct hsc_spec_css_out *speco = css_out_get_spec(chip, out);
+
+	if (!css_in_is_valid(chip, in) || !speco || !speco->sel.valid)
+		return -EINVAL;
+
+	regmap_update_bits(r, speco->sel.reg, speco->sel.mask,
+			   field_prep(speco->sel.mask, in));
+
+	regmap_update_bits(r, CSS_OUTPUTENABLE, BIT(out), (en) ? ~0 : 0);
+
+	return 0;
+}
diff --git a/drivers/media/platform/uniphier/hsc-dma.c b/drivers/media/platform/uniphier/hsc-dma.c
new file mode 100644
index 000000000000..0b3e471a68f7
--- /dev/null
+++ b/drivers/media/platform/uniphier/hsc-dma.c
@@ -0,0 +1,302 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Socionext UniPhier DVB driver for High-speed Stream Controller (HSC).
+// MPEG2-TS DMA control.
+//
+// Copyright (c) 2018 Socionext Inc.
+
+#include <linux/bitfield.h>
+#include <linux/kernel.h>
+
+#include "hsc.h"
+#include "hsc-reg.h"
+
+u64 hsc_rb_cnt(struct hsc_dma_buf *buf)
+{
+	if (buf->rd_offs <= buf->wr_offs)
+		return buf->wr_offs - buf->rd_offs;
+	else
+		return buf->size - (buf->rd_offs - buf->wr_offs);
+}
+
+u64 hsc_rb_cnt_to_end(struct hsc_dma_buf *buf)
+{
+	if (buf->rd_offs <= buf->wr_offs)
+		return buf->wr_offs - buf->rd_offs;
+	else
+		return buf->size - buf->rd_offs;
+}
+
+u64 hsc_rb_space(struct hsc_dma_buf *buf)
+{
+	if (buf->rd_offs <= buf->wr_offs)
+		return buf->size - (buf->wr_offs - buf->rd_offs) - 8;
+	else
+		return buf->rd_offs - buf->wr_offs - 8;
+}
+
+u64 hsc_rb_space_to_end(struct hsc_dma_buf *buf)
+{
+	if (buf->rd_offs > buf->wr_offs)
+		return buf->rd_offs - buf->wr_offs - 8;
+	else if (buf->rd_offs > 0)
+		return buf->size - buf->wr_offs;
+	else
+		return buf->size - buf->wr_offs - 8;
+}
+
+static void dma_set_buffer(struct hsc_chip *chip, int dma_ch,
+			   u64 bg, u64 ed)
+{
+	struct regmap *r = chip->regmap;
+
+	regmap_write(r, CDMBC_RBBGNADRSD(dma_ch), bg);
+	regmap_write(r, CDMBC_RBBGNADRSU(dma_ch), bg >> 32);
+	regmap_write(r, CDMBC_RBENDADRSD(dma_ch), ed);
+	regmap_write(r, CDMBC_RBENDADRSU(dma_ch), ed >> 32);
+}
+
+static u64 dma_get_rp(struct hsc_chip *chip, int dma_ch)
+{
+	struct regmap *r = chip->regmap;
+	u32 d, u;
+
+	regmap_read(r, CDMBC_RBRDPTRD(dma_ch), &d);
+	regmap_read(r, CDMBC_RBRDPTRU(dma_ch), &u);
+
+	return ((u64)u << 32) | d;
+}
+
+static void dma_set_rp(struct hsc_chip *chip, int dma_ch, u64 pos)
+{
+	struct regmap *r = chip->regmap;
+
+	regmap_write(r, CDMBC_RBRDPTRD(dma_ch), pos);
+	regmap_write(r, CDMBC_RBRDPTRU(dma_ch), pos >> 32);
+}
+
+static u64 dma_get_wp(struct hsc_chip *chip, int dma_ch)
+{
+	struct regmap *r = chip->regmap;
+	u32 d, u;
+
+	regmap_read(r, CDMBC_RBWRPTRD(dma_ch), &d);
+	regmap_read(r, CDMBC_RBWRPTRU(dma_ch), &u);
+
+	return ((u64)u << 32) | d;
+}
+
+static void dma_set_wp(struct hsc_chip *chip, int dma_ch, u64 pos)
+{
+	struct regmap *r = chip->regmap;
+
+	regmap_write(r, CDMBC_RBWRPTRD(dma_ch), pos);
+	regmap_write(r, CDMBC_RBWRPTRU(dma_ch), pos >> 32);
+}
+
+static void dma_set_chkp(struct hsc_chip *chip, int dma_ch, u64 pos)
+{
+	struct regmap *r = chip->regmap;
+
+	regmap_write(r, CDMBC_CHIRADRSD(dma_ch), pos);
+	regmap_write(r, CDMBC_CHIRADRSU(dma_ch), pos >> 32);
+}
+
+static void dma_set_enable(struct hsc_chip *chip, int dma_ch,
+			   const struct hsc_dma_en *dma_en, bool en)
+{
+	struct regmap *r = chip->regmap;
+	u32 v;
+	bool now;
+
+	regmap_read(r, dma_en->reg, &v);
+	now = !!(v & BIT(dma_en->sft_toggle));
+
+	/* Toggle DMA state if needed */
+	if ((en && !now) || (!en && now))
+		regmap_write(r, dma_en->reg, BIT(dma_en->sft_toggle));
+}
+
+static bool dma_in_is_valid(struct hsc_chip *chip, enum HSC_DMA_IN in)
+{
+	if (in >= chip->spec->num_dma_in ||
+	    !chip->spec->dma_in[in].intr.valid)
+		return false;
+
+	return true;
+}
+
+int hsc_dma_in_init(struct hsc_dma_in *dma_in, struct hsc_chip *chip,
+		    enum HSC_DMA_IN in, struct hsc_dma_buf *buf)
+{
+	if (!dma_in || !dma_in_is_valid(chip, in))
+		return -EINVAL;
+
+	dma_in->chip = chip;
+	dma_in->id = in;
+	dma_in->spec = &chip->spec->dma_in[in];
+	dma_in->buf = buf;
+
+	return 0;
+}
+
+void hsc_dma_in_start(struct hsc_dma_in *dma_in, bool en)
+{
+	struct hsc_chip *chip = dma_in->chip;
+	const struct hsc_spec_dma *spec = dma_in->spec;
+	struct hsc_dma_buf *buf = dma_in->buf;
+	struct regmap *r = chip->regmap;
+	u64 bg, ed;
+	u32 v;
+
+	bg = buf->phys;
+	ed = buf->phys + buf->size;
+	dma_set_buffer(chip, spec->dma_ch, bg, ed);
+
+	buf->rd_offs = 0;
+	buf->wr_offs = 0;
+	buf->chk_offs = buf->size_chk;
+	dma_set_rp(chip, spec->dma_ch, buf->rd_offs + buf->phys);
+	dma_set_wp(chip, spec->dma_ch, buf->wr_offs + buf->phys);
+	dma_set_chkp(chip, spec->dma_ch, buf->chk_offs + buf->phys);
+
+	regmap_update_bits(r, CDMBC_CHSRCAMODE(spec->dma_ch),
+			   CDMBC_CHAMODE_TYPE_RB, ~0);
+	regmap_update_bits(r, CDMBC_CHCTRL1(spec->dma_ch),
+			   CDMBC_CHCTRL1_IND_SIZE_UND, ~0);
+
+	v = (en) ? ~0 : 0;
+	regmap_update_bits(r, CDMBC_CHIE(spec->dma_ch), CDMBC_CHI_TRANSIT, v);
+	regmap_update_bits(r, spec->intr.reg, BIT(spec->intr.sft_intr), v);
+
+	dma_set_enable(chip, spec->dma_ch, &spec->en, en);
+}
+
+void hsc_dma_in_sync(struct hsc_dma_in *dma_in)
+{
+	struct hsc_chip *chip = dma_in->chip;
+	const struct hsc_spec_dma *spec = dma_in->spec;
+	struct hsc_dma_buf *buf = dma_in->buf;
+
+	buf->rd_offs = dma_get_rp(chip, spec->dma_ch) - buf->phys;
+	dma_set_wp(chip, spec->dma_ch, buf->rd_offs + buf->phys);
+	dma_set_chkp(chip, spec->dma_ch, buf->chk_offs + buf->phys);
+}
+
+int hsc_dma_in_get_intr(struct hsc_dma_in *dma_in, u32 *stat)
+{
+	struct regmap *r = dma_in->chip->regmap;
+
+	if (!stat)
+		return -EINVAL;
+
+	regmap_read(r, CDMBC_CHID(dma_in->spec->dma_ch), stat);
+
+	return 0;
+}
+
+void hsc_dma_in_clear_intr(struct hsc_dma_in *dma_in, u32 v)
+{
+	struct regmap *r = dma_in->chip->regmap;
+
+	regmap_write(r, CDMBC_CHIR(dma_in->spec->dma_ch), v);
+}
+
+static bool dma_out_is_valid(struct hsc_chip *chip, enum HSC_DMA_OUT out)
+{
+	if (out >= chip->spec->num_dma_out ||
+	    !chip->spec->dma_out[out].intr.valid)
+		return false;
+
+	return true;
+}
+
+int hsc_dma_out_init(struct hsc_dma_out *dma_out, struct hsc_chip *chip,
+		     enum HSC_DMA_OUT out, struct hsc_dma_buf *buf)
+{
+	if (!dma_out || !dma_out_is_valid(chip, out))
+		return -EINVAL;
+
+	dma_out->chip = chip;
+	dma_out->id = out;
+	dma_out->spec = &chip->spec->dma_out[out];
+	dma_out->buf = buf;
+
+	return 0;
+}
+
+void hsc_dma_out_set_src_ts_in(struct hsc_dma_out *dma_out,
+			       enum HSC_TS_IN ts_in)
+{
+	struct regmap *r = dma_out->chip->regmap;
+	const struct hsc_spec_dma *spec = dma_out->spec;
+	u32 m, v;
+
+	m = CDMBC_CHTDCTRLH_STREM_MASK |
+		CDMBC_CHTDCTRLH_ALL_EN;
+	v = FIELD_PREP(CDMBC_CHTDCTRLH_STREM_MASK, ts_in) |
+		CDMBC_CHTDCTRLH_ALL_EN;
+	regmap_update_bits(r, CDMBC_CHTDCTRLH(spec->dma_ch), m, v);
+}
+
+void hsc_dma_out_start(struct hsc_dma_out *dma_out, bool en)
+{
+	struct hsc_chip *chip = dma_out->chip;
+	const struct hsc_spec_dma *spec = dma_out->spec;
+	struct hsc_dma_buf *buf = dma_out->buf;
+	struct regmap *r = chip->regmap;
+	u64 bg, ed;
+	u32 v;
+
+	bg = buf->phys;
+	ed = buf->phys + buf->size;
+	dma_set_buffer(chip, spec->dma_ch, bg, ed);
+
+	buf->rd_offs = 0;
+	buf->wr_offs = 0;
+	buf->chk_offs = buf->size_chk;
+	dma_set_rp(chip, spec->dma_ch, buf->rd_offs + buf->phys);
+	dma_set_wp(chip, spec->dma_ch, buf->wr_offs + buf->phys);
+	dma_set_chkp(chip, spec->dma_ch, buf->chk_offs + buf->phys);
+
+	regmap_update_bits(r, CDMBC_CHDSTAMODE(spec->dma_ch),
+			   CDMBC_CHAMODE_TYPE_RB, ~0);
+	regmap_update_bits(r, CDMBC_CHCTRL1(spec->dma_ch),
+			   CDMBC_CHCTRL1_IND_SIZE_UND, ~0);
+
+	v = (en) ? ~0 : 0;
+	regmap_update_bits(r, CDMBC_CHIE(spec->dma_ch), CDMBC_CHI_TRANSIT, v);
+	regmap_update_bits(r, spec->intr.reg, BIT(spec->intr.sft_intr), v);
+
+	dma_set_enable(chip, spec->dma_ch, &spec->en, en);
+}
+
+void hsc_dma_out_sync(struct hsc_dma_out *dma_out)
+{
+	struct hsc_chip *chip = dma_out->chip;
+	const struct hsc_spec_dma *spec = dma_out->spec;
+	struct hsc_dma_buf *buf = dma_out->buf;
+
+	dma_set_rp(chip, spec->dma_ch, buf->rd_offs + buf->phys);
+	buf->wr_offs = dma_get_wp(chip, spec->dma_ch) - buf->phys;
+	dma_set_chkp(chip, spec->dma_ch, buf->chk_offs + buf->phys);
+}
+
+int hsc_dma_out_get_intr(struct hsc_dma_out *dma_out, u32 *stat)
+{
+	struct regmap *r = dma_out->chip->regmap;
+
+	if (!stat)
+		return -EINVAL;
+
+	regmap_read(r, CDMBC_CHID(dma_out->spec->dma_ch), stat);
+
+	return 0;
+}
+
+void hsc_dma_out_clear_intr(struct hsc_dma_out *dma_out, u32 clear)
+{
+	struct regmap *r = dma_out->chip->regmap;
+
+	regmap_write(r, CDMBC_CHIR(dma_out->spec->dma_ch), clear);
+}
diff --git a/drivers/media/platform/uniphier/hsc-ts.c b/drivers/media/platform/uniphier/hsc-ts.c
new file mode 100644
index 000000000000..4539c3280021
--- /dev/null
+++ b/drivers/media/platform/uniphier/hsc-ts.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Socionext UniPhier DVB driver for High-speed Stream Controller (HSC).
+// MPEG2-TS input/output port setting.
+//
+// Copyright (c) 2018 Socionext Inc.
+
+#include <linux/bitfield.h>
+#include <linux/kernel.h>
+
+#include "hsc.h"
+#include "hsc-reg.h"
+
+#define PARAMA_OFFSET_TS      0x02
+#define PARAMA_LOOPADDR_TS    0x31
+#define PARAMA_COUNT_TS       0xc4
+
+static bool ts_in_is_valid(struct hsc_chip *chip, enum HSC_TS_IN in)
+{
+	if (in >= chip->spec->num_ts_in || !chip->spec->ts_in[in].intr.valid)
+		return false;
+
+	return true;
+}
+
+static const struct hsc_spec_ts *ts_in_get_spec(struct hsc_chip *chip,
+						enum HSC_TS_IN in)
+{
+	const struct hsc_spec_ts *spec = chip->spec->ts_in;
+
+	if (!ts_in_is_valid(chip, in))
+		return NULL;
+
+	return &spec[in];
+}
+
+int hsc_ts_in_set_enable(struct hsc_chip *chip, enum HSC_TS_IN in, bool en)
+{
+	struct regmap *r = chip->regmap;
+	const struct hsc_spec_ts *speci = ts_in_get_spec(chip, in);
+	u32 m, v;
+
+	if (!speci)
+		return -EINVAL;
+
+	m = TSI_SYNCCNTROL_FRAME_MASK;
+	v = TSI_SYNCCNTROL_FRAME_EXTSYNC2;
+	regmap_update_bits(r, TSI_SYNCCNTROL(in), m, v);
+
+	m = TSI_CONFIG_ATSMD_MASK | TSI_CONFIG_STCMD_MASK |
+		TSI_CONFIG_CHEN_START;
+	v = TSI_CONFIG_ATSMD_DPLL | TSI_CONFIG_STCMD_DPLL;
+	if (en)
+		v |= TSI_CONFIG_CHEN_START;
+	regmap_update_bits(r, TSI_CONFIG(in), m, v);
+
+	v = (en) ? ~0 : 0;
+	regmap_update_bits(r, TSI_INTREN(in),
+			   TSI_INTR_SERR | TSI_INTR_LOST, v);
+	regmap_update_bits(r, speci->intr.reg, BIT(speci->intr.sft_intr), v);
+
+	return 0;
+}
+
+int hsc_ts_in_set_dmaparam(struct hsc_chip *chip, enum HSC_TS_IN in,
+			   enum HSC_TSIF_FMT ifmt)
+{
+	struct regmap *r = chip->regmap;
+	u32 v, ats, offset, loop, cnt;
+
+	if (!ts_in_is_valid(chip, in))
+		return -EINVAL;
+
+	switch (ifmt) {
+	case HSC_TSIF_MPEG2_TS:
+		ats = 0;
+		offset = PARAMA_OFFSET_TS;
+		loop = PARAMA_LOOPADDR_TS;
+		cnt = PARAMA_COUNT_TS;
+		break;
+	case HSC_TSIF_MPEG2_TS_ATS:
+		ats = TSI_CONFIG_ATSADD_ON;
+		offset = PARAMA_OFFSET_TS;
+		loop = PARAMA_LOOPADDR_TS;
+		cnt = PARAMA_COUNT_TS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(r, TSI_CONFIG(in), TSI_CONFIG_ATSADD_ON, ats);
+
+	v = FIELD_PREP(SBC_DMAPARAMA_OFFSET_MASK, offset) |
+		FIELD_PREP(SBC_DMAPARAMA_LOOPADDR_MASK, loop) |
+		FIELD_PREP(SBC_DMAPARAMA_COUNT_MASK, cnt);
+	regmap_write(r, SBC_DMAPARAMA(in), v);
+
+	return 0;
+}
diff --git a/drivers/media/platform/uniphier/hsc-ucode.c b/drivers/media/platform/uniphier/hsc-ucode.c
new file mode 100644
index 000000000000..bad1d70b0968
--- /dev/null
+++ b/drivers/media/platform/uniphier/hsc-ucode.c
@@ -0,0 +1,436 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Socionext UniPhier DVB driver for High-speed Stream Controller (HSC).
+// Core init and uCode loader.
+//
+// Copyright (c) 2018 Socionext Inc.
+
+#include <linux/bitfield.h>
+#include <linux/firmware.h>
+#include <linux/kernel.h>
+
+#include "hsc.h"
+#include "hsc-reg.h"
+
+struct hsc_cip_file_dma_param {
+	u32 cip_file_ch;
+	dma_addr_t cip_r_sdram;
+	dma_addr_t cip_w_sdram;
+	size_t inter_size;
+	size_t total_size;
+	u8 key_id1;
+	u8 key_id0;
+	u8 endian;
+	int id1_en;
+	int push;
+};
+
+static void core_start(struct hsc_chip *chip)
+{
+	struct regmap *r = chip->regmap;
+
+	regmap_write(r, IOB_RESET0, ~0);
+	regmap_write(r, IOB_RESET1, ~0);
+
+	regmap_write(r, IOB_CLKSTOP, 0);
+	/* Deassert all internal resets, but AP core is later for uCode */
+	regmap_write(r, IOB_RESET0, IOB_RESET0_APCORE);
+	regmap_write(r, IOB_RESET1, 0);
+
+	/* Halt SPU for uCode */
+	regmap_write(r, IOB_DEBUG, IOB_DEBUG_SPUHALT);
+}
+
+static void core_stop(struct hsc_chip *chip)
+{
+	struct regmap *r = chip->regmap;
+
+	regmap_write(r, IOB_RESET0, 0);
+	regmap_write(r, IOB_RESET1, 0);
+
+	regmap_write(r, IOB_CLKSTOP, ~0);
+}
+
+static void core_clear_ram(struct hsc_chip *chip)
+{
+	struct regmap *r = chip->regmap;
+	const struct hsc_spec_init_ram *rams = chip->spec->init_rams;
+	size_t i, s;
+
+	for (i = 0; i < chip->spec->num_init_rams; i++)
+		for (s = 0; s < rams[i].size; s += 4)
+			regmap_write(r, rams[i].addr + s, rams[i].pattern);
+}
+
+static void core_start_spu(struct hsc_chip *chip)
+{
+	struct regmap *r = chip->regmap;
+
+	regmap_write(r, IOB_DEBUG, 0);
+}
+
+static void core_start_ap(struct hsc_chip *chip)
+{
+	struct regmap *r = chip->regmap;
+
+	regmap_write(r, IOB_RESET0, 0);
+}
+
+static int ucode_set_data_addr(struct hsc_chip *chip, int mode)
+{
+	struct regmap *r = chip->regmap;
+	dma_addr_t addr;
+
+	switch (mode) {
+	case HSC_UCODE_SPU_0:
+	case HSC_UCODE_SPU_1:
+		addr = chip->ucode_spu.phys_data;
+		regmap_write(r, UCODE_DLADDR0, addr);
+		regmap_write(r, UCODE_DLADDR1, addr >> 32);
+		break;
+	case HSC_UCODE_ACE:
+		addr = chip->ucode_am.phys_data;
+		regmap_write(r, CIP_UCODEADDR_AM0, addr);
+		regmap_write(r, CIP_UCODEADDR_AM1, addr >> 32);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void file_channel_dma_set(struct hsc_chip *chip,
+				 struct hsc_cip_file_dma_param *p)
+{
+	struct regmap *r = chip->regmap;
+	u32 cipr_rsc_no;
+	u32 cipw_rsc_no;
+	dma_addr_t cipr_sdram_start;
+	dma_addr_t cipw_sdram_start;
+	dma_addr_t cipr_sdram_end;
+	dma_addr_t cipw_sdram_end;
+	u32 v;
+
+	cipr_rsc_no = HSC_CIP_FILE_TO_CIPR_DMCH(p->cip_file_ch);
+	cipw_rsc_no = HSC_CIP_FILE_TO_CIPW_DMCH(p->cip_file_ch);
+	cipr_sdram_start = p->cip_r_sdram;
+	cipw_sdram_start = p->cip_w_sdram;
+	cipr_sdram_end = p->cip_r_sdram + p->total_size;
+	cipw_sdram_end = p->cip_w_sdram + p->total_size;
+
+	/* For CIP Read */
+	v = FIELD_PREP(CDMBC_CHCTRL1_LINKCH1_MASK, 1) |
+		FIELD_PREP(CDMBC_CHCTRL1_STATSEL_MASK, 4) |
+		CDMBC_CHCTRL1_TYPE_INTERMIT;
+	regmap_write(r, CDMBC_CHCTRL1(cipr_rsc_no), v);
+
+	regmap_write(r, CDMBC_CHCAUSECTRL(cipr_rsc_no), 0);
+
+	v = FIELD_PREP(CDMBC_CHAMODE_ENDIAN_MASK, p->endian) |
+		FIELD_PREP(CDMBC_CHAMODE_AUPDT_MASK, 0) |
+		CDMBC_CHAMODE_TYPE_RB;
+	regmap_write(r, CDMBC_CHSRCAMODE(cipr_rsc_no), v);
+
+	v = FIELD_PREP(CDMBC_CHAMODE_ENDIAN_MASK, 1) |
+		FIELD_PREP(CDMBC_CHAMODE_AUPDT_MASK, 2);
+	regmap_write(r, CDMBC_CHDSTAMODE(cipr_rsc_no), v);
+
+	v = FIELD_PREP(CDMBC_CHDSTSTRTADRS_TID_MASK, 0xc) |
+		FIELD_PREP(CDMBC_CHDSTSTRTADRS_ID1_EN_MASK, p->id1_en) |
+		FIELD_PREP(CDMBC_CHDSTSTRTADRS_KEY_ID1_MASK, p->key_id1) |
+		FIELD_PREP(CDMBC_CHDSTSTRTADRS_KEY_ID0_MASK, p->key_id0);
+	regmap_write(r, CDMBC_CHDSTSTRTADRSD(cipr_rsc_no), v);
+
+	regmap_write(r, CDMBC_CHSIZE(cipr_rsc_no), p->inter_size);
+
+	/* For CIP Write */
+	v = FIELD_PREP(CDMBC_CHCTRL1_LINKCH1_MASK, 5) |
+		FIELD_PREP(CDMBC_CHCTRL1_STATSEL_MASK, 4) |
+		CDMBC_CHCTRL1_TYPE_INTERMIT |
+		CDMBC_CHCTRL1_IND_SIZE_UND;
+	regmap_write(r, CDMBC_CHCTRL1(cipw_rsc_no), v);
+
+	v = FIELD_PREP(CDMBC_CHAMODE_ENDIAN_MASK, 1) |
+		FIELD_PREP(CDMBC_CHAMODE_AUPDT_MASK, 2);
+	regmap_write(r, CDMBC_CHSRCAMODE(cipw_rsc_no), v);
+
+	v = FIELD_PREP(CDMBC_CHAMODE_ENDIAN_MASK, p->endian) |
+		FIELD_PREP(CDMBC_CHAMODE_AUPDT_MASK, 0) |
+		CDMBC_CHAMODE_TYPE_RB;
+	regmap_write(r, CDMBC_CHDSTAMODE(cipw_rsc_no), v);
+
+	/* Transferring size */
+	regmap_write(r, CDMBC_ITSTEPS(cipr_rsc_no), p->total_size);
+
+	/* For ring buffer */
+	regmap_write(r, CDMBC_RBBGNADRSD(cipr_rsc_no), cipr_sdram_start);
+	regmap_write(r, CDMBC_RBENDADRSD(cipr_rsc_no), cipr_sdram_end);
+	regmap_write(r, CDMBC_RBRDPTRD(cipr_rsc_no), cipr_sdram_start);
+	regmap_write(r, CDMBC_RBWRPTRD(cipr_rsc_no), cipr_sdram_end);
+
+	regmap_write(r, CDMBC_RBBGNADRSU(cipr_rsc_no), cipr_sdram_start >> 32);
+	regmap_write(r, CDMBC_RBENDADRSU(cipr_rsc_no), cipr_sdram_end >> 32);
+	regmap_write(r, CDMBC_RBRDPTRU(cipr_rsc_no), cipr_sdram_start >> 32);
+	regmap_write(r, CDMBC_RBWRPTRU(cipr_rsc_no), cipr_sdram_end >> 32);
+
+	regmap_write(r, CDMBC_RBBGNADRSD(cipw_rsc_no), cipw_sdram_start);
+	regmap_write(r, CDMBC_RBENDADRSD(cipw_rsc_no), cipw_sdram_end);
+	regmap_write(r, CDMBC_RBRDPTRD(cipw_rsc_no), cipw_sdram_end);
+	regmap_write(r, CDMBC_RBWRPTRD(cipw_rsc_no), cipw_sdram_start);
+
+	regmap_write(r, CDMBC_RBBGNADRSU(cipw_rsc_no), cipw_sdram_start >> 32);
+	regmap_write(r, CDMBC_RBENDADRSU(cipw_rsc_no), cipw_sdram_end >> 32);
+	regmap_write(r, CDMBC_RBRDPTRU(cipw_rsc_no), cipw_sdram_end >> 32);
+	regmap_write(r, CDMBC_RBWRPTRU(cipw_rsc_no), cipw_sdram_start >> 32);
+
+	/* Transfer settings */
+	regmap_write(r, CDMBC_CIPMODE(p->cip_file_ch),
+		     (p->push) ? CDMBC_CIPMODE_PUSH : 0);
+
+	regmap_write(r, CDMBC_CIPPRIORITY(p->cip_file_ch),
+		     FIELD_PREP(CDMBC_CIPPRIORITY_PRIOR_MASK, 3));
+}
+
+static void file_channel_start(struct hsc_chip *chip, int cip_file_ch,
+			       bool push, bool mmu_en)
+{
+	struct regmap *r = chip->regmap;
+	int cipr_rsc_no, cipw_rsc_no;
+	int cipr_tdbp_no, cipw_tdbp_no;
+	u32 v = 0;
+
+	cipr_rsc_no = HSC_CIP_FILE_TO_CIPR_DMCH(cip_file_ch);
+	cipw_rsc_no = HSC_CIP_FILE_TO_CIPW_DMCH(cip_file_ch);
+	cipr_tdbp_no = HSC_CIP_FILE_TO_CIPR(cip_file_ch);
+	cipw_tdbp_no = HSC_CIP_FILE_TO_CIPW(cip_file_ch);
+
+	regmap_write(r, CDMBC_CIPMODE(cip_file_ch),
+		     (push) ? CDMBC_CIPMODE_PUSH : 0);
+
+	if (mmu_en) {
+		v = CDMBC_CHDDR_REG_LOAD_ON | CDMBC_CHDDR_AT_CHEN_ON;
+
+		/* Enable IOMMU for CIP-R and CIP-W */
+		regmap_write(r, CDMBC_CHDDR(cipr_rsc_no),
+			     v | CDMBC_CHDDR_SET_MCB_RD);
+		regmap_write(r, CDMBC_CHDDR(cipw_rsc_no),
+			     v | CDMBC_CHDDR_SET_MCB_WR);
+	}
+
+	v = 0x01000000 | (1 << cipr_tdbp_no) | (1 << cipw_tdbp_no);
+	regmap_write(r, CDMBC_STRT(1), v);
+}
+
+static int ucode_load_dma(struct hsc_chip *chip, int mode)
+{
+	struct regmap *r = chip->regmap;
+	struct hsc_ucode_buf *ucode;
+	struct hsc_cip_file_dma_param dma_p = {0};
+	u32 cip_f_ctrl, v;
+
+	switch (mode) {
+	case HSC_UCODE_SPU_0:
+	case HSC_UCODE_SPU_1:
+		ucode = &chip->ucode_spu;
+		cip_f_ctrl = 0x2f090001;
+		break;
+	case HSC_UCODE_ACE:
+		ucode = &chip->ucode_am;
+		cip_f_ctrl = 0x3f090001;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_write(r, CIP_F_CTRL, cip_f_ctrl);
+
+	regmap_write(r, IOB_INTREN(HSC_INTR_IOB_2),
+		     INTR2_CIP_AUTH_S |
+		     INTR2_MBC_CIP_R(0) | INTR2_MBC_CIP_W(0));
+
+	dma_p.cip_file_ch = HSC_CIP_FILE_NO_0;
+	dma_p.cip_r_sdram = ucode->phys_code;
+	dma_p.cip_w_sdram = 0;
+	dma_p.inter_size = ucode->size_code;
+	dma_p.total_size = ucode->size_code;
+	dma_p.key_id1 = 0;
+	dma_p.key_id0 = 0;
+	dma_p.endian = 1;
+	dma_p.id1_en = 0;
+	file_channel_dma_set(chip, &dma_p);
+	file_channel_start(chip, HSC_CIP_FILE_NO_0, true, false);
+
+	do {
+		regmap_read(r, CDMBC_CHIR(HSC_MBC_DMCH_CIP0_R), &v);
+		msleep(20);
+	} while (!(v & INTR_MBC_CH_WDONE));
+	regmap_write(r, CDMBC_CHIR(HSC_MBC_DMCH_CIP0_R), v);
+
+	do {
+		regmap_read(r, CDMBC_CHIR(HSC_MBC_DMCH_CIP0_W), &v);
+		msleep(20);
+	} while (!(v & INTR_MBC_CH_WDONE));
+	regmap_write(r, CDMBC_CHIR(HSC_MBC_DMCH_CIP0_W), v);
+
+	regmap_read(r, CDMBC_RBIR(HSC_MBC_DMCH_CIP0_R), &v);
+	regmap_write(r, CDMBC_RBIR(HSC_MBC_DMCH_CIP0_R), v);
+
+	regmap_read(r, CDMBC_RBIR(HSC_MBC_DMCH_CIP0_W), &v);
+	regmap_write(r, CDMBC_RBIR(HSC_MBC_DMCH_CIP0_W), v);
+
+	/* Clear & disable interrupt */
+	regmap_read(r, IOB_INTRST(HSC_INTR_IOB_2), &v);
+	regmap_write(r, IOB_INTRST(HSC_INTR_IOB_2), v);
+
+	regmap_write(r, IOB_INTREN(HSC_INTR_IOB_2), 0);
+
+	return 0;
+}
+
+static int ucode_load(struct hsc_chip *chip, int mode)
+{
+	struct device *dev = &chip->pdev->dev;
+	const struct hsc_spec_ucode *spec;
+	struct hsc_ucode_buf *ucode;
+	const struct firmware *firm_code, *firm_data;
+	int ret;
+
+	switch (mode) {
+	case HSC_UCODE_SPU_0:
+	case HSC_UCODE_SPU_1:
+		spec = &chip->spec->ucode_spu;
+		ucode = &chip->ucode_spu;
+		break;
+	case HSC_UCODE_ACE:
+		spec = &chip->spec->ucode_ace;
+		ucode = &chip->ucode_am;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = request_firmware(&firm_code, spec->name_code, dev);
+	if (ret) {
+		dev_err(dev, "Failed to load firmware '%s'.\n",
+			spec->name_code);
+		return ret;
+	}
+
+	ret = request_firmware(&firm_data, spec->name_data, dev);
+	if (ret) {
+		dev_err(dev, "Failed to load firmware '%s'.\n",
+			spec->name_data);
+		goto err_firm_code;
+	}
+
+	ucode->buf_code = dma_alloc_coherent(dev, firm_code->size,
+					     &ucode->phys_code, GFP_KERNEL);
+	if (!ucode->buf_code) {
+		ret = -ENOMEM;
+		goto err_firm_data;
+	}
+	ucode->size_code = firm_code->size;
+
+	ucode->buf_data = dma_alloc_coherent(dev, firm_data->size,
+					     &ucode->phys_data, GFP_KERNEL);
+	if (!ucode->buf_data) {
+		ret = -ENOMEM;
+		goto err_buf_code;
+	}
+	ucode->size_data = firm_data->size;
+
+	memcpy(ucode->buf_code, firm_code->data, firm_code->size);
+	memcpy(ucode->buf_data, firm_data->data, firm_data->size);
+
+	ret = ucode_set_data_addr(chip, mode);
+	if (ret)
+		goto err_buf_data;
+
+	ret = ucode_load_dma(chip, mode);
+	if (ret)
+		goto err_buf_data;
+
+	release_firmware(firm_data);
+	release_firmware(firm_code);
+
+	return 0;
+
+err_buf_data:
+	dma_free_coherent(dev, ucode->size_data, ucode->buf_data,
+			  ucode->phys_data);
+
+err_buf_code:
+	dma_free_coherent(dev, ucode->size_code, ucode->buf_code,
+			  ucode->phys_code);
+
+err_firm_data:
+	release_firmware(firm_data);
+
+err_firm_code:
+	release_firmware(firm_code);
+
+	return ret;
+}
+
+static int ucode_unload(struct hsc_chip *chip, int mode)
+{
+	struct device *dev = &chip->pdev->dev;
+	struct hsc_ucode_buf *ucode;
+
+	switch (mode) {
+	case HSC_UCODE_SPU_0:
+	case HSC_UCODE_SPU_1:
+		ucode = &chip->ucode_spu;
+		break;
+	case HSC_UCODE_ACE:
+		ucode = &chip->ucode_am;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	dma_free_coherent(dev, ucode->size_data, ucode->buf_data,
+			  ucode->phys_data);
+	dma_free_coherent(dev, ucode->size_code, ucode->buf_code,
+			  ucode->phys_code);
+
+	return 0;
+}
+
+int hsc_ucode_load_all(struct hsc_chip *chip)
+{
+	int ret;
+
+	core_start(chip);
+	core_clear_ram(chip);
+
+	ret = ucode_load(chip, HSC_UCODE_SPU_0);
+	if (ret)
+		return ret;
+	core_start_spu(chip);
+
+	ret = ucode_load(chip, HSC_UCODE_ACE);
+	if (ret)
+		return ret;
+	core_start_ap(chip);
+
+	return 0;
+}
+
+int hsc_ucode_unload_all(struct hsc_chip *chip)
+{
+	int ret;
+
+	core_stop(chip);
+
+	ret = ucode_unload(chip, HSC_UCODE_SPU_0);
+	if (ret)
+		return ret;
+
+	ret = ucode_unload(chip, HSC_UCODE_ACE);
+	if (ret)
+		return ret;
+
+	return 0;
+}
-- 
2.17.0

^ permalink raw reply related

* [PATCH 2/8] media: uniphier: add headers of HSC MPEG2-TS I/O driver
From: Katsuhiro Suzuki @ 2018-05-30  9:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180530090946.1635-1-suzuki.katsuhiro@socionext.com>

This patch adds register definitions of  HSC (High speed Stream
Controller) driver for Socionext UniPhier SoCs. The HSC enables to
input and output MPEG2-TS stream from/to outer world of SoC.

Signed-off-by: Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>
---
 drivers/media/platform/Kconfig            |   1 +
 drivers/media/platform/Makefile           |   2 +
 drivers/media/platform/uniphier/Kconfig   |   9 +
 drivers/media/platform/uniphier/Makefile  |   1 +
 drivers/media/platform/uniphier/hsc-reg.h | 491 ++++++++++++++++++++++
 drivers/media/platform/uniphier/hsc.h     | 480 +++++++++++++++++++++
 6 files changed, 984 insertions(+)
 create mode 100644 drivers/media/platform/uniphier/Kconfig
 create mode 100644 drivers/media/platform/uniphier/Makefile
 create mode 100644 drivers/media/platform/uniphier/hsc-reg.h
 create mode 100644 drivers/media/platform/uniphier/hsc.h

diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 2728376b04b5..289ab4dfd30e 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -525,6 +525,7 @@ menuconfig DVB_PLATFORM_DRIVERS
 
 if DVB_PLATFORM_DRIVERS
 source "drivers/media/platform/sti/c8sectpfe/Kconfig"
+source "drivers/media/platform/uniphier/Kconfig"
 endif #DVB_PLATFORM_DRIVERS
 
 menuconfig CEC_PLATFORM_DRIVERS
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index 04bc1502a30e..08d5052119ef 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -93,3 +93,5 @@ obj-$(CONFIG_VIDEO_QCOM_CAMSS)		+= qcom/camss-8x16/
 obj-$(CONFIG_VIDEO_QCOM_VENUS)		+= qcom/venus/
 
 obj-y					+= meson/
+
+obj-$(CONFIG_DVB_UNIPHIER)		+= uniphier/
diff --git a/drivers/media/platform/uniphier/Kconfig b/drivers/media/platform/uniphier/Kconfig
new file mode 100644
index 000000000000..1b4543ec1e3c
--- /dev/null
+++ b/drivers/media/platform/uniphier/Kconfig
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+config DVB_UNIPHIER
+	tristate "Socionext UniPhier Frontend"
+	depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF
+	depends on ARCH_UNIPHIER
+	help
+	  Driver for UniPhier frontend for MPEG2-TS input/output,
+	  demux and descramble.
+	  Say Y when you want to support this frontend.
diff --git a/drivers/media/platform/uniphier/Makefile b/drivers/media/platform/uniphier/Makefile
new file mode 100644
index 000000000000..f66554cd5c45
--- /dev/null
+++ b/drivers/media/platform/uniphier/Makefile
@@ -0,0 +1 @@
+# SPDX-License-Identifier: GPL-2.0
diff --git a/drivers/media/platform/uniphier/hsc-reg.h b/drivers/media/platform/uniphier/hsc-reg.h
new file mode 100644
index 000000000000..5f0a9b86cf49
--- /dev/null
+++ b/drivers/media/platform/uniphier/hsc-reg.h
@@ -0,0 +1,491 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Socionext UniPhier DVB driver for High-speed Stream Controller (HSC).
+ *
+ * Copyright (c) 2018 Socionext Inc.
+ */
+
+#ifndef DVB_UNIPHIER_HSC_REG_H__
+#define DVB_UNIPHIER_HSC_REG_H__
+
+/*
+ * CH_0 : CIP-R8, W9
+ * CH_1 : CIP-R10,W11
+ * CH_2 : CIP-R12,W13
+ * CH_3 : CIP-R14,W15
+ * CH_4 : CIP-R16,W17
+ */
+enum HSC_CIP_FILE_NO {
+	HSC_CIP_FILE_NO_0 = 0x0,
+	HSC_CIP_FILE_NO_1,
+	HSC_CIP_FILE_NO_2,
+	HSC_CIP_FILE_NO_3,
+	HSC_CIP_FILE_NO_4,
+	HSC_CIP_FILE_NO_END,
+	HSC_CIP_FILE_NO_DISABLE,
+};
+
+#define HSC_CIP_FILE_TO_CIPR(i)       ((i) * 2 + 0)
+#define HSC_CIP_FILE_TO_CIPW(i)       ((i) * 2 + 1)
+#define HSC_CIP_FILE_TO_CIPR_DMCH(i)  (HSC_CIP_FILE_TO_CIPR(i) + 8)
+#define HSC_CIP_FILE_TO_CIPW_DMCH(i)  (HSC_CIP_FILE_TO_CIPW(i) + 8)
+
+/* RAM Address */
+#define FLT_PATN_RAM_TOP_ADDR           0x0a000
+#define FLT_MASK_RAM_TOP_ADDR           0x0b000
+#define SHARE_MEMORY_0_NORMAL           0x10000
+#define SHARE_MEMORY_1_NORMAL           0x11000
+#define SHARE_MEMORY_2_NORMAL           0x12000
+#define SHARE_MEMORY_3_NORMAL           0x13000
+#define SHARE_MEMORY_4_NORMAL           0x14000
+#define SHARE_MEMORY_5_NORMAL           0x15000
+#define SHARE_MEMORY_6_NORMAL           0x16000
+#define SHARE_MEMORY_7_NORMAL           0x17000
+
+/* RAM size */
+#define FLT_PATN_RAM_SIZE               0x0800
+#define FLT_MASK_RAM_SIZE               0x0800
+#define FLT_PIDPATTERN_SIZE             0x0160
+#define SHARE_MEMORY_0_SIZE             0x1000
+#define SHARE_MEMORY_1_SIZE             0x1000
+#define SHARE_MEMORY_2_SIZE             0x1000
+#define SHARE_MEMORY_3_SIZE             0x1000
+#define SHARE_MEMORY_4_SIZE             0x1000
+#define SHARE_MEMORY_5_SIZE             0x1000
+#define SHARE_MEMORY_6_SIZE             0x1000
+#define SHARE_MEMORY_7_SIZE             0x1000
+
+/* CIP SPU Stream */
+#define CIP_S_ID             0x14c0
+#define CIP_S_MODE           0x14c4
+#define CIP_S_CTRL           0x14c8
+#define CIP_S_SIZE           0x14cc
+#define CIP_S_BASE           0x14f8
+#define CIP_DEBUG            0x14fc
+
+/* CIP SPU HDC */
+#define HDC_CTRL             0x1520
+#define HDC_PTS              0x1524
+#define HDC_STAT             0x1528
+#define HDC_SPN_STAT         0x152c
+#define HDC_SPN              0x1530
+#define HDC_PATTERN          0x1534
+#define HDC_RESULT           0x1538
+#define HDC_RESULT_POS       0x153c
+
+/* CIP SPU File */
+#define CIP_F_ID             0x1540
+#define CIP_F_MODE           0x1544
+#define CIP_F_CTRL           0x1548
+#define CIP_F_SKIP           0x154c
+#define CIP_F_PAYLOAD        0x1560
+#define CIP_F_AUX0           0x156c
+#define CIP_F_AUX1           0x1570
+#define CIP_F_AUX2           0x1574
+#define CIP_F_REMAIN         0x1578
+#define CIP_F_EPNVERIFY1     0x157c
+#define CIP_F_EPNVERIFY2     0x1580
+#define CIP_F_EPNCNT         0x1584
+#define CIP_F_PKTCNT         0x1588
+#define CIP_F_STAT           0x1590
+#define CIP_F_SIZE           0x1594
+#define CIP_F_IBUF           0x1598
+#define CIP_F_OBUF           0x159c
+#define CIP_F_BASE           0x15b8
+#define CIP_F_BASEDIVX       0x15bc
+
+/* FLT1 SPU, FLT2 HOST */
+#define FLT_CTRL1            0x15c0
+#define FLT_CTRL2            0x15c4
+#define FLT_CTRL3            0x15c8
+#define FLT_CTRL4            0x15cc
+#define FLT_STATUS           0x15d0
+#define FLT_INTENABLE        0x15d4
+#define FLT_INTSTATUS        0x15d8
+#define FLT_LINE(i)          (0x15e0 + (i) * 0x04)
+#define FLT_LENMODE          0x15f8
+#define FLT_LEN              0x15fc
+#define FLT_TRNUM            0x1600
+#define FLT_COUNT1           0x1604
+#define FLT_COUNT2           0x1608
+#define FLT_BUFCOUNT         0x160c
+#define FLT_INBUF(i)         (0x1610 + (i) * 0x04)
+#define FLT_CRC              0x1624
+#define FLT_CRCCALC          0x1628
+#define FLT_SECNUM           0x1630
+#define FLT_COMP             0x1634
+#define FLT_SWACE            0x163c
+
+#define FLT_ATR(i)           (0x1d00 + (i) * 0x04)
+#define FLT_PIDNUM           0x1d24
+
+/* SBC1, 2 */
+#define SBC_ACE_DMA_EN                0x6000
+#define SBC_DMAPARAM21                0x6004
+#define SBC_ACE_INTREN                0x6008
+#define SBC_ACE_INTRST                0x600c
+#define SBC_DMA_STATUS0               0x6010
+#define SBC_DMA_STATUS1               0x6014
+#define SBC_DMAPARAMA(i)              (0x6018 + (i) * 0x04)
+#define   SBC_DMAPARAMA_OFFSET_MASK     GENMASK(31, 29)
+#define   SBC_DMAPARAMA_LOOPADDR_MASK   GENMASK(28, 23)
+#define   SBC_DMAPARAMA_COUNT_MASK      GENMASK(7, 0)
+#define SBC_DMAPARAMB(i)              (0x6038 + (i) * 0x04)
+
+#define SBC_INTRENABLE0               0x60a0
+#define SBC_INTRSTATUS0               0x60a4
+#define SBC_INTRENABLE1               0x60a8
+#define SBC_INTRSTATUS1               0x60ac
+
+#define SBC_CONFIG0                   0x60c0
+#define SBC_PARREGION0                0x60c4
+#define SBC_PARREGION1                0x60c8
+
+/* IOB1, 2, 3 */
+#define IOB_PKTCNT                    0x1740
+#define IOB_PKTCNTRST                 0x1744
+#define IOB_PKTCNTST                  0x1744
+#define IOB_DUMMY_ENABLE              0x1748
+#define IOB_FORMATCHANGE_EN           0x174c
+#define IOB_UASSIST0                  0x1750
+#define IOB_UASSIST1                  0x1754
+#define IOB_URESERVE(i)               (0x1758 + (i) * 0x4)
+#define IOB_PCRRECEN                  IOB_URESERVE(2)
+#define IOB_UPARTIAL(i)               (0x1768 + (i) * 0x4)
+#define IOB_SPUINTREN                 0x1778
+
+#define IOB_HSCREV                    0x1a00
+#define IOB_SECCLK(i)                 (0x1a08 + (i) * 0x6c)
+#define IOB_SECTIMEH(i)               (0x1a0c + (i) * 0x6c)
+#define IOB_SECTIMEL(i)               (0x1a10 + (i) * 0x6c)
+#define IOB_RESET0                    0x1a14
+#define   IOB_RESET0_APCORE             BIT(20)
+#define IOB_RESET1                    0x1a18
+#define IOB_CLKSTOP                   0x1a1c
+#define IOB_DEBUG                     0x1a20
+#define   IOB_DEBUG_SPUHALT             BIT(0)
+#define IOB_INTREN(i)                 (0x1a24 + (i) * 0x8)
+#define IOB_INTRST(i)                 (0x1a28 + (i) * 0x8)
+#define IOB_INTREN0                   0x1a24
+#define IOB_INTRST0                   0x1a28
+#define IOB_INTREN0_1                 0x1a2c
+#define IOB_INTRST0_1                 0x1a30
+#define IOB_INTREN0_2                 0x1a34
+#define IOB_INTRST0_2                 0x1a38
+#define IOB_INTREN1                   0x1a3c
+#define IOB_INTRST1                   0x1a40
+#define IOB_INTREN1_1                 0x1a44
+#define IOB_INTRST1_1                 0x1a48
+#define IOB_INTREN2                   0x1a4c
+#define IOB_INTRST2                   0x1a50
+#define   INTR2_DRV                     BIT(31)
+#define   INTR2_CIP_FRMT(i)             BIT((i) + 16)
+#define   INTR2_CIP_NORMAL              BIT(16)
+#define   INTR2_SEC_CLK_A               BIT(15)
+#define   INTR2_SEC_CLK_S               BIT(14)
+#define   INTR2_MBC_CIP_W(i)            BIT((i) + 9)
+#define   INTR2_MBC_CIP_R(i)            BIT((i) + 4)
+#define   INTR2_CIP_AUTH_A              BIT(1)
+#define   INTR2_CIP_AUTH_S              BIT(0)
+#define IOB_INTREN3                   0x1a54
+#define IOB_INTRST3                   0x1a58
+#define   INTR3_DRV                     BIT(31)
+#define   INTR3_CIP_FRMT(i)             BIT((i) + 16)
+#define   INTR3_SEC_CLK_A               BIT(15)
+#define   INTR3_SEC_CLK_S               BIT(14)
+#define   INTR3_MBC_CIP_W(i)            BIT((i) + 9)
+#define   INTR3_MBC_CIP_R(i)            BIT((i) + 4)
+#define   INTR3_CIP_AUTH_A              BIT(1)
+#define   INTR3_CIP_AUTH_S              BIT(0)
+#define IOB_INTREN4                   0x1a5c
+#define IOB_INTRST4                   0x1a60
+#define IOB_CGCTRL                    0x1a64
+#define IOB_VCXOCTL                   0x1a68
+#define IOB_IO_ATTRIBUTE              0x1a6c
+
+#define IOB_MONDAT                    0x5000
+#define IOB_MONDAT2                   0x5004
+#define IOB_TESTMODE                  0x5008
+#define IOB_TESTMODE2                 0x500c
+#define IOB_DEBUGTCERT                0x5010
+
+/* MBC1-7 Common */
+#define CDMBC_STRT(i)                (0x2300 + ((i) - 1) * 0x4)
+#define CDMBC_PERFCNFG               0x230c
+#define CDMBC_STAT(i)                (0x2320 + (i) * 0x4)
+#define CDMBC_PARTRESET(i)           (0x234c + (i) * 0x4)
+#define CDMBC_MONNUM                 0x2358
+#define CDMBC_MONDAT                 0x235c
+#define CDMBC_PRC0CHIE0              0x2380
+#define CDMBC_PRC0RBIE0              0x2384
+#define CDMBC_PRC1CHIE0              0x2388
+#define CDMBC_PRC2CHIE0              0x2390
+#define CDMBC_PRC2RBIE0              0x2394
+#define CDMBC_SOFTFLRQ               0x239c
+#define CDMBC_TDSTRT                 0x23a0
+
+#define INTR_MBC_CH_END              BIT(15)
+#define INTR_MBC_CH_STOP             BIT(13)
+#define INTR_MBC_CH_ADDR             BIT(6)
+#define INTR_MBC_CH_IWDONE           BIT(3)
+#define INTR_MBC_CH_WDONE            BIT(1)
+
+/* MBC
+ * i: channel number
+ *    1- 3: Record0,1,2
+ *   19-21: Record3,4,5
+ */
+#define CDMBC_CHTDCTRLH(i)            (((i) < 19) ? \
+					(0x23a4 + ((i) - 1) * 0x20) : \
+					(0x23b4 + ((i) - 19) * 0x20))
+#define   CDMBC_CHTDCTRLH_STREM_MASK    GENMASK(20, 16)
+#define   CDMBC_CHTDCTRLH_NOT_FLT       BIT(7)
+#define   CDMBC_CHTDCTRLH_ALL_EN        BIT(6)
+#define CDMBC_CHTDCTRLU(i)            (((i) < 19) ? \
+					(0x23a8 + ((i) - 1) * 0x20) : \
+					(0x23b8 + ((i) - 19) * 0x20))
+
+#define CDMBC_TDSTAT                  0x23f8
+#define CDMBC_TDIR                    0x23fc
+#define CDMBC_REPRATECTRL             0x2400
+#define CDMBC_ATRIBUTE0               0x24e8
+#define CDMBC_ATRIBUTE1               0x24ec
+#define CDMBC_ATRIBUTE2               0x24f0
+#define CDMBC_ATRIBUTE3               0x24f4
+#define CDMBC_ATRIBUTE4               0x24f8
+#define CDMBC_CIPMODE(i)              (0x24fc + (i) * 0x4)
+#define   CDMBC_CIPMODE_PUSH            BIT(0)
+#define CDMBC_CIPPRIORITY(i)          (0x2510 + (i) * 0x4)
+#define   CDMBC_CIPPRIORITY_PRIOR_MASK  GENMASK(1, 0)
+#define CDMBC_CH18ATTRIBUTE           (0x2524)
+
+/* MBC Channel
+ * i: channel number
+ *    0   : Section
+ *    1- 3: Record0,1,2
+ *    4   : Partial
+ *    5- 7: Replay0,1,2
+ *    8-17: Even: CIP-Read
+ *          Odd : CIP-Write
+ *   18   : AM32
+ *   19-21: Record3,4,5
+ *   22-24: Replay3,4,5
+ */
+#define CDMBC_CHCTRL1(i)                  (0x2540 + (i) * 0x50)
+#define   CDMBC_CHCTRL1_LINKCH1_MASK        GENMASK(12, 10)
+#define   CDMBC_CHCTRL1_STATSEL_MASK        GENMASK(9, 7)
+#define   CDMBC_CHCTRL1_TYPE_INTERMIT       BIT(1)
+#define   CDMBC_CHCTRL1_IND_SIZE_UND        BIT(0)
+#define CDMBC_CHCTRL2(i)                  (0x2544 + (i) * 0x50)
+#define CDMBC_CHDDR(i)                    (0x2548 + (i) * 0x50)
+#define   CDMBC_CHDDR_REG_LOAD_ON           BIT(4)
+#define   CDMBC_CHDDR_AT_CHEN_ON            BIT(3)
+#define   CDMBC_CHDDR_SET_MCB_MASK          GENMASK(2, 1)
+#define   CDMBC_CHDDR_SET_MCB_WR            (0x0 << 1)
+#define   CDMBC_CHDDR_SET_MCB_RD            (0x3 << 1)
+#define   CDMBC_CHDDR_SET_DDR_1             BIT(0)
+#define CDMBC_CHCAUSECTRL(i)              (0x254c + (i) * 0x50)
+#define   CDMBC_CHCAUSECTRL_MODE_MASK       BIT(31)
+#define   CDMBC_CHCAUSECTRL_CSEL2_MASK      GENMASK(20, 12)
+#define   CDMBC_CHCAUSECTRL_CSEL1_MASK      GENMASK(8, 0)
+#define CDMBC_CHSTAT(i)                   (0x2550 + (i) * 0x50)
+#define CDMBC_CHIR(i)                     (0x2554 + (i) * 0x50)
+#define CDMBC_CHIE(i)                     (0x2558 + (i) * 0x50)
+#define CDMBC_CHID(i)                     (0x255c + (i) * 0x50)
+#define   CDMBC_CHI_STOPPED                 BIT(13)
+#define   CDMBC_CHI_TRANSIT                 BIT(6)
+#define   CDMBC_CHI_STARTING                BIT(1)
+#define CDMBC_CHSRCAMODE(i)               (0x2560 + (i) * 0x50)
+#define CDMBC_CHDSTAMODE(i)               (0x2564 + (i) * 0x50)
+#define   CDMBC_CHAMODE_TUNIT_MASK          GENMASK(29, 28)
+#define   CDMBC_CHAMODE_ENDIAN_MASK         GENMASK(17, 16)
+#define   CDMBC_CHAMODE_AUPDT_MASK          GENMASK(5, 4)
+#define   CDMBC_CHAMODE_TYPE_RB             BIT(2)
+#define CDMBC_CHSRCSTRTADRSD(i)           (0x2568 + (i) * 0x50)
+#define CDMBC_CHSRCSTRTADRSU(i)           (0x256c + (i) * 0x50)
+#define CDMBC_CHDSTSTRTADRSD(i)           (0x2570 + (i) * 0x50)
+#define CDMBC_CHDSTSTRTADRSU(i)           (0x2574 + (i) * 0x50)
+#define   CDMBC_CHDSTSTRTADRS_TID_MASK      GENMASK(31, 28)
+#define   CDMBC_CHDSTSTRTADRS_ID1_EN_MASK   BIT(15)
+#define   CDMBC_CHDSTSTRTADRS_KEY_ID1_MASK  GENMASK(12, 8)
+#define   CDMBC_CHDSTSTRTADRS_KEY_ID0_MASK  GENMASK(4, 0)
+#define CDMBC_CHSIZE(i)                   (0x2578 + (i) * 0x50)
+#define CDMBC_CHIRADRSD(i)                (0x2580 + (i) * 0x50)
+#define CDMBC_CHIRADRSU(i)                (0x2584 + (i) * 0x50)
+#define CDMBC_CHDST1STUSIZE(i)            (0x258C + (i) * 0x50)
+
+/* MBC DMA
+ * i: channel number
+ *    5- 7: Replay0,1,2
+ *    8-17: Even: CIP-Read
+ *          Odd : CIP-Write
+ *   22-24: Replay3-5
+ */
+static inline int HSC_IT_INT(int i)
+{
+	if (i > 21)
+		return i - 9;
+
+	return i - 5;
+}
+
+#define CDMBC_ITCTRL(i)              (0x3000 + HSC_IT_INT(i) * 0x20)
+#define CDMBC_ITSTEPS(i)             (0x3018 + HSC_IT_INT(i) * 0x20)
+
+/* MBC Ring buffer
+ * i: channel number
+ *    0   : Section (RB0)
+ *    1- 3: Record0,1,2 (RB1-3)
+ *    5- 7: Replay0,1,2 (RB4-6)
+ *    8-17: Even: CIP-Read
+ *          Odd : CIP-Write (RB7-16)
+ *   19-21: Record3-4 (RB17-19)
+ *   22-24: Replay3-4 (RB20-22)
+ */
+static inline int HSC_INT(int i)
+{
+	if (i > 18)
+		return i - 2;
+	if (i > 4)
+		return i - 1;
+
+	return i;
+}
+
+#define CDMBC_RBBGNADRS(i)           (0x3200 + HSC_INT(i) * 0x40)
+#define CDMBC_RBBGNADRSD(i)          (0x3200 + HSC_INT(i) * 0x40)
+#define CDMBC_RBBGNADRSU(i)          (0x3204 + HSC_INT(i) * 0x40)
+#define CDMBC_RBENDADRS(i)           (0x3208 + HSC_INT(i) * 0x40)
+#define CDMBC_RBENDADRSD(i)          (0x3208 + HSC_INT(i) * 0x40)
+#define CDMBC_RBENDADRSU(i)          (0x320C + HSC_INT(i) * 0x40)
+#define CDMBC_RBIR(i)                (0x3214 + HSC_INT(i) * 0x40)
+#define CDMBC_RBIE(i)                (0x3218 + HSC_INT(i) * 0x40)
+#define CDMBC_RBID(i)                (0x321c + HSC_INT(i) * 0x40)
+#define CDMBC_RBRDPTR(i)             (0x3220 + HSC_INT(i) * 0x40)
+#define CDMBC_RBRDPTRD(i)            (0x3220 + HSC_INT(i) * 0x40)
+#define CDMBC_RBRDPTRU(i)            (0x3224 + HSC_INT(i) * 0x40)
+#define CDMBC_RBWRPTR(i)             (0x3228 + HSC_INT(i) * 0x40)
+#define CDMBC_RBWRPTRD(i)            (0x3228 + HSC_INT(i) * 0x40)
+#define CDMBC_RBWRPTRU(i)            (0x322C + HSC_INT(i) * 0x40)
+#define CDMBC_RBERRCNFG(i)           (0x3238 + HSC_INT(i) * 0x40)
+
+/* MBC Rate */
+#define CDMBC_RCNMSKCYC(i)           (MBC6_TOP_ADDR + 0x000 + (i) * 0x04)
+
+/* MBC Address Transfer */
+#define CDMBC_CHPSIZE(i)             (0x3c00 + ((i) - 1) * 0x48)
+#define CDMBC_CHATCTRL(i)            (0x3c04 + ((i) - 1) * 0x48)
+#define CDMBC_CHBTPAGE(i, j)         (0x3c08 + ((i) - 1) * 0x48 + (j) * 0x10)
+#define CDMBC_CHBTPAGED(i, j)        (0x3c08 + ((i) - 1) * 0x48 + (j) * 0x10)
+#define CDMBC_CHBTPAGEU(i, j)        (0x3c0C + ((i) - 1) * 0x48 + (j) * 0x10)
+#define CDMBC_CHATPAGE(i, j)         (0x3c10 + ((i) - 1) * 0x48 + (j) * 0x10)
+#define CDMBC_CHATPAGED(i, j)        (0x3c10 + ((i) - 1) * 0x48 + (j) * 0x10)
+#define CDMBC_CHATPAGEU(i, j)        (0x3c14 + ((i) - 1) * 0x48 + (j) * 0x10)
+
+/* CSS */
+#define CSS_PTSOCONFIG                   0x1c00
+#define CSS_PTSISIGNALPOL                0x1c04
+#define CSS_SIGNALPOLCH(i)               (0x1c08 + (i) * 0x4)
+#define CSS_OUTPUTENABLE                 0x1c10
+#define CSS_OUTPUTCTRL(i)                (0x1c14 + (i) * 0x4)
+#define CSS_STSOCONFIG                   0x1c2c
+#define CSS_STSOSIGNALPOL                0x1c30
+#define CSS_DMDSIGNALPOL                 0x1c34
+#define CSS_PTSOSIGNALPOL                0x1c38
+#define CSS_PF0CONFIG                    0x1c3c
+#define CSS_PF1CONFIG                    0x1c40
+#define CSS_PFINTENABLE                  0x1c44
+#define CSS_PFINTSTATUS                  0x1c48
+#define CSS_AVOUTPUTCTRL(i)              (0x1c4c + (i) * 0x4)
+#define CSS_DPCTRL(i)                    (0x1c54 + (i) * 0x4)
+#define   CSS_DPCTRL_DPSEL_MASK            GENMASK(22, 0)
+#define   CSS_DPCTRL_DPSEL_PLAY5           BIT(15)
+#define   CSS_DPCTRL_DPSEL_PLAY4           BIT(14)
+#define   CSS_DPCTRL_DPSEL_PLAY3           BIT(13)
+#define   CSS_DPCTRL_DPSEL_PLAY2           BIT(12)
+#define   CSS_DPCTRL_DPSEL_PLAY1           BIT(11)
+#define   CSS_DPCTRL_DPSEL_PLAY0           BIT(10)
+#define   CSS_DPCTRL_DPSEL_TSI4            BIT(4)
+#define   CSS_DPCTRL_DPSEL_TSI3            BIT(3)
+#define   CSS_DPCTRL_DPSEL_TSI2            BIT(2)
+#define   CSS_DPCTRL_DPSEL_TSI1            BIT(1)
+#define   CSS_DPCTRL_DPSEL_TSI0            BIT(0)
+
+/* TSI */
+#define TSI_SYNCCNTROL(i)                (0x7100 + (i) * 0x70)
+#define   TSI_SYNCCNTROL_FRAME_MASK        GENMASK(18, 16)
+#define   TSI_SYNCCNTROL_FRAME_EXTSYNC1    (0x0 << 16)
+#define   TSI_SYNCCNTROL_FRAME_EXTSYNC2    (0x1 << 16)
+#define TSI_CONFIG(i)                    (0x7104 + (i) * 0x70)
+#define   TSI_CONFIG_ATSMD_MASK            GENMASK(22, 21)
+#define   TSI_CONFIG_ATSMD_PCRPLL0         (0x0 << 21)
+#define   TSI_CONFIG_ATSMD_PCRPLL1         (0x1 << 21)
+#define   TSI_CONFIG_ATSMD_DPLL            (0x3 << 21)
+#define   TSI_CONFIG_ATSADD_ON             BIT(20)
+#define   TSI_CONFIG_STCMD_MASK            GENMASK(7, 6)
+#define   TSI_CONFIG_STCMD_PCRPLL0         (0x0 << 6)
+#define   TSI_CONFIG_STCMD_PCRPLL1         (0x1 << 6)
+#define   TSI_CONFIG_STCMD_DPLL            (0x3 << 6)
+#define   TSI_CONFIG_CHEN_START            BIT(0)
+#define TSI_RATEUPLMT(i)                 (0x7108 + (i) * 0x70)
+#define TSI_RATELOWLMT(i)                (0x710c + (i) * 0x70)
+#define TSI_CNTINTR(i)                   (0x7110 + (i) * 0x70)
+#define TSI_INTREN(i)                    (0x7114 + (i) * 0x70)
+#define   TSI_INTR_NTP                     BIT(13)
+#define   TSI_INTR_NTPCNT                  BIT(12)
+#define   TSI_INTR_PKTEND                  BIT(11)
+#define   TSI_INTR_PCR                     BIT(9)
+#define   TSI_INTR_LOAD                    BIT(8)
+#define   TSI_INTR_SERR                    BIT(7)
+#define   TSI_INTR_SOF                     BIT(6)
+#define   TSI_INTR_TOF                     BIT(5)
+#define   TSI_INTR_UL                      BIT(4)
+#define   TSI_INTR_LL                      BIT(3)
+#define   TSI_INTR_CNT                     BIT(2)
+#define   TSI_INTR_LOST                    BIT(1)
+#define   TSI_INTR_LOCK                    BIT(0)
+#define TSI_SYNCSTATUS(i)                (0x7118 + (i) * 0x70)
+#define   TSI_STAT_PKTST_ERR               BIT(21)
+#define   TSI_STAT_LARGE_ERR               BIT(20)
+#define   TSI_STAT_SMALL_ERR               BIT(19)
+#define   TSI_STAT_LOCK                    BIT(18)
+#define   TSI_STAT_SYNC                    BIT(17)
+#define   TSI_STAT_SEARCH                  BIT(16)
+#define TSI_PCRPID(i)                    (0x711c + (i) * 0x70)
+#define TSI_PCRCTRL(i)                   (0x7120 + (i) * 0x70)
+#define TSI_STCBASE(i)                   (0x7124 + (i) * 0x70)
+#define TSI_STCEXT(i)                    (0x7128 + (i) * 0x70)
+#define TSI_CURSTC1(i)                   (0x712c + (i) * 0x70)
+#define TSI_CURSTCBASE(i)                (0x712c + (i) * 0x70)
+#define TSI_CURSTC2(i)                   (0x7130 + (i) * 0x70)
+#define TSI_CURSTCEXT(i)                 (0x7130 + (i) * 0x70)
+#define TSI_STC2BASE(i)                  (0x7134 + (i) * 0x70)
+#define TSI_STC2EXT(i)                   (0x7138 + (i) * 0x70)
+#define TSI_PCRBASE(i)                   (0x713c + (i) * 0x70)
+#define TSI_PCREXT(i)                    (0x7140 + (i) * 0x70)
+#define TSI_TIMESTAMP(i)                 (0x7144 + (i) * 0x70)
+#define TSI_CNTCTRL0(i)                  (0x7148 + (i) * 0x70)
+#define TSI_CNTCTRL1(i)                  (0x714c + (i) * 0x70)
+#define TSI_DEBUG(i)                     (0x7150 + (i) * 0x70)
+
+#define TSI_STCCMPCTRL                   0x7000
+#define VCXOSTCBASE(i)                   (0x7010 + (i) * 0x18)
+#define VCXOSTCEXT(i)                    (0x7014 + (i) * 0x18)
+#define VCXOCURSTC1(i)                   (0x7018 + (i) * 0x18)
+#define VCXOCURSTC2(i)                   (0x701c + (i) * 0x18)
+#define VCXOSTC2BASE(i)                  (0x7020 + (i) * 0x18)
+#define VCXOSTC2EXT(i)                   (0x7024 + (i) * 0x18)
+
+/* UCODE DL */
+#define UCODE_REVISION_AM                0x10fd0
+#define CIP_UCODEADDR_AM1                0x10fd4
+#define CIP_UCODEADDR_AM0                0x10fd8
+#define CORRECTATS_CTRL                  0x10fdc
+#define UCODE_REVISION                   0x10fe0
+#define AM_UCODE_IGPGCTRL                0x10fe4
+#define REPDPLLCTRLEN                    0x10fe8
+#define UCODE_DLADDR1                    0x10fec
+#define UCODE_DLADDR0                    0x10ff0
+#define UCODE_ERRLOGCTRL                 0x10ff4
+
+#endif /* DVB_UNIPHIER_HSC_REG_H__ */
diff --git a/drivers/media/platform/uniphier/hsc.h b/drivers/media/platform/uniphier/hsc.h
new file mode 100644
index 000000000000..ad57fea58675
--- /dev/null
+++ b/drivers/media/platform/uniphier/hsc.h
@@ -0,0 +1,480 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Socionext UniPhier DVB driver for High-speed Stream Controller (HSC).
+ *
+ * Copyright (c) 2018 Socionext Inc.
+ */
+
+#ifndef DVB_UNIPHIER_HSC_H__
+#define DVB_UNIPHIER_HSC_H__
+
+#include <linux/gpio/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#include <media/dmxdev.h>
+#include <media/dvbdev.h>
+#include <media/dvb_demux.h>
+#include <media/dvb_frontend.h>
+
+enum HSC_CORE {
+	HSC_CORE_0,
+	HSC_CORE_1,
+	HSC_CORE_2,
+};
+
+enum HSC_UCODE {
+	HSC_UCODE_SPU_0,
+	HSC_UCODE_SPU_1,
+	HSC_UCODE_ACE,
+};
+
+enum HSC_INTR_IOB {
+	HSC_INTR_IOB_0,
+	HSC_INTR_IOB_0_1,
+	HSC_INTR_IOB_0_2,
+	HSC_INTR_IOB_1,
+	HSC_INTR_IOB_1_1,
+	HSC_INTR_IOB_2,
+	HSC_INTR_IOB_3,
+	HSC_INTR_IOB_4,
+	HSC_INTR_IOB_5,
+	HSC_INTR_IOB_5_1,
+	HSC_INTR_IOB_5_2,
+	HSC_INTR_IOB_6,
+	HSC_INTR_IOB_6_1,
+	HSC_INTR_IOB_7,
+	HSC_INTR_IOB_8,
+	HSC_INTR_IOB_9,
+
+	HSC_INTR_IOB_NUM,
+};
+
+enum HSC_DPLL {
+	HSC_DPLL0,
+	HSC_DPLL1,
+	HSC_DPLL2,
+	HSC_DPLL3,
+
+	HSC_DPLL_NUM,
+};
+
+enum HSC_DPLL_SRC {
+	HSC_DPLL_SRC_NONE = -1,
+	HSC_DPLL_SRC_TSI0 = 0x00,
+	HSC_DPLL_SRC_TSI1,
+	HSC_DPLL_SRC_TSI2,
+	HSC_DPLL_SRC_TSI3,
+	HSC_DPLL_SRC_TSI4,
+	HSC_DPLL_SRC_TSI5,
+	HSC_DPLL_SRC_TSI6,
+	HSC_DPLL_SRC_TSI7,
+	HSC_DPLL_SRC_TSI8,
+	HSC_DPLL_SRC_TSI9,
+	HSC_DPLL_SRC_REP0 = 0x0a,
+	HSC_DPLL_SRC_REP1,
+	HSC_DPLL_SRC_REP2,
+	HSC_DPLL_SRC_REP3,
+	HSC_DPLL_SRC_REP4,
+	HSC_DPLL_SRC_REP5,
+
+	HSC_DPLL_SRC_NUM,
+};
+
+/* Port to send to CSS */
+enum HSC_CSS_IN {
+	HSC_CSS_IN_1394_0 = 0x00,
+	HSC_CSS_IN_1394_1,
+	HSC_CSS_IN_1394_2,
+	HSC_CSS_IN_1394_3,
+	HSC_CSS_IN_DMD0 = 0x04,
+	HSC_CSS_IN_DMD1,
+	HSC_CSS_IN_SRLTS0 = 0x06,
+	HSC_CSS_IN_SRLTS1,
+	HSC_CSS_IN_SRLTS2,
+	HSC_CSS_IN_SRLTS3,
+	HSC_CSS_IN_SRLTS4,
+	HSC_CSS_IN_SRLTS5,
+	HSC_CSS_IN_SRLTS6,
+	HSC_CSS_IN_SRLTS7,
+	HSC_CSS_IN_PARTS0 = 0x10,
+	HSC_CSS_IN_PARTS1,
+	HSC_CSS_IN_PARTS2,
+	HSC_CSS_IN_PARTS3,
+	HSC_CSS_IN_TSO0 = 0x18,
+	HSC_CSS_IN_TSO1,
+	HSC_CSS_IN_TSO2,
+	HSC_CSS_IN_TSO3,
+	HSC_CSS_IN_ENCORDER0_IN = 0x1c,
+	HSC_CSS_IN_ENCORDER1_IN,
+
+	HSC_CSS_IN_NUM,
+};
+
+/* Port to receive from CSS */
+enum HSC_CSS_OUT {
+	HSC_CSS_OUT_SRLTS0 = 0x00,
+	HSC_CSS_OUT_SRLTS1,
+	HSC_CSS_OUT_SRLTS2,
+	HSC_CSS_OUT_SRLTS3,
+	HSC_CSS_OUT_TSI0 = 0x04,
+	HSC_CSS_OUT_TSI1,
+	HSC_CSS_OUT_TSI2,
+	HSC_CSS_OUT_TSI3,
+	HSC_CSS_OUT_TSI4,
+	HSC_CSS_OUT_TSI5,
+	HSC_CSS_OUT_TSI6,
+	HSC_CSS_OUT_TSI7,
+	HSC_CSS_OUT_TSI8,
+	HSC_CSS_OUT_TSI9,
+	HSC_CSS_OUT_PARTS0 = 0x10,
+	HSC_CSS_OUT_PARTS1,
+	HSC_CSS_OUT_PKTFF0 = 0x14,
+	HSC_CSS_OUT_PKTFF1,
+};
+
+/* TS input interface */
+enum HSC_TS_IN {
+	HSC_TSI0,
+	HSC_TSI1,
+	HSC_TSI2,
+	HSC_TSI3,
+	HSC_TSI4,
+	HSC_TSI5,
+	HSC_TSI6,
+	HSC_TSI7,
+	HSC_TSI8,
+	HSC_TSI9,
+
+	HSC_TS_IN_NUM,
+};
+
+/* TS output interface */
+enum HSC_TS_OUT {
+	HSC_TS_OUT0,
+	HSC_TS_OUT1,
+	HSC_TS_OUT2,
+	HSC_TS_OUT3,
+	HSC_TS_OUT4,
+	HSC_TS_OUT5,
+	HSC_TS_OUT6,
+	HSC_TS_OUT7,
+	HSC_TS_OUT8,
+	HSC_TS_OUT9,
+
+	HSC_TS_OUT_NUM,
+};
+
+/* DMA to read from memory (Replay DMA) */
+enum HSC_DMA_IN {
+	HSC_DMA_IN0,
+	HSC_DMA_IN1,
+	HSC_DMA_IN2,
+	HSC_DMA_IN3,
+	HSC_DMA_IN4,
+	HSC_DMA_IN5,
+	HSC_DMA_IN6,
+	HSC_DMA_IN7,
+	HSC_DMA_IN8,
+	HSC_DMA_IN9,
+
+	HSC_DMA_IN_NUM,
+};
+
+/* DMA to write to memory (Record DMA) */
+enum HSC_DMA_OUT {
+	HSC_DMA_OUT0,
+	HSC_DMA_OUT1,
+	HSC_DMA_OUT2,
+	HSC_DMA_OUT3,
+	HSC_DMA_OUT4,
+	HSC_DMA_OUT5,
+	HSC_DMA_OUT6,
+	HSC_DMA_OUT7,
+	HSC_DMA_OUT8,
+	HSC_DMA_OUT9,
+
+	HSC_DMA_OUT_NUM,
+};
+
+enum HSC_TSIF_FMT {
+	HSC_TSIF_MPEG2_TS,
+	HSC_TSIF_MPEG2_TS_ATS,
+};
+
+#define HSC_STREAM_IF_NUM    2
+
+#define HSC_DMAIF_TS_BUFSIZE    (192 * 1024 * 5)
+
+#define HSC_MBC_DMCH_REC0       1
+#define HSC_MBC_DMCH_REC1       2
+#define HSC_MBC_DMCH_REC2       3
+#define HSC_MBC_DMCH_REP0       5
+#define HSC_MBC_DMCH_REP1       6
+#define HSC_MBC_DMCH_REP2       7
+#define HSC_MBC_DMCH_CIP0_R     8
+#define HSC_MBC_DMCH_CIP0_W     9
+#define HSC_MBC_DMCH_CIP1_R    10
+#define HSC_MBC_DMCH_CIP1_W    11
+#define HSC_MBC_DMCH_CIP2_R    12
+#define HSC_MBC_DMCH_CIP2_W    13
+#define HSC_MBC_DMCH_CIP3_R    14
+#define HSC_MBC_DMCH_CIP3_W    15
+#define HSC_MBC_DMCH_CIP4_R    16
+#define HSC_MBC_DMCH_CIP4_W    17
+#define HSC_MBC_DMCH_REC3      19
+#define HSC_MBC_DMCH_REC4      20
+#define HSC_MBC_DMCH_REC5      21
+#define HSC_MBC_DMCH_REP3      22
+#define HSC_MBC_DMCH_REP4      23
+#define HSC_MBC_DMCH_REP5      24
+
+struct hsc_ucode_buf {
+	void *buf_code;
+	dma_addr_t phys_code;
+	size_t size_code;
+	void *buf_data;
+	dma_addr_t phys_data;
+	size_t size_data;
+};
+
+struct hsc_spec_ucode {
+	const char *name_code;
+	const char *name_data;
+};
+
+struct hsc_spec_init_ram {
+	u32 addr;
+	size_t size;
+	u32 pattern;
+};
+
+struct hsc_css_pol {
+	int valid;
+	u32 reg;
+	int sft_sync;
+	int sft_val;
+	int sft_clk;
+};
+
+struct hsc_css_sel {
+	int valid;
+	u32 reg;
+	u32 mask;
+};
+
+struct hsc_spec_css_in {
+	struct hsc_css_pol pol;
+};
+
+struct hsc_spec_css_out {
+	struct hsc_css_pol pol;
+	struct hsc_css_sel sel;
+};
+
+struct hsc_cmn_intr {
+	int valid;
+	u32 reg;
+	int sft_intr;
+};
+
+struct hsc_spec_ts {
+	struct hsc_cmn_intr intr;
+};
+
+struct hsc_dma_en {
+	int valid;
+	u32 reg;
+	int sft_toggle;
+};
+
+struct hsc_spec_dma {
+	int dma_ch;
+	struct hsc_dma_en en;
+	struct hsc_cmn_intr intr;
+};
+
+struct hsc_spec {
+	const struct hsc_spec_ucode ucode_spu;
+	const struct hsc_spec_ucode ucode_ace;
+	const struct hsc_spec_init_ram *init_rams;
+	size_t num_init_rams;
+	const struct hsc_spec_css_in *css_in;
+	size_t num_css_in;
+	const struct hsc_spec_css_out *css_out;
+	size_t num_css_out;
+	const struct hsc_spec_ts *ts_in;
+	size_t num_ts_in;
+	const struct hsc_spec_dma *dma_in;
+	size_t num_dma_in;
+	const struct hsc_spec_dma *dma_out;
+	size_t num_dma_out;
+};
+
+struct hsc_tsif {
+	struct hsc_chip *chip;
+
+	struct dvb_adapter adapter;
+	struct dvb_demux demux;
+	struct dmxdev dmxdev;
+	struct dvb_frontend *fe;
+	int valid_adapter;
+	int valid_demux;
+	int valid_dmxdev;
+	int valid_fe;
+
+	enum HSC_CSS_IN css_in;
+	enum HSC_CSS_OUT css_out;
+	enum HSC_TS_IN tsi;
+	enum HSC_DPLL dpll;
+	enum HSC_DPLL_SRC dpll_src;
+	struct hsc_dmaif *dmaif;
+
+	int running;
+	struct delayed_work recover_work;
+	unsigned long recover_delay;
+};
+
+struct hsc_dma_in {
+	struct hsc_chip *chip;
+
+	enum HSC_DMA_IN id;
+	const struct hsc_spec_dma *spec;
+	struct hsc_dma_buf *buf;
+};
+
+struct hsc_dma_out {
+	struct hsc_chip *chip;
+
+	enum HSC_DMA_OUT id;
+	const struct hsc_spec_dma *spec;
+	struct hsc_dma_buf *buf;
+};
+
+struct hsc_dma_buf {
+	void *virt;
+	dma_addr_t phys;
+	u64 size;
+	u64 size_chk;
+	u64 rd_offs;
+	u64 wr_offs;
+	u64 chk_offs;
+};
+
+struct hsc_dmaif {
+	struct hsc_chip *chip;
+
+	struct hsc_dma_buf buf_out;
+	struct hsc_dma_out dma_out;
+
+	struct hsc_tsif *tsif;
+
+	/* guard read/write pointer of DMA buffer from interrupt handler */
+	spinlock_t lock;
+	int running;
+	struct work_struct feed_work;
+};
+
+struct hsc_chip {
+	const struct hsc_spec *spec;
+	short *adapter_nums;
+
+	struct platform_device *pdev;
+	struct regmap *regmap;
+	struct clk *clk_stdmac;
+	struct clk *clk_hsc;
+	struct reset_control *rst_stdmac;
+	struct reset_control *rst_hsc;
+
+	struct hsc_dmaif dmaif[HSC_STREAM_IF_NUM];
+	struct hsc_tsif tsif[HSC_STREAM_IF_NUM];
+
+	struct hsc_ucode_buf ucode_spu;
+	struct hsc_ucode_buf ucode_am;
+};
+
+struct hsc_conf {
+	enum HSC_CSS_IN css_in;
+	enum HSC_CSS_OUT css_out;
+	enum HSC_DPLL dpll;
+	enum HSC_DMA_OUT dma_out;
+};
+
+static inline u32 field_prep(u32 mask, u32 v)
+{
+	int sft = ffs(mask) - 1;
+
+	return (v << sft) & mask;
+}
+
+static inline u32 field_get(u32 mask, u32 v)
+{
+	int sft = ffs(mask) - 1;
+
+	return (v & mask) >> sft;
+}
+
+/* CSS */
+enum HSC_TS_IN hsc_css_out_to_ts_in(enum HSC_CSS_OUT out);
+enum HSC_DPLL_SRC hsc_css_out_to_dpll_src(enum HSC_CSS_OUT out);
+
+int hsc_dpll_get_src(struct hsc_chip *chip, enum HSC_DPLL dpll,
+		     enum HSC_DPLL_SRC *src);
+int hsc_dpll_set_src(struct hsc_chip *chip, enum HSC_DPLL dpll,
+		     enum HSC_DPLL_SRC src);
+int hsc_css_in_get_polarity(struct hsc_chip *chip, enum HSC_CSS_IN in,
+			    bool *sync_bit, bool *val_bit, bool *clk_fall);
+int hsc_css_in_set_polarity(struct hsc_chip *chip, enum HSC_CSS_IN in,
+			    bool sync_bit, bool val_bit, bool clk_fall);
+int hsc_css_out_get_polarity(struct hsc_chip *chip, enum HSC_CSS_OUT out,
+			     bool *sync_bit, bool *val_bit, bool *clk_fall);
+int hsc_css_out_set_polarity(struct hsc_chip *chip, enum HSC_CSS_OUT out,
+			     bool sync_bit, bool val_bit, bool clk_fall);
+int hsc_css_out_get_src(struct hsc_chip *chip, enum HSC_CSS_IN *in,
+			enum HSC_CSS_OUT out, bool *en);
+int hsc_css_out_set_src(struct hsc_chip *chip, enum HSC_CSS_IN in,
+			enum HSC_CSS_OUT out, bool en);
+
+/* TSI */
+const struct hsc_spec_tsi *hsc_ts_in_get_spec(struct hsc_chip *chip,
+					      enum HSC_TS_IN in);
+int hsc_ts_in_set_enable(struct hsc_chip *chip, enum HSC_TS_IN in, bool en);
+int hsc_ts_in_set_dmaparam(struct hsc_chip *chip, enum HSC_TS_IN in,
+			   enum HSC_TSIF_FMT ifmt);
+
+/* DMA */
+u64 hsc_rb_cnt(struct hsc_dma_buf *buf);
+u64 hsc_rb_cnt_to_end(struct hsc_dma_buf *buf);
+u64 hsc_rb_space(struct hsc_dma_buf *buf);
+u64 hsc_rb_space_to_end(struct hsc_dma_buf *buf);
+int hsc_dma_in_init(struct hsc_dma_in *dma_in, struct hsc_chip *chip,
+		    enum HSC_DMA_IN in, struct hsc_dma_buf *buf);
+void hsc_dma_in_start(struct hsc_dma_in *dma_in, bool en);
+void hsc_dma_in_sync(struct hsc_dma_in *dma_in);
+int hsc_dma_in_get_intr(struct hsc_dma_in *dma_in, u32 *stat);
+void hsc_dma_in_clear_intr(struct hsc_dma_in *dma_in, u32 clear);
+int hsc_dma_out_init(struct hsc_dma_out *dma_out, struct hsc_chip *chip,
+		     enum HSC_DMA_OUT out, struct hsc_dma_buf *buf);
+void hsc_dma_out_set_src_ts_in(struct hsc_dma_out *dma_out,
+			       enum HSC_TS_IN ts_in);
+void hsc_dma_out_start(struct hsc_dma_out *dma_out, bool en);
+void hsc_dma_out_sync(struct hsc_dma_out *dma_out);
+int hsc_dma_out_get_intr(struct hsc_dma_out *dma_out, u32 *stat);
+void hsc_dma_out_clear_intr(struct hsc_dma_out *dma_out, u32 clear);
+
+/* UCODE DL */
+int hsc_ucode_load_all(struct hsc_chip *chip);
+int hsc_ucode_unload_all(struct hsc_chip *chip);
+
+/* For Adapter */
+int hsc_register_dvb(struct hsc_tsif *tsif);
+void hsc_unregister_dvb(struct hsc_tsif *tsif);
+int hsc_tsif_init(struct hsc_tsif *tsif, const struct hsc_conf *conf);
+void hsc_tsif_release(struct hsc_tsif *tsif);
+int hsc_dmaif_init(struct hsc_dmaif *dmaif, const struct hsc_conf *conf);
+void hsc_dmaif_release(struct hsc_dmaif *dmaif);
+extern const struct hsc_spec uniphier_hsc_ld11_spec;
+extern const struct hsc_spec uniphier_hsc_ld20_spec;
+
+#endif /* DVB_UNIPHIER_HSC_H__ */
-- 
2.17.0

^ permalink raw reply related

* [PATCH 1/8] media: uniphier: add DT bindings documentation for UniPhier HSC
From: Katsuhiro Suzuki @ 2018-05-30  9:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180530090946.1635-1-suzuki.katsuhiro@socionext.com>

This patch adds DT binding documentation for UniPhier HSC which is
MPEG2-TS input/output and demux subsystem.

Signed-off-by: Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>
---
 .../bindings/media/uniphier,hsc.txt           | 38 +++++++++++++++++++
 1 file changed, 38 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/uniphier,hsc.txt

diff --git a/Documentation/devicetree/bindings/media/uniphier,hsc.txt b/Documentation/devicetree/bindings/media/uniphier,hsc.txt
new file mode 100644
index 000000000000..4242483b2ecc
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/uniphier,hsc.txt
@@ -0,0 +1,38 @@
+Socionext UniPhier HSC (High-speed Stream Controller)
+
+The Socionext UniPhier HSC subsystem consists of MPEG2-TS input/output and
+demultiplexer cores in the same register space.
+
+This interface is support TS serial signals (clock, valid, sync, data) from
+external demodulators.
+
+Required properties:
+- compatible      : should be one of the following:
+		    "socionext,uniphier-ld11-hsc"
+		    "socionext,uniphier-ld20-hsc"
+- reg             : offset and length of the register set for the device.
+- interrupts      : should contain DMA and TSI error interrupt.
+- pinctrl-names   : should be "default".
+- pinctrl-0       : defined TS serial signal pins for external demodulators.
+- clock-names     : should include following entries:
+                    "hsc", "stdmac"
+- clocks          : a list of phandle, should contain an entry for each
+                    entry in clock-names.
+- reset-names     : should include following entries:
+                    "hsc", "stdmac"
+- resets          : a list of phandle, should contain an entry for each
+                    entry in reset-names.
+
+Example:
+	hsc {
+		compatible = "socionext,uniphier-ld20-hsc";
+		reg = <0x5c000000 0x100000>;
+		interrupts = <0 100 4>, <0 101 4>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_hscin2_s>,
+			    <&pinctrl_hscin3_s>;
+		clock-names = "stdmac", "hsc";
+		clocks = <&sys_clk 8>, <&sys_clk 9>;
+		reset-names = "stdmac", "hsc";
+		resets = <&sys_rst 8>, <&sys_rst 9>;
+	};
-- 
2.17.0

^ permalink raw reply related

* [PATCH 0/8] add UniPhier DVB Frontend system support
From: Katsuhiro Suzuki @ 2018-05-30  9:09 UTC (permalink / raw)
  To: linux-arm-kernel

This series adds support for DVB Frontend system named HSC support
for UniPhier LD11/LD20 SoCs. This driver supports MPEG2-TS serial
signal input from external demodulator and DMA MPEG2-TS stream data
onto memory.

UniPhier HSC driver provides many ports of TS input. Since the HSC
has mixed register map for those ports. It hard to split each register
areas.

Katsuhiro Suzuki (8):
  media: uniphier: add DT bindings documentation for UniPhier HSC
  media: uniphier: add headers of HSC MPEG2-TS I/O driver
  media: uniphier: add submodules of HSC MPEG2-TS I/O driver
  media: uniphier: add common module of HSC MPEG2-TS I/O driver
  media: uniphier: add LD11/LD20 HSC support
  media: uniphier: add common module of DVB adapter drivers
  media: uniphier: add LD11 adapter driver for ISDB
  media: uniphier: add LD20 adapter driver for ISDB

 .../bindings/media/uniphier,hsc.txt           |  38 ++
 drivers/media/platform/Kconfig                |   1 +
 drivers/media/platform/Makefile               |   2 +
 drivers/media/platform/uniphier/Kconfig       |  37 ++
 drivers/media/platform/uniphier/Makefile      |  12 +
 drivers/media/platform/uniphier/hsc-core.c    | 506 ++++++++++++++++++
 drivers/media/platform/uniphier/hsc-css.c     | 258 +++++++++
 drivers/media/platform/uniphier/hsc-dma.c     | 302 +++++++++++
 drivers/media/platform/uniphier/hsc-ld11.c    | 219 ++++++++
 drivers/media/platform/uniphier/hsc-reg.h     | 491 +++++++++++++++++
 drivers/media/platform/uniphier/hsc-ts.c      |  99 ++++
 drivers/media/platform/uniphier/hsc-ucode.c   | 436 +++++++++++++++
 drivers/media/platform/uniphier/hsc.h         | 480 +++++++++++++++++
 .../platform/uniphier/ld11-mn884433-helene.c  | 265 +++++++++
 .../platform/uniphier/ld20-mn884434-helene.c  | 274 ++++++++++
 .../platform/uniphier/uniphier-adapter.c      |  54 ++
 .../platform/uniphier/uniphier-adapter.h      |  42 ++
 17 files changed, 3516 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/uniphier,hsc.txt
 create mode 100644 drivers/media/platform/uniphier/Kconfig
 create mode 100644 drivers/media/platform/uniphier/Makefile
 create mode 100644 drivers/media/platform/uniphier/hsc-core.c
 create mode 100644 drivers/media/platform/uniphier/hsc-css.c
 create mode 100644 drivers/media/platform/uniphier/hsc-dma.c
 create mode 100644 drivers/media/platform/uniphier/hsc-ld11.c
 create mode 100644 drivers/media/platform/uniphier/hsc-reg.h
 create mode 100644 drivers/media/platform/uniphier/hsc-ts.c
 create mode 100644 drivers/media/platform/uniphier/hsc-ucode.c
 create mode 100644 drivers/media/platform/uniphier/hsc.h
 create mode 100644 drivers/media/platform/uniphier/ld11-mn884433-helene.c
 create mode 100644 drivers/media/platform/uniphier/ld20-mn884434-helene.c
 create mode 100644 drivers/media/platform/uniphier/uniphier-adapter.c
 create mode 100644 drivers/media/platform/uniphier/uniphier-adapter.h

-- 
2.17.0

^ permalink raw reply


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