* [PATCH v2 2/4] serial: 8250: Add new port type for TI DA8xx/OMAPL13x/AM17xx/AM18xx/C66x
From: Sekhar Nori @ 2017-01-05 8:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483561814-21953-3-git-send-email-david@lechnology.com>
On Thursday 05 January 2017 02:00 AM, David Lechner wrote:
> This adds a new UART port type for TI DA8xx/OMAPL13x/AM17xx/AM18xx/C66x.
The Keystone2 processors do include the C66x DSP. But the SoCs being
targeted with this patch are the ARM + DSP variants. Using 66AK2x is
more appropriate.
http://www.ti.com/lsds/ti/processors/dsp/c6000_dsp-arm/66ak2x/overview.page
Also, DA8xx includes DA830 which is pin-compatible with AM17x. So you
can shorten the list of supported processors to DA8xx/66AK2x.
> These SoCs have standard 8250 registers plus some extra non-standard
> registers.
>
> The UART will not function unless the non-standard Power and Emulation
> Management Register (PWREMU_MGMT) is configured correctly. This is
> currently handled in arch/arm/mach-davinci/serial.c for non-device-tree
> boards. Making this part of the UART driver will allow UART to work on
> device-tree boards as well and the mach code can eventually be removed.
>
> Signed-off-by: David Lechner <david@lechnology.com>
Looks good to me, apart from the minor change above.
Acked-by: Sekhar Nori <nsekhar@ti.com>
Thanks,
Sekhar
^ permalink raw reply
* [PATCH v6 08/14] ACPI: ARM64: IORT: rework iort_node_get_id()
From: Hanjun Guo @ 2017-01-05 8:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170104175822.GD8604@red-moon>
Hi Lorenzo,
On 2017/1/5 1:58, Lorenzo Pieralisi wrote:
> On Mon, Jan 02, 2017 at 09:31:39PM +0800, Hanjun Guo wrote:
>> iort_node_get_id() has two output, one is the mapped ids,
>> the other is the referenced parent node which is returned
>> from the function.
>>
>> For now we need a API just return its parent node for
>> single mapping, so just update this function slightly then
>> reuse it later.
>
> I think we need to fix iort_node_get_id() first though, I am referring
> to the index usage in relation to acpi_iort_id_mapping.output_reference
> and related parent pointer retrieval as you reported to me, I am happy
> to send it upstream independently.
Sure, please.
>
> As for this patch it is ok even though we can create an API that
> just retrieve a node parent without fiddling about with passing
> a NULL pointer for the id_out to achieve the same.
Since you commented "[PATCH v6 05/14] ACPI: platform-msi: retrieve dev
id from IORT" which also refer to this API, I will reply in that
email.
Thanks
Hanjun
^ permalink raw reply
* [PATCH 05/22] ARM: dtsi: axp209: add AXP209 ADC subnode
From: Chen-Yu Tsai @ 2017-01-05 8:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1ddf7012-3336-84c2-6392-353b01beea93@free-electrons.com>
On Thu, Jan 5, 2017 at 4:08 PM, Quentin Schulz
<quentin.schulz@free-electrons.com> wrote:
> On 05/01/2017 06:51, Chen-Yu Tsai wrote:
>> On Tue, Jan 3, 2017 at 12:37 AM, Quentin Schulz
>> <quentin.schulz@free-electrons.com> wrote:
>>> X-Powers AXP209 PMIC has multiple ADCs, each one exposing data from the
>>> different power supplies connected to the PMIC.
>>>
>>> This adds the ADC subnode for AXP20X PMIC.
>>>
>>> Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
>>> ---
>>> arch/arm/boot/dts/axp209.dtsi | 5 +++++
>>> 1 file changed, 5 insertions(+)
>>>
>>> diff --git a/arch/arm/boot/dts/axp209.dtsi b/arch/arm/boot/dts/axp209.dtsi
>>> index 675bb0f..2a4e8ee 100644
>>> --- a/arch/arm/boot/dts/axp209.dtsi
>>> +++ b/arch/arm/boot/dts/axp209.dtsi
>>> @@ -53,6 +53,11 @@
>>> interrupt-controller;
>>> #interrupt-cells = <1>;
>>>
>>> + axp209_adc: axp209_adc {
>>
>> Node name should be generic. Please change it to "adc".
>>
>
> OK, do I keep the label as is?
>
> axp209_adc: adc {
Yup. The label is for dereferencing and stuff, and exists in a global scope.
You wouldn't want 2 label names clashing.
ChenYu
>
> Thanks,
> Quentin
>
> --
> Quentin Schulz, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com
^ permalink raw reply
* [PATCH v2,9/9] irqchip/ls-scfg-msi: add MSI affinity support
From: Minghuan Lian @ 2017-01-05 8:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483603837-4629-1-git-send-email-Minghuan.Lian@nxp.com>
For LS1046a and LS1043a v1.1, the MSI controller has 4 MSIRs and 4
CPUs. A GIC SPI interrupt of MSIR can be associated with a CPU.
When changing MSI interrupt affinity, this MSI will be moved to the
corresponding MSIR and MSI message data will be changed according to
MSIR. when requesting a MSI, the bits of all 4 MSIR will be reserved.
The parameter 'msi_affinity_flag' is provide to change this mode.
"lsmsi=no-affinity" will disable affinity, all MSI can only be
associated with CPU 0.
Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com>
---
v2-v1:
- None
drivers/irqchip/irq-ls-scfg-msi.c | 75 ++++++++++++++++++++++++++++++++++++---
1 file changed, 70 insertions(+), 5 deletions(-)
diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c
index dc19569..753fe39 100644
--- a/drivers/irqchip/irq-ls-scfg-msi.c
+++ b/drivers/irqchip/irq-ls-scfg-msi.c
@@ -40,6 +40,7 @@ struct ls_scfg_msir {
unsigned int gic_irq;
unsigned int bit_start;
unsigned int bit_end;
+ unsigned int srs; /* Shared interrupt register select */
void __iomem *reg;
};
@@ -70,6 +71,19 @@ struct ls_scfg_msi {
.chip = &ls_scfg_msi_irq_chip,
};
+static int msi_affinity_flag = 1;
+
+static int __init early_parse_ls_scfg_msi(char *p)
+{
+ if (p && strncmp(p, "no-affinity", 11) == 0)
+ msi_affinity_flag = 0;
+ else
+ msi_affinity_flag = 1;
+
+ return 0;
+}
+early_param("lsmsi", early_parse_ls_scfg_msi);
+
static void ls_scfg_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
{
struct ls_scfg_msi *msi_data = irq_data_get_irq_chip_data(data);
@@ -77,12 +91,43 @@ static void ls_scfg_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
msg->address_hi = upper_32_bits(msi_data->msiir_addr);
msg->address_lo = lower_32_bits(msi_data->msiir_addr);
msg->data = data->hwirq;
+
+ if (msi_affinity_flag) {
+ u32 msir_index;
+
+ msir_index = cpumask_first(data->common->affinity);
+ if (msir_index >= msi_data->msir_num)
+ msir_index = 0;
+
+ msg->data |= msir_index;
+ }
}
static int ls_scfg_msi_set_affinity(struct irq_data *irq_data,
const struct cpumask *mask, bool force)
{
- return -EINVAL;
+ struct ls_scfg_msi *msi_data = irq_data_get_irq_chip_data(irq_data);
+ u32 cpu;
+
+ if (!msi_affinity_flag)
+ return -EINVAL;
+
+ if (!force)
+ cpu = cpumask_any_and(mask, cpu_online_mask);
+ else
+ cpu = cpumask_first(mask);
+
+ if (cpu >= msi_data->msir_num)
+ return -EINVAL;
+
+ if (msi_data->msir[cpu].gic_irq <= 0) {
+ pr_warn("cannot bind the irq to cpu%d\n", cpu);
+ return -EINVAL;
+ }
+
+ cpumask_copy(irq_data->common->affinity, mask);
+
+ return IRQ_SET_MASK_OK;
}
static struct irq_chip ls_scfg_msi_parent_chip = {
@@ -158,7 +203,7 @@ static void ls_scfg_msi_irq_handler(struct irq_desc *desc)
for_each_set_bit_from(pos, &val, size) {
hwirq = ((msir->bit_end - pos) << msi_data->cfg->ibs_shift) |
- msir->index;
+ msir->srs;
virq = irq_find_mapping(msi_data->parent, hwirq);
if (virq)
generic_handle_irq(virq);
@@ -221,10 +266,19 @@ static int ls_scfg_msi_setup_hwirq(struct ls_scfg_msi *msi_data, int index)
ls_scfg_msi_irq_handler,
msir);
+ if (msi_affinity_flag) {
+ /* Associate MSIR interrupt to the cpu */
+ irq_set_affinity(msir->gic_irq, get_cpu_mask(index));
+ msir->srs = 0; /* This value is determined by the CPU */
+ } else
+ msir->srs = index;
+
/* Release the hwirqs corresponding to this MSIR */
- for (i = 0; i < msi_data->cfg->msir_irqs; i++) {
- hwirq = i << msi_data->cfg->ibs_shift | msir->index;
- bitmap_clear(msi_data->used, hwirq, 1);
+ if (!msi_affinity_flag || msir->index == 0) {
+ for (i = 0; i < msi_data->cfg->msir_irqs; i++) {
+ hwirq = i << msi_data->cfg->ibs_shift | msir->index;
+ bitmap_clear(msi_data->used, hwirq, 1);
+ }
}
return 0;
@@ -316,6 +370,17 @@ static int ls_scfg_msi_probe(struct platform_device *pdev)
bitmap_set(msi_data->used, 0, msi_data->irqs_num);
msi_data->msir_num = of_irq_count(pdev->dev.of_node);
+
+ if (msi_affinity_flag) {
+ u32 cpu_num;
+
+ cpu_num = num_possible_cpus();
+ if (msi_data->msir_num >= cpu_num)
+ msi_data->msir_num = cpu_num;
+ else
+ msi_affinity_flag = 0;
+ }
+
msi_data->msir = devm_kcalloc(&pdev->dev, msi_data->msir_num,
sizeof(*msi_data->msir),
GFP_KERNEL);
--
1.9.1
^ permalink raw reply related
* [PATCH v2,8/9] irqchip/ls-scfg-msi: add LS1043a v1.1 MSI support
From: Minghuan Lian @ 2017-01-05 8:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483603837-4629-1-git-send-email-Minghuan.Lian@nxp.com>
A MSI controller of LS1043a v1.0 only includes one MSIR and
is assigned one GIC interrupt. In order to support affinity,
LS1043a v1.1 MSI is assigned 4 MSIRs and 4 GIC interrupts.
But the MSIR has the different offset and only supports 8 MSIs.
The bits between variable bit_start and bit_end in structure
ls_scfg_msir are used to show 8 MSI interrupts. msir_irqs and
msir_base are added to describe the difference of MSI between
LS1043a v1.1 and other SoCs.
Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com>
Acked-by: Rob Herring <robh@kernel.org>
---
v2-v1:
- None
.../interrupt-controller/fsl,ls-scfg-msi.txt | 1 +
drivers/irqchip/irq-ls-scfg-msi.c | 45 +++++++++++++++++++---
2 files changed, 40 insertions(+), 6 deletions(-)
diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
index dde4552..49ccabb 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
@@ -7,6 +7,7 @@ Required properties:
"fsl,ls1021a-msi"
"fsl,ls1043a-msi"
"fsl,ls1046a-msi"
+ "fsl,ls1043a-v1.1-msi"
- msi-controller: indicates that this is a PCIe MSI controller node
- reg: physical base address of the controller and length of memory mapped.
- interrupts: an interrupt to the parent interrupt controller.
diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c
index 67547bd..dc19569 100644
--- a/drivers/irqchip/irq-ls-scfg-msi.c
+++ b/drivers/irqchip/irq-ls-scfg-msi.c
@@ -25,14 +25,21 @@
#define MSI_IRQS_PER_MSIR 32
#define MSI_MSIR_OFFSET 4
+#define MSI_LS1043V1_1_IRQS_PER_MSIR 8
+#define MSI_LS1043V1_1_MSIR_OFFSET 0x10
+
struct ls_scfg_msi_cfg {
u32 ibs_shift; /* Shift of interrupt bit select */
+ u32 msir_irqs; /* The irq number per MSIR */
+ u32 msir_base; /* The base address of MSIR */
};
struct ls_scfg_msir {
struct ls_scfg_msi *msi_data;
unsigned int index;
unsigned int gic_irq;
+ unsigned int bit_start;
+ unsigned int bit_end;
void __iomem *reg;
};
@@ -140,13 +147,18 @@ static void ls_scfg_msi_irq_handler(struct irq_desc *desc)
struct ls_scfg_msir *msir = irq_desc_get_handler_data(desc);
struct ls_scfg_msi *msi_data = msir->msi_data;
unsigned long val;
- int pos, virq, hwirq;
+ int pos, size, virq, hwirq;
chained_irq_enter(irq_desc_get_chip(desc), desc);
val = ioread32be(msir->reg);
- for_each_set_bit(pos, &val, MSI_IRQS_PER_MSIR) {
- hwirq = ((31 - pos) << msi_data->cfg->ibs_shift) | msir->index;
+
+ pos = msir->bit_start;
+ size = msir->bit_end + 1;
+
+ for_each_set_bit_from(pos, &val, size) {
+ hwirq = ((msir->bit_end - pos) << msi_data->cfg->ibs_shift) |
+ msir->index;
virq = irq_find_mapping(msi_data->parent, hwirq);
if (virq)
generic_handle_irq(virq);
@@ -193,14 +205,24 @@ static int ls_scfg_msi_setup_hwirq(struct ls_scfg_msi *msi_data, int index)
msir->index = index;
msir->msi_data = msi_data;
msir->gic_irq = virq;
- msir->reg = msi_data->regs + MSI_MSIR_OFFSET + 4 * index;
+ msir->reg = msi_data->regs + msi_data->cfg->msir_base + 4 * index;
+
+ if (msi_data->cfg->msir_irqs == MSI_LS1043V1_1_IRQS_PER_MSIR) {
+ msir->bit_start = 32 - ((msir->index + 1) *
+ MSI_LS1043V1_1_IRQS_PER_MSIR);
+ msir->bit_end = msir->bit_start +
+ MSI_LS1043V1_1_IRQS_PER_MSIR - 1;
+ } else {
+ msir->bit_start = 0;
+ msir->bit_end = msi_data->cfg->msir_irqs - 1;
+ }
irq_set_chained_handler_and_data(msir->gic_irq,
ls_scfg_msi_irq_handler,
msir);
/* Release the hwirqs corresponding to this MSIR */
- for (i = 0; i < MSI_IRQS_PER_MSIR; i++) {
+ for (i = 0; i < msi_data->cfg->msir_irqs; i++) {
hwirq = i << msi_data->cfg->ibs_shift | msir->index;
bitmap_clear(msi_data->used, hwirq, 1);
}
@@ -216,7 +238,7 @@ static int ls_scfg_msi_teardown_hwirq(struct ls_scfg_msir *msir)
if (msir->gic_irq > 0)
irq_set_chained_handler_and_data(msir->gic_irq, NULL, NULL);
- for (i = 0; i < MSI_IRQS_PER_MSIR; i++) {
+ for (i = 0; i < msi_data->cfg->msir_irqs; i++) {
hwirq = i << msi_data->cfg->ibs_shift | msir->index;
bitmap_set(msi_data->used, hwirq, 1);
}
@@ -226,15 +248,26 @@ static int ls_scfg_msi_teardown_hwirq(struct ls_scfg_msir *msir)
static struct ls_scfg_msi_cfg ls1021_msi_cfg = {
.ibs_shift = 3,
+ .msir_irqs = MSI_IRQS_PER_MSIR,
+ .msir_base = MSI_MSIR_OFFSET,
};
static struct ls_scfg_msi_cfg ls1046_msi_cfg = {
.ibs_shift = 2,
+ .msir_irqs = MSI_IRQS_PER_MSIR,
+ .msir_base = MSI_MSIR_OFFSET,
+};
+
+static struct ls_scfg_msi_cfg ls1043_v1_1_msi_cfg = {
+ .ibs_shift = 2,
+ .msir_irqs = MSI_LS1043V1_1_IRQS_PER_MSIR,
+ .msir_base = MSI_LS1043V1_1_MSIR_OFFSET,
};
static const struct of_device_id ls_scfg_msi_id[] = {
{ .compatible = "fsl,ls1021a-msi", .data = &ls1021_msi_cfg },
{ .compatible = "fsl,ls1043a-msi", .data = &ls1021_msi_cfg },
+ { .compatible = "fsl,ls1043a-v1.1-msi", .data = &ls1043_v1_1_msi_cfg },
{ .compatible = "fsl,ls1046a-msi", .data = &ls1046_msi_cfg },
{},
};
--
1.9.1
^ permalink raw reply related
* [PATCH 15/22] mfd: axp20x: add CHRG_CTRL1 to writeable regs for AXP20X/AXP22X
From: Quentin Schulz @ 2017-01-05 8:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGb2v67KmaECfFO+QBxKbtKscD0O=KNVHO1TS4FspYEdaLWUCA@mail.gmail.com>
On 05/01/2017 07:10, Chen-Yu Tsai wrote:
> On Tue, Jan 3, 2017 at 12:37 AM, Quentin Schulz
> <quentin.schulz@free-electrons.com> wrote:
>> The CHR_CTRL1 register is made of 7 read-write bits with one being used
>> to set the target voltage for battery charging.
>
> The description is incorrect.
>
> All 8 bits are read-write:
>
> - The highest bit enables the charger module
> - Bits [6:5] set the target voltage
> - Bits [4:3] set when the charge cycle ends, based on percentage
> of charge current
> - Bits [2:0] set the charge current
>
> Feel free to use the above in the commit message.
>
Thanks for the correction.
>>
>> This adds the CHRG_CTRL1 register to the list of writeable registers for
>> AXP20X and AXP22X PMICs.
>
> You might want to add up to CHRG_CTRL3 for the AXP22x and CHRG_CTRL2
> for the AXP20x. These control additional aspects of the charger.
>
ACK.
> AXP20X_CHRG_BAK_CTRL controls the charger for the RTC battery. You
> could add this now, or let the person doing the RTC battery driver
> add it.
I'll let the person adding the RTC battery driver add it.
Thanks,
Quentin
--
Quentin Schulz, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
^ permalink raw reply
* [PATCH v2,7/9] irqchip/ls-scfg-msi: add LS1046a MSI support
From: Minghuan Lian @ 2017-01-05 8:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483603837-4629-1-git-send-email-Minghuan.Lian@nxp.com>
LS1046a includes 4 MSIRs, each MSIR is assigned a dedicate GIC
SPI interrupt and provides 32 MSI interrupts. Compared to previous
MSI, LS1046a's IBS(interrupt bit select) shift is changed to 2 and
total MSI interrupt number is changed to 128.
The patch adds structure 'ls_scfg_msir' to describe MSIR setting and
'ibs_shift' to store the different value between the SoCs.
Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com>
---
v2-v1:
- MSI dts node change has been merged into the patch 6/9
drivers/irqchip/irq-ls-scfg-msi.c | 161 +++++++++++++++++++++++++++++---------
1 file changed, 126 insertions(+), 35 deletions(-)
diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c
index cef67cc..67547bd 100644
--- a/drivers/irqchip/irq-ls-scfg-msi.c
+++ b/drivers/irqchip/irq-ls-scfg-msi.c
@@ -17,13 +17,24 @@
#include <linux/irq.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
#include <linux/of_pci.h>
#include <linux/of_platform.h>
#include <linux/spinlock.h>
-#define MSI_MAX_IRQS 32
-#define MSI_IBS_SHIFT 3
-#define MSIR 4
+#define MSI_IRQS_PER_MSIR 32
+#define MSI_MSIR_OFFSET 4
+
+struct ls_scfg_msi_cfg {
+ u32 ibs_shift; /* Shift of interrupt bit select */
+};
+
+struct ls_scfg_msir {
+ struct ls_scfg_msi *msi_data;
+ unsigned int index;
+ unsigned int gic_irq;
+ void __iomem *reg;
+};
struct ls_scfg_msi {
spinlock_t lock;
@@ -32,8 +43,11 @@ struct ls_scfg_msi {
struct irq_domain *msi_domain;
void __iomem *regs;
phys_addr_t msiir_addr;
- int irq;
- DECLARE_BITMAP(used, MSI_MAX_IRQS);
+ struct ls_scfg_msi_cfg *cfg;
+ u32 msir_num;
+ struct ls_scfg_msir *msir;
+ u32 irqs_num;
+ unsigned long *used;
};
static struct irq_chip ls_scfg_msi_irq_chip = {
@@ -55,7 +69,7 @@ static void ls_scfg_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
msg->address_hi = upper_32_bits(msi_data->msiir_addr);
msg->address_lo = lower_32_bits(msi_data->msiir_addr);
- msg->data = data->hwirq << MSI_IBS_SHIFT;
+ msg->data = data->hwirq;
}
static int ls_scfg_msi_set_affinity(struct irq_data *irq_data,
@@ -81,8 +95,8 @@ static int ls_scfg_msi_domain_irq_alloc(struct irq_domain *domain,
WARN_ON(nr_irqs != 1);
spin_lock(&msi_data->lock);
- pos = find_first_zero_bit(msi_data->used, MSI_MAX_IRQS);
- if (pos < MSI_MAX_IRQS)
+ pos = find_first_zero_bit(msi_data->used, msi_data->irqs_num);
+ if (pos < msi_data->irqs_num)
__set_bit(pos, msi_data->used);
else
err = -ENOSPC;
@@ -106,7 +120,7 @@ static void ls_scfg_msi_domain_irq_free(struct irq_domain *domain,
int pos;
pos = d->hwirq;
- if (pos < 0 || pos >= MSI_MAX_IRQS) {
+ if (pos < 0 || pos >= msi_data->irqs_num) {
pr_err("failed to teardown msi. Invalid hwirq %d\n", pos);
return;
}
@@ -123,15 +137,17 @@ static void ls_scfg_msi_domain_irq_free(struct irq_domain *domain,
static void ls_scfg_msi_irq_handler(struct irq_desc *desc)
{
- struct ls_scfg_msi *msi_data = irq_desc_get_handler_data(desc);
+ struct ls_scfg_msir *msir = irq_desc_get_handler_data(desc);
+ struct ls_scfg_msi *msi_data = msir->msi_data;
unsigned long val;
- int pos, virq;
+ int pos, virq, hwirq;
chained_irq_enter(irq_desc_get_chip(desc), desc);
- val = ioread32be(msi_data->regs + MSIR);
- for_each_set_bit(pos, &val, MSI_MAX_IRQS) {
- virq = irq_find_mapping(msi_data->parent, (31 - pos));
+ val = ioread32be(msir->reg);
+ for_each_set_bit(pos, &val, MSI_IRQS_PER_MSIR) {
+ hwirq = ((31 - pos) << msi_data->cfg->ibs_shift) | msir->index;
+ virq = irq_find_mapping(msi_data->parent, hwirq);
if (virq)
generic_handle_irq(virq);
}
@@ -143,7 +159,7 @@ static int ls_scfg_msi_domains_init(struct ls_scfg_msi *msi_data)
{
/* Initialize MSI domain parent */
msi_data->parent = irq_domain_add_linear(NULL,
- MSI_MAX_IRQS,
+ msi_data->irqs_num,
&ls_scfg_msi_domain_ops,
msi_data);
if (!msi_data->parent) {
@@ -164,16 +180,83 @@ static int ls_scfg_msi_domains_init(struct ls_scfg_msi *msi_data)
return 0;
}
+static int ls_scfg_msi_setup_hwirq(struct ls_scfg_msi *msi_data, int index)
+{
+ struct ls_scfg_msir *msir;
+ int virq, i, hwirq;
+
+ virq = platform_get_irq(msi_data->pdev, index);
+ if (virq <= 0)
+ return -ENODEV;
+
+ msir = &msi_data->msir[index];
+ msir->index = index;
+ msir->msi_data = msi_data;
+ msir->gic_irq = virq;
+ msir->reg = msi_data->regs + MSI_MSIR_OFFSET + 4 * index;
+
+ irq_set_chained_handler_and_data(msir->gic_irq,
+ ls_scfg_msi_irq_handler,
+ msir);
+
+ /* Release the hwirqs corresponding to this MSIR */
+ for (i = 0; i < MSI_IRQS_PER_MSIR; i++) {
+ hwirq = i << msi_data->cfg->ibs_shift | msir->index;
+ bitmap_clear(msi_data->used, hwirq, 1);
+ }
+
+ return 0;
+}
+
+static int ls_scfg_msi_teardown_hwirq(struct ls_scfg_msir *msir)
+{
+ struct ls_scfg_msi *msi_data = msir->msi_data;
+ int i, hwirq;
+
+ if (msir->gic_irq > 0)
+ irq_set_chained_handler_and_data(msir->gic_irq, NULL, NULL);
+
+ for (i = 0; i < MSI_IRQS_PER_MSIR; i++) {
+ hwirq = i << msi_data->cfg->ibs_shift | msir->index;
+ bitmap_set(msi_data->used, hwirq, 1);
+ }
+
+ return 0;
+}
+
+static struct ls_scfg_msi_cfg ls1021_msi_cfg = {
+ .ibs_shift = 3,
+};
+
+static struct ls_scfg_msi_cfg ls1046_msi_cfg = {
+ .ibs_shift = 2,
+};
+
+static const struct of_device_id ls_scfg_msi_id[] = {
+ { .compatible = "fsl,ls1021a-msi", .data = &ls1021_msi_cfg },
+ { .compatible = "fsl,ls1043a-msi", .data = &ls1021_msi_cfg },
+ { .compatible = "fsl,ls1046a-msi", .data = &ls1046_msi_cfg },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ls_scfg_msi_id);
+
static int ls_scfg_msi_probe(struct platform_device *pdev)
{
+ const struct of_device_id *match;
struct ls_scfg_msi *msi_data;
struct resource *res;
- int ret;
+ int i, ret;
+
+ match = of_match_device(ls_scfg_msi_id, &pdev->dev);
+ if (!match)
+ return -ENODEV;
msi_data = devm_kzalloc(&pdev->dev, sizeof(*msi_data), GFP_KERNEL);
if (!msi_data)
return -ENOMEM;
+ msi_data->cfg = (struct ls_scfg_msi_cfg *) match->data;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
msi_data->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(msi_data->regs)) {
@@ -182,23 +265,37 @@ static int ls_scfg_msi_probe(struct platform_device *pdev)
}
msi_data->msiir_addr = res->start;
- msi_data->irq = platform_get_irq(pdev, 0);
- if (msi_data->irq <= 0) {
- dev_err(&pdev->dev, "failed to get MSI irq\n");
- return -ENODEV;
- }
-
msi_data->pdev = pdev;
spin_lock_init(&msi_data->lock);
+ msi_data->irqs_num = MSI_IRQS_PER_MSIR *
+ (1 << msi_data->cfg->ibs_shift);
+ msi_data->used = devm_kcalloc(&pdev->dev,
+ BITS_TO_LONGS(msi_data->irqs_num),
+ sizeof(*msi_data->used),
+ GFP_KERNEL);
+ if (!msi_data->used)
+ return -ENOMEM;
+ /*
+ * Reserve all the hwirqs
+ * The available hwirqs will be released in ls1_msi_setup_hwirq()
+ */
+ bitmap_set(msi_data->used, 0, msi_data->irqs_num);
+
+ msi_data->msir_num = of_irq_count(pdev->dev.of_node);
+ msi_data->msir = devm_kcalloc(&pdev->dev, msi_data->msir_num,
+ sizeof(*msi_data->msir),
+ GFP_KERNEL);
+ if (!msi_data->msir)
+ return -ENOMEM;
+
+ for (i = 0; i < msi_data->msir_num; i++)
+ ls_scfg_msi_setup_hwirq(msi_data, i);
+
ret = ls_scfg_msi_domains_init(msi_data);
if (ret)
return ret;
- irq_set_chained_handler_and_data(msi_data->irq,
- ls_scfg_msi_irq_handler,
- msi_data);
-
platform_set_drvdata(pdev, msi_data);
return 0;
@@ -207,8 +304,10 @@ static int ls_scfg_msi_probe(struct platform_device *pdev)
static int ls_scfg_msi_remove(struct platform_device *pdev)
{
struct ls_scfg_msi *msi_data = platform_get_drvdata(pdev);
+ int i;
- irq_set_chained_handler_and_data(msi_data->irq, NULL, NULL);
+ for (i = 0; i < msi_data->msir_num; i++)
+ ls_scfg_msi_teardown_hwirq(&msi_data->msir[i]);
irq_domain_remove(msi_data->msi_domain);
irq_domain_remove(msi_data->parent);
@@ -218,14 +317,6 @@ static int ls_scfg_msi_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id ls_scfg_msi_id[] = {
- { .compatible = "fsl,1s1021a-msi", }, /* a typo */
- { .compatible = "fsl,1s1043a-msi", }, /* a typo */
- { .compatible = "fsl,ls1021a-msi", },
- { .compatible = "fsl,ls1043a-msi", },
- {},
-};
-
static struct platform_driver ls_scfg_msi_driver = {
.driver = {
.name = "ls-scfg-msi",
--
1.9.1
^ permalink raw reply related
* [PATCH v2,6/9] arm64: dts: ls1046a: add MSI dts node
From: Minghuan Lian @ 2017-01-05 8:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483603837-4629-1-git-send-email-Minghuan.Lian@nxp.com>
LS1046a includes 3 MSI controllers.
Each controller supports 128 interrupts.
Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com>
Acked-by: Rob Herring <robh@kernel.org>
---
v2-v1:
- change whitespace number
.../interrupt-controller/fsl,ls-scfg-msi.txt | 1 +
arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 31 ++++++++++++++++++++++
2 files changed, 32 insertions(+)
diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
index 2755cd1..dde4552 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
@@ -6,6 +6,7 @@ Required properties:
Layerscape PCIe MSI controller block such as:
"fsl,ls1021a-msi"
"fsl,ls1043a-msi"
+ "fsl,ls1046a-msi"
- msi-controller: indicates that this is a PCIe MSI controller node
- reg: physical base address of the controller and length of memory mapped.
- interrupts: an interrupt to the parent interrupt controller.
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
index 38806ca..49dbafc 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
@@ -511,5 +511,36 @@
interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clockgen 4 1>;
};
+
+ msi1: msi-controller at 1580000 {
+ compatible = "fsl,ls1046a-msi";
+ msi-controller;
+ reg = <0x0 0x1580000 0x0 0x10000>;
+ interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ msi2: msi-controller at 1590000 {
+ compatible = "fsl,ls1046a-msi";
+ msi-controller;
+ reg = <0x0 0x1590000 0x0 0x10000>;
+ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ msi3: msi-controller at 15a0000 {
+ compatible = "fsl,ls1046a-msi";
+ msi-controller;
+ reg = <0x0 0x15a0000 0x0 0x10000>;
+ interrupts = <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
};
};
--
1.9.1
^ permalink raw reply related
* [PATCH v2,5/9] arm64: dts: ls1043a: share all MSIs
From: Minghuan Lian @ 2017-01-05 8:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483603837-4629-1-git-send-email-Minghuan.Lian@nxp.com>
In order to maximize the use of MSI, a PCIe controller will share
all MSI controllers. The patch changes "msi-parent" to refer to all
MSI controller dts nodes.
Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com>
---
v2-v1:
- None
arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
index 692fc35..3947220 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
@@ -625,7 +625,7 @@
bus-range = <0x0 0xff>;
ranges = <0x81000000 0x0 0x00000000 0x40 0x00010000 0x0 0x00010000 /* downstream I/O */
0x82000000 0x0 0x40000000 0x40 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
- msi-parent = <&msi1>;
+ msi-parent = <&msi1>, <&msi2>, <&msi3>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0000 0 0 1 &gic 0 110 0x4>,
@@ -650,7 +650,7 @@
bus-range = <0x0 0xff>;
ranges = <0x81000000 0x0 0x00000000 0x48 0x00010000 0x0 0x00010000 /* downstream I/O */
0x82000000 0x0 0x40000000 0x48 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
- msi-parent = <&msi2>;
+ msi-parent = <&msi1>, <&msi2>, <&msi3>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0000 0 0 1 &gic 0 120 0x4>,
@@ -675,7 +675,7 @@
bus-range = <0x0 0xff>;
ranges = <0x81000000 0x0 0x00000000 0x50 0x00010000 0x0 0x00010000 /* downstream I/O */
0x82000000 0x0 0x40000000 0x50 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
- msi-parent = <&msi3>;
+ msi-parent = <&msi1>, <&msi2>, <&msi3>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0000 0 0 1 &gic 0 154 0x4>,
--
1.9.1
^ permalink raw reply related
* [PATCH v2,4/9] arm: dts: ls1021a: share all MSIs
From: Minghuan Lian @ 2017-01-05 8:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483603837-4629-1-git-send-email-Minghuan.Lian@nxp.com>
In order to maximize the use of MSI, a PCIe controller will share
all MSI controllers. The patch changes msi-parent to refer to all
MSI controller dts nodes.
Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com>
---
v2-v1:
- None
arch/arm/boot/dts/ls1021a.dtsi | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi
index 6651938..1c82024 100644
--- a/arch/arm/boot/dts/ls1021a.dtsi
+++ b/arch/arm/boot/dts/ls1021a.dtsi
@@ -723,7 +723,7 @@
bus-range = <0x0 0xff>;
ranges = <0x81000000 0x0 0x00000000 0x40 0x00010000 0x0 0x00010000 /* downstream I/O */
0x82000000 0x0 0x40000000 0x40 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
- msi-parent = <&msi1>;
+ msi-parent = <&msi1>, <&msi2>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0000 0 0 1 &gic GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>,
@@ -746,7 +746,7 @@
bus-range = <0x0 0xff>;
ranges = <0x81000000 0x0 0x00000000 0x48 0x00010000 0x0 0x00010000 /* downstream I/O */
0x82000000 0x0 0x40000000 0x48 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
- msi-parent = <&msi2>;
+ msi-parent = <&msi1>, <&msi2>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0000 0 0 1 &gic GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>,
--
1.9.1
^ permalink raw reply related
* [PATCH v2, 3/9] arm64: dts: ls1043a: fix typo of MSI compatible string
From: Minghuan Lian @ 2017-01-05 8:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483603837-4629-1-git-send-email-Minghuan.Lian@nxp.com>
"1" should be replaced by "l". This is a typo.
The patch is to fix it.
Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com>
---
v2-v1:
- None
arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
index ec13a6e..692fc35 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
@@ -589,21 +589,21 @@
};
msi1: msi-controller1 at 1571000 {
- compatible = "fsl,1s1043a-msi";
+ compatible = "fsl,ls1043a-msi";
reg = <0x0 0x1571000 0x0 0x8>;
msi-controller;
interrupts = <0 116 0x4>;
};
msi2: msi-controller2 at 1572000 {
- compatible = "fsl,1s1043a-msi";
+ compatible = "fsl,ls1043a-msi";
reg = <0x0 0x1572000 0x0 0x8>;
msi-controller;
interrupts = <0 126 0x4>;
};
msi3: msi-controller3 at 1573000 {
- compatible = "fsl,1s1043a-msi";
+ compatible = "fsl,ls1043a-msi";
reg = <0x0 0x1573000 0x0 0x8>;
msi-controller;
interrupts = <0 160 0x4>;
--
1.9.1
^ permalink raw reply related
* [PATCH v2,2/9] arm: dts: ls1021a: fix typo of MSI compatible string
From: Minghuan Lian @ 2017-01-05 8:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483603837-4629-1-git-send-email-Minghuan.Lian@nxp.com>
"1" should be replaced by "l". This is a typo.
The patch is to fix it.
Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com>
---
v2-v1:
- None
arch/arm/boot/dts/ls1021a.dtsi | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi
index 282d854..6651938 100644
--- a/arch/arm/boot/dts/ls1021a.dtsi
+++ b/arch/arm/boot/dts/ls1021a.dtsi
@@ -122,14 +122,14 @@
};
msi1: msi-controller at 1570e00 {
- compatible = "fsl,1s1021a-msi";
+ compatible = "fsl,ls1021a-msi";
reg = <0x0 0x1570e00 0x0 0x8>;
msi-controller;
interrupts = <GIC_SPI 179 IRQ_TYPE_LEVEL_HIGH>;
};
msi2: msi-controller at 1570e08 {
- compatible = "fsl,1s1021a-msi";
+ compatible = "fsl,ls1021a-msi";
reg = <0x0 0x1570e08 0x0 0x8>;
msi-controller;
interrupts = <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>;
--
1.9.1
^ permalink raw reply related
* [PATCH v2, 1/9] irqchip/ls-scfg-msi: fix typo of MSI compatible strings
From: Minghuan Lian @ 2017-01-05 8:10 UTC (permalink / raw)
To: linux-arm-kernel
The patch is to fix typo of the Layerscape SCFG MSI dts compatible
strings. "1" is replaced by "l".
Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com>
Acked-by: Rob Herring <robh@kernel.org>
---
v2-v1:
- None
.../devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt | 6 +++---
drivers/irqchip/irq-ls-scfg-msi.c | 6 ++++--
2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
index 9e38949..2755cd1 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
@@ -4,8 +4,8 @@ Required properties:
- compatible: should be "fsl,<soc-name>-msi" to identify
Layerscape PCIe MSI controller block such as:
- "fsl,1s1021a-msi"
- "fsl,1s1043a-msi"
+ "fsl,ls1021a-msi"
+ "fsl,ls1043a-msi"
- msi-controller: indicates that this is a PCIe MSI controller node
- reg: physical base address of the controller and length of memory mapped.
- interrupts: an interrupt to the parent interrupt controller.
@@ -23,7 +23,7 @@ MSI controller node
Examples:
msi1: msi-controller at 1571000 {
- compatible = "fsl,1s1043a-msi";
+ compatible = "fsl,ls1043a-msi";
reg = <0x0 0x1571000 0x0 0x8>,
msi-controller;
interrupts = <0 116 0x4>;
diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c
index 02cca74c..cef67cc 100644
--- a/drivers/irqchip/irq-ls-scfg-msi.c
+++ b/drivers/irqchip/irq-ls-scfg-msi.c
@@ -219,8 +219,10 @@ static int ls_scfg_msi_remove(struct platform_device *pdev)
}
static const struct of_device_id ls_scfg_msi_id[] = {
- { .compatible = "fsl,1s1021a-msi", },
- { .compatible = "fsl,1s1043a-msi", },
+ { .compatible = "fsl,1s1021a-msi", }, /* a typo */
+ { .compatible = "fsl,1s1043a-msi", }, /* a typo */
+ { .compatible = "fsl,ls1021a-msi", },
+ { .compatible = "fsl,ls1043a-msi", },
{},
};
--
1.9.1
^ permalink raw reply related
* [PATCH RESEND] dmaengine: stm32-dma: Add error messages if xlate fails
From: M'boumba Cedric Madianga @ 2017-01-05 8:09 UTC (permalink / raw)
To: linux-arm-kernel
This patch adds some error messages when a slave device fails to request a
channel.
Signed-off-by: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
Reviewed-by: Ludovic BARRE <ludovic.barre@st.com>
---
Resolve conflicts issue
---
drivers/dma/stm32-dma.c | 24 +++++++++++++++---------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c
index fc9738e..4eacd9d 100644
--- a/drivers/dma/stm32-dma.c
+++ b/drivers/dma/stm32-dma.c
@@ -987,30 +987,36 @@ static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec,
struct of_dma *ofdma)
{
struct stm32_dma_device *dmadev = ofdma->of_dma_data;
+ struct device *dev = dmadev->ddev.dev;
struct stm32_dma_cfg cfg;
struct stm32_dma_chan *chan;
struct dma_chan *c;
- if (dma_spec->args_count < 3)
+ if (dma_spec->args_count < 4) {
+ dev_err(dev, "Bad number of cells\n");
return NULL;
+ }
cfg.channel_id = dma_spec->args[0];
cfg.request_line = dma_spec->args[1];
cfg.stream_config = dma_spec->args[2];
- cfg.threshold = 0;
+ cfg.threshold = dma_spec->args[3];
- if ((cfg.channel_id >= STM32_DMA_MAX_CHANNELS) || (cfg.request_line >=
- STM32_DMA_MAX_REQUEST_ID))
+ if ((cfg.channel_id >= STM32_DMA_MAX_CHANNELS) ||
+ (cfg.request_line >= STM32_DMA_MAX_REQUEST_ID)) {
+ dev_err(dev, "Bad channel and/or request id\n");
return NULL;
-
- if (dma_spec->args_count > 3)
- cfg.threshold = dma_spec->args[3];
+ }
chan = &dmadev->chan[cfg.channel_id];
c = dma_get_slave_channel(&chan->vchan.chan);
- if (c)
- stm32_dma_set_config(chan, &cfg);
+ if (!c) {
+ dev_err(dev, "No more channel avalaible\n");
+ return NULL;
+ }
+
+ stm32_dma_set_config(chan, &cfg);
return c;
}
--
1.9.1
^ permalink raw reply related
* [PATCH 05/22] ARM: dtsi: axp209: add AXP209 ADC subnode
From: Quentin Schulz @ 2017-01-05 8:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGb2v66dw=DECuHpLDzHnMP-O4UwZ+RkPsH0RofOGdBa7z7OHw@mail.gmail.com>
On 05/01/2017 06:51, Chen-Yu Tsai wrote:
> On Tue, Jan 3, 2017 at 12:37 AM, Quentin Schulz
> <quentin.schulz@free-electrons.com> wrote:
>> X-Powers AXP209 PMIC has multiple ADCs, each one exposing data from the
>> different power supplies connected to the PMIC.
>>
>> This adds the ADC subnode for AXP20X PMIC.
>>
>> Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
>> ---
>> arch/arm/boot/dts/axp209.dtsi | 5 +++++
>> 1 file changed, 5 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/axp209.dtsi b/arch/arm/boot/dts/axp209.dtsi
>> index 675bb0f..2a4e8ee 100644
>> --- a/arch/arm/boot/dts/axp209.dtsi
>> +++ b/arch/arm/boot/dts/axp209.dtsi
>> @@ -53,6 +53,11 @@
>> interrupt-controller;
>> #interrupt-cells = <1>;
>>
>> + axp209_adc: axp209_adc {
>
> Node name should be generic. Please change it to "adc".
>
OK, do I keep the label as is?
axp209_adc: adc {
Thanks,
Quentin
--
Quentin Schulz, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
^ permalink raw reply
* [PATCH 03/22] iio: adc: add support for X-Powers AXP20X and AXP22X PMICs ADCs
From: Quentin Schulz @ 2017-01-05 8:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGb2v67S==AG=jZA=mO-bB4u1F2TOwhmBXg385W1xhUa3RAFbA@mail.gmail.com>
Hi Chen-Yu,
On 05/01/2017 06:42, Chen-Yu Tsai wrote:
> On Tue, Jan 3, 2017 at 12:37 AM, Quentin Schulz
> <quentin.schulz@free-electrons.com> wrote:
[...]
>> +
>> +#define AXP20X_ADC_RATE_MASK (3 << 6)
>> +#define AXP20X_ADC_RATE_25HZ (0 << 6)
>> +#define AXP20X_ADC_RATE_50HZ BIT(6)
>
> Please be consistent with the format.
>
>> +#define AXP20X_ADC_RATE_100HZ (2 << 6)
>> +#define AXP20X_ADC_RATE_200HZ (3 << 6)
>> +
>> +#define AXP22X_ADC_RATE_100HZ (0 << 6)
>> +#define AXP22X_ADC_RATE_200HZ BIT(6)
>> +#define AXP22X_ADC_RATE_400HZ (2 << 6)
>> +#define AXP22X_ADC_RATE_800HZ (3 << 6)
>
> These are power-of-2 multiples of some base rate. May I suggest
> a formula macro instead. Either way, you seem to be using only
> one value. Will this be made configurable in the future?
>
Yes, I could use a formula macro instead. No plan to make it
configurable, should I make it configurable?
>> +
>> +#define AXP20X_ADC_CHANNEL(_channel, _name, _type, _reg) \
>> + { \
>> + .type = _type, \
>> + .indexed = 1, \
>> + .channel = _channel, \
>> + .address = _reg, \
>> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
>> + BIT(IIO_CHAN_INFO_SCALE), \
>> + .datasheet_name = _name, \
>> + }
>> +
>> +#define AXP20X_ADC_CHANNEL_OFFSET(_channel, _name, _type, _reg) \
>> + { \
>> + .type = _type, \
>> + .indexed = 1, \
>> + .channel = _channel, \
>> + .address = _reg, \
>> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
>> + BIT(IIO_CHAN_INFO_SCALE) |\
>> + BIT(IIO_CHAN_INFO_OFFSET),\
>> + .datasheet_name = _name, \
>> + }
>> +
>> +struct axp20x_adc_iio {
>> + struct iio_dev *indio_dev;
>> + struct regmap *regmap;
>> +};
>> +
>> +enum axp20x_adc_channel {
>> + AXP20X_ACIN_V = 0,
>> + AXP20X_ACIN_I,
>> + AXP20X_VBUS_V,
>> + AXP20X_VBUS_I,
>> + AXP20X_TEMP_ADC,
>
> PMIC_TEMP would be better. And please save a slot for TS input.
>
ACK.
Hum.. I'm wondering what should be the IIO type of the TS input channel
then? The TS Pin can be used in two modes: either to monitor the
temperature of the battery or as an external ADC, at least that's what I
understand from the datasheet.
>> + AXP20X_GPIO0_V,
>> + AXP20X_GPIO1_V,
>
> Please skip a slot for "battery instantaneous power".
>
>> + AXP20X_BATT_V,
>> + AXP20X_BATT_CHRG_I,
>> + AXP20X_BATT_DISCHRG_I,
>> + AXP20X_IPSOUT_V,
>> +};
>> +
>> +enum axp22x_adc_channel {
>> + AXP22X_TEMP_ADC = 0,
>
> Same comments as AXP20X_TEMP_ADC.
>
>> + AXP22X_BATT_V,
>> + AXP22X_BATT_CHRG_I,
>> + AXP22X_BATT_DISCHRG_I,
>> +};
>
> Shouldn't these channel numbers be exported as part of the device tree
> bindings? At the very least, they shouldn't be changed.
>
I don't understand what you mean by that. Do you mean you want a
consistent numbering between the AXP20X and the AXP22X, so that
AXP22X_BATT_V would have the same channel number than AXP20X_BATT_V?
Could you explain a bit more your thoughts on the channel numbers being
exported as part of the device tree bindings?
> Also please add a comment saying that the channels are numbered
> in the order of their respective registers, and not the table
> describing the ADCs in the datasheet (9.7 Signal Capture for AXP209
> and 9.5 E-Gauge for AXP221).
>
Yes I can.
What about Rob wanting channel numbers to start at zero for each
different IIO type (i.e., today we have AXP22X_BATT_CHRG_I being
exported as in_current1_raw whereas he wants in_current0_raw).
[...]
>> +static int axp22x_adc_read_raw(struct iio_dev *indio_dev,
>> + struct iio_chan_spec const *channel, int *val,
>> + int *val2)
>> +{
>> + struct axp20x_adc_iio *info = iio_priv(indio_dev);
>> + int size = 12, ret;
>> +
>> + switch (channel->channel) {
>> + case AXP22X_BATT_DISCHRG_I:
>> + size = 13;
>> + case AXP22X_TEMP_ADC:
>> + case AXP22X_BATT_V:
>> + case AXP22X_BATT_CHRG_I:
>
> According to the datasheet, AXP22X_BATT_CHRG_I is also 13 bits wide.
>
Where did you get that?
Also, the datasheet is inconsistent:
- 9.5 E-Gauge Fuel Gauge system => the min value is at 0x0 and the max
value at 0xfff for all channels, that's 12 bits.
- 10.1.4 ADC Data => all channels except battery discharge current are
on 12 bits (8 high, 4 low).
[...]
>> +static int axp22x_read_raw(struct iio_dev *indio_dev,
>> + struct iio_chan_spec const *chan, int *val,
>> + int *val2, long mask)
>> +{
>> + switch (mask) {
>> + case IIO_CHAN_INFO_OFFSET:
>> + *val = -2667;
>
> Datasheet says -267.7 C, or -2677 here.
>
The formula in the datasheet is (in milli Celsius):
processed = raw * 100 - 266700;
while the IIO framework asks for a scale and an offset which are then
applied as:
processed = (raw + offset) * scale;
Thus by factorizing, we get:
processed = (raw - 2667) * 100;
[...]
>> +static int axp20x_remove(struct platform_device *pdev)
>> +{
>> + struct axp20x_adc_iio *info;
>> + struct iio_dev *indio_dev = platform_get_drvdata(pdev);
>> +
>> + info = iio_priv(indio_dev);
>
> Nit: you could just reverse the 2 declarations above and join this
> line after struct axp20x_adc_iio *info;
>
>> + regmap_write(info->regmap, AXP20X_ADC_EN1, 0);
>> + regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
>
> The existing VBUS power supply driver enables the VBUS ADC bits itself,
> and does not check them later on. This means if one were to remove this
> axp20x-adc module, the voltage/current readings in the VBUS power supply
> would be invalid. Some sort of workaround would be needed here in this
> driver of the VBUS driver.
>
That would be one reason to migrate the VBUS driver to use the IIO
channels, wouldn't it?
But ACK, I'll think about something to work around this issue.
>> +
>> + return 0;
>> +}
>> +
>> +static struct platform_driver axp20x_adc_driver = {
>> + .driver = {
>> + .name = "axp20x-adc",
>> + .of_match_table = axp20x_adc_of_match,
>> + },
>> + .probe = axp20x_probe,
>> + .remove = axp20x_remove,
>> +};
>> +
>> +module_platform_driver(axp20x_adc_driver);
>> +
>> +MODULE_DESCRIPTION("ADC driver for AXP20X and AXP22X PMICs");
>> +MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");
>> +MODULE_LICENSE("GPL");
>> diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h
>> index a4860bc..650c6f6 100644
>> --- a/include/linux/mfd/axp20x.h
>> +++ b/include/linux/mfd/axp20x.h
>> @@ -150,6 +150,10 @@ enum {
>> #define AXP20X_VBUS_I_ADC_L 0x5d
>> #define AXP20X_TEMP_ADC_H 0x5e
>> #define AXP20X_TEMP_ADC_L 0x5f
>> +
>> +#define AXP22X_TEMP_ADC_H 0x56
>> +#define AXP22X_TEMP_ADC_L 0x57
>> +
>
> This is in the wrong patch. Also we already have
>
> /* AXP22X specific registers */
> #define AXP22X_PMIC_ADC_H 0x56
> #define AXP22X_PMIC_ADC_L 0x57
> #define AXP22X_TS_ADC_H 0x58
> #define AXP22X_TS_ADC_L 0x59
>
> If you want, you could just rename them to be consistent.
>
ACK.
Thanks,
Quentin
--
Quentin Schulz, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
^ permalink raw reply
* [PATCH 6/9] arm64: dts: ls1046a: add MSI dts node
From: M.H. Lian @ 2017-01-05 8:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170103171258.h5djzsarokjjldjx@rob-hp-laptop>
Hi Rob,
Thanks for your comment.
I will change whitespace.
Thanks,
Minghuan
> -----Original Message-----
> From: Rob Herring [mailto:robh at kernel.org]
> Sent: Wednesday, January 04, 2017 1:13 AM
> To: M.H. Lian <minghuan.lian@nxp.com>
> Cc: linux-arm-kernel at lists.infradead.org; linux-kernel at vger.kernel.org;
> devicetree at vger.kernel.org; Marc Zyngier <marc.zyngier@arm.com>; Jason
> Cooper <jason@lakedaemon.net>; Roy Zang <roy.zang@nxp.com>; Mingkai
> Hu <mingkai.hu@nxp.com>; Stuart Yoder <stuart.yoder@nxp.com>; Leo Li
> <leoyang.li@nxp.com>; Scott Wood <scott.wood@nxp.com>
> Subject: Re: [PATCH 6/9] arm64: dts: ls1046a: add MSI dts node
>
> On Tue, Dec 27, 2016 at 05:13:02PM +0800, Minghuan Lian wrote:
> > LS1046a includes 3 MSI controllers.
> > Each controller supports 128 interrupts.
> >
> > Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com>
> > ---
> > .../interrupt-controller/fsl,ls-scfg-msi.txt | 1 +
> > arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 31
> ++++++++++++++++++++++
> > 2 files changed, 32 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-
> scfg-msi.txt b/Documentation/devicetree/bindings/interrupt-
> controller/fsl,ls-scfg-msi.txt
> > index 2755cd1..54597b0 100644
> > --- a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-
> msi.txt
> > +++ b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-
> msi.txt
> > @@ -6,6 +6,7 @@ Required properties:
> > Layerscape PCIe MSI controller block such as:
> > "fsl,ls1021a-msi"
> > "fsl,ls1043a-msi"
> > + "fsl,ls1046a-msi"
>
> Differing whitespace.
>
> Otherwise,
>
> Acked-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* [GIT PULL] Renesas ARM Based SoC Fixes for v4.10
From: Simon Horman @ 2017-01-05 7:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <3426031.nFTgvuDslP@wuerfel>
On Wed, Jan 04, 2017 at 04:10:09PM +0100, Arnd Bergmann wrote:
> On Monday, December 12, 2016 9:30:00 AM CET Simon Horman wrote:
> > This provides an sd0_uhs node rather than duplicate sdh0 nodes
> > resolving an error introduced in a clean-up patch.
> >
> > This pull request is based on "Second Round of Renesas ARM Based SoC DT
> > Updates for v4.10", tagged as renesas-arm64-dt2-for-v4.10,
> > which you have already pulled. The error corrected by this change
> > was introduced in that pull-request.
> >
>
> Pulled into fixes, sorry for the delay.
Great, thanks!
^ permalink raw reply
* [PATCH v2] mfd: mc13xxx: Set the irq type.
From: Lee Jones @ 2017-01-05 7:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAM=E1R59oKhT3b8=nJ3Utg4cPi0Z6oiLkj8DU7grg6T+2CoMAw@mail.gmail.com>
Thomas,
On Wed, 04 Jan 2017, Magnus Lilja wrote:
> On 4 January 2017 at 12:09, Lee Jones <lee.jones@linaro.org> wrote:
> > On Fri, 30 Dec 2016, Magnus Lilja wrote:
> >
> >> Commit 10f9edaeaa30 ("mfd: mc13xxx: Use regmap irq framework for
> >> interrupts") removed the passing of the IRQF_TRIGGER_HIGH flag when
> >> registering the interrupt.
> >> This commit fixes that problem by setting the IRQF_TRIGGER_HIGH flag in
> >> case no irq type is set via irqd framework (e.g. device tree). In the
> >> latter case the irq flag from irqd is used.
> >
> > This looks like a hack.
> >
> > Why can't you set the trigger type in Device Tree instead?
>
> The i.MX31 PDK board has not, like many (all?) i.MX31 boards, not been
> converted to use device tree yet. I think there is work in progress in
> this area. However, as the IRQF_TRIGGER problem also affects several
> stable kernel series (since 3.18.x) I thought it was worthwhile to fix
> this.
I would like Thomas' advice on this.
> >> Tested on i.MX31 PDK hardware.
> >>
> >> Fixes: 10f9edaeaa30 ("mfd: mc13xxx: Use regmap irq framework for interrupts")
> >> Cc: <stable@vger.kernel.org> # 3.18.x
> >> Cc: Lee Jones <lee.jones@linaro.org>
> >> Signed-off-by: Magnus Lilja <lilja.magnus@gmail.com>
> >> ---
> >> Changes from v1 (which was part of a patch series):
> >> - Now uses irqd_-functions to check if irq type is defined
> >> - Added Fixes: and Cc: to stable kernel.
> >>
> >> drivers/mfd/mc13xxx-core.c | 8 +++++++-
> >> 1 file changed, 7 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
> >> index d7f54e4..e1757ea 100644
> >> --- a/drivers/mfd/mc13xxx-core.c
> >> +++ b/drivers/mfd/mc13xxx-core.c
> >> @@ -15,6 +15,7 @@
> >> #include <linux/of_device.h>
> >> #include <linux/platform_device.h>
> >> #include <linux/mfd/core.h>
> >> +#include <linux/irq.h>
> >>
> >> #include "mc13xxx.h"
> >>
> >> @@ -410,6 +411,7 @@ int mc13xxx_common_init(struct device *dev)
> >> struct mc13xxx *mc13xxx = dev_get_drvdata(dev);
> >> u32 revision;
> >> int i, ret;
> >> + unsigned int flags;
> >>
> >> mc13xxx->dev = dev;
> >>
> >> @@ -440,7 +442,11 @@ int mc13xxx_common_init(struct device *dev)
> >> mc13xxx->irq_chip.irqs = mc13xxx->irqs;
> >> mc13xxx->irq_chip.num_irqs = ARRAY_SIZE(mc13xxx->irqs);
> >>
> >> - ret = regmap_add_irq_chip(mc13xxx->regmap, mc13xxx->irq, IRQF_ONESHOT,
> >> + flags = irqd_get_trigger_type(irq_get_irq_data(mc13xxx->irq));
> >> + flags = (flags == IRQ_TYPE_NONE) ? IRQF_TRIGGER_HIGH : flags;
> >> +
> >> + ret = regmap_add_irq_chip(mc13xxx->regmap, mc13xxx->irq,
> >> + IRQF_ONESHOT | flags,
> >> 0, &mc13xxx->irq_chip, &mc13xxx->irq_data);
> >> if (ret)
> >> return ret;
> >
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* [PATCH V7 3/4] drm/bridge: Add driver for GE B850v3 LVDS/DP++ Bridge
From: Archit Taneja @ 2017-01-05 7:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4232c88a99f44a24287d04d74b891e2eb139864c.1483301745.git.peter.senna@collabora.com>
Hi,
Some comments below.
On 01/02/2017 01:54 AM, Peter Senna Tschudin wrote:
> Add a driver that create a drm_bridge and a drm_connector for the LVDS
> to DP++ display bridge of the GE B850v3.
>
> There are two physical bridges on the video signal pipeline: a
> STDP4028(LVDS to DP) and a STDP2690(DP to DP++). The hardware and
> firmware made it complicated for this binding to comprise two device
> tree nodes, as the design goal is to configure both bridges based on
> the LVDS signal, which leave the driver powerless to control the video
> processing pipeline. The two bridges behaves as a single bridge, and
> the driver is only needed for telling the host about EDID / HPD, and
> for giving the host powers to ack interrupts. The video signal pipeline
> is as follows:
>
> Host -> LVDS|--(STDP4028)--|DP -> DP|--(STDP2690)--|DP++ -> Video output
>
> Cc: Martyn Welch <martyn.welch@collabora.co.uk>
> Cc: Martin Donnelly <martin.donnelly@ge.com>
> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> Cc: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> Cc: Philipp Zabel <p.zabel@pengutronix.de>
> Cc: Rob Herring <robh@kernel.org>
> Cc: Fabio Estevam <fabio.estevam@nxp.com>
> CC: David Airlie <airlied@linux.ie>
> CC: Thierry Reding <treding@nvidia.com>
> CC: Thierry Reding <thierry.reding@gmail.com>
> CC: Archit Taneja <architt@codeaurora.org>
> Reviewed-by: Enric Balletbo <enric.balletbo@collabora.com>
> Signed-off-by: Peter Senna Tschudin <peter.senna@collabora.com>
> ---
> drivers/gpu/drm/bridge/Kconfig | 11 +
> drivers/gpu/drm/bridge/Makefile | 1 +
> drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c | 384 +++++++++++++++++++++++++++++
> 3 files changed, 396 insertions(+)
> create mode 100644 drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c
>
> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
> index eb8688e..e3e1f3b 100644
> --- a/drivers/gpu/drm/bridge/Kconfig
> +++ b/drivers/gpu/drm/bridge/Kconfig
> @@ -48,6 +48,17 @@ config DRM_DW_HDMI_I2S_AUDIO
> Support the I2S Audio interface which is part of the Synopsis
> Designware HDMI block.
>
> +config DRM_GE_B850V3_LVDS_DP
> + tristate "GE B850v3 LVDS to DP++ display bridge"
> + depends on OF
> + select DRM_KMS_HELPER
> + select DRM_PANEL
> + ---help---
> + This is a driver for the display bridge of
> + GE B850v3 that convert dual channel LVDS
> + to DP++. This is used with the i.MX6 imx-ldb
> + driver.
> +
> config DRM_NXP_PTN3460
> tristate "NXP PTN3460 DP/LVDS bridge"
> depends on OF
> diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
> index 2e83a785..886d0fd 100644
> --- a/drivers/gpu/drm/bridge/Makefile
> +++ b/drivers/gpu/drm/bridge/Makefile
> @@ -5,6 +5,7 @@ obj-$(CONFIG_DRM_DUMB_VGA_DAC) += dumb-vga-dac.o
> obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
> obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
> obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o
> +obj-$(CONFIG_DRM_GE_B850V3_LVDS_DP) += ge_b850v3_lvds_dp.o
> obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
> obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
> obj-$(CONFIG_DRM_SIL_SII8620) += sil-sii8620.o
> diff --git a/drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c b/drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c
> new file mode 100644
> index 0000000..4574f6e
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c
> @@ -0,0 +1,384 @@
> +/*
> + * Driver for GE B850v3 DP display bridge
Mentioning LVDS to DP++ here would be nice.
> +
> + * Copyright (c) 2016, Collabora Ltd.
> + * Copyright (c) 2016, General Electric Company
> +
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> +
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
> +
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> +
> + * This driver creates a drm_bridge and a drm_connector for the LVDS to DP++
> + * display bridge of the GE B850v3. There are two physical bridges on the video
> + * signal pipeline: a STDP4028(LVDS to DP) and a STDP2690(DP to DP++). However
> + * the physical bridges are automatically configured by the input video signal,
> + * and the driver has no access to the video processing pipeline. The driver is
> + * only needed to read EDID from the STDP2690 and to handle HPD events from the
> + * STDP4028. The driver communicates with both bridges over i2c. The video
> + * signal pipeline is as follows:
> + *
> + * Host -> LVDS|--(STDP4028)--|DP -> DP|--(STDP2690)--|DP++ -> Video output
> + *
> + */
> +
> +#include <linux/gpio.h>
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_edid.h>
> +#include <drm/drmP.h>
> +
> +#define DEFAULT_EDID_REG 0x72
> +#define DEFAULT_EDID_REG_NAME "edid"
> +
> +#define EDID_EXT_BLOCK_CNT 0x7E
> +
> +#define STDP4028_IRQ_OUT_CONF_REG 0x02
> +#define STDP4028_DPTX_IRQ_EN_REG 0x3C
> +#define STDP4028_DPTX_IRQ_STS_REG 0x3D
> +#define STDP4028_DPTX_STS_REG 0x3E
> +
> +#define STDP4028_DPTX_DP_IRQ_EN 0x1000
> +
> +#define STDP4028_DPTX_HOTPLUG_IRQ_EN 0x0400
> +#define STDP4028_DPTX_LINK_CH_IRQ_EN 0x2000
> +#define STDP4028_DPTX_IRQ_CONFIG \
> + (STDP4028_DPTX_LINK_CH_IRQ_EN | STDP4028_DPTX_HOTPLUG_IRQ_EN)
> +
> +#define STDP4028_DPTX_HOTPLUG_STS 0x0200
> +#define STDP4028_DPTX_LINK_STS 0x1000
> +#define STDP4028_CON_STATE_CONNECTED \
> + (STDP4028_DPTX_HOTPLUG_STS | STDP4028_DPTX_LINK_STS)
> +
> +#define STDP4028_DPTX_HOTPLUG_CH_STS 0x0400
> +#define STDP4028_DPTX_LINK_CH_STS 0x2000
> +#define STDP4028_DPTX_IRQ_CLEAR \
> + (STDP4028_DPTX_LINK_CH_STS | STDP4028_DPTX_HOTPLUG_CH_STS)
> +
> +struct ge_b850v3_lvds_dp {
> + struct drm_connector connector;
> + struct drm_bridge bridge;
> + struct i2c_client *ge_b850v3_lvds_dp_i2c;
> + struct i2c_client *edid_i2c;
> + struct edid *edid;
> + struct mutex edid_mutex;
> + struct mutex irq_reg_mutex;
> +};
> +
> +static inline struct ge_b850v3_lvds_dp *
> + bridge_to_ge_b850v3_lvds_dp(struct drm_bridge *bridge)
> +{
> + return container_of(bridge, struct ge_b850v3_lvds_dp, bridge);
> +}
> +
> +static inline struct ge_b850v3_lvds_dp *
> + connector_to_ge_b850v3_lvds_dp(struct drm_connector *connector)
> +{
> + return container_of(connector, struct ge_b850v3_lvds_dp, connector);
> +}
> +
> +u8 *stdp2690_get_edid(struct i2c_client *client)
> +{
> + struct i2c_adapter *adapter = client->adapter;
> + unsigned char start = 0x00;
> + unsigned int total_size;
> + u8 *block = kmalloc(EDID_LENGTH, GFP_KERNEL);
> +
> + struct i2c_msg msgs[] = {
> + {
> + .addr = client->addr,
> + .flags = 0,
> + .len = 1,
> + .buf = &start,
> + }, {
> + .addr = client->addr,
> + .flags = I2C_M_RD,
> + .len = EDID_LENGTH,
> + .buf = block,
> + }
> + };
> +
> + if (!block)
> + return NULL;
> +
> + if (i2c_transfer(adapter, msgs, 2) != 2) {
> + DRM_ERROR("Unable to read EDID.\n");
> + goto err;
> + }
> +
> + if (!drm_edid_block_valid(block, 0, false, NULL)) {
> + DRM_ERROR("Invalid EDID block\n");
> + goto err;
> + }
> +
> + total_size = (block[EDID_EXT_BLOCK_CNT] + 1) * EDID_LENGTH;
> + if (total_size > EDID_LENGTH) {
> + kfree(block);
> + block = kmalloc(total_size, GFP_KERNEL);
> + if (!block)
> + return NULL;
> +
> + /* Yes, read the entire buffer, and do not skip the first
> + * EDID_LENGTH bytes.
> + */
Is this the reason why you aren't using drm_do_get_edid()?
> + start = 0x00;
> + msgs[1].len = total_size;
> + msgs[1].buf = block;
> +
> + if (i2c_transfer(adapter, msgs, 2) != 2) {
> + DRM_ERROR("Unable to read EDID extension blocks.\n");
> + goto err;
> + }
We should ideally check if the extension blocks are valid too.
> + }
> +
> + return block;
> +
> +err:
> + kfree(block);
> + return NULL;
> +}
> +
> +static int ge_b850v3_lvds_dp_get_modes(struct drm_connector *connector)
> +{
> + struct ge_b850v3_lvds_dp *ptn_bridge;
Why are the bridge pointers named ptn_bridge? I'm guessing it's because you
used nxp-ptn3460 bridge driver as reference. You should use something relevant
to your device.
> + struct i2c_client *client;
> + int num_modes = 0;
> +
> + ptn_bridge = connector_to_ge_b850v3_lvds_dp(connector);
> + client = ptn_bridge->edid_i2c;
> +
> + mutex_lock(&ptn_bridge->edid_mutex);
Do we really need this mutex? All the paths that call a connector's get_modes
hold the drm device's dev->mode_config.mutex lock anyway.
> +
> + kfree(ptn_bridge->edid);
> + ptn_bridge->edid = (struct edid *) stdp2690_get_edid(client);
> +
> + if (ptn_bridge->edid) {
> + drm_mode_connector_update_edid_property(connector,
> + ptn_bridge->edid);
> + num_modes = drm_add_edid_modes(connector, ptn_bridge->edid);
> + }
> +
> + mutex_unlock(&ptn_bridge->edid_mutex);
> +
> + return num_modes;
> +}
> +
> +
> +static enum drm_mode_status ge_b850v3_lvds_dp_mode_valid(
> + struct drm_connector *connector, struct drm_display_mode *mode)
> +{
> + return MODE_OK;
> +}
> +
> +static const struct
> +drm_connector_helper_funcs ge_b850v3_lvds_dp_connector_helper_funcs = {
> + .get_modes = ge_b850v3_lvds_dp_get_modes,
> + .mode_valid = ge_b850v3_lvds_dp_mode_valid,
> +};
> +
> +static enum drm_connector_status ge_b850v3_lvds_dp_detect(
> + struct drm_connector *connector, bool force)
> +{
> + struct ge_b850v3_lvds_dp *ptn_bridge =
> + connector_to_ge_b850v3_lvds_dp(connector);
> + struct i2c_client *ge_b850v3_lvds_dp_i2c =
> + ptn_bridge->ge_b850v3_lvds_dp_i2c;
> + s32 link_state;
> +
> + link_state = i2c_smbus_read_word_data(ge_b850v3_lvds_dp_i2c,
> + STDP4028_DPTX_STS_REG);
> +
> + if (link_state == STDP4028_CON_STATE_CONNECTED)
> + return connector_status_connected;
> +
> + if (link_state == 0)
> + return connector_status_disconnected;
> +
> + return connector_status_unknown;
> +}
> +
> +static const struct drm_connector_funcs ge_b850v3_lvds_dp_connector_funcs = {
> + .dpms = drm_atomic_helper_connector_dpms,
> + .fill_modes = drm_helper_probe_single_connector_modes,
> + .detect = ge_b850v3_lvds_dp_detect,
> + .destroy = drm_connector_cleanup,
> + .reset = drm_atomic_helper_connector_reset,
> + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +};
> +
> +static irqreturn_t ge_b850v3_lvds_dp_irq_handler(int irq, void *dev_id)
> +{
> + struct ge_b850v3_lvds_dp *ptn_bridge = dev_id;
> + struct i2c_client *ge_b850v3_lvds_dp_i2c
> + = ptn_bridge->ge_b850v3_lvds_dp_i2c;
> +
> + mutex_lock(&ptn_bridge->irq_reg_mutex);
Do we need this mutex? The handler is registered with the IRQF_ONESHOT
flag, so we won't get another interrupt until this handler returns.
> +
> + i2c_smbus_write_word_data(ge_b850v3_lvds_dp_i2c,
> + STDP4028_DPTX_IRQ_STS_REG, STDP4028_DPTX_IRQ_CLEAR);
> +
> + mutex_unlock(&ptn_bridge->irq_reg_mutex);
> +
> + if (ptn_bridge->connector.dev)
> + drm_kms_helper_hotplug_event(ptn_bridge->connector.dev);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int ge_b850v3_lvds_dp_attach(struct drm_bridge *bridge)
> +{
> + struct ge_b850v3_lvds_dp *ptn_bridge
> + = bridge_to_ge_b850v3_lvds_dp(bridge);
> + struct drm_connector *connector = &ptn_bridge->connector;
> + struct i2c_client *ge_b850v3_lvds_dp_i2c
> + = ptn_bridge->ge_b850v3_lvds_dp_i2c;
> + int ret;
> +
> + if (!bridge->encoder) {
> + DRM_ERROR("Parent encoder object not found");
> + return -ENODEV;
> + }
> +
> + connector->polled = DRM_CONNECTOR_POLL_HPD;
> +
> + drm_connector_helper_add(connector,
> + &ge_b850v3_lvds_dp_connector_helper_funcs);
> +
> + ret = drm_connector_init(bridge->dev, connector,
> + &ge_b850v3_lvds_dp_connector_funcs,
> + DRM_MODE_CONNECTOR_DisplayPort);
> + if (ret) {
> + DRM_ERROR("Failed to initialize connector with drm\n");
> + return ret;
> + }
> +
> + ret = drm_mode_connector_attach_encoder(connector, bridge->encoder);
> + if (ret)
> + return ret;
> +
> + drm_helper_hpd_irq_event(connector->dev);
This call doesn't serve any purpose for a connector until it is registered.
You can drop this.
> +
> + /* Configures the bridge to re-enable interrupts after each ack. */
> + i2c_smbus_write_word_data(ge_b850v3_lvds_dp_i2c,
> + STDP4028_IRQ_OUT_CONF_REG, STDP4028_DPTX_DP_IRQ_EN);
> +
> + /* Enable interrupts */
> + i2c_smbus_write_word_data(ge_b850v3_lvds_dp_i2c,
> + STDP4028_DPTX_IRQ_EN_REG, STDP4028_DPTX_IRQ_CONFIG);
> +
> + return 0;
> +}
> +
> +static void ge_b850v3_lvds_dp_detach(struct drm_bridge *bridge)
> +{
> + struct ge_b850v3_lvds_dp *ptn_bridge
> + = bridge_to_ge_b850v3_lvds_dp(bridge);
> + struct i2c_client *ge_b850v3_lvds_dp_i2c
> + = ptn_bridge->ge_b850v3_lvds_dp_i2c;
> +
> + /* Disable interrupts */
> + i2c_smbus_write_word_data(ge_b850v3_lvds_dp_i2c,
> + STDP4028_DPTX_IRQ_EN_REG, ~STDP4028_DPTX_IRQ_CONFIG);
> +}
> +
> +static const struct drm_bridge_funcs ge_b850v3_lvds_dp_funcs = {
> + .attach = ge_b850v3_lvds_dp_attach,
> + .detach = ge_b850v3_lvds_dp_detach,
> +};
> +
> +static int ge_b850v3_lvds_dp_probe(struct i2c_client *ge_b850v3_lvds_dp_i2c,
> + const struct i2c_device_id *id)
> +{
> + struct device *dev = &ge_b850v3_lvds_dp_i2c->dev;
> + struct ge_b850v3_lvds_dp *ptn_bridge;
> +
> + ptn_bridge = devm_kzalloc(dev, sizeof(*ptn_bridge), GFP_KERNEL);
> + if (!ptn_bridge)
> + return -ENOMEM;
> +
> + mutex_init(&ptn_bridge->edid_mutex);
> + mutex_init(&ptn_bridge->irq_reg_mutex);
> +
> + ptn_bridge->ge_b850v3_lvds_dp_i2c = ge_b850v3_lvds_dp_i2c;
> + ptn_bridge->bridge.driver_private = ptn_bridge;
bridge->driver_private isn't used by the driver anywhere. It's probably
better to drop it until it is used.
> + i2c_set_clientdata(ge_b850v3_lvds_dp_i2c, ptn_bridge);
> +
> + ptn_bridge->edid_i2c = i2c_new_secondary_device(ge_b850v3_lvds_dp_i2c,
> + DEFAULT_EDID_REG_NAME, DEFAULT_EDID_REG);
> +
> + if (!ptn_bridge->edid_i2c) {
> + dev_err(dev, "Error registering edid i2c_client, aborting...\n");
> + return -ENODEV;
> + }
> +
> + ptn_bridge->bridge.funcs = &ge_b850v3_lvds_dp_funcs;
> + ptn_bridge->bridge.of_node = dev->of_node;
> + drm_bridge_add(&ptn_bridge->bridge);
> +
> + /* Clear pending interrupts since power up. */
> + i2c_smbus_write_word_data(ge_b850v3_lvds_dp_i2c,
> + STDP4028_DPTX_IRQ_STS_REG, STDP4028_DPTX_IRQ_CLEAR);
> +
> + if (!ge_b850v3_lvds_dp_i2c->irq)
> + return 0;
> +
> + return devm_request_threaded_irq(&ge_b850v3_lvds_dp_i2c->dev,
> + ge_b850v3_lvds_dp_i2c->irq, NULL,
> + ge_b850v3_lvds_dp_irq_handler,
> + IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
> + "ge-b850v3-lvds-dp", ptn_bridge);
> +}
> +
> +static int ge_b850v3_lvds_dp_remove(struct i2c_client *ge_b850v3_lvds_dp_i2c)
> +{
> + struct ge_b850v3_lvds_dp *ptn_bridge =
> + i2c_get_clientdata(ge_b850v3_lvds_dp_i2c);
> +
> + i2c_unregister_device(ptn_bridge->edid_i2c);
> +
> + drm_bridge_remove(&ptn_bridge->bridge);
> +
> + kfree(ptn_bridge->edid);
> +
> + return 0;
> +}
> +
> +static const struct i2c_device_id ge_b850v3_lvds_dp_i2c_table[] = {
> + {"b850v3-lvds-dp", 0},
> + {},
> +};
> +MODULE_DEVICE_TABLE(i2c, ge_b850v3_lvds_dp_i2c_table);
> +
> +static const struct of_device_id ge_b850v3_lvds_dp_match[] = {
> + { .compatible = "ge,b850v3-lvds-dp" },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, ge_b850v3_lvds_dp_match);
> +
> +static struct i2c_driver ge_b850v3_lvds_dp_driver = {
> + .id_table = ge_b850v3_lvds_dp_i2c_table,
> + .probe = ge_b850v3_lvds_dp_probe,
> + .remove = ge_b850v3_lvds_dp_remove,
> + .driver = {
> + .name = "b850v3-lvds-dp",
> + .of_match_table = ge_b850v3_lvds_dp_match,
> + },
> +};
> +module_i2c_driver(ge_b850v3_lvds_dp_driver);
> +
> +MODULE_AUTHOR("Peter Senna Tschudin <peter.senna@collabora.com>");
> +MODULE_AUTHOR("Martyn Welch <martyn.welch@collabora.co.uk>");
> +MODULE_DESCRIPTION("GE LVDS to DP++ display bridge)");
> +MODULE_LICENSE("GPL v2");
>
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* [PATCH 1/2] mfd: micon: Add Buffalo Kurobox Pro, Terastation II Pro/Live driver
From: Lee Jones @ 2017-01-05 7:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <3e9b7bfe-8305-64fc-f175-e612576d58a7@gmail.com>
On Wed, 04 Jan 2017, Florian Fainelli wrote:
> Le 01/04/17 ? 03:22, Lee Jones a ?crit :
> > On Wed, 28 Dec 2016, Florian Fainelli wrote:
> >
> >> This driver is currently only used to reboot the devices, but the
> >> microcontroller hanging off UART1 on the Buffalo Kurobox Pro and
> >> Terastation II Pro/Live is capable of a lot more than that, which we
> >> will support in subsequent patches. For now, just add the reboot
> >> functionality to make the kernel reboot correctly.
> >
> > This is not an MFD driver. You have written a UART driver.
> >
> > Please relocate it to drivers/char/tty/serial.
>
> Not that simple, and as explained in the cover letter the UART attached
> micro controller can do a lot more than just reboot the machine, but
That's fine. This is precisely why we have MFD. But the core (MFD)
driver should only conduct set-up of shared resources, registration of
child devices and maybe some shared functionality required by >1 child
device. All child device (i.e. UART) capability should be handled by
the child drivers.
> someone else is working on the driver, so this patch series can be ignored.
Okay.
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* [PATCH v6 5/5] soc: zte: pm_domains: Add support for zx296718
From: Shawn Guo @ 2017-01-05 7:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483530494-14177-5-git-send-email-baoyou.xie@linaro.org>
On Wed, Jan 04, 2017 at 07:48:14PM +0800, Baoyou Xie wrote:
> This patch introduces the power domain driver of zx296718
> which belongs to zte's zx2967 family.
>
> Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
> Reviewed-by: Jun Nie <jun.nie@linaro.org>
> ---
> drivers/soc/zte/Makefile | 1 +
> drivers/soc/zte/zx296718_pm_domains.c | 181 ++++++++++++++++++++++++++++++++++
> 2 files changed, 182 insertions(+)
> create mode 100644 drivers/soc/zte/zx296718_pm_domains.c
>
> diff --git a/drivers/soc/zte/Makefile b/drivers/soc/zte/Makefile
> index 8a37f2f..96b7cd4 100644
> --- a/drivers/soc/zte/Makefile
> +++ b/drivers/soc/zte/Makefile
> @@ -2,3 +2,4 @@
> # ZTE SOC drivers
> #
> obj-$(CONFIG_ZX2967_PM_DOMAINS) += zx2967_pm_domains.o
> +obj-$(CONFIG_ZX2967_PM_DOMAINS) += zx296718_pm_domains.o
> diff --git a/drivers/soc/zte/zx296718_pm_domains.c b/drivers/soc/zte/zx296718_pm_domains.c
> new file mode 100644
> index 0000000..52003ee
> --- /dev/null
> +++ b/drivers/soc/zte/zx296718_pm_domains.c
> @@ -0,0 +1,181 @@
> +/*
> + * Copyright (C) 2017 ZTE Ltd.
> + *
> + * Author: Baoyou Xie <baoyou.xie@linaro.org>
> + * License terms: GNU General Public License (GPL) version 2
> + */
Please have a newline between licence declaration and headers to improve
the readability. Same for zx2967_pm_domains.c.
> +#include <dt-bindings/soc/zte,pm_domains.h>
> +#include "zx2967_pm_domains.h"
> +
> +static u16 zx296718_offsets[REG_ARRAY_SIZE] = {
> + [REG_CLKEN] = 0x18,
> + [REG_ISOEN] = 0x1c,
> + [REG_RSTEN] = 0x20,
> + [REG_PWREN] = 0x24,
> + [REG_ACK_SYNC] = 0x28,
> +};
> +
> +enum {
> + PCU_DM_VOU = 0,
> + PCU_DM_SAPPU,
> + PCU_DM_VDE,
> + PCU_DM_VCE,
> + PCU_DM_HDE,
> + PCU_DM_VIU,
> + PCU_DM_USB20,
> + PCU_DM_USB21,
> + PCU_DM_USB30,
> + PCU_DM_HSIC,
> + PCU_DM_GMAC,
> + PCU_DM_TS,
> +};
I think we can save this enum completely by defining those
DM_ZX296718_xxx constants in zte,pm_domains.h in the same order of this
enum (hardware bit position order), so that DM_ZX296718_xxx can directly
be used as .bit field of struct zx2967_pm_domain.
#define DM_ZX296718_VOU 0
#define DM_ZX296718_SAPPU 1
#define DM_ZX296718_VDE 2 /* g1v6 */
#define DM_ZX296718_VCE 3 /* h1v6 */
#define DM_ZX296718_HDE 4 /* g2v2 */
#define DM_ZX296718_VIU 5
#define DM_ZX296718_USB20 6
#define DM_ZX296718_USB21 7
#define DM_ZX296718_USB30 8
#define DM_ZX296718_HSIC 9
#define DM_ZX296718_GMAC 10
#define DM_ZX296718_TS 11
> +
> +static struct zx2967_pm_domain vou_domain = {
> + .dm = {
> + .name = "vou_domain",
> + },
> + .bit = PCU_DM_VOU,
> + .polarity = PWREN,
> + .reg_offset = zx296718_offsets,
> +};
> +
> +static struct zx2967_pm_domain sappu_domain = {
> + .dm = {
> + .name = "sappu_domain",
> + },
> + .bit = PCU_DM_SAPPU,
> + .polarity = PWREN,
> + .reg_offset = zx296718_offsets,
> +};
> +
> +static struct zx2967_pm_domain vde_domain = {
> + .dm = {
> + .name = "vde_domain",
> + },
> + .bit = PCU_DM_VDE,
> + .polarity = PWREN,
> + .reg_offset = zx296718_offsets,
> +};
> +
> +static struct zx2967_pm_domain vce_domain = {
> + .dm = {
> + .name = "vce_domain",
> + },
> + .bit = PCU_DM_VCE,
> + .polarity = PWREN,
> + .reg_offset = zx296718_offsets,
> +};
> +
> +static struct zx2967_pm_domain hde_domain = {
> + .dm = {
> + .name = "hde_domain",
> + },
> + .bit = PCU_DM_HDE,
> + .polarity = PWREN,
> + .reg_offset = zx296718_offsets,
> +};
> +
> +static struct zx2967_pm_domain viu_domain = {
> + .dm = {
> + .name = "viu_domain",
> + },
> + .bit = PCU_DM_VIU,
> + .polarity = PWREN,
> + .reg_offset = zx296718_offsets,
> +};
> +
> +static struct zx2967_pm_domain usb20_domain = {
> + .dm = {
> + .name = "usb20_domain",
> + },
> + .bit = PCU_DM_USB20,
> + .polarity = PWREN,
> + .reg_offset = zx296718_offsets,
> +};
> +
> +static struct zx2967_pm_domain usb21_domain = {
> + .dm = {
> + .name = "usb21_domain",
> + },
> + .bit = PCU_DM_USB21,
> + .polarity = PWREN,
> + .reg_offset = zx296718_offsets,
> +};
> +
> +static struct zx2967_pm_domain usb30_domain = {
> + .dm = {
> + .name = "usb30_domain",
> + },
> + .bit = PCU_DM_USB30,
> + .polarity = PWREN,
> + .reg_offset = zx296718_offsets,
> +};
> +
> +static struct zx2967_pm_domain hsic_domain = {
> + .dm = {
> + .name = "hsic_domain",
> + },
> + .bit = PCU_DM_HSIC,
> + .polarity = PWREN,
> + .reg_offset = zx296718_offsets,
> +};
> +
> +static struct zx2967_pm_domain gmac_domain = {
> + .dm = {
> + .name = "gmac_domain",
> + },
> + .bit = PCU_DM_GMAC,
> + .polarity = PWREN,
> + .reg_offset = zx296718_offsets,
> +};
> +
> +static struct zx2967_pm_domain ts_domain = {
> + .dm = {
> + .name = "ts_domain",
> + },
> + .bit = PCU_DM_TS,
> + .polarity = PWREN,
> + .reg_offset = zx296718_offsets,
> +};
> +
> +static struct generic_pm_domain *zx296718_pm_domains[] = {
> + [DM_ZX296718_SAPPU] = &sappu_domain.dm,
> + [DM_ZX296718_VDE] = &vde_domain.dm,
> + [DM_ZX296718_VCE] = &vce_domain.dm,
> + [DM_ZX296718_HDE] = &hde_domain.dm,
> + [DM_ZX296718_VIU] = &viu_domain.dm,
> + [DM_ZX296718_USB20] = &usb20_domain.dm,
> + [DM_ZX296718_USB21] = &usb21_domain.dm,
> + [DM_ZX296718_USB30] = &usb30_domain.dm,
> + [DM_ZX296718_HSIC] = &hsic_domain.dm,
> + [DM_ZX296718_GMAC] = &gmac_domain.dm,
> + [DM_ZX296718_TS] = &ts_domain.dm,
> + [DM_ZX296718_VOU] = &vou_domain.dm,
If you update the order of DM_ZX296718_xxx in zte,pm_domains.h, it would
be nice to update this list accordingly as well.
> +};
> +
> +static int zx296718_pd_probe(struct platform_device *pdev)
> +{
> + return zx2967_pd_probe(pdev,
> + zx296718_pm_domains,
> + ARRAY_SIZE(zx296718_pm_domains));
> +}
> +
> +static const struct of_device_id zx296718_pm_domain_matches[] = {
> + { .compatible = "zte,zx296718-pcu", },
> + { },
> +};
> +
> +static struct platform_driver zx296718_pd_driver = {
> + .driver = {
> + .name = "zx-powerdomain",
This is a zx296718 specific driver. So zx296718-powerdomain should
be a better name?
Shawn
> + .owner = THIS_MODULE,
> + .of_match_table = zx296718_pm_domain_matches,
> + },
> + .probe = zx296718_pd_probe,
> +};
> +
> +static int __init zx296718_pd_init(void)
> +{
> + return platform_driver_register(&zx296718_pd_driver);
> +}
> +subsys_initcall(zx296718_pd_init);
> --
> 2.7.4
>
^ permalink raw reply
* [PATCH v3 2/3] drm: zte: add .atomic_disable hook to disable graphic layer
From: Sean Paul @ 2017-01-05 7:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482979048-32037-3-git-send-email-shawnguo@kernel.org>
On Wed, Dec 28, 2016 at 9:37 PM, Shawn Guo <shawnguo@kernel.org> wrote:
> From: Shawn Guo <shawn.guo@linaro.org>
>
> There are a few hardware bits for each graphic layer to control main/aux
> channel and clock selection, as well as the layer enabling. These bits
> sit outside the layer block itself, but in VOU control glue block. We
> currently set these bits up at CRTC initialization for once, and do not
> support disabling the layer.
>
> This patch creates a pair of functions zx_vou_layer_enable[disable] to
> be invoked from plane hooks .atomic_update and .atomic_disable to set up
> and tear down the layer. This is generic for both graphic and video
> layers, so it will make the overlay plane support to be added later much
> easier.
>
This feels ever so slightly awkward since the plane is calling back to
the crtc in enable/disable, but i suppose this is a byproduct of
defining the atomic plane hooks in zx_plane. I think we just need to
be careful not to introduce more of these cross-block/file
dependencies, as that might signify that zx_plane should be merged
into zx_vou. At the moment, I feel like this is fine, so,
Reviewed-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> ---
> drivers/gpu/drm/zte/zx_plane.c | 15 +++++++++
> drivers/gpu/drm/zte/zx_plane.h | 1 +
> drivers/gpu/drm/zte/zx_vou.c | 70 ++++++++++++++++++++++++++++++------------
> drivers/gpu/drm/zte/zx_vou.h | 3 ++
> 4 files changed, 69 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/gpu/drm/zte/zx_plane.c b/drivers/gpu/drm/zte/zx_plane.c
> index 78d29b1db91c..5445eebf830f 100644
> --- a/drivers/gpu/drm/zte/zx_plane.c
> +++ b/drivers/gpu/drm/zte/zx_plane.c
> @@ -197,12 +197,27 @@ static void zx_gl_plane_atomic_update(struct drm_plane *plane,
> /* Enable HBSC block */
> zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN);
>
> + zx_vou_layer_enable(plane);
> +
> zx_gl_set_update(zplane);
> }
>
> +static void zx_plane_atomic_disable(struct drm_plane *plane,
> + struct drm_plane_state *old_state)
> +{
> + struct zx_plane *zplane = to_zx_plane(plane);
> + void __iomem *hbsc = zplane->hbsc;
> +
> + zx_vou_layer_disable(plane);
> +
> + /* Disable HBSC block */
> + zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, 0);
> +}
> +
> static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = {
> .atomic_check = zx_gl_plane_atomic_check,
> .atomic_update = zx_gl_plane_atomic_update,
> + .atomic_disable = zx_plane_atomic_disable,
> };
>
> static void zx_plane_destroy(struct drm_plane *plane)
> diff --git a/drivers/gpu/drm/zte/zx_plane.h b/drivers/gpu/drm/zte/zx_plane.h
> index 264a92e0b532..933611ddffd0 100644
> --- a/drivers/gpu/drm/zte/zx_plane.h
> +++ b/drivers/gpu/drm/zte/zx_plane.h
> @@ -18,6 +18,7 @@ struct zx_plane {
> void __iomem *csc;
> void __iomem *hbsc;
> void __iomem *rsz;
> + const struct vou_layer_bits *bits;
> };
>
> #define to_zx_plane(plane) container_of(plane, struct zx_plane, plane)
> diff --git a/drivers/gpu/drm/zte/zx_vou.c b/drivers/gpu/drm/zte/zx_vou.c
> index d5c801f6f97b..3fb4fc04e693 100644
> --- a/drivers/gpu/drm/zte/zx_vou.c
> +++ b/drivers/gpu/drm/zte/zx_vou.c
> @@ -65,7 +65,6 @@ struct zx_crtc_bits {
> u32 polarity_shift;
> u32 int_frame_mask;
> u32 tc_enable;
> - u32 gl_enable;
> };
>
> static const struct zx_crtc_bits main_crtc_bits = {
> @@ -73,7 +72,6 @@ struct zx_crtc_bits {
> .polarity_shift = MAIN_POL_SHIFT,
> .int_frame_mask = TIMING_INT_MAIN_FRAME,
> .tc_enable = MAIN_TC_EN,
> - .gl_enable = OSD_CTRL0_GL0_EN,
> };
>
> static const struct zx_crtc_bits aux_crtc_bits = {
> @@ -81,7 +79,6 @@ struct zx_crtc_bits {
> .polarity_shift = AUX_POL_SHIFT,
> .int_frame_mask = TIMING_INT_AUX_FRAME,
> .tc_enable = AUX_TC_EN,
> - .gl_enable = OSD_CTRL0_GL1_EN,
> };
>
> struct zx_crtc {
> @@ -97,6 +94,24 @@ struct zx_crtc {
>
> #define to_zx_crtc(x) container_of(x, struct zx_crtc, crtc)
>
> +struct vou_layer_bits {
> + u32 enable;
> + u32 chnsel;
> + u32 clksel;
> +};
> +
> +static const struct vou_layer_bits zx_gl_bits[GL_NUM] = {
> + {
> + .enable = OSD_CTRL0_GL0_EN,
> + .chnsel = OSD_CTRL0_GL0_SEL,
> + .clksel = VOU_CLK_GL0_SEL,
> + }, {
> + .enable = OSD_CTRL0_GL1_EN,
> + .chnsel = OSD_CTRL0_GL1_SEL,
> + .clksel = VOU_CLK_GL1_SEL,
> + },
> +};
> +
> struct zx_vou_hw {
> struct device *dev;
> void __iomem *osd;
> @@ -220,10 +235,6 @@ static void zx_crtc_enable(struct drm_crtc *crtc)
> /* Enable channel */
> zx_writel_mask(zcrtc->chnreg + CHN_CTRL0, CHN_ENABLE, CHN_ENABLE);
>
> - /* Enable Graphic Layer */
> - zx_writel_mask(vou->osd + OSD_CTRL0, bits->gl_enable,
> - bits->gl_enable);
> -
> drm_crtc_vblank_on(crtc);
>
> ret = clk_set_rate(zcrtc->pixclk, mode->clock * 1000);
> @@ -247,9 +258,6 @@ static void zx_crtc_disable(struct drm_crtc *crtc)
>
> drm_crtc_vblank_off(crtc);
>
> - /* Disable Graphic Layer */
> - zx_writel_mask(vou->osd + OSD_CTRL0, bits->gl_enable, 0);
> -
> /* Disable channel */
> zx_writel_mask(zcrtc->chnreg + CHN_CTRL0, CHN_ENABLE, 0);
>
> @@ -316,6 +324,7 @@ static int zx_crtc_init(struct drm_device *drm, struct zx_vou_hw *vou,
> zplane->csc = vou->osd + MAIN_CSC_OFFSET;
> zplane->hbsc = vou->osd + MAIN_HBSC_OFFSET;
> zplane->rsz = vou->otfppu + MAIN_RSZ_OFFSET;
> + zplane->bits = &zx_gl_bits[0];
> zcrtc->chnreg = vou->osd + OSD_MAIN_CHN;
> zcrtc->regs = &main_crtc_regs;
> zcrtc->bits = &main_crtc_bits;
> @@ -324,6 +333,7 @@ static int zx_crtc_init(struct drm_device *drm, struct zx_vou_hw *vou,
> zplane->csc = vou->osd + AUX_CSC_OFFSET;
> zplane->hbsc = vou->osd + AUX_HBSC_OFFSET;
> zplane->rsz = vou->otfppu + AUX_RSZ_OFFSET;
> + zplane->bits = &zx_gl_bits[1];
> zcrtc->chnreg = vou->osd + OSD_AUX_CHN;
> zcrtc->regs = &aux_crtc_regs;
> zcrtc->bits = &aux_crtc_bits;
> @@ -411,6 +421,36 @@ void zx_vou_disable_vblank(struct drm_device *drm, unsigned int pipe)
> zcrtc->bits->int_frame_mask, 0);
> }
>
> +void zx_vou_layer_enable(struct drm_plane *plane)
> +{
> + struct zx_crtc *zcrtc = to_zx_crtc(plane->state->crtc);
> + struct zx_vou_hw *vou = zcrtc->vou;
> + struct zx_plane *zplane = to_zx_plane(plane);
> + const struct vou_layer_bits *bits = zplane->bits;
> +
> + if (zcrtc->chn_type == VOU_CHN_MAIN) {
> + zx_writel_mask(vou->osd + OSD_CTRL0, bits->chnsel, 0);
> + zx_writel_mask(vou->vouctl + VOU_CLK_SEL, bits->clksel, 0);
> + } else {
> + zx_writel_mask(vou->osd + OSD_CTRL0, bits->chnsel,
> + bits->chnsel);
> + zx_writel_mask(vou->vouctl + VOU_CLK_SEL, bits->clksel,
> + bits->clksel);
> + }
> +
> + zx_writel_mask(vou->osd + OSD_CTRL0, bits->enable, bits->enable);
> +}
> +
> +void zx_vou_layer_disable(struct drm_plane *plane)
> +{
> + struct zx_crtc *zcrtc = to_zx_crtc(plane->crtc);
> + struct zx_vou_hw *vou = zcrtc->vou;
> + struct zx_plane *zplane = to_zx_plane(plane);
> + const struct vou_layer_bits *bits = zplane->bits;
> +
> + zx_writel_mask(vou->osd + OSD_CTRL0, bits->enable, 0);
> +}
> +
> static irqreturn_t vou_irq_handler(int irq, void *dev_id)
> {
> struct zx_vou_hw *vou = dev_id;
> @@ -469,19 +509,9 @@ static void vou_dtrc_init(struct zx_vou_hw *vou)
>
> static void vou_hw_init(struct zx_vou_hw *vou)
> {
> - /* Set GL0 to main channel and GL1 to aux channel */
> - zx_writel_mask(vou->osd + OSD_CTRL0, OSD_CTRL0_GL0_SEL, 0);
> - zx_writel_mask(vou->osd + OSD_CTRL0, OSD_CTRL0_GL1_SEL,
> - OSD_CTRL0_GL1_SEL);
> -
> /* Release reset for all VOU modules */
> zx_writel(vou->vouctl + VOU_SOFT_RST, ~0);
>
> - /* Select main clock for GL0 and aux clock for GL1 module */
> - zx_writel_mask(vou->vouctl + VOU_CLK_SEL, VOU_CLK_GL0_SEL, 0);
> - zx_writel_mask(vou->vouctl + VOU_CLK_SEL, VOU_CLK_GL1_SEL,
> - VOU_CLK_GL1_SEL);
> -
> /* Enable clock auto-gating for all VOU modules */
> zx_writel(vou->vouctl + VOU_CLK_REQEN, ~0);
>
> diff --git a/drivers/gpu/drm/zte/zx_vou.h b/drivers/gpu/drm/zte/zx_vou.h
> index 349e06cd86f4..4b4339be641b 100644
> --- a/drivers/gpu/drm/zte/zx_vou.h
> +++ b/drivers/gpu/drm/zte/zx_vou.h
> @@ -43,4 +43,7 @@ struct vou_inf {
> int zx_vou_enable_vblank(struct drm_device *drm, unsigned int pipe);
> void zx_vou_disable_vblank(struct drm_device *drm, unsigned int pipe);
>
> +void zx_vou_layer_enable(struct drm_plane *plane);
> +void zx_vou_layer_disable(struct drm_plane *plane);
> +
> #endif /* __ZX_VOU_H__ */
> --
> 1.9.1
>
--
Sean Paul, Software Engineer, Google / Chromium OS
^ permalink raw reply
* [PATCH v3 1/3] drm: zte: make zx_plane accessible from zx_vou driver
From: Sean Paul @ 2017-01-05 7:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482979048-32037-2-git-send-email-shawnguo@kernel.org>
On Wed, Dec 28, 2016 at 9:37 PM, Shawn Guo <shawnguo@kernel.org> wrote:
> From: Shawn Guo <shawn.guo@linaro.org>
>
> Move struct zx_plane from zx_plane.c to zx_plane.h, so that it can be
> accessed from zx_vou driver, and we can save the use of struct
> zx_layer_data completely. More importantly, those additional data used
> by VOU controller to enable/disable graphic and video layers can later
> be added and accessed much more easily from zx_vou driver.
>
> While at it, we make two changes to zx_plane_init() interface:
>
> - Encode struct device pointer in zx_plane, so that we do not need to
> pass it as a parameter.
> - Change return of zx_plane_init() from struct drm_plane pointer to
> error code, since we can get the pointer from zx_plane in zx_vou
> driver now.
>
Reviewed-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> ---
> drivers/gpu/drm/zte/zx_plane.c | 36 +++++++-----------------------------
> drivers/gpu/drm/zte/zx_plane.h | 11 +++++++----
> drivers/gpu/drm/zte/zx_vou.c | 31 +++++++++++++++++++------------
> 3 files changed, 33 insertions(+), 45 deletions(-)
>
> diff --git a/drivers/gpu/drm/zte/zx_plane.c b/drivers/gpu/drm/zte/zx_plane.c
> index 546eb92a94e8..78d29b1db91c 100644
> --- a/drivers/gpu/drm/zte/zx_plane.c
> +++ b/drivers/gpu/drm/zte/zx_plane.c
> @@ -21,16 +21,6 @@
> #include "zx_plane_regs.h"
> #include "zx_vou.h"
>
> -struct zx_plane {
> - struct drm_plane plane;
> - void __iomem *layer;
> - void __iomem *csc;
> - void __iomem *hbsc;
> - void __iomem *rsz;
> -};
> -
> -#define to_zx_plane(plane) container_of(plane, struct zx_plane, plane)
> -
> static const uint32_t gl_formats[] = {
> DRM_FORMAT_ARGB8888,
> DRM_FORMAT_XRGB8888,
> @@ -248,28 +238,16 @@ static void zx_plane_hbsc_init(struct zx_plane *zplane)
> zx_writel(hbsc + HBSC_THRESHOLD_COL3, (0x3c0 << 16) | 0x40);
> }
>
> -struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
> - struct zx_layer_data *data,
> - enum drm_plane_type type)
> +int zx_plane_init(struct drm_device *drm, struct zx_plane *zplane,
> + enum drm_plane_type type)
> {
> const struct drm_plane_helper_funcs *helper;
> - struct zx_plane *zplane;
> - struct drm_plane *plane;
> + struct drm_plane *plane = &zplane->plane;
> + struct device *dev = zplane->dev;
> const uint32_t *formats;
> unsigned int format_count;
> int ret;
>
> - zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL);
> - if (!zplane)
> - return ERR_PTR(-ENOMEM);
> -
> - plane = &zplane->plane;
> -
> - zplane->layer = data->layer;
> - zplane->hbsc = data->hbsc;
> - zplane->csc = data->csc;
> - zplane->rsz = data->rsz;
> -
> zx_plane_hbsc_init(zplane);
>
> switch (type) {
> @@ -282,7 +260,7 @@ struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
> /* TODO: add video layer (vl) support */
> break;
> default:
> - return ERR_PTR(-ENODEV);
> + return -ENODEV;
> }
>
> ret = drm_universal_plane_init(drm, plane, VOU_CRTC_MASK,
> @@ -290,10 +268,10 @@ struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
> type, NULL);
> if (ret) {
> DRM_DEV_ERROR(dev, "failed to init universal plane: %d\n", ret);
> - return ERR_PTR(ret);
> + return ret;
> }
>
> drm_plane_helper_add(plane, helper);
>
> - return plane;
> + return 0;
> }
> diff --git a/drivers/gpu/drm/zte/zx_plane.h b/drivers/gpu/drm/zte/zx_plane.h
> index 2b82cd558d9d..264a92e0b532 100644
> --- a/drivers/gpu/drm/zte/zx_plane.h
> +++ b/drivers/gpu/drm/zte/zx_plane.h
> @@ -11,16 +11,19 @@
> #ifndef __ZX_PLANE_H__
> #define __ZX_PLANE_H__
>
> -struct zx_layer_data {
> +struct zx_plane {
> + struct drm_plane plane;
> + struct device *dev;
> void __iomem *layer;
> void __iomem *csc;
> void __iomem *hbsc;
> void __iomem *rsz;
> };
>
> -struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
> - struct zx_layer_data *data,
> - enum drm_plane_type type);
> +#define to_zx_plane(plane) container_of(plane, struct zx_plane, plane)
> +
> +int zx_plane_init(struct drm_device *drm, struct zx_plane *zplane,
> + enum drm_plane_type type);
> void zx_plane_set_update(struct drm_plane *plane);
>
> #endif /* __ZX_PLANE_H__ */
> diff --git a/drivers/gpu/drm/zte/zx_vou.c b/drivers/gpu/drm/zte/zx_vou.c
> index 73fe15c17c32..d5c801f6f97b 100644
> --- a/drivers/gpu/drm/zte/zx_vou.c
> +++ b/drivers/gpu/drm/zte/zx_vou.c
> @@ -294,7 +294,7 @@ static int zx_crtc_init(struct drm_device *drm, struct zx_vou_hw *vou,
> enum vou_chn_type chn_type)
> {
> struct device *dev = vou->dev;
> - struct zx_layer_data data;
> + struct zx_plane *zplane;
> struct zx_crtc *zcrtc;
> int ret;
>
> @@ -305,19 +305,25 @@ static int zx_crtc_init(struct drm_device *drm, struct zx_vou_hw *vou,
> zcrtc->vou = vou;
> zcrtc->chn_type = chn_type;
>
> + zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL);
> + if (!zplane)
> + return -ENOMEM;
> +
> + zplane->dev = dev;
> +
> if (chn_type == VOU_CHN_MAIN) {
> - data.layer = vou->osd + MAIN_GL_OFFSET;
> - data.csc = vou->osd + MAIN_CSC_OFFSET;
> - data.hbsc = vou->osd + MAIN_HBSC_OFFSET;
> - data.rsz = vou->otfppu + MAIN_RSZ_OFFSET;
> + zplane->layer = vou->osd + MAIN_GL_OFFSET;
> + zplane->csc = vou->osd + MAIN_CSC_OFFSET;
> + zplane->hbsc = vou->osd + MAIN_HBSC_OFFSET;
> + zplane->rsz = vou->otfppu + MAIN_RSZ_OFFSET;
> zcrtc->chnreg = vou->osd + OSD_MAIN_CHN;
> zcrtc->regs = &main_crtc_regs;
> zcrtc->bits = &main_crtc_bits;
> } else {
> - data.layer = vou->osd + AUX_GL_OFFSET;
> - data.csc = vou->osd + AUX_CSC_OFFSET;
> - data.hbsc = vou->osd + AUX_HBSC_OFFSET;
> - data.rsz = vou->otfppu + AUX_RSZ_OFFSET;
> + zplane->layer = vou->osd + AUX_GL_OFFSET;
> + zplane->csc = vou->osd + AUX_CSC_OFFSET;
> + zplane->hbsc = vou->osd + AUX_HBSC_OFFSET;
> + zplane->rsz = vou->otfppu + AUX_RSZ_OFFSET;
> zcrtc->chnreg = vou->osd + OSD_AUX_CHN;
> zcrtc->regs = &aux_crtc_regs;
> zcrtc->bits = &aux_crtc_bits;
> @@ -331,13 +337,14 @@ static int zx_crtc_init(struct drm_device *drm, struct zx_vou_hw *vou,
> return ret;
> }
>
> - zcrtc->primary = zx_plane_init(drm, dev, &data, DRM_PLANE_TYPE_PRIMARY);
> - if (IS_ERR(zcrtc->primary)) {
> - ret = PTR_ERR(zcrtc->primary);
> + ret = zx_plane_init(drm, zplane, DRM_PLANE_TYPE_PRIMARY);
> + if (ret) {
> DRM_DEV_ERROR(dev, "failed to init primary plane: %d\n", ret);
> return ret;
> }
>
> + zcrtc->primary = &zplane->plane;
> +
> ret = drm_crtc_init_with_planes(drm, &zcrtc->crtc, zcrtc->primary, NULL,
> &zx_crtc_funcs, NULL);
> if (ret) {
> --
> 1.9.1
>
--
Sean Paul, Software Engineer, Google / Chromium OS
^ permalink raw reply
* [PATCH v3 3/3] drm: zte: add overlay plane support
From: Sean Paul @ 2017-01-05 7:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482979048-32037-4-git-send-email-shawnguo@kernel.org>
On Wed, Dec 28, 2016 at 9:37 PM, Shawn Guo <shawnguo@kernel.org> wrote:
> From: Shawn Guo <shawn.guo@linaro.org>
>
> It enables VOU VL (Video Layer) to support overlay plane with scaling
> function. VL0 has some quirks on scaling support. We choose to skip it
> and only adds VL1 and VL2 into DRM core for now.
>
> Function zx_plane_atomic_disable() gets moved around with no changes to
> save a forward declaration.
>
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> ---
> drivers/gpu/drm/zte/zx_plane.c | 311 +++++++++++++++++++++++++++++++++---
> drivers/gpu/drm/zte/zx_plane_regs.h | 51 ++++++
> drivers/gpu/drm/zte/zx_vou.c | 80 +++++++++-
> drivers/gpu/drm/zte/zx_vou_regs.h | 18 +++
> 4 files changed, 431 insertions(+), 29 deletions(-)
>
> diff --git a/drivers/gpu/drm/zte/zx_plane.c b/drivers/gpu/drm/zte/zx_plane.c
> index 5445eebf830f..c5ac42647735 100644
> --- a/drivers/gpu/drm/zte/zx_plane.c
> +++ b/drivers/gpu/drm/zte/zx_plane.c
> @@ -30,6 +30,275 @@
> DRM_FORMAT_ARGB4444,
> };
>
> +static const uint32_t vl_formats[] = {
> + DRM_FORMAT_NV12, /* Semi-planar YUV420 */
> + DRM_FORMAT_YUV420, /* Planar YUV420 */
> + DRM_FORMAT_YUYV, /* Packed YUV422 */
> + DRM_FORMAT_YVYU,
> + DRM_FORMAT_UYVY,
> + DRM_FORMAT_VYUY,
> + DRM_FORMAT_YUV444, /* YUV444 8bit */
> + /*
> + * TODO: add formats below that HW supports:
> + * - YUV420 P010
> + * - YUV420 Hantro
> + * - YUV444 10bit
> + */
> +};
> +
> +#define FRAC_16_16(mult, div) (((mult) << 16) / (div))
> +
> +static int zx_vl_plane_atomic_check(struct drm_plane *plane,
> + struct drm_plane_state *plane_state)
> +{
> + struct drm_framebuffer *fb = plane_state->fb;
> + struct drm_crtc *crtc = plane_state->crtc;
> + struct drm_crtc_state *crtc_state;
> + struct drm_rect clip;
> + int min_scale = FRAC_16_16(1, 8);
> + int max_scale = FRAC_16_16(8, 1);
> +
> + if (!crtc || !fb)
> + return 0;
> +
> + crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state,
> + crtc);
> + if (WARN_ON(!crtc_state))
> + return -EINVAL;
> +
> + /* nothing to check when disabling or disabled */
> + if (!crtc_state->enable)
> + return 0;
> +
> + /* plane must be enabled */
> + if (!plane_state->crtc)
> + return -EINVAL;
> +
> + clip.x1 = 0;
> + clip.y1 = 0;
> + clip.x2 = crtc_state->adjusted_mode.hdisplay;
> + clip.y2 = crtc_state->adjusted_mode.vdisplay;
> +
> + return drm_plane_helper_check_state(plane_state, &clip,
> + min_scale, max_scale,
> + true, true);
> +}
> +
> +static u32 zx_vl_get_fmt(uint32_t format)
> +{
> + u32 val = 0;
> +
> + switch (format) {
> + case DRM_FORMAT_NV12:
> + val = VL_FMT_YUV420;
> + break;
> + case DRM_FORMAT_YUV420:
> + val = VL_YUV420_PLANAR | VL_FMT_YUV420;
> + break;
> + case DRM_FORMAT_YUYV:
> + val = VL_YUV422_YUYV | VL_FMT_YUV422;
> + break;
> + case DRM_FORMAT_YVYU:
> + val = VL_YUV422_YVYU | VL_FMT_YUV422;
> + break;
> + case DRM_FORMAT_UYVY:
> + val = VL_YUV422_UYVY | VL_FMT_YUV422;
> + break;
> + case DRM_FORMAT_VYUY:
> + val = VL_YUV422_VYUY | VL_FMT_YUV422;
> + break;
> + case DRM_FORMAT_YUV444:
> + val = VL_FMT_YUV444_8BIT;
Minor nit: You could have eliminated val and just returned directly
from all of the cases. Seems like there are a few other functions this
is also true for.
> + break;
> + default:
> + WARN_ONCE(1, "invalid pixel format %d\n", format);
> + }
> +
> + return val;
> +}
> +
> +static inline void zx_vl_set_update(struct zx_plane *zplane)
> +{
> + void __iomem *layer = zplane->layer;
> +
> + zx_writel_mask(layer + VL_CTRL0, VL_UPDATE, VL_UPDATE);
> +}
> +
> +static inline void zx_vl_rsz_set_update(struct zx_plane *zplane)
> +{
> + zx_writel(zplane->rsz + RSZ_VL_ENABLE_CFG, 1);
> +}
> +
> +static u32 zx_vl_rsz_get_fmt(uint32_t format)
> +{
> + u32 val = 0;
> +
> + switch (format) {
> + case DRM_FORMAT_NV12:
> + case DRM_FORMAT_YUV420:
> + val = RSZ_VL_FMT_YCBCR420;
> + break;
> + case DRM_FORMAT_YUYV:
> + case DRM_FORMAT_YVYU:
> + case DRM_FORMAT_UYVY:
> + case DRM_FORMAT_VYUY:
> + val = RSZ_VL_FMT_YCBCR422;
> + break;
> + case DRM_FORMAT_YUV444:
> + val = RSZ_VL_FMT_YCBCR444;
> + break;
> + default:
> + WARN_ONCE(1, "invalid pixel format %d\n", format);
> + }
> +
> + return val;
> +}
> +
> +static inline u32 rsz_step_value(u32 src, u32 dst)
> +{
> + u32 val = 0;
> +
> + if (src == dst)
> + val = 0;
> + else if (src < dst)
> + val = RSZ_PARA_STEP((src << 16) / dst);
> + else if (src > dst)
> + val = RSZ_DATA_STEP(src / dst) |
> + RSZ_PARA_STEP(((src << 16) / dst) & 0xffff);
> +
> + return val;
> +}
> +
> +static void zx_vl_rsz_setup(struct zx_plane *zplane, uint32_t format,
> + u32 src_w, u32 src_h, u32 dst_w, u32 dst_h)
> +{
> + void __iomem *rsz = zplane->rsz;
> + u32 src_chroma_w = src_w;
> + u32 src_chroma_h = src_h;
> + u32 fmt;
> +
> + /* Set up source and destination resolution */
> + zx_writel(rsz + RSZ_SRC_CFG, RSZ_VER(src_h - 1) | RSZ_HOR(src_w - 1));
> + zx_writel(rsz + RSZ_DEST_CFG, RSZ_VER(dst_h - 1) | RSZ_HOR(dst_w - 1));
> +
> + /* Configure data format for VL RSZ */
> + fmt = zx_vl_rsz_get_fmt(format);
> + zx_writel_mask(rsz + RSZ_VL_CTRL_CFG, RSZ_VL_FMT_MASK, fmt);
> +
> + /* Calculate Chroma heigth and width */
s/heigth/height/
> + if (fmt == RSZ_VL_FMT_YCBCR420) {
> + src_chroma_w = src_w >> 1;
> + src_chroma_h = src_h >> 1;
> + } else if (fmt == RSZ_VL_FMT_YCBCR422) {
> + src_chroma_w = src_w >> 1;
> + }
> +
> + /* Set up Luma and Chroma step registers */
> + zx_writel(rsz + RSZ_VL_LUMA_HOR, rsz_step_value(src_w, dst_w));
> + zx_writel(rsz + RSZ_VL_LUMA_VER, rsz_step_value(src_h, dst_h));
> + zx_writel(rsz + RSZ_VL_CHROMA_HOR, rsz_step_value(src_chroma_w, dst_w));
> + zx_writel(rsz + RSZ_VL_CHROMA_VER, rsz_step_value(src_chroma_h, dst_h));
> +
> + zx_vl_rsz_set_update(zplane);
> +}
> +
> +static void zx_vl_plane_atomic_update(struct drm_plane *plane,
> + struct drm_plane_state *old_state)
> +{
> + struct zx_plane *zplane = to_zx_plane(plane);
> + struct drm_plane_state *state = plane->state;
> + struct drm_framebuffer *fb = state->fb;
> + struct drm_rect *src = &state->src;
> + struct drm_rect *dst = &state->dst;
> + struct drm_gem_cma_object *cma_obj;
> + void __iomem *layer = zplane->layer;
> + void __iomem *hbsc = zplane->hbsc;
> + void __iomem *paddr_reg;
> + dma_addr_t paddr;
> + u32 src_x, src_y, src_w, src_h;
> + u32 dst_x, dst_y, dst_w, dst_h;
> + uint32_t format;
> + u32 fmt;
> + int num_planes;
> + int i;
> +
> + if (!fb)
> + return;
> +
> + format = fb->pixel_format;
> +
> + src_x = src->x1 >> 16;
> + src_y = src->y1 >> 16;
> + src_w = drm_rect_width(src) >> 16;
> + src_h = drm_rect_height(src) >> 16;
> +
> + dst_x = dst->x1;
> + dst_y = dst->y1;
> + dst_w = drm_rect_width(dst);
> + dst_h = drm_rect_height(dst);
> +
> + /* Set up data address registers for Y, Cb and Cr planes */
> + num_planes = drm_format_num_planes(format);
> + paddr_reg = layer + VL_Y;
> + for (i = 0; i < num_planes; i++) {
> + cma_obj = drm_fb_cma_get_gem_obj(fb, i);
> + paddr = cma_obj->paddr + fb->offsets[i];
> + paddr += src_y * fb->pitches[i];
> + paddr += src_x * drm_format_plane_cpp(format, i);
> + zx_writel(paddr_reg, paddr);
> + paddr_reg += 4;
> + }
> +
> + /* Set up source height/width register */
> + zx_writel(layer + VL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
> +
> + /* Set up start position register */
> + zx_writel(layer + VL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
> +
> + /* Set up end position register */
> + zx_writel(layer + VL_POS_END,
> + GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
> +
> + /* Strides of Cb and Cr planes should be identical */
> + zx_writel(layer + VL_STRIDE, LUMA_STRIDE(fb->pitches[0]) |
> + CHROMA_STRIDE(fb->pitches[1]));
> +
> + /* Set up video layer data format */
> + fmt = zx_vl_get_fmt(format);
> + zx_writel(layer + VL_CTRL1, fmt);
> +
> + /* Always use scaler since it exists (set for not bypass) */
> + zx_writel_mask(layer + VL_CTRL2, VL_SCALER_BYPASS_MODE,
> + VL_SCALER_BYPASS_MODE);
> +
> + zx_vl_rsz_setup(zplane, format, src_w, src_h, dst_w, dst_h);
> +
> + /* Enable HBSC block */
> + zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN);
> +
> + zx_vou_layer_enable(plane);
> +
> + zx_vl_set_update(zplane);
> +}
> +
> +static void zx_plane_atomic_disable(struct drm_plane *plane,
> + struct drm_plane_state *old_state)
> +{
> + struct zx_plane *zplane = to_zx_plane(plane);
> + void __iomem *hbsc = zplane->hbsc;
> +
> + zx_vou_layer_disable(plane);
> +
> + /* Disable HBSC block */
> + zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, 0);
> +}
> +
> +static const struct drm_plane_helper_funcs zx_vl_plane_helper_funcs = {
> + .atomic_check = zx_vl_plane_atomic_check,
> + .atomic_update = zx_vl_plane_atomic_update,
> + .atomic_disable = zx_plane_atomic_disable,
> +};
> +
> static int zx_gl_plane_atomic_check(struct drm_plane *plane,
> struct drm_plane_state *plane_state)
> {
> @@ -97,14 +366,6 @@ static inline void zx_gl_rsz_set_update(struct zx_plane *zplane)
> zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1);
> }
>
> -void zx_plane_set_update(struct drm_plane *plane)
> -{
> - struct zx_plane *zplane = to_zx_plane(plane);
> -
> - zx_gl_rsz_set_update(zplane);
> - zx_gl_set_update(zplane);
> -}
> -
> static void zx_gl_rsz_setup(struct zx_plane *zplane, u32 src_w, u32 src_h,
> u32 dst_w, u32 dst_h)
> {
> @@ -202,18 +463,6 @@ static void zx_gl_plane_atomic_update(struct drm_plane *plane,
> zx_gl_set_update(zplane);
> }
>
> -static void zx_plane_atomic_disable(struct drm_plane *plane,
> - struct drm_plane_state *old_state)
> -{
> - struct zx_plane *zplane = to_zx_plane(plane);
> - void __iomem *hbsc = zplane->hbsc;
> -
> - zx_vou_layer_disable(plane);
> -
> - /* Disable HBSC block */
> - zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, 0);
> -}
> -
> static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = {
> .atomic_check = zx_gl_plane_atomic_check,
> .atomic_update = zx_gl_plane_atomic_update,
> @@ -235,6 +484,24 @@ static void zx_plane_destroy(struct drm_plane *plane)
> .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
> };
>
> +void zx_plane_set_update(struct drm_plane *plane)
> +{
> + struct zx_plane *zplane = to_zx_plane(plane);
> +
> + switch (plane->type) {
> + case DRM_PLANE_TYPE_PRIMARY:
> + zx_gl_rsz_set_update(zplane);
> + zx_gl_set_update(zplane);
> + break;
> + case DRM_PLANE_TYPE_OVERLAY:
> + zx_vl_rsz_set_update(zplane);
> + zx_vl_set_update(zplane);
> + break;
> + default:
> + WARN_ONCE(1, "unsupported plane type %d\n", plane->type);
> + }
> +}
> +
> static void zx_plane_hbsc_init(struct zx_plane *zplane)
> {
> void __iomem *hbsc = zplane->hbsc;
> @@ -272,7 +539,9 @@ int zx_plane_init(struct drm_device *drm, struct zx_plane *zplane,
> format_count = ARRAY_SIZE(gl_formats);
> break;
> case DRM_PLANE_TYPE_OVERLAY:
> - /* TODO: add video layer (vl) support */
> + helper = &zx_vl_plane_helper_funcs;
> + formats = vl_formats;
> + format_count = ARRAY_SIZE(vl_formats);
> break;
> default:
> return -ENODEV;
> diff --git a/drivers/gpu/drm/zte/zx_plane_regs.h b/drivers/gpu/drm/zte/zx_plane_regs.h
> index 3dde6716a558..65f271aeabed 100644
> --- a/drivers/gpu/drm/zte/zx_plane_regs.h
> +++ b/drivers/gpu/drm/zte/zx_plane_regs.h
> @@ -46,6 +46,37 @@
> #define GL_POS_X(x) (((x) << GL_POS_X_SHIFT) & GL_POS_X_MASK)
> #define GL_POS_Y(x) (((x) << GL_POS_Y_SHIFT) & GL_POS_Y_MASK)
>
> +/* VL registers */
> +#define VL_CTRL0 0x00
> +#define VL_UPDATE BIT(3)
> +#define VL_CTRL1 0x04
> +#define VL_YUV420_PLANAR BIT(5)
> +#define VL_YUV422_SHIFT 3
> +#define VL_YUV422_YUYV (0 << VL_YUV422_SHIFT)
> +#define VL_YUV422_YVYU (1 << VL_YUV422_SHIFT)
> +#define VL_YUV422_UYVY (2 << VL_YUV422_SHIFT)
> +#define VL_YUV422_VYUY (3 << VL_YUV422_SHIFT)
> +#define VL_FMT_YUV420 0
> +#define VL_FMT_YUV422 1
> +#define VL_FMT_YUV420_P010 2
> +#define VL_FMT_YUV420_HANTRO 3
> +#define VL_FMT_YUV444_8BIT 4
> +#define VL_FMT_YUV444_10BIT 5
> +#define VL_CTRL2 0x08
> +#define VL_SCALER_BYPASS_MODE BIT(0)
> +#define VL_STRIDE 0x0c
> +#define LUMA_STRIDE_SHIFT 16
> +#define LUMA_STRIDE_MASK (0xffff << LUMA_STRIDE_SHIFT)
> +#define CHROMA_STRIDE_SHIFT 0
> +#define CHROMA_STRIDE_MASK (0xffff << CHROMA_STRIDE_SHIFT)
> +#define VL_SRC_SIZE 0x10
> +#define VL_Y 0x14
> +#define VL_POS_START 0x30
> +#define VL_POS_END 0x34
> +
> +#define LUMA_STRIDE(x) (((x) << LUMA_STRIDE_SHIFT) & LUMA_STRIDE_MASK)
> +#define CHROMA_STRIDE(x) (((x) << CHROMA_STRIDE_SHIFT) & CHROMA_STRIDE_MASK)
> +
> /* CSC registers */
> #define CSC_CTRL0 0x30
> #define CSC_COV_MODE_SHIFT 16
> @@ -69,6 +100,18 @@
> #define RSZ_DEST_CFG 0x04
> #define RSZ_ENABLE_CFG 0x14
>
> +#define RSZ_VL_LUMA_HOR 0x08
> +#define RSZ_VL_LUMA_VER 0x0c
> +#define RSZ_VL_CHROMA_HOR 0x10
> +#define RSZ_VL_CHROMA_VER 0x14
> +#define RSZ_VL_CTRL_CFG 0x18
> +#define RSZ_VL_FMT_SHIFT 3
> +#define RSZ_VL_FMT_MASK (0x3 << RSZ_VL_FMT_SHIFT)
> +#define RSZ_VL_FMT_YCBCR420 (0x0 << RSZ_VL_FMT_SHIFT)
> +#define RSZ_VL_FMT_YCBCR422 (0x1 << RSZ_VL_FMT_SHIFT)
> +#define RSZ_VL_FMT_YCBCR444 (0x2 << RSZ_VL_FMT_SHIFT)
> +#define RSZ_VL_ENABLE_CFG 0x1c
> +
> #define RSZ_VER_SHIFT 16
> #define RSZ_VER_MASK (0xffff << RSZ_VER_SHIFT)
> #define RSZ_HOR_SHIFT 0
> @@ -77,6 +120,14 @@
> #define RSZ_VER(x) (((x) << RSZ_VER_SHIFT) & RSZ_VER_MASK)
> #define RSZ_HOR(x) (((x) << RSZ_HOR_SHIFT) & RSZ_HOR_MASK)
>
> +#define RSZ_DATA_STEP_SHIFT 16
> +#define RSZ_DATA_STEP_MASK (0xffff << RSZ_DATA_STEP_SHIFT)
> +#define RSZ_PARA_STEP_SHIFT 0
> +#define RSZ_PARA_STEP_MASK (0xffff << RSZ_PARA_STEP_SHIFT)
> +
> +#define RSZ_DATA_STEP(x) (((x) << RSZ_DATA_STEP_SHIFT) & RSZ_DATA_STEP_MASK)
> +#define RSZ_PARA_STEP(x) (((x) << RSZ_PARA_STEP_SHIFT) & RSZ_PARA_STEP_MASK)
> +
> /* HBSC registers */
> #define HBSC_SATURATION 0x00
> #define HBSC_HUE 0x04
> diff --git a/drivers/gpu/drm/zte/zx_vou.c b/drivers/gpu/drm/zte/zx_vou.c
> index 3fb4fc04e693..e832c2ec3156 100644
> --- a/drivers/gpu/drm/zte/zx_vou.c
> +++ b/drivers/gpu/drm/zte/zx_vou.c
> @@ -84,6 +84,8 @@ struct zx_crtc_bits {
> struct zx_crtc {
> struct drm_crtc crtc;
> struct drm_plane *primary;
> + struct drm_plane *overlay_active[VL_NUM];
> + unsigned int overlay_active_num;
I don't think this belongs here. You can instead add an active (or
enabled) bool to the zx_plane struct and keep track of it via
atomic_plane_update/disable. This allows you to call
zx_plane_set_update unconditionally in the vou irq handler and check
active/enabled in zx_plane_set_update.
This also seems potentially racey, so be careful.
> struct zx_vou_hw *vou;
> void __iomem *chnreg;
> const struct zx_crtc_regs *regs;
> @@ -112,6 +114,22 @@ struct vou_layer_bits {
> },
> };
>
> +static const struct vou_layer_bits zx_vl_bits[VL_NUM] = {
> + {
> + .enable = OSD_CTRL0_VL0_EN,
> + .chnsel = OSD_CTRL0_VL0_SEL,
> + .clksel = VOU_CLK_VL0_SEL,
> + }, {
> + .enable = OSD_CTRL0_VL1_EN,
> + .chnsel = OSD_CTRL0_VL1_SEL,
> + .clksel = VOU_CLK_VL1_SEL,
> + }, {
> + .enable = OSD_CTRL0_VL2_EN,
> + .chnsel = OSD_CTRL0_VL2_SEL,
> + .clksel = VOU_CLK_VL2_SEL,
> + },
> +};
> +
> struct zx_vou_hw {
> struct device *dev;
> void __iomem *osd;
> @@ -439,6 +457,9 @@ void zx_vou_layer_enable(struct drm_plane *plane)
> }
>
> zx_writel_mask(vou->osd + OSD_CTRL0, bits->enable, bits->enable);
> +
> + if (plane->type == DRM_PLANE_TYPE_OVERLAY)
> + zcrtc->overlay_active[zcrtc->overlay_active_num++] = plane;
> }
>
> void zx_vou_layer_disable(struct drm_plane *plane)
> @@ -449,6 +470,51 @@ void zx_vou_layer_disable(struct drm_plane *plane)
> const struct vou_layer_bits *bits = zplane->bits;
>
> zx_writel_mask(vou->osd + OSD_CTRL0, bits->enable, 0);
> +
> + if (plane->type == DRM_PLANE_TYPE_OVERLAY)
> + zcrtc->overlay_active[zcrtc->overlay_active_num--] = NULL;
> +}
> +
> +static void zx_overlay_init(struct drm_device *drm, struct zx_vou_hw *vou)
> +{
> + struct device *dev = vou->dev;
> + struct zx_plane *zplane;
> + int i;
> + int ret;
> +
> + /*
> + * VL0 has some quirks on scaling support which need special handling.
> + * Let's leave it out for now.
> + */
> + for (i = 1; i < VL_NUM; i++) {
> + zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL);
> + if (!zplane) {
> + DRM_DEV_ERROR(dev, "failed to allocate zplane %d\n", i);
> + return;
> + }
> +
> + zplane->layer = vou->osd + OSD_VL_OFFSET(i);
> + zplane->hbsc = vou->osd + HBSC_VL_OFFSET(i);
> + zplane->rsz = vou->otfppu + RSZ_VL_OFFSET(i);
> + zplane->bits = &zx_vl_bits[i];
> +
> + ret = zx_plane_init(drm, zplane, DRM_PLANE_TYPE_OVERLAY);
> + if (ret) {
> + DRM_DEV_ERROR(dev, "failed to init overlay %d\n", i);
> + continue;
> + }
> + }
> +}
> +
> +static inline void zx_osd_int_update(struct zx_crtc *zcrtc)
> +{
> + int i;
> +
> + vou_chn_set_update(zcrtc);
> + zx_plane_set_update(zcrtc->primary);
> +
> + for (i = 0; i < zcrtc->overlay_active_num; i++)
> + zx_plane_set_update(zcrtc->overlay_active[i]);
> }
>
> static irqreturn_t vou_irq_handler(int irq, void *dev_id)
> @@ -470,15 +536,11 @@ static irqreturn_t vou_irq_handler(int irq, void *dev_id)
> state = zx_readl(vou->osd + OSD_INT_STA);
> zx_writel(vou->osd + OSD_INT_CLRSTA, state);
>
> - if (state & OSD_INT_MAIN_UPT) {
> - vou_chn_set_update(vou->main_crtc);
> - zx_plane_set_update(vou->main_crtc->primary);
> - }
> + if (state & OSD_INT_MAIN_UPT)
> + zx_osd_int_update(vou->main_crtc);
>
> - if (state & OSD_INT_AUX_UPT) {
> - vou_chn_set_update(vou->aux_crtc);
> - zx_plane_set_update(vou->aux_crtc->primary);
> - }
> + if (state & OSD_INT_AUX_UPT)
> + zx_osd_int_update(vou->aux_crtc);
>
> if (state & OSD_INT_ERROR)
> DRM_DEV_ERROR(vou->dev, "OSD ERROR: 0x%08x!\n", state);
> @@ -648,6 +710,8 @@ static int zx_crtc_bind(struct device *dev, struct device *master, void *data)
> goto disable_ppu_clk;
> }
>
> + zx_overlay_init(drm, vou);
> +
> return 0;
>
> disable_ppu_clk:
> diff --git a/drivers/gpu/drm/zte/zx_vou_regs.h b/drivers/gpu/drm/zte/zx_vou_regs.h
> index f44e7a4ae441..193c1ce01fe7 100644
> --- a/drivers/gpu/drm/zte/zx_vou_regs.h
> +++ b/drivers/gpu/drm/zte/zx_vou_regs.h
> @@ -22,6 +22,15 @@
> #define AUX_HBSC_OFFSET 0x860
> #define AUX_RSZ_OFFSET 0x800
>
> +#define OSD_VL0_OFFSET 0x040
> +#define OSD_VL_OFFSET(i) (OSD_VL0_OFFSET + 0x050 * (i))
> +
> +#define HBSC_VL0_OFFSET 0x760
> +#define HBSC_VL_OFFSET(i) (HBSC_VL0_OFFSET + 0x040 * (i))
> +
> +#define RSZ_VL1_U0 0xa00
> +#define RSZ_VL_OFFSET(i) (RSZ_VL1_U0 + 0x200 * (i))
> +
> /* OSD (GPC_GLOBAL) registers */
> #define OSD_INT_STA 0x04
> #define OSD_INT_CLRSTA 0x08
> @@ -42,6 +51,12 @@
> )
> #define OSD_INT_ENABLE (OSD_INT_ERROR | OSD_INT_AUX_UPT | OSD_INT_MAIN_UPT)
> #define OSD_CTRL0 0x10
> +#define OSD_CTRL0_VL0_EN BIT(13)
> +#define OSD_CTRL0_VL0_SEL BIT(12)
> +#define OSD_CTRL0_VL1_EN BIT(11)
> +#define OSD_CTRL0_VL1_SEL BIT(10)
> +#define OSD_CTRL0_VL2_EN BIT(9)
> +#define OSD_CTRL0_VL2_SEL BIT(8)
> #define OSD_CTRL0_GL0_EN BIT(7)
> #define OSD_CTRL0_GL0_SEL BIT(6)
> #define OSD_CTRL0_GL1_EN BIT(5)
> @@ -146,6 +161,9 @@
> #define VOU_INF_DATA_SEL 0x08
> #define VOU_SOFT_RST 0x14
> #define VOU_CLK_SEL 0x18
> +#define VOU_CLK_VL2_SEL BIT(8)
> +#define VOU_CLK_VL1_SEL BIT(7)
> +#define VOU_CLK_VL0_SEL BIT(6)
> #define VOU_CLK_GL1_SEL BIT(5)
> #define VOU_CLK_GL0_SEL BIT(4)
> #define VOU_CLK_REQEN 0x20
> --
> 1.9.1
>
--
Sean Paul, Software Engineer, Google / Chromium OS
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox