* Re: [PATCH v3] ASoC: ssm2305: Add amplifier driver
From: Lars-Peter Clausen @ 2018-05-17 14:44 UTC (permalink / raw)
To: Marco Felsch, lgirdwood, broonie, robh+dt, mark.rutland
Cc: devicetree, alsa-devel, kernel
In-Reply-To: <20180517135518.29345-1-m.felsch@pengutronix.de>
On 05/17/2018 03:55 PM, Marco Felsch wrote:
> The ssm2305 is a simple Class-D audio amplifier. A application can
> turn on/off the device by a gpio. It's also possible to hardwire the
> shutdown pin.
>
> Tested on a i.MX6 based custom board.
>
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
Reviewed-by: Lars-Peter Clausen <lars@metafoo.de>
Thanks.
^ permalink raw reply
* RE: [PATCH v5 05/14] usb: typec: add API to get typec basic port power and data config
From: Jun Li @ 2018-05-17 14:41 UTC (permalink / raw)
To: Heikki Krogerus
Cc: Mats Karrman, robh+dt@kernel.org, gregkh@linuxfoundation.org,
linux@roeck-us.net, a.hajda@samsung.com, cw00.choi@samsung.com,
shufan_lee@richtek.com, Peter Chen, gsomlo@gmail.com,
devicetree@vger.kernel.org, linux-usb@vger.kernel.org,
dl-linux-imx
In-Reply-To: <20180517142420.GH11469@kuha.fi.intel.com>
Hi
> -----Original Message-----
> From: Heikki Krogerus [mailto:heikki.krogerus@linux.intel.com]
> Sent: 2018年5月17日 22:24
> To: Jun Li <jun.li@nxp.com>
> Cc: Mats Karrman <mats.dev.list@gmail.com>; robh+dt@kernel.org;
> gregkh@linuxfoundation.org; linux@roeck-us.net; a.hajda@samsung.com;
> cw00.choi@samsung.com; shufan_lee@richtek.com; Peter Chen
> <peter.chen@nxp.com>; gsomlo@gmail.com; devicetree@vger.kernel.org;
> linux-usb@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> Subject: Re: [PATCH v5 05/14] usb: typec: add API to get typec basic port power
> and data config
>
> On Thu, May 17, 2018 at 02:05:41PM +0000, Jun Li wrote:
> > Hi Heikki,
> >
> > > > I reread this patch and tried to see it more in the context of the
> > > > other patches and the existing code. The naming of the existing
> > > > string tables doesn't help in getting this right, however I have a proposal:
> > > >
> > > > typec_find_port_power_role() to get to TYPEC_PORT_SRC/SNK/DRP
> > > > typec_find_port_data_role() to get to TYPEC_PORT_DFP/UFP/DRD
> > > > typec_find_power_role() to get to TYPEC_SINK/SOURCE
> > > >
> > > > and sometime, if the use should arise
> > > >
> > > > typec_find_data_role() to get to TYPEC_DEVICE/HOST
> > > >
> > > > I think it is fairly comprehensible, *_port_* concerns a
> > > > capability and without *_port_* it is an actual state. Plus it
> > > > matches the names of the constants.
> > >
> > > Well, there are now four things to consider:
> > >
> > > 1) the roles (power and data) the port is capable of supporting
> > > 2) Try.SRC and Try.SNK, i.e. the preferred role
> > > 3) the current roles
> > > 4) the role(s) the user want's to limit the use of a port with DRP
> > > ports
> > >
> > > The last one I don't know if it's relevant with these functions.
> > > It's not information that we would get for example from firmware.
> > >
> > > I also don't think we need to use these functions with the current
> > > roles the port is in.
> > >
> > > If the preferred role is "sink" or "source", so just like the power
> > > role, we don't need separate function for it here.
> > >
> > > So isn't two functions all we need here: one for the power and one
> > > for data role?
> >
> > Take power as an example, can we use one function to only look up
> > typec_port_types[]? as capability(typec_port_type) and
> > state(typec_role) are different enum, and the allowed strings are different.
> >
> > static const char * const typec_roles[] = {
> > [TYPEC_SINK] = "sink",
> > [TYPEC_SOURCE] = "source",
> > };
> >
> > static const char * const typec_port_types[] = {
> > [TYPEC_PORT_SRC] = "source",
> > [TYPEC_PORT_SNK] = "sink",
> > [TYPEC_PORT_DRP] = "dual",
> > };
>
> Where out side the class code we need to convert the current role, the "state",
> with these functions?
Currently, the only call site is getting the preferred power role from firmware.
Thanks
Li Jun
>
>
> Thanks,
>
> --
> heikki
^ permalink raw reply
* [PATCH] ARM: dts: stm32: enable USB Host (USBH) EHCI controller on stm32mp157c-ev1
From: Amelie Delaunay @ 2018-05-17 14:36 UTC (permalink / raw)
To: Maxime Coquelin, Alexandre Torgue, Rob Herring, Mark Rutland
Cc: linux-arm-kernel, devicetree, linux-kernel, Amelie Delaunay
This patch enables USB Host (USBH) EHCI controller on stm32mp157c-ev1.
As a hub is used between USBH and USB connectors, no need to enable
USBH OHCI controller: all low- and full-speed traffic is managed by the
hub.
Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
---
arch/arm/boot/dts/stm32mp157c-ev1.dts | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm/boot/dts/stm32mp157c-ev1.dts b/arch/arm/boot/dts/stm32mp157c-ev1.dts
index 9382d80..933036b 100644
--- a/arch/arm/boot/dts/stm32mp157c-ev1.dts
+++ b/arch/arm/boot/dts/stm32mp157c-ev1.dts
@@ -103,6 +103,12 @@
};
};
+&usbh_ehci {
+ phys = <&usbphyc_port0>;
+ phy-names = "usb";
+ status = "okay";
+};
+
&usbphyc {
status = "okay";
};
--
2.7.4
^ permalink raw reply related
* Re: [PATCH v10 25/27] ARM: davinci: add device tree support to timer
From: Sekhar Nori @ 2018-05-17 14:35 UTC (permalink / raw)
To: David Lechner, linux-clk, devicetree, linux-arm-kernel
Cc: Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland,
Kevin Hilman, Bartosz Golaszewski, Adam Ford, linux-kernel
In-Reply-To: <20180509172606.29387-26-david@lechnology.com>
Hi David,
On Wednesday 09 May 2018 10:56 PM, David Lechner wrote:
> This adds device tree support to the davinci timer so that when clocks
> are moved to device tree, the timer will still work.
>
> Signed-off-by: David Lechner <david@lechnology.com>
> ---
> +static int __init of_davinci_timer_init(struct device_node *np)
> +{
> + struct clk *clk;
> +
> + clk = of_clk_get(np, 0);
> + if (IS_ERR(clk)) {
> + struct of_phandle_args clkspec;
> +
> + /*
> + * Fall back to using ref_clk if the actual clock is not
> + * available. There will be problems later if the real clock
> + * source is disabled.
> + */
> +
> + pr_warn("%s: falling back to ref_clk\n", __func__);
> +
> + clkspec.np = of_find_node_by_name(NULL, "ref_clk");
> + if (IS_ERR(clkspec.np)) {
> + pr_err("%s: No clock available for timer!\n", __func__);
> + return PTR_ERR(clkspec.np);
> + }
> + clk = of_clk_get_from_provider(&clkspec);
> + of_node_put(clkspec.np);
> + }
Do we need this error path now?
Thanks,
Sekhar
^ permalink raw reply
* Re: [PATCH v6 2/2] leds: lm3601x: Introduce the lm3601x LED driver
From: Dan Murphy @ 2018-05-17 14:34 UTC (permalink / raw)
To: Jacek Anaszewski, Andy Shevchenko
Cc: Rob Herring, Mark Rutland, Pavel Machek, devicetree,
Linux Kernel Mailing List, Linux LED Subsystem
In-Reply-To: <f155e9da-e41d-1201-a9f9-c321654be42e@ti.com>
Jacek
On 05/16/2018 04:17 PM, Dan Murphy wrote:
<snip>
>>>>
>>>>
>>>>>>> + if (!ret)
>>>>>>
>>>>>> if (ret) sounds more natural. And better just to split
>>>>>>
>>>>>>> + snprintf(led->led_name, sizeof(led->led_name),
>>>>>>> + "%s:%s", led->led_node->name, name);
>>>>>>> + else
>>>>>>> + snprintf(led->led_name, sizeof(led->led_name),
>>>>>>> + "%s:torch", led->led_node->name);
>>>>>>
>>>>>> const char *tmp;
>>>>>>
>>>>>> ret = device_property_read_...(&tmp);
>>>>>> if (ret)
>>>>>> tmp = ...
>>>>>> sprintf(...);
>>>
>>> We're no longer taking devicename section of a LED class device name
>>> from DT, so it will look differently anyway.
>>>
So in adding the device_property code I think we again are reaching the LED label issue.
In ARM with DT we would take the parent device node name and append it to the label
if the optional label property was not available. In migrating to the device_property
APIs we don't or can't depend on that parent node anymore.
So for the case where the label property does not exist should we use a hard coded name
or should we try to use the name from a device_id table.
This is how we did this for the leds-lp8860 driver. If the label did not exist we used the
i2c_device_id table and pulled the string from there.
Thoughts?
<snip>
--
------------------
Dan Murphy
^ permalink raw reply
* Re: [PATCH v2 05/40] iommu/sva: Track mm changes with an MMU notifier
From: Jonathan Cameron @ 2018-05-17 14:25 UTC (permalink / raw)
To: Jean-Philippe Brucker
Cc: kvm-u79uwXL29TY76Z2rM5mHXA, linux-pci-u79uwXL29TY76Z2rM5mHXA,
xuzaibo-hv44wF8Li93QT0dZR+AlfA, will.deacon-5wv7dgnIgG8,
okaya-sgV2jX0FEOL9JmXXK+q4OQ, linux-mm-Bw31MaZKKs3YtjvyW6yDsg,
ashok.raj-ral2JQCrhuEAvxtiuMwx3w, bharatku-gjFFaj9aHVfQT0dZR+AlfA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, rfranz-YGCgFSpz5w/QT0dZR+AlfA,
devicetree-u79uwXL29TY76Z2rM5mHXA, rgummal-gjFFaj9aHVfQT0dZR+AlfA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
dwmw2-wEGCiKHe2LqWVfeAwA7xHQ,
ilias.apalodimas-QSEj5FYQhm4dnm+yROfE0A,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
christian.koenig-5C7GfCeVMHo
In-Reply-To: <20180511190641.23008-6-jean-philippe.brucker-5wv7dgnIgG8@public.gmane.org>
On Fri, 11 May 2018 20:06:06 +0100
Jean-Philippe Brucker <jean-philippe.brucker-5wv7dgnIgG8@public.gmane.org> wrote:
> When creating an io_mm structure, register an MMU notifier that informs
> us when the virtual address space changes and disappears.
>
> Add a new operation to the IOMMU driver, mm_invalidate, called when a
> range of addresses is unmapped to let the IOMMU driver send ATC
> invalidations. mm_invalidate cannot sleep.
>
> Adding the notifier complicates io_mm release. In one case device
> drivers free the io_mm explicitly by calling unbind (or detaching the
> device from its domain). In the other case the process could crash
> before unbind, in which case the release notifier has to do all the
> work.
>
> Allowing the device driver's mm_exit() handler to sleep adds another
> complication, but it will greatly simplify things for users. For example
> VFIO can take the IOMMU mutex and remove any trace of io_mm, instead of
> introducing complex synchronization to delicatly handle this race. But
> relaxing the user side does force unbind() to sleep and wait for all
> pending mm_exit() calls to finish.
>
> Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker-5wv7dgnIgG8@public.gmane.org>
>
> ---
> v1->v2:
> * Unbind() waits for mm_exit to finish
> * mm_exit can sleep
> ---
> drivers/iommu/Kconfig | 1 +
> drivers/iommu/iommu-sva.c | 248 +++++++++++++++++++++++++++++++++++---
> include/linux/iommu.h | 10 ++
> 3 files changed, 244 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
> index cca8e06903c7..38434899e283 100644
> --- a/drivers/iommu/Kconfig
> +++ b/drivers/iommu/Kconfig
> @@ -77,6 +77,7 @@ config IOMMU_DMA
> config IOMMU_SVA
> bool
> select IOMMU_API
> + select MMU_NOTIFIER
>
> config FSL_PAMU
> bool "Freescale IOMMU support"
> diff --git a/drivers/iommu/iommu-sva.c b/drivers/iommu/iommu-sva.c
> index 0700893c679d..e9afae2537a2 100644
> --- a/drivers/iommu/iommu-sva.c
> +++ b/drivers/iommu/iommu-sva.c
> @@ -7,6 +7,7 @@
>
> #include <linux/idr.h>
> #include <linux/iommu.h>
> +#include <linux/mmu_notifier.h>
> #include <linux/sched/mm.h>
> #include <linux/slab.h>
> #include <linux/spinlock.h>
> @@ -106,6 +107,9 @@ struct iommu_bond {
> struct list_head mm_head;
> struct list_head dev_head;
> struct list_head domain_head;
> + refcount_t refs;
> + struct wait_queue_head mm_exit_wq;
> + bool mm_exit_active;
>
> void *drvdata;
> };
> @@ -124,6 +128,8 @@ static DEFINE_IDR(iommu_pasid_idr);
> */
> static DEFINE_SPINLOCK(iommu_sva_lock);
>
> +static struct mmu_notifier_ops iommu_mmu_notifier;
> +
> static struct io_mm *
> io_mm_alloc(struct iommu_domain *domain, struct device *dev,
> struct mm_struct *mm, unsigned long flags)
> @@ -151,6 +157,7 @@ io_mm_alloc(struct iommu_domain *domain, struct device *dev,
>
> io_mm->flags = flags;
> io_mm->mm = mm;
> + io_mm->notifier.ops = &iommu_mmu_notifier;
> io_mm->release = domain->ops->mm_free;
> INIT_LIST_HEAD(&io_mm->devices);
>
> @@ -167,8 +174,29 @@ io_mm_alloc(struct iommu_domain *domain, struct device *dev,
> goto err_free_mm;
> }
>
> - /* TODO: keep track of mm. For the moment, abort. */
> - ret = -ENOSYS;
> + ret = mmu_notifier_register(&io_mm->notifier, mm);
> + if (ret)
> + goto err_free_pasid;
> +
> + /*
> + * Now that the MMU notifier is valid, we can allow users to grab this
> + * io_mm by setting a valid refcount. Before that it was accessible in
> + * the IDR but invalid.
> + *
> + * The following barrier ensures that users, who obtain the io_mm with
> + * kref_get_unless_zero, don't read uninitialized fields in the
> + * structure.
> + */
> + smp_wmb();
> + kref_init(&io_mm->kref);
> +
> + return io_mm;
> +
> +err_free_pasid:
> + /*
> + * Even if the io_mm is accessible from the IDR at this point, kref is
> + * 0 so no user could get a reference to it. Free it manually.
> + */
> spin_lock(&iommu_sva_lock);
> idr_remove(&iommu_pasid_idr, io_mm->pasid);
> spin_unlock(&iommu_sva_lock);
> @@ -180,9 +208,13 @@ io_mm_alloc(struct iommu_domain *domain, struct device *dev,
> return ERR_PTR(ret);
> }
>
> -static void io_mm_free(struct io_mm *io_mm)
> +static void io_mm_free(struct rcu_head *rcu)
> {
> - struct mm_struct *mm = io_mm->mm;
> + struct io_mm *io_mm;
> + struct mm_struct *mm;
> +
> + io_mm = container_of(rcu, struct io_mm, rcu);
> + mm = io_mm->mm;
>
> io_mm->release(io_mm);
> mmdrop(mm);
> @@ -197,7 +229,22 @@ static void io_mm_release(struct kref *kref)
>
> idr_remove(&iommu_pasid_idr, io_mm->pasid);
>
> - io_mm_free(io_mm);
> + /*
> + * If we're being released from mm exit, the notifier callback ->release
> + * has already been called. Otherwise we don't need ->release, the io_mm
> + * isn't attached to anything anymore. Hence no_release.
> + */
> + mmu_notifier_unregister_no_release(&io_mm->notifier, io_mm->mm);
> +
> + /*
> + * We can't free the structure here, because if mm exits during
> + * unbind(), then ->release might be attempting to grab the io_mm
> + * concurrently. And in the other case, if ->release is calling
> + * io_mm_release, then __mmu_notifier_release expects to still have a
> + * valid mn when returning. So free the structure when it's safe, after
> + * the RCU grace period elapsed.
> + */
> + mmu_notifier_call_srcu(&io_mm->rcu, io_mm_free);
> }
>
> /*
> @@ -206,8 +253,14 @@ static void io_mm_release(struct kref *kref)
> */
> static int io_mm_get_locked(struct io_mm *io_mm)
> {
> - if (io_mm)
> - return kref_get_unless_zero(&io_mm->kref);
> + if (io_mm && kref_get_unless_zero(&io_mm->kref)) {
> + /*
> + * kref_get_unless_zero doesn't provide ordering for reads. This
> + * barrier pairs with the one in io_mm_alloc.
> + */
> + smp_rmb();
> + return 1;
> + }
>
> return 0;
> }
> @@ -233,7 +286,8 @@ static int io_mm_attach(struct iommu_domain *domain, struct device *dev,
> struct iommu_bond *bond, *tmp;
> struct iommu_sva_param *param = dev->iommu_param->sva_param;
>
> - if (!domain->ops->mm_attach || !domain->ops->mm_detach)
> + if (!domain->ops->mm_attach || !domain->ops->mm_detach ||
> + !domain->ops->mm_invalidate)
> return -ENODEV;
>
> if (pasid > param->max_pasid || pasid < param->min_pasid)
> @@ -247,6 +301,8 @@ static int io_mm_attach(struct iommu_domain *domain, struct device *dev,
> bond->io_mm = io_mm;
> bond->dev = dev;
> bond->drvdata = drvdata;
> + refcount_set(&bond->refs, 1);
> + init_waitqueue_head(&bond->mm_exit_wq);
>
> spin_lock(&iommu_sva_lock);
> /*
> @@ -275,12 +331,37 @@ static int io_mm_attach(struct iommu_domain *domain, struct device *dev,
> return 0;
> }
>
> -static void io_mm_detach_locked(struct iommu_bond *bond)
> +static void io_mm_detach_locked(struct iommu_bond *bond, bool wait)
> {
> struct iommu_bond *tmp;
> bool detach_domain = true;
> struct iommu_domain *domain = bond->domain;
>
> + if (wait) {
> + bool do_detach = true;
> + /*
> + * If we're unbind() then we're deleting the bond no matter
> + * what. Tell the mm_exit thread that we're cleaning up, and
> + * wait until it finishes using the bond.
> + *
> + * refs is guaranteed to be one or more, otherwise it would
> + * already have been removed from the list. Check is someone is
Check if someone...
> + * already waiting, in which case we wait but do not free.
> + */
> + if (refcount_read(&bond->refs) > 1)
> + do_detach = false;
> +
> + refcount_inc(&bond->refs);
> + wait_event_lock_irq(bond->mm_exit_wq, !bond->mm_exit_active,
> + iommu_sva_lock);
> + if (!do_detach)
> + return;
> +
> + } else if (!refcount_dec_and_test(&bond->refs)) {
> + /* unbind() is waiting to free the bond */
> + return;
> + }
> +
> list_for_each_entry(tmp, &domain->mm_list, domain_head) {
> if (tmp->io_mm == bond->io_mm && tmp->dev != bond->dev) {
> detach_domain = false;
> @@ -298,6 +379,129 @@ static void io_mm_detach_locked(struct iommu_bond *bond)
> kfree(bond);
> }
>
> +static int iommu_signal_mm_exit(struct iommu_bond *bond)
> +{
> + struct device *dev = bond->dev;
> + struct io_mm *io_mm = bond->io_mm;
> + struct iommu_sva_param *param = dev->iommu_param->sva_param;
> +
> + /*
> + * We can't hold the device's param_lock. If we did and the device
> + * driver used a global lock around io_mm, we would risk getting the
> + * following deadlock:
> + *
> + * exit_mm() | Shutdown SVA
> + * mutex_lock(param->lock) | mutex_lock(glob lock)
> + * param->mm_exit() | sva_device_shutdown()
> + * mutex_lock(glob lock) | mutex_lock(param->lock)
> + *
> + * Fortunately unbind() waits for us to finish, and sva_device_shutdown
> + * requires that any bond is removed, so we can safely access mm_exit
> + * and drvdata without taking any lock.
> + */
> + if (!param || !param->mm_exit)
> + return 0;
> +
> + return param->mm_exit(dev, io_mm->pasid, bond->drvdata);
> +}
> +
> +/* Called when the mm exits. Can race with unbind(). */
> +static void iommu_notifier_release(struct mmu_notifier *mn, struct mm_struct *mm)
> +{
> + struct iommu_bond *bond, *next;
> + struct io_mm *io_mm = container_of(mn, struct io_mm, notifier);
> +
> + /*
> + * If the mm is exiting then devices are still bound to the io_mm.
> + * A few things need to be done before it is safe to release:
> + *
> + * - As the mmu notifier doesn't hold any reference to the io_mm when
> + * calling ->release(), try to take a reference.
> + * - Tell the device driver to stop using this PASID.
> + * - Clear the PASID table and invalidate TLBs.
> + * - Drop all references to this io_mm by freeing the bonds.
> + */
> + spin_lock(&iommu_sva_lock);
> + if (!io_mm_get_locked(io_mm)) {
> + /* Someone's already taking care of it. */
> + spin_unlock(&iommu_sva_lock);
> + return;
> + }
> +
> + list_for_each_entry_safe(bond, next, &io_mm->devices, mm_head) {
> + /*
> + * Release the lock to let the handler sleep. We need to be
> + * careful about concurrent modifications to the list and to the
> + * bond. Tell unbind() not to free the bond until we're done.
> + */
> + bond->mm_exit_active = true;
> + spin_unlock(&iommu_sva_lock);
> +
> + if (iommu_signal_mm_exit(bond))
> + dev_WARN(bond->dev, "possible leak of PASID %u",
> + io_mm->pasid);
> +
> + spin_lock(&iommu_sva_lock);
> + next = list_next_entry(bond, mm_head);
> +
> + /* If someone is waiting, let them delete the bond now */
> + bond->mm_exit_active = false;
> + wake_up_all(&bond->mm_exit_wq);
> +
> + /* Otherwise, do it ourselves */
> + io_mm_detach_locked(bond, false);
> + }
> + spin_unlock(&iommu_sva_lock);
> +
> + /*
> + * We're now reasonably certain that no more fault is being handled for
> + * this io_mm, since we just flushed them all out of the fault queue.
> + * Release the last reference to free the io_mm.
> + */
> + io_mm_put(io_mm);
> +}
> +
> +static void iommu_notifier_invalidate_range(struct mmu_notifier *mn,
> + struct mm_struct *mm,
> + unsigned long start,
> + unsigned long end)
> +{
> + struct iommu_bond *bond;
> + struct io_mm *io_mm = container_of(mn, struct io_mm, notifier);
> +
> + spin_lock(&iommu_sva_lock);
> + list_for_each_entry(bond, &io_mm->devices, mm_head) {
> + struct iommu_domain *domain = bond->domain;
> +
> + domain->ops->mm_invalidate(domain, bond->dev, io_mm, start,
> + end - start);
> + }
> + spin_unlock(&iommu_sva_lock);
> +}
> +
> +static int iommu_notifier_clear_flush_young(struct mmu_notifier *mn,
> + struct mm_struct *mm,
> + unsigned long start,
> + unsigned long end)
> +{
> + iommu_notifier_invalidate_range(mn, mm, start, end);
> + return 0;
> +}
> +
> +static void iommu_notifier_change_pte(struct mmu_notifier *mn,
> + struct mm_struct *mm,
> + unsigned long address, pte_t pte)
> +{
> + iommu_notifier_invalidate_range(mn, mm, address, address + PAGE_SIZE);
> +}
> +
> +static struct mmu_notifier_ops iommu_mmu_notifier = {
> + .release = iommu_notifier_release,
> + .clear_flush_young = iommu_notifier_clear_flush_young,
> + .change_pte = iommu_notifier_change_pte,
> + .invalidate_range = iommu_notifier_invalidate_range,
> +};
> +
> /**
> * iommu_sva_device_init() - Initialize Shared Virtual Addressing for a device
> * @dev: the device
> @@ -320,6 +524,12 @@ static void io_mm_detach_locked(struct iommu_bond *bond)
> * The handler gets an opaque pointer corresponding to the drvdata passed as
> * argument of bind().
> *
> + * The @mm_exit handler is allowed to sleep. Be careful about the locks taken in
> + * @mm_exit, because they might lead to deadlocks if they are also held when
> + * dropping references to the mm. Consider the following call chain:
> + * mutex_lock(A); mmput(mm) -> exit_mm() -> @mm_exit() -> mutex_lock(A)
> + * Using mmput_async() prevents this scenario.
> + *
> * The device should not be performing any DMA while this function is running,
> * otherwise the behavior is undefined.
> *
> @@ -484,15 +694,16 @@ int __iommu_sva_unbind_device(struct device *dev, int pasid)
> if (!param || WARN_ON(!domain))
> return -EINVAL;
>
> - spin_lock(&iommu_sva_lock);
> + /* spin_lock_irq matches the one in wait_event_lock_irq */
> + spin_lock_irq(&iommu_sva_lock);
> list_for_each_entry(bond, ¶m->mm_list, dev_head) {
> if (bond->io_mm->pasid == pasid) {
> - io_mm_detach_locked(bond);
> + io_mm_detach_locked(bond, true);
> ret = 0;
> break;
> }
> }
> - spin_unlock(&iommu_sva_lock);
> + spin_unlock_irq(&iommu_sva_lock);
>
> return ret;
> }
> @@ -503,18 +714,25 @@ EXPORT_SYMBOL_GPL(__iommu_sva_unbind_device);
> * @dev: the device
> *
> * When detaching @device from a domain, IOMMU drivers should use this helper.
> + * This function may sleep while waiting for bonds to be released.
> */
> void __iommu_sva_unbind_dev_all(struct device *dev)
> {
> struct iommu_sva_param *param;
> struct iommu_bond *bond, *next;
>
> + /*
> + * io_mm_detach_locked might wait, so we shouldn't call it with the dev
> + * param lock held. It's fine to read sva_param outside the lock because
> + * it can only be freed by iommu_sva_device_shutdown when there are no
> + * more bonds in the list.
> + */
> param = dev->iommu_param->sva_param;
> if (param) {
> - spin_lock(&iommu_sva_lock);
> + spin_lock_irq(&iommu_sva_lock);
> list_for_each_entry_safe(bond, next, ¶m->mm_list, dev_head)
> - io_mm_detach_locked(bond);
> - spin_unlock(&iommu_sva_lock);
> + io_mm_detach_locked(bond, true);
> + spin_unlock_irq(&iommu_sva_lock);
> }
> }
> EXPORT_SYMBOL_GPL(__iommu_sva_unbind_dev_all);
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index 439c8fffd836..caa6f79785b9 100644
> --- a/include/linux/iommu.h
> +++ b/include/linux/iommu.h
> @@ -24,6 +24,7 @@
> #include <linux/types.h>
> #include <linux/errno.h>
> #include <linux/err.h>
> +#include <linux/mmu_notifier.h>
> #include <linux/of.h>
> #include <uapi/linux/iommu.h>
>
> @@ -111,10 +112,15 @@ struct io_mm {
> unsigned long flags;
> struct list_head devices;
> struct kref kref;
> +#if defined(CONFIG_MMU_NOTIFIER)
> + struct mmu_notifier notifier;
> +#endif
> struct mm_struct *mm;
>
> /* Release callback for this mm */
> void (*release)(struct io_mm *io_mm);
> + /* For postponed release */
> + struct rcu_head rcu;
> };
>
> enum iommu_cap {
> @@ -249,6 +255,7 @@ struct iommu_sva_param {
> * @mm_attach: attach io_mm to a device. Install PASID entry if necessary
> * @mm_detach: detach io_mm from a device. Remove PASID entry and
> * flush associated TLB entries.
> + * @mm_invalidate: Invalidate a range of mappings for an mm
> * @map: map a physically contiguous memory region to an iommu domain
> * @unmap: unmap a physically contiguous memory region from an iommu domain
> * @map_sg: map a scatter-gather list of physically contiguous memory chunks
> @@ -298,6 +305,9 @@ struct iommu_ops {
> struct io_mm *io_mm, bool attach_domain);
> void (*mm_detach)(struct iommu_domain *domain, struct device *dev,
> struct io_mm *io_mm, bool detach_domain);
> + void (*mm_invalidate)(struct iommu_domain *domain, struct device *dev,
> + struct io_mm *io_mm, unsigned long vaddr,
> + size_t size);
> int (*map)(struct iommu_domain *domain, unsigned long iova,
> phys_addr_t paddr, size_t size, int prot);
> size_t (*unmap)(struct iommu_domain *domain, unsigned long iova,
^ permalink raw reply
* Re: [PATCH v2 03/40] iommu/sva: Manage process address spaces
From: Jonathan Cameron @ 2018-05-17 14:25 UTC (permalink / raw)
To: Jean-Philippe Brucker
Cc: kvm-u79uwXL29TY76Z2rM5mHXA, linux-pci-u79uwXL29TY76Z2rM5mHXA,
xuzaibo-hv44wF8Li93QT0dZR+AlfA, will.deacon-5wv7dgnIgG8,
okaya-sgV2jX0FEOL9JmXXK+q4OQ, linux-mm-Bw31MaZKKs3YtjvyW6yDsg,
ashok.raj-ral2JQCrhuEAvxtiuMwx3w, bharatku-gjFFaj9aHVfQT0dZR+AlfA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, rfranz-YGCgFSpz5w/QT0dZR+AlfA,
devicetree-u79uwXL29TY76Z2rM5mHXA, rgummal-gjFFaj9aHVfQT0dZR+AlfA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
dwmw2-wEGCiKHe2LqWVfeAwA7xHQ,
ilias.apalodimas-QSEj5FYQhm4dnm+yROfE0A,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
christian.koenig-5C7GfCeVMHo
In-Reply-To: <20180511190641.23008-4-jean-philippe.brucker-5wv7dgnIgG8@public.gmane.org>
On Fri, 11 May 2018 20:06:04 +0100
Jean-Philippe Brucker <jean-philippe.brucker-5wv7dgnIgG8@public.gmane.org> wrote:
> Allocate IOMMU mm structures and binding them to devices. Four operations
> are added to IOMMU drivers:
>
> * mm_alloc(): to create an io_mm structure and perform architecture-
> specific operations required to grab the process (for instance on ARM,
> pin down the CPU ASID so that the process doesn't get assigned a new
> ASID on rollover).
>
> There is a single valid io_mm structure per Linux mm. Future extensions
> may also use io_mm for kernel-managed address spaces, populated with
> map()/unmap() calls instead of bound to process address spaces. This
> patch focuses on "shared" io_mm.
>
> * mm_attach(): attach an mm to a device. The IOMMU driver checks that the
> device is capable of sharing an address space, and writes the PASID
> table entry to install the pgd.
>
> Some IOMMU drivers will have a single PASID table per domain, for
> convenience. Other can implement it differently but to help these
> drivers, mm_attach and mm_detach take 'attach_domain' and
> 'detach_domain' parameters, that tell whether they need to set and clear
> the PASID entry or only send the required TLB invalidations.
>
> * mm_detach(): detach an mm from a device. The IOMMU driver removes the
> PASID table entry and invalidates the IOTLBs.
>
> * mm_free(): free a structure allocated by mm_alloc(), and let arch
> release the process.
>
> mm_attach and mm_detach operations are serialized with a spinlock. When
> trying to optimize this code, we should at least prevent concurrent
> attach()/detach() on the same domain (so multi-level PASID table code can
> allocate tables lazily). mm_alloc() can sleep, but mm_free must not
> (because we'll have to call it from call_srcu later on).
>
> At the moment we use an IDR for allocating PASIDs and retrieving contexts.
> We also use a single spinlock. These can be refined and optimized later (a
> custom allocator will be needed for top-down PASID allocation).
>
> Keeping track of address spaces requires the use of MMU notifiers.
> Handling process exit with regard to unbind() is tricky, so it is left for
> another patch and we explicitly fail mm_alloc() for the moment.
>
> Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker-5wv7dgnIgG8@public.gmane.org>
A few minor bits and bobs inline. Looks good in general + nice diags!
Thanks,
Jonathan
>
> ---
> v1->v2: sanity-check of flags
> ---
> drivers/iommu/iommu-sva.c | 380 +++++++++++++++++++++++++++++++++++++-
> drivers/iommu/iommu.c | 1 +
> include/linux/iommu.h | 28 +++
> 3 files changed, 406 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/iommu/iommu-sva.c b/drivers/iommu/iommu-sva.c
> index 8d98f9c09864..6ac679c48f3c 100644
> --- a/drivers/iommu/iommu-sva.c
> +++ b/drivers/iommu/iommu-sva.c
> @@ -5,8 +5,298 @@
> * Copyright (C) 2018 ARM Ltd.
> */
>
> +#include <linux/idr.h>
> #include <linux/iommu.h>
> +#include <linux/sched/mm.h>
> #include <linux/slab.h>
> +#include <linux/spinlock.h>
> +
> +/**
> + * DOC: io_mm model
> + *
> + * The io_mm keeps track of process address spaces shared between CPU and IOMMU.
> + * The following example illustrates the relation between structures
> + * iommu_domain, io_mm and iommu_bond. An iommu_bond is a link between io_mm and
> + * device. A device can have multiple io_mm and an io_mm may be bound to
> + * multiple devices.
> + * ___________________________
> + * | IOMMU domain A |
> + * | ________________ |
> + * | | IOMMU group | +------- io_pgtables
> + * | | | |
> + * | | dev 00:00.0 ----+------- bond --- io_mm X
> + * | |________________| \ |
> + * | '----- bond ---.
> + * |___________________________| \
> + * ___________________________ \
> + * | IOMMU domain B | io_mm Y
> + * | ________________ | / /
> + * | | IOMMU group | | / /
> + * | | | | / /
> + * | | dev 00:01.0 ------------ bond -' /
> + * | | dev 00:01.1 ------------ bond --'
> + * | |________________| |
> + * | +------- io_pgtables
> + * |___________________________|
> + *
> + * In this example, device 00:00.0 is in domain A, devices 00:01.* are in domain
> + * B. All devices within the same domain access the same address spaces. Device
> + * 00:00.0 accesses address spaces X and Y, each corresponding to an mm_struct.
> + * Devices 00:01.* only access address space Y. In addition each
> + * IOMMU_DOMAIN_DMA domain has a private address space, io_pgtable, that is
> + * managed with iommu_map()/iommu_unmap(), and isn't shared with the CPU MMU.
> + *
> + * To obtain the above configuration, users would for instance issue the
> + * following calls:
> + *
> + * iommu_sva_bind_device(dev 00:00.0, mm X, ...) -> PASID 1
> + * iommu_sva_bind_device(dev 00:00.0, mm Y, ...) -> PASID 2
> + * iommu_sva_bind_device(dev 00:01.0, mm Y, ...) -> PASID 2
> + * iommu_sva_bind_device(dev 00:01.1, mm Y, ...) -> PASID 2
> + *
> + * A single Process Address Space ID (PASID) is allocated for each mm. In the
> + * example, devices use PASID 1 to read/write into address space X and PASID 2
> + * to read/write into address space Y.
> + *
> + * Hardware tables describing this configuration in the IOMMU would typically
> + * look like this:
> + *
> + * PASID tables
> + * of domain A
> + * .->+--------+
> + * / 0 | |-------> io_pgtable
> + * / +--------+
> + * Device tables / 1 | |-------> pgd X
> + * +--------+ / +--------+
> + * 00:00.0 | A |-' 2 | |--.
> + * +--------+ +--------+ \
> + * : : 3 | | \
> + * +--------+ +--------+ --> pgd Y
> + * 00:01.0 | B |--. /
> + * +--------+ \ |
> + * 00:01.1 | B |----+ PASID tables |
> + * +--------+ \ of domain B |
> + * '->+--------+ |
> + * 0 | |-- | --> io_pgtable
> + * +--------+ |
> + * 1 | | |
> + * +--------+ |
> + * 2 | |---'
> + * +--------+
> + * 3 | |
> + * +--------+
> + *
> + * With this model, a single call binds all devices in a given domain to an
> + * address space. Other devices in the domain will get the same bond implicitly.
> + * However, users must issue one bind() for each device, because IOMMUs may
> + * implement SVA differently. Furthermore, mandating one bind() per device
> + * allows the driver to perform sanity-checks on device capabilities.
> + *
> + * On Arm and AMD IOMMUs, entry 0 of the PASID table can be used to hold
> + * non-PASID translations. In this case PASID 0 is reserved and entry 0 points
> + * to the io_pgtable base. On Intel IOMMU, the io_pgtable base would be held in
> + * the device table and PASID 0 would be available to the allocator.
> + */
> +
> +struct iommu_bond {
> + struct io_mm *io_mm;
> + struct device *dev;
> + struct iommu_domain *domain;
> +
> + struct list_head mm_head;
> + struct list_head dev_head;
> + struct list_head domain_head;
> +
> + void *drvdata;
> +};
> +
> +/*
> + * Because we're using an IDR, PASIDs are limited to 31 bits (the sign bit is
> + * used for returning errors). In practice implementations will use at most 20
> + * bits, which is the PCI limit.
> + */
> +static DEFINE_IDR(iommu_pasid_idr);
> +
> +/*
> + * For the moment this is an all-purpose lock. It serializes
> + * access/modifications to bonds, access/modifications to the PASID IDR, and
> + * changes to io_mm refcount as well.
> + */
> +static DEFINE_SPINLOCK(iommu_sva_lock);
> +
> +static struct io_mm *
> +io_mm_alloc(struct iommu_domain *domain, struct device *dev,
> + struct mm_struct *mm, unsigned long flags)
> +{
> + int ret;
> + int pasid;
> + struct io_mm *io_mm;
> + struct iommu_sva_param *param = dev->iommu_param->sva_param;
> +
> + if (!domain->ops->mm_alloc || !domain->ops->mm_free)
> + return ERR_PTR(-ENODEV);
> +
> + io_mm = domain->ops->mm_alloc(domain, mm, flags);
> + if (IS_ERR(io_mm))
> + return io_mm;
> + if (!io_mm)
> + return ERR_PTR(-ENOMEM);
> +
> + /*
> + * The mm must not be freed until after the driver frees the io_mm
> + * (which may involve unpinning the CPU ASID for instance, requiring a
> + * valid mm struct.)
> + */
> + mmgrab(mm);
> +
> + io_mm->flags = flags;
> + io_mm->mm = mm;
> + io_mm->release = domain->ops->mm_free;
> + INIT_LIST_HEAD(&io_mm->devices);
> +
> + idr_preload(GFP_KERNEL);
> + spin_lock(&iommu_sva_lock);
> + pasid = idr_alloc(&iommu_pasid_idr, io_mm, param->min_pasid,
> + param->max_pasid + 1, GFP_ATOMIC);
I'd expect the IDR cleanup to be in io_mm_free as that would 'match'
against io_mm_alloc but it's in io_mm_release just before the io_mm_free
call, perhaps move it or am I missing something?
Hmm. This is reworked in patch 5 to use call rcu to do the free. I suppose
we may be burning an idr entry if we take a while to get round to the
free.. If so a comment to explain this would be great.
> + io_mm->pasid = pasid;
> + spin_unlock(&iommu_sva_lock);
> + idr_preload_end();
> +
> + if (pasid < 0) {
> + ret = pasid;
> + goto err_free_mm;
> + }
> +
> + /* TODO: keep track of mm. For the moment, abort. */
>From later patches, I can now see why we didn't init the kref
here, but perhaps a comment would make that clear rather than
people checking it is correctly used throughout? Actually just grab
the comment from patch 5 and put it in this one and that will
do the job nicely.
> + ret = -ENOSYS;
> + spin_lock(&iommu_sva_lock);
> + idr_remove(&iommu_pasid_idr, io_mm->pasid);
> + spin_unlock(&iommu_sva_lock);
> +
> +err_free_mm:
> + domain->ops->mm_free(io_mm);
Really minor, but you now have io_mm->release set so to keep
this obviously the same as the io_mm_free path, perhaps call
that rather than mm_free directly.
> + mmdrop(mm);
> +
> + return ERR_PTR(ret);
> +}
> +
> +static void io_mm_free(struct io_mm *io_mm)
> +{
> + struct mm_struct *mm = io_mm->mm;
> +
> + io_mm->release(io_mm);
> + mmdrop(mm);
> +}
> +
> +static void io_mm_release(struct kref *kref)
> +{
> + struct io_mm *io_mm;
> +
> + io_mm = container_of(kref, struct io_mm, kref);
> + WARN_ON(!list_empty(&io_mm->devices));
> +
> + idr_remove(&iommu_pasid_idr, io_mm->pasid);
> +
> + io_mm_free(io_mm);
> +}
> +
> +/*
> + * Returns non-zero if a reference to the io_mm was successfully taken.
> + * Returns zero if the io_mm is being freed and should not be used.
> + */
> +static int io_mm_get_locked(struct io_mm *io_mm)
> +{
> + if (io_mm)
> + return kref_get_unless_zero(&io_mm->kref);
> +
> + return 0;
> +}
> +
> +static void io_mm_put_locked(struct io_mm *io_mm)
> +{
> + kref_put(&io_mm->kref, io_mm_release);
> +}
> +
> +static void io_mm_put(struct io_mm *io_mm)
> +{
> + spin_lock(&iommu_sva_lock);
> + io_mm_put_locked(io_mm);
> + spin_unlock(&iommu_sva_lock);
> +}
> +
> +static int io_mm_attach(struct iommu_domain *domain, struct device *dev,
> + struct io_mm *io_mm, void *drvdata)
> +{
> + int ret;
> + bool attach_domain = true;
> + int pasid = io_mm->pasid;
> + struct iommu_bond *bond, *tmp;
> + struct iommu_sva_param *param = dev->iommu_param->sva_param;
> +
> + if (!domain->ops->mm_attach || !domain->ops->mm_detach)
> + return -ENODEV;
> +
> + if (pasid > param->max_pasid || pasid < param->min_pasid)
> + return -ERANGE;
> +
> + bond = kzalloc(sizeof(*bond), GFP_KERNEL);
> + if (!bond)
> + return -ENOMEM;
> +
> + bond->domain = domain;
> + bond->io_mm = io_mm;
> + bond->dev = dev;
> + bond->drvdata = drvdata;
> +
> + spin_lock(&iommu_sva_lock);
> + /*
> + * Check if this io_mm is already bound to the domain. In which case the
> + * IOMMU driver doesn't have to install the PASID table entry.
> + */
> + list_for_each_entry(tmp, &domain->mm_list, domain_head) {
> + if (tmp->io_mm == io_mm) {
> + attach_domain = false;
> + break;
> + }
> + }
> +
> + ret = domain->ops->mm_attach(domain, dev, io_mm, attach_domain);
> + if (ret) {
> + kfree(bond);
> + spin_unlock(&iommu_sva_lock);
> + return ret;
> + }
> +
> + list_add(&bond->mm_head, &io_mm->devices);
> + list_add(&bond->domain_head, &domain->mm_list);
> + list_add(&bond->dev_head, ¶m->mm_list);
> + spin_unlock(&iommu_sva_lock);
> +
> + return 0;
> +}
> +
> +static void io_mm_detach_locked(struct iommu_bond *bond)
> +{
> + struct iommu_bond *tmp;
> + bool detach_domain = true;
> + struct iommu_domain *domain = bond->domain;
> +
> + list_for_each_entry(tmp, &domain->mm_list, domain_head) {
> + if (tmp->io_mm == bond->io_mm && tmp->dev != bond->dev) {
> + detach_domain = false;
> + break;
> + }
> + }
> +
> + domain->ops->mm_detach(domain, bond->dev, bond->io_mm, detach_domain);
> +
I can't see an immediate reason to have a different order in her to the reverse of
the attach above. So I think you should be detaching after the list_del calls.
If there is a reason, can we have a comment so I don't ask on v10.
> + list_del(&bond->mm_head);
> + list_del(&bond->domain_head);
> + list_del(&bond->dev_head);
> + io_mm_put_locked(bond->io_mm);
> +
> + kfree(bond);
> +}
>
> /**
> * iommu_sva_device_init() - Initialize Shared Virtual Addressing for a device
> @@ -47,6 +337,7 @@ int iommu_sva_device_init(struct device *dev, unsigned long features,
>
> param->features = features;
> param->max_pasid = max_pasid;
> + INIT_LIST_HEAD(¶m->mm_list);
>
> /*
> * IOMMU driver updates the limits depending on the IOMMU and device
> @@ -114,13 +405,87 @@ EXPORT_SYMBOL_GPL(iommu_sva_device_shutdown);
> int __iommu_sva_bind_device(struct device *dev, struct mm_struct *mm,
> int *pasid, unsigned long flags, void *drvdata)
> {
> - return -ENOSYS; /* TODO */
> + int i, ret = 0;
> + struct io_mm *io_mm = NULL;
> + struct iommu_domain *domain;
> + struct iommu_bond *bond = NULL, *tmp;
> + struct iommu_sva_param *param = dev->iommu_param->sva_param;
> +
> + domain = iommu_get_domain_for_dev(dev);
> + if (!domain)
> + return -EINVAL;
> +
> + /*
> + * The device driver does not call sva_device_init/shutdown and
> + * bind/unbind concurrently, so no need to take the param lock.
> + */
> + if (WARN_ON_ONCE(!param) || (flags & ~param->features))
> + return -EINVAL;
> +
> + /* If an io_mm already exists, use it */
> + spin_lock(&iommu_sva_lock);
> + idr_for_each_entry(&iommu_pasid_idr, io_mm, i) {
> + if (io_mm->mm == mm && io_mm_get_locked(io_mm)) {
> + /* ... Unless it's already bound to this device */
> + list_for_each_entry(tmp, &io_mm->devices, mm_head) {
> + if (tmp->dev == dev) {
> + bond = tmp;
Using bond for this is clear in a sense, but can we not just use ret
so it is obvious here that we are going to return -EEXIST?
At first glance I thought you were going to carry on with this bond
and couldn't work out why it would ever make sense to have two bonds
between a device an an io_mm (which it doesn't!)
> + io_mm_put_locked(io_mm);
> + break;
> + }
> + }
> + break;
> + }
> + }
> + spin_unlock(&iommu_sva_lock);
> +
> + if (bond)
> + return -EEXIST;
> +
> + /* Require identical features within an io_mm for now */
> + if (io_mm && (flags != io_mm->flags)) {
> + io_mm_put(io_mm);
> + return -EDOM;
> + }
> +
> + if (!io_mm) {
> + io_mm = io_mm_alloc(domain, dev, mm, flags);
> + if (IS_ERR(io_mm))
> + return PTR_ERR(io_mm);
> + }
> +
> + ret = io_mm_attach(domain, dev, io_mm, drvdata);
> + if (ret)
> + io_mm_put(io_mm);
> + else
> + *pasid = io_mm->pasid;
> +
> + return ret;
> }
> EXPORT_SYMBOL_GPL(__iommu_sva_bind_device);
>
> int __iommu_sva_unbind_device(struct device *dev, int pasid)
> {
> - return -ENOSYS; /* TODO */
> + int ret = -ESRCH;
> + struct iommu_domain *domain;
> + struct iommu_bond *bond = NULL;
> + struct iommu_sva_param *param = dev->iommu_param->sva_param;
> +
> + domain = iommu_get_domain_for_dev(dev);
> + if (!param || WARN_ON(!domain))
> + return -EINVAL;
> +
> + spin_lock(&iommu_sva_lock);
> + list_for_each_entry(bond, ¶m->mm_list, dev_head) {
> + if (bond->io_mm->pasid == pasid) {
> + io_mm_detach_locked(bond);
> + ret = 0;
> + break;
> + }
> + }
> + spin_unlock(&iommu_sva_lock);
> +
> + return ret;
> }
> EXPORT_SYMBOL_GPL(__iommu_sva_unbind_device);
>
> @@ -132,6 +497,15 @@ EXPORT_SYMBOL_GPL(__iommu_sva_unbind_device);
> */
> void __iommu_sva_unbind_dev_all(struct device *dev)
> {
> - /* TODO */
> + struct iommu_sva_param *param;
> + struct iommu_bond *bond, *next;
> +
> + param = dev->iommu_param->sva_param;
> + if (param) {
> + spin_lock(&iommu_sva_lock);
> + list_for_each_entry_safe(bond, next, ¶m->mm_list, dev_head)
> + io_mm_detach_locked(bond);
> + spin_unlock(&iommu_sva_lock);
> + }
> }
> EXPORT_SYMBOL_GPL(__iommu_sva_unbind_dev_all);
> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> index bd2819deae5b..333801e1519c 100644
> --- a/drivers/iommu/iommu.c
> +++ b/drivers/iommu/iommu.c
> @@ -1463,6 +1463,7 @@ static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus,
> domain->type = type;
> /* Assume all sizes by default; the driver may override this later */
> domain->pgsize_bitmap = bus->iommu_ops->pgsize_bitmap;
> + INIT_LIST_HEAD(&domain->mm_list);
>
> return domain;
> }
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index da59c20c4f12..d5f21719a5a0 100644
> --- a/include/linux/iommu.h
> +++ b/include/linux/iommu.h
> @@ -100,6 +100,20 @@ struct iommu_domain {
> void *handler_token;
> struct iommu_domain_geometry geometry;
> void *iova_cookie;
> +
> + struct list_head mm_list;
> +};
> +
> +struct io_mm {
> + int pasid;
> + /* IOMMU_SVA_FEAT_* */
> + unsigned long flags;
> + struct list_head devices;
> + struct kref kref;
> + struct mm_struct *mm;
> +
> + /* Release callback for this mm */
> + void (*release)(struct io_mm *io_mm);
> };
>
> enum iommu_cap {
> @@ -216,6 +230,7 @@ struct iommu_sva_param {
> unsigned long features;
> unsigned int min_pasid;
> unsigned int max_pasid;
> + struct list_head mm_list;
> };
>
> /**
> @@ -227,6 +242,11 @@ struct iommu_sva_param {
> * @detach_dev: detach device from an iommu domain
> * @sva_device_init: initialize Shared Virtual Adressing for a device
> * @sva_device_shutdown: shutdown Shared Virtual Adressing for a device
> + * @mm_alloc: allocate io_mm
> + * @mm_free: free io_mm
> + * @mm_attach: attach io_mm to a device. Install PASID entry if necessary
> + * @mm_detach: detach io_mm from a device. Remove PASID entry and
> + * flush associated TLB entries.
> * @map: map a physically contiguous memory region to an iommu domain
> * @unmap: unmap a physically contiguous memory region from an iommu domain
> * @map_sg: map a scatter-gather list of physically contiguous memory chunks
> @@ -268,6 +288,14 @@ struct iommu_ops {
> struct iommu_sva_param *param);
> void (*sva_device_shutdown)(struct device *dev,
> struct iommu_sva_param *param);
> + struct io_mm *(*mm_alloc)(struct iommu_domain *domain,
> + struct mm_struct *mm,
> + unsigned long flags);
> + void (*mm_free)(struct io_mm *io_mm);
> + int (*mm_attach)(struct iommu_domain *domain, struct device *dev,
> + struct io_mm *io_mm, bool attach_domain);
> + void (*mm_detach)(struct iommu_domain *domain, struct device *dev,
> + struct io_mm *io_mm, bool detach_domain);
> int (*map)(struct iommu_domain *domain, unsigned long iova,
> phys_addr_t paddr, size_t size, int prot);
> size_t (*unmap)(struct iommu_domain *domain, unsigned long iova,
^ permalink raw reply
* Re: [PATCH v5 05/14] usb: typec: add API to get typec basic port power and data config
From: Heikki Krogerus @ 2018-05-17 14:24 UTC (permalink / raw)
To: Jun Li
Cc: Mats Karrman, robh+dt@kernel.org, gregkh@linuxfoundation.org,
linux@roeck-us.net, a.hajda@samsung.com, cw00.choi@samsung.com,
shufan_lee@richtek.com, Peter Chen, gsomlo@gmail.com,
devicetree@vger.kernel.org, linux-usb@vger.kernel.org,
dl-linux-imx
In-Reply-To: <VI1PR0402MB39179F63BCF3E605443D877389910@VI1PR0402MB3917.eurprd04.prod.outlook.com>
On Thu, May 17, 2018 at 02:05:41PM +0000, Jun Li wrote:
> Hi Heikki,
>
> > > I reread this patch and tried to see it more in the context of the
> > > other patches and the existing code. The naming of the existing string
> > > tables doesn't help in getting this right, however I have a proposal:
> > >
> > > typec_find_port_power_role() to get to TYPEC_PORT_SRC/SNK/DRP
> > > typec_find_port_data_role() to get to TYPEC_PORT_DFP/UFP/DRD
> > > typec_find_power_role() to get to TYPEC_SINK/SOURCE
> > >
> > > and sometime, if the use should arise
> > >
> > > typec_find_data_role() to get to TYPEC_DEVICE/HOST
> > >
> > > I think it is fairly comprehensible, *_port_* concerns a capability
> > > and without *_port_* it is an actual state. Plus it matches the names
> > > of the constants.
> >
> > Well, there are now four things to consider:
> >
> > 1) the roles (power and data) the port is capable of supporting
> > 2) Try.SRC and Try.SNK, i.e. the preferred role
> > 3) the current roles
> > 4) the role(s) the user want's to limit the use of a port with DRP ports
> >
> > The last one I don't know if it's relevant with these functions. It's not
> > information that we would get for example from firmware.
> >
> > I also don't think we need to use these functions with the current roles the port
> > is in.
> >
> > If the preferred role is "sink" or "source", so just like the power role, we don't
> > need separate function for it here.
> >
> > So isn't two functions all we need here: one for the power and one for data
> > role?
>
> Take power as an example, can we use one function to only look up
> typec_port_types[]? as capability(typec_port_type) and state(typec_role)
> are different enum, and the allowed strings are different.
>
> static const char * const typec_roles[] = {
> [TYPEC_SINK] = "sink",
> [TYPEC_SOURCE] = "source",
> };
>
> static const char * const typec_port_types[] = {
> [TYPEC_PORT_SRC] = "source",
> [TYPEC_PORT_SNK] = "sink",
> [TYPEC_PORT_DRP] = "dual",
> };
Where out side the class code we need to convert the current role, the
"state", with these functions?
Thanks,
--
heikki
^ permalink raw reply
* [PATCH 3/3] ARM: multi_v7_defconfig: enable STM32 SPI
From: Amelie Delaunay @ 2018-05-17 14:21 UTC (permalink / raw)
To: Maxime Coquelin, Alexandre Torgue, Rob Herring, Mark Rutland,
Russell King, Arnd Bergmann
Cc: linux-arm-kernel, devicetree, linux-kernel, Amelie Delaunay
In-Reply-To: <1526566904-24514-1-git-send-email-amelie.delaunay@st.com>
Enable the STM32 SPI driver, implemented on STM32MP1 SoC.
Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
---
arch/arm/configs/multi_v7_defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index 89167cd..f990335 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -411,6 +411,7 @@ CONFIG_SPI_S3C64XX=m
CONFIG_SPI_SH_MSIOF=m
CONFIG_SPI_SH_HSPI=y
CONFIG_SPI_SIRF=y
+CONFIG_SPI_STM32=y
CONFIG_SPI_SUN4I=y
CONFIG_SPI_SUN6I=y
CONFIG_SPI_TEGRA114=y
--
2.7.4
^ permalink raw reply related
* [PATCH 2/3] ARM: dts: stm32: add SPI1 support on stm32mp157c-ev1
From: Amelie Delaunay @ 2018-05-17 14:21 UTC (permalink / raw)
To: Maxime Coquelin, Alexandre Torgue, Rob Herring, Mark Rutland,
Russell King, Arnd Bergmann
Cc: linux-arm-kernel, devicetree, linux-kernel, Amelie Delaunay
In-Reply-To: <1526566904-24514-1-git-send-email-amelie.delaunay@st.com>
This patch adds SPI1 support on stm32mp157c-ev1 board.
SPI1 is available on GPIO expansion connector but kept disabled
so these pins can be used as GPIOs by default.
Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
---
arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 16 +++++++++++++++-
arch/arm/boot/dts/stm32mp157c-ev1.dts | 6 ++++++
2 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
index 88e9133..b35f151 100644
--- a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
@@ -277,7 +277,6 @@
compatible = "st,stm32mp157-z-pinctrl";
ranges = <0 0x54004000 0x400>;
pins-are-numbered;
- status = "disabled";
gpioz: gpio@54004000 {
gpio-controller;
@@ -301,6 +300,21 @@
slew-rate = <0>;
};
};
+
+ spi1_pins_a: spi1-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('Z', 0, AF5)>, /* SPI1_SCK */
+ <STM32_PINMUX('Z', 2, AF5)>; /* SPI1_MOSI */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <1>;
+ };
+
+ pins2 {
+ pinmux = <STM32_PINMUX('Z', 1, AF5)>; /* SPI1_MISO */
+ bias-disable;
+ };
+ };
};
};
};
diff --git a/arch/arm/boot/dts/stm32mp157c-ev1.dts b/arch/arm/boot/dts/stm32mp157c-ev1.dts
index 9382d80..7584e1f 100644
--- a/arch/arm/boot/dts/stm32mp157c-ev1.dts
+++ b/arch/arm/boot/dts/stm32mp157c-ev1.dts
@@ -67,6 +67,12 @@
};
};
+&spi1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi1_pins_a>;
+ status = "disabled";
+};
+
&timers2 {
status = "disabled";
pwm {
--
2.7.4
^ permalink raw reply related
* [PATCH 1/3] ARM: dts: stm32: add STM32 SPI support on stm32mp157c
From: Amelie Delaunay @ 2018-05-17 14:21 UTC (permalink / raw)
To: Maxime Coquelin, Alexandre Torgue, Rob Herring, Mark Rutland,
Russell King, Arnd Bergmann
Cc: linux-arm-kernel, devicetree, linux-kernel, Amelie Delaunay
In-Reply-To: <1526566904-24514-1-git-send-email-amelie.delaunay@st.com>
This patch adds all STM32 SPI instances on stm32mp157c.
Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
---
arch/arm/boot/dts/stm32mp157c.dtsi | 84 ++++++++++++++++++++++++++++++++++++++
1 file changed, 84 insertions(+)
diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi
index b66f673..49ce7f0 100644
--- a/arch/arm/boot/dts/stm32mp157c.dtsi
+++ b/arch/arm/boot/dts/stm32mp157c.dtsi
@@ -311,6 +311,34 @@
};
};
+ spi2: spi@4000b000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "st,stm32h7-spi";
+ reg = <0x4000b000 0x400>;
+ interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc SPI2_K>;
+ resets = <&rcc SPI2_R>;
+ dmas = <&dmamux1 39 0x400 0x05>,
+ <&dmamux1 40 0x400 0x05>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
+ spi3: spi@4000c000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "st,stm32h7-spi";
+ reg = <0x4000c000 0x400>;
+ interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc SPI3_K>;
+ resets = <&rcc SPI3_R>;
+ dmas = <&dmamux1 61 0x400 0x05>,
+ <&dmamux1 62 0x400 0x05>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
usart2: serial@4000e000 {
compatible = "st,stm32h7-uart";
reg = <0x4000e000 0x400>;
@@ -494,6 +522,34 @@
status = "disabled";
};
+ spi1: spi@44004000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "st,stm32h7-spi";
+ reg = <0x44004000 0x400>;
+ interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc SPI1_K>;
+ resets = <&rcc SPI1_R>;
+ dmas = <&dmamux1 37 0x400 0x05>,
+ <&dmamux1 38 0x400 0x05>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
+ spi4: spi@44005000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "st,stm32h7-spi";
+ reg = <0x44005000 0x400>;
+ interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc SPI4_K>;
+ resets = <&rcc SPI4_R>;
+ dmas = <&dmamux1 83 0x400 0x05>,
+ <&dmamux1 84 0x400 0x05>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
timers15: timer@44006000 {
#address-cells = <1>;
#size-cells = <0>;
@@ -556,6 +612,20 @@
};
};
+ spi5: spi@44009000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "st,stm32h7-spi";
+ reg = <0x44009000 0x400>;
+ interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc SPI5_K>;
+ resets = <&rcc SPI5_R>;
+ dmas = <&dmamux1 85 0x400 0x05>,
+ <&dmamux1 86 0x400 0x05>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
dma1: dma@48000000 {
compatible = "st,stm32-dma";
reg = <0x48000000 0x400>;
@@ -805,6 +875,20 @@
status = "disabled";
};
+ spi6: spi@5c001000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "st,stm32h7-spi";
+ reg = <0x5c001000 0x400>;
+ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc SPI6_K>;
+ resets = <&rcc SPI6_R>;
+ dmas = <&mdma1 34 0x0 0x40008 0x0 0x0 0>,
+ <&mdma1 35 0x0 0x40002 0x0 0x0 0>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
i2c4: i2c@5c002000 {
compatible = "st,stm32f7-i2c";
reg = <0x5c002000 0x400>;
--
2.7.4
^ permalink raw reply related
* [PATCH 0/3] Add STM32 SPI support on stm32mp157c
From: Amelie Delaunay @ 2018-05-17 14:21 UTC (permalink / raw)
To: Maxime Coquelin, Alexandre Torgue, Rob Herring, Mark Rutland,
Russell King, Arnd Bergmann
Cc: linux-arm-kernel, devicetree, linux-kernel, Amelie Delaunay
This patch adds STM32 SPI support on stm32mp157c SoC.
SPI1, available on GPIO expansion connector, is kept disabled, so these
pins can be used as GPIOs by default.
Amelie Delaunay (3):
ARM: dts: stm32: add STM32 SPI support on stm32mp157c
ARM: dts: stm32: add SPI1 support on stm32mp157c-ev1
ARM: multi_v7_defconfig: enable STM32 SPI
arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 16 +++++-
arch/arm/boot/dts/stm32mp157c-ev1.dts | 6 +++
arch/arm/boot/dts/stm32mp157c.dtsi | 84 +++++++++++++++++++++++++++++++
arch/arm/configs/multi_v7_defconfig | 1 +
4 files changed, 106 insertions(+), 1 deletion(-)
--
2.7.4
^ permalink raw reply
* RE: [PATCH v5 05/14] usb: typec: add API to get typec basic port power and data config
From: Jun Li @ 2018-05-17 14:05 UTC (permalink / raw)
To: Heikki Krogerus, Mats Karrman
Cc: robh+dt@kernel.org, gregkh@linuxfoundation.org,
linux@roeck-us.net, a.hajda@samsung.com, cw00.choi@samsung.com,
shufan_lee@richtek.com, Peter Chen, gsomlo@gmail.com,
devicetree@vger.kernel.org, linux-usb@vger.kernel.org,
dl-linux-imx
In-Reply-To: <20180517123506.GF11469@kuha.fi.intel.com>
Hi Heikki,
> > I reread this patch and tried to see it more in the context of the
> > other patches and the existing code. The naming of the existing string
> > tables doesn't help in getting this right, however I have a proposal:
> >
> > typec_find_port_power_role() to get to TYPEC_PORT_SRC/SNK/DRP
> > typec_find_port_data_role() to get to TYPEC_PORT_DFP/UFP/DRD
> > typec_find_power_role() to get to TYPEC_SINK/SOURCE
> >
> > and sometime, if the use should arise
> >
> > typec_find_data_role() to get to TYPEC_DEVICE/HOST
> >
> > I think it is fairly comprehensible, *_port_* concerns a capability
> > and without *_port_* it is an actual state. Plus it matches the names
> > of the constants.
>
> Well, there are now four things to consider:
>
> 1) the roles (power and data) the port is capable of supporting
> 2) Try.SRC and Try.SNK, i.e. the preferred role
> 3) the current roles
> 4) the role(s) the user want's to limit the use of a port with DRP ports
>
> The last one I don't know if it's relevant with these functions. It's not
> information that we would get for example from firmware.
>
> I also don't think we need to use these functions with the current roles the port
> is in.
>
> If the preferred role is "sink" or "source", so just like the power role, we don't
> need separate function for it here.
>
> So isn't two functions all we need here: one for the power and one for data
> role?
Take power as an example, can we use one function to only look up
typec_port_types[]? as capability(typec_port_type) and state(typec_role)
are different enum, and the allowed strings are different.
static const char * const typec_roles[] = {
[TYPEC_SINK] = "sink",
[TYPEC_SOURCE] = "source",
};
static const char * const typec_port_types[] = {
[TYPEC_PORT_SRC] = "source",
[TYPEC_PORT_SNK] = "sink",
[TYPEC_PORT_DRP] = "dual",
};
Thanks
Li Jun
>
>
> Thanks,
>
> --
> heikki
^ permalink raw reply
* [PATCH v3] ASoC: ssm2305: Add amplifier driver
From: Marco Felsch @ 2018-05-17 13:55 UTC (permalink / raw)
To: lars, lgirdwood, broonie, robh+dt, mark.rutland
Cc: devicetree, alsa-devel, kernel
The ssm2305 is a simple Class-D audio amplifier. A application can
turn on/off the device by a gpio. It's also possible to hardwire the
shutdown pin.
Tested on a i.MX6 based custom board.
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
Notes (changelog):
v2:
- fix copyright information
- rename shutdown gpio and add some more documentation
- mark shutdown gpio as required
- rm registration information
v3:
- fix error handling
.../devicetree/bindings/sound/adi,ssm2305.txt | 14 +++
sound/soc/codecs/Kconfig | 7 ++
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/ssm2305.c | 104 ++++++++++++++++++
4 files changed, 127 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/adi,ssm2305.txt
create mode 100644 sound/soc/codecs/ssm2305.c
diff --git a/Documentation/devicetree/bindings/sound/adi,ssm2305.txt b/Documentation/devicetree/bindings/sound/adi,ssm2305.txt
new file mode 100644
index 000000000000..a9c9d83c8a30
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/adi,ssm2305.txt
@@ -0,0 +1,14 @@
+Analog Devices SSM2305 Speaker Amplifier
+========================================
+
+Required properties:
+ - compatible : "adi,ssm2305"
+ - shutdown-gpios : The gpio connected to the shutdown pin.
+ The gpio signal is ACTIVE_LOW.
+
+Example:
+
+ssm2305: analog-amplifier {
+ compatible = "adi,ssm2305";
+ shutdown-gpios = <&gpio3 20 GPIO_ACTIVE_LOW>;
+};
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 9548f63ca531..d81b0cb291a3 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -142,6 +142,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_SI476X if MFD_SI476X_CORE
select SND_SOC_SIRF_AUDIO_CODEC
select SND_SOC_SPDIF
+ select SND_SOC_SSM2305
select SND_SOC_SSM2518 if I2C
select SND_SOC_SSM2602_SPI if SPI_MASTER
select SND_SOC_SSM2602_I2C if I2C
@@ -883,6 +884,12 @@ config SND_SOC_SIRF_AUDIO_CODEC
config SND_SOC_SPDIF
tristate "S/PDIF CODEC"
+config SND_SOC_SSM2305
+ tristate "Analog Devices SSM2305 Class-D Amplifier"
+ help
+ Enable support for Analog Devices SSM2305 filterless
+ high-efficiency mono Class-D audio power amplifiers.
+
config SND_SOC_SSM2518
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index e849d1495308..7d75ac8f6716 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -153,6 +153,7 @@ snd-soc-si476x-objs := si476x.o
snd-soc-sirf-audio-codec-objs := sirf-audio-codec.o
snd-soc-spdif-tx-objs := spdif_transmitter.o
snd-soc-spdif-rx-objs := spdif_receiver.o
+snd-soc-ssm2305-objs := ssm2305.o
snd-soc-ssm2518-objs := ssm2518.o
snd-soc-ssm2602-objs := ssm2602.o
snd-soc-ssm2602-spi-objs := ssm2602-spi.o
@@ -404,6 +405,7 @@ obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP) += snd-soc-sigmadsp-regmap.o
obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o
obj-$(CONFIG_SND_SOC_SIRF_AUDIO_CODEC) += sirf-audio-codec.o
+obj-$(CONFIG_SND_SOC_SSM2305) += snd-soc-ssm2305.o
obj-$(CONFIG_SND_SOC_SSM2518) += snd-soc-ssm2518.o
obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
obj-$(CONFIG_SND_SOC_SSM2602_SPI) += snd-soc-ssm2602-spi.o
diff --git a/sound/soc/codecs/ssm2305.c b/sound/soc/codecs/ssm2305.c
new file mode 100644
index 000000000000..39d8b01cd852
--- /dev/null
+++ b/sound/soc/codecs/ssm2305.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Analog Devices SSM2305 Amplifier Driver
+ *
+ * Copyright (C) 2018 Pengutronix, Marco Felsch <kernel@pengutronix.de>
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+
+#define DRV_NAME "ssm2305"
+
+struct ssm2305 {
+ /* shutdown gpio */
+ struct gpio_desc *gpiod_shutdown;
+};
+
+static int ssm2305_power_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kctrl, int event)
+{
+ struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
+ struct ssm2305 *data = snd_soc_component_get_drvdata(c);
+
+ gpiod_set_value_cansleep(data->gpiod_shutdown,
+ SND_SOC_DAPM_EVENT_ON(event));
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget ssm2305_dapm_widgets[] = {
+ /* Stereo input/output */
+ SND_SOC_DAPM_INPUT("L_IN"),
+ SND_SOC_DAPM_INPUT("R_IN"),
+ SND_SOC_DAPM_OUTPUT("L_OUT"),
+ SND_SOC_DAPM_OUTPUT("R_OUT"),
+
+ SND_SOC_DAPM_SUPPLY("Power", SND_SOC_NOPM, 0, 0, ssm2305_power_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route ssm2305_dapm_routes[] = {
+ { "L_OUT", NULL, "L_IN" },
+ { "R_OUT", NULL, "R_IN" },
+ { "L_IN", NULL, "Power" },
+ { "R_IN", NULL, "Power" },
+};
+
+static const struct snd_soc_component_driver ssm2305_component_driver = {
+ .dapm_widgets = ssm2305_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(ssm2305_dapm_widgets),
+ .dapm_routes = ssm2305_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(ssm2305_dapm_routes),
+};
+
+static int ssm2305_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ssm2305 *priv;
+ int err;
+
+ /* Allocate the private data */
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, priv);
+
+ /* Get shutdown gpio */
+ priv->gpiod_shutdown = devm_gpiod_get(dev, "shutdown",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(priv->gpiod_shutdown)) {
+ err = PTR_ERR(priv->gpiod_shutdown);
+ if (err != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get 'shutdown' gpio: %d\n",
+ err);
+ return err;
+ }
+
+ return devm_snd_soc_register_component(dev, &ssm2305_component_driver,
+ NULL, 0);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id ssm2305_of_match[] = {
+ { .compatible = "adi,ssm2305", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ssm2305_of_match);
+#endif
+
+static struct platform_driver ssm2305_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = of_match_ptr(ssm2305_of_match),
+ },
+ .probe = ssm2305_probe,
+};
+
+module_platform_driver(ssm2305_driver);
+
+MODULE_DESCRIPTION("ASoC SSM2305 amplifier driver");
+MODULE_AUTHOR("Marco Felsch <m.felsch@pengutronix.de>");
+MODULE_LICENSE("GPL v2");
--
2.17.0
^ permalink raw reply related
* RE: [PATCH v5 05/14] usb: typec: add API to get typec basic port power and data config
From: Jun Li @ 2018-05-17 13:53 UTC (permalink / raw)
To: Mats Karrman, Heikki Krogerus
Cc: robh+dt@kernel.org, gregkh@linuxfoundation.org,
linux@roeck-us.net, a.hajda@samsung.com, cw00.choi@samsung.com,
shufan_lee@richtek.com, Peter Chen, gsomlo@gmail.com,
devicetree@vger.kernel.org, linux-usb@vger.kernel.org,
dl-linux-imx
In-Reply-To: <33d02e76-bdf2-be50-68ec-9d520acdbe82@gmail.com>
Hi Mats
> I reread this patch and tried to see it more in the context of the other patches
> and the existing code. The naming of the existing string tables doesn't help in
> getting this right, however I have a proposal:
>
> typec_find_port_power_role() to get to TYPEC_PORT_SRC/SNK/DRP
> typec_find_port_data_role() to get to TYPEC_PORT_DFP/UFP/DRD
> typec_find_power_role() to get to TYPEC_SINK/SOURCE
>
> and sometime, if the use should arise
>
> typec_find_data_role() to get to TYPEC_DEVICE/HOST
>
> I think it is fairly comprehensible, *_port_* concerns a capability and without
> *_port_* it is an actual state. Plus it matches the names of the constants.
>
Reasonable to me, I was using "type" to concern a capability but it was not
preferred, if Heikki agree this proposal, I will change the API names like this
and include 4 APIs above.
Thanks
Li Jun
^ permalink raw reply
* Re: [PATCH v5 4/4] drm/rockchip: support dp training outside dp firmware
From: Sean Paul @ 2018-05-17 13:51 UTC (permalink / raw)
To: Lin Huang
Cc: devicetree, airlied, briannorris, dianders, linux-kernel,
linux-rockchip, robh+dt, dri-devel, zyw, daniel.vetter,
linux-arm-kernel
In-Reply-To: <1526548680-2552-4-git-send-email-hl@rock-chips.com>
On Thu, May 17, 2018 at 05:18:00PM +0800, Lin Huang wrote:
> DP firmware uses fixed phy config values to do training, but some
> boards need to adjust these values to fit for their unique hardware
> design. So get phy config values from dts and use software link training
> instead of relying on firmware, if software training fail, keep firmware
> training as a fallback if sw training fails.
>
> Signed-off-by: Chris Zhong <zyw@rock-chips.com>
> Signed-off-by: Lin Huang <hl@rock-chips.com>
> ---
> Changes in v2:
> - update patch following Enric suggest
> Changes in v3:
> - use variable fw_training instead sw_training_success
> - base on DP SPCE, if training fail use lower link rate to retry training
> Changes in v4:
> - improve cdn_dp_get_lower_link_rate() and cdn_dp_software_train_link() follow Sean suggest
> Changes in v5:
> - fix some whitespcae issue
>
> drivers/gpu/drm/rockchip/Makefile | 3 +-
> drivers/gpu/drm/rockchip/cdn-dp-core.c | 24 +-
> drivers/gpu/drm/rockchip/cdn-dp-core.h | 2 +
> drivers/gpu/drm/rockchip/cdn-dp-link-training.c | 420 ++++++++++++++++++++++++
> drivers/gpu/drm/rockchip/cdn-dp-reg.c | 31 +-
> drivers/gpu/drm/rockchip/cdn-dp-reg.h | 38 ++-
> 6 files changed, 505 insertions(+), 13 deletions(-)
> create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-link-training.c
>
> diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
> index a314e21..b932f62 100644
> --- a/drivers/gpu/drm/rockchip/Makefile
> +++ b/drivers/gpu/drm/rockchip/Makefile
> @@ -9,7 +9,8 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
> rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
>
> rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
> -rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
> +rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o \
> + cdn-dp-link-training.o
> rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
> rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o
> rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o
> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
> index cce64c1..d9d0d4d 100644
> --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
> +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
> @@ -629,11 +629,13 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder)
> goto out;
> }
> }
> -
> - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE);
> - if (ret) {
> - DRM_DEV_ERROR(dp->dev, "Failed to idle video %d\n", ret);
> - goto out;
> + if (dp->use_fw_training == true) {
> + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE);
> + if (ret) {
> + DRM_DEV_ERROR(dp->dev,
> + "Failed to idle video %d\n", ret);
> + goto out;
> + }
> }
>
> ret = cdn_dp_config_video(dp);
> @@ -642,11 +644,15 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder)
> goto out;
> }
>
> - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID);
> - if (ret) {
> - DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret);
> - goto out;
> + if (dp->use_fw_training == true) {
> + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID);
> + if (ret) {
> + DRM_DEV_ERROR(dp->dev,
> + "Failed to valid video %d\n", ret);
> + goto out;
> + }
> }
> +
> out:
> mutex_unlock(&dp->lock);
> }
> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h
> index 46159b2..77a9793 100644
> --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h
> +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h
> @@ -84,6 +84,7 @@ struct cdn_dp_device {
> bool connected;
> bool active;
> bool suspended;
> + bool use_fw_training;
>
> const struct firmware *fw; /* cdn dp firmware */
> unsigned int fw_version; /* cdn fw version */
> @@ -106,6 +107,7 @@ struct cdn_dp_device {
> u8 ports;
> u8 lanes;
> int active_port;
> + u8 train_set[4];
>
> u8 dpcd[DP_RECEIVER_CAP_SIZE];
> bool sink_has_audio;
> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-link-training.c b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c
> new file mode 100644
> index 0000000..73c3290
> --- /dev/null
> +++ b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c
> @@ -0,0 +1,420 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
> + * Author: Chris Zhong <zyw@rock-chips.com>
> + */
> +
> +#include <linux/device.h>
> +#include <linux/delay.h>
> +#include <linux/phy/phy.h>
> +#include <soc/rockchip/rockchip_phy_typec.h>
> +
> +#include "cdn-dp-core.h"
> +#include "cdn-dp-reg.h"
> +
> +static void cdn_dp_set_signal_levels(struct cdn_dp_device *dp)
> +{
> + struct cdn_dp_port *port = dp->port[dp->active_port];
> + struct rockchip_typec_phy *tcphy = phy_get_drvdata(port->phy);
You ignored Brian's comment on the previous patch:
This is still antithetical to the PHY framework; you're assuming that
this is a particular type of PHY here.
FWIW, the mediatek drm driver also assumes a certain PHY type. A quick grep of
drivers/ shows that the only other non-phy/ driver using this function
(pinctrl-tegra-xusb.c) also casts it.
Sean
> +
> + int rate = drm_dp_bw_code_to_link_rate(dp->link.rate);
> + u8 swing = (dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) >>
> + DP_TRAIN_VOLTAGE_SWING_SHIFT;
> + u8 pre_emphasis = (dp->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
> + >> DP_TRAIN_PRE_EMPHASIS_SHIFT;
> +
> + tcphy->typec_phy_config(port->phy, rate, dp->link.num_lanes,
> + swing, pre_emphasis);
> +}
> +
> +static int cdn_dp_set_pattern(struct cdn_dp_device *dp, uint8_t dp_train_pat)
> +{
> + u32 phy_config, global_config;
> + int ret;
> + uint8_t pattern = dp_train_pat & DP_TRAINING_PATTERN_MASK;
> +
> + global_config = NUM_LANES(dp->link.num_lanes - 1) | SST_MODE |
> + GLOBAL_EN | RG_EN | ENC_RST_DIS | WR_VHSYNC_FALL;
> +
> + phy_config = DP_TX_PHY_ENCODER_BYPASS(0) |
> + DP_TX_PHY_SKEW_BYPASS(0) |
> + DP_TX_PHY_DISPARITY_RST(0) |
> + DP_TX_PHY_LANE0_SKEW(0) |
> + DP_TX_PHY_LANE1_SKEW(1) |
> + DP_TX_PHY_LANE2_SKEW(2) |
> + DP_TX_PHY_LANE3_SKEW(3) |
> + DP_TX_PHY_10BIT_ENABLE(0);
> +
> + if (pattern != DP_TRAINING_PATTERN_DISABLE) {
> + global_config |= NO_VIDEO;
> + phy_config |= DP_TX_PHY_TRAINING_ENABLE(1) |
> + DP_TX_PHY_SCRAMBLER_BYPASS(1) |
> + DP_TX_PHY_TRAINING_PATTERN(pattern);
> + }
> +
> + ret = cdn_dp_reg_write(dp, DP_FRAMER_GLOBAL_CONFIG, global_config);
> + if (ret) {
> + DRM_ERROR("fail to set DP_FRAMER_GLOBAL_CONFIG, error: %d\n",
> + ret);
> + return ret;
> + }
> +
> + ret = cdn_dp_reg_write(dp, DP_TX_PHY_CONFIG_REG, phy_config);
> + if (ret) {
> + DRM_ERROR("fail to set DP_TX_PHY_CONFIG_REG, error: %d\n",
> + ret);
> + return ret;
> + }
> +
> + ret = cdn_dp_reg_write(dp, DPTX_LANE_EN, BIT(dp->link.num_lanes) - 1);
> + if (ret) {
> + DRM_ERROR("fail to set DPTX_LANE_EN, error: %d\n", ret);
> + return ret;
> + }
> +
> + if (drm_dp_enhanced_frame_cap(dp->dpcd))
> + ret = cdn_dp_reg_write(dp, DPTX_ENHNCD, 1);
> + else
> + ret = cdn_dp_reg_write(dp, DPTX_ENHNCD, 0);
> + if (ret)
> + DRM_ERROR("failed to set DPTX_ENHNCD, error: %x\n", ret);
> +
> + return ret;
> +}
> +
> +static u8 cdn_dp_pre_emphasis_max(u8 voltage_swing)
> +{
> + switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
> + return DP_TRAIN_PRE_EMPH_LEVEL_3;
> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
> + return DP_TRAIN_PRE_EMPH_LEVEL_2;
> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
> + return DP_TRAIN_PRE_EMPH_LEVEL_1;
> + default:
> + return DP_TRAIN_PRE_EMPH_LEVEL_0;
> + }
> +}
> +
> +static void cdn_dp_get_adjust_train(struct cdn_dp_device *dp,
> + uint8_t link_status[DP_LINK_STATUS_SIZE])
> +{
> + int i;
> + uint8_t v = 0, p = 0;
> + uint8_t preemph_max;
> +
> + for (i = 0; i < dp->link.num_lanes; i++) {
> + v = max(v, drm_dp_get_adjust_request_voltage(link_status, i));
> + p = max(p, drm_dp_get_adjust_request_pre_emphasis(link_status,
> + i));
> + }
> +
> + if (v >= VOLTAGE_LEVEL_2)
> + v = VOLTAGE_LEVEL_2 | DP_TRAIN_MAX_SWING_REACHED;
> +
> + preemph_max = cdn_dp_pre_emphasis_max(v);
> + if (p >= preemph_max)
> + p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
> +
> + for (i = 0; i < dp->link.num_lanes; i++)
> + dp->train_set[i] = v | p;
> +}
> +
> +/*
> + * Pick training pattern for channel equalization. Training Pattern 3 for HBR2
> + * or 1.2 devices that support it, Training Pattern 2 otherwise.
> + */
> +static u32 cdn_dp_select_chaneq_pattern(struct cdn_dp_device *dp)
> +{
> + u32 training_pattern = DP_TRAINING_PATTERN_2;
> +
> + /*
> + * cdn dp support HBR2 also support TPS3. TPS3 support is also mandatory
> + * for downstream devices that support HBR2. However, not all sinks
> + * follow the spec.
> + */
> + if (drm_dp_tps3_supported(dp->dpcd))
> + training_pattern = DP_TRAINING_PATTERN_3;
> + else
> + DRM_DEBUG_KMS("5.4 Gbps link rate without sink TPS3 support\n");
> +
> + return training_pattern;
> +}
> +
> +
> +static bool cdn_dp_link_max_vswing_reached(struct cdn_dp_device *dp)
> +{
> + int lane;
> +
> + for (lane = 0; lane < dp->link.num_lanes; lane++)
> + if ((dp->train_set[lane] & DP_TRAIN_MAX_SWING_REACHED) == 0)
> + return false;
> +
> + return true;
> +}
> +
> +static int cdn_dp_update_link_train(struct cdn_dp_device *dp)
> +{
> + int ret;
> +
> + cdn_dp_set_signal_levels(dp);
> +
> + ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET,
> + dp->train_set, dp->link.num_lanes);
> + if (ret != dp->link.num_lanes)
> + return -EINVAL;
> +
> + return 0;
> +}
> +
> +static int cdn_dp_set_link_train(struct cdn_dp_device *dp,
> + uint8_t dp_train_pat)
> +{
> + uint8_t buf[sizeof(dp->train_set) + 1];
> + int ret, len;
> +
> + buf[0] = dp_train_pat;
> + if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) ==
> + DP_TRAINING_PATTERN_DISABLE) {
> + /* don't write DP_TRAINING_LANEx_SET on disable */
> + len = 1;
> + } else {
> + /* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
> + memcpy(buf + 1, dp->train_set, dp->link.num_lanes);
> + len = dp->link.num_lanes + 1;
> + }
> +
> + ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_PATTERN_SET,
> + buf, len);
> + if (ret != len)
> + return -EINVAL;
> +
> + return 0;
> +}
> +
> +static int cdn_dp_reset_link_train(struct cdn_dp_device *dp,
> + uint8_t dp_train_pat)
> +{
> + int ret;
> +
> + memset(dp->train_set, 0, sizeof(dp->train_set));
> +
> + cdn_dp_set_signal_levels(dp);
> +
> + ret = cdn_dp_set_pattern(dp, dp_train_pat);
> + if (ret)
> + return ret;
> +
> + return cdn_dp_set_link_train(dp, dp_train_pat);
> +}
> +
> +/* Enable corresponding port and start training pattern 1 */
> +static int cdn_dp_link_training_clock_recovery(struct cdn_dp_device *dp)
> +{
> + u8 voltage;
> + u8 link_status[DP_LINK_STATUS_SIZE];
> + u32 voltage_tries, max_vswing_tries;
> + int ret;
> +
> + /* clock recovery */
> + ret = cdn_dp_reset_link_train(dp, DP_TRAINING_PATTERN_1 |
> + DP_LINK_SCRAMBLING_DISABLE);
> + if (ret) {
> + DRM_ERROR("failed to start link train\n");
> + return ret;
> + }
> +
> + voltage_tries = 1;
> + max_vswing_tries = 0;
> + for (;;) {
> + drm_dp_link_train_clock_recovery_delay(dp->dpcd);
> + if (drm_dp_dpcd_read_link_status(&dp->aux, link_status) !=
> + DP_LINK_STATUS_SIZE) {
> + DRM_ERROR("failed to get link status\n");
> + return -EINVAL;
> + }
> +
> + if (drm_dp_clock_recovery_ok(link_status, dp->link.num_lanes)) {
> + DRM_DEBUG_KMS("clock recovery OK\n");
> + return 0;
> + }
> +
> + if (voltage_tries >= 5) {
> + DRM_DEBUG_KMS("Same voltage tried 5 times\n");
> + return -EINVAL;
> + }
> +
> + if (max_vswing_tries >= 1) {
> + DRM_DEBUG_KMS("Max Voltage Swing reached\n");
> + return -EINVAL;
> + }
> +
> + voltage = dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
> +
> + /* Update training set as requested by target */
> + cdn_dp_get_adjust_train(dp, link_status);
> + if (cdn_dp_update_link_train(dp)) {
> + DRM_ERROR("failed to update link training\n");
> + return -EINVAL;
> + }
> +
> + if ((dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) ==
> + voltage)
> + ++voltage_tries;
> + else
> + voltage_tries = 1;
> +
> + if (cdn_dp_link_max_vswing_reached(dp))
> + ++max_vswing_tries;
> + }
> +}
> +
> +static int cdn_dp_link_training_channel_equalization(struct cdn_dp_device *dp)
> +{
> + int tries, ret;
> + u32 training_pattern;
> + uint8_t link_status[DP_LINK_STATUS_SIZE];
> +
> + training_pattern = cdn_dp_select_chaneq_pattern(dp);
> + training_pattern |= DP_LINK_SCRAMBLING_DISABLE;
> +
> + ret = cdn_dp_set_pattern(dp, training_pattern);
> + if (ret)
> + return ret;
> +
> + ret = cdn_dp_set_link_train(dp, training_pattern);
> + if (ret) {
> + DRM_ERROR("failed to start channel equalization\n");
> + return ret;
> + }
> +
> + for (tries = 0; tries < 5; tries++) {
> + drm_dp_link_train_channel_eq_delay(dp->dpcd);
> + if (drm_dp_dpcd_read_link_status(&dp->aux, link_status) !=
> + DP_LINK_STATUS_SIZE) {
> + DRM_ERROR("failed to get link status\n");
> + break;
> + }
> +
> + /* Make sure clock is still ok */
> + if (!drm_dp_clock_recovery_ok(link_status,
> + dp->link.num_lanes)) {
> + DRM_DEBUG_KMS("Clock recovery check failed\n");
> + break;
> + }
> +
> + if (drm_dp_channel_eq_ok(link_status, dp->link.num_lanes)) {
> + DRM_DEBUG_KMS("Channel EQ done\n");
> + return 0;
> + }
> +
> + /* Update training set as requested by target */
> + cdn_dp_get_adjust_train(dp, link_status);
> + if (cdn_dp_update_link_train(dp)) {
> + DRM_ERROR("failed to update link training\n");
> + break;
> + }
> + }
> +
> + /* Try 5 times, else fail and try at lower BW */
> + if (tries == 5)
> + DRM_DEBUG_KMS("Channel equalization failed 5 times\n");
> +
> + return -EINVAL;
> +}
> +
> +static int cdn_dp_stop_link_train(struct cdn_dp_device *dp)
> +{
> + int ret = cdn_dp_set_pattern(dp, DP_TRAINING_PATTERN_DISABLE);
> +
> + if (ret)
> + return ret;
> +
> + return cdn_dp_set_link_train(dp, DP_TRAINING_PATTERN_DISABLE);
> +}
> +
> +static int cdn_dp_get_lower_link_rate(struct cdn_dp_device *dp)
> +{
> + switch (dp->link.rate) {
> + case DP_LINK_BW_1_62:
> + return -EINVAL;
> + case DP_LINK_BW_2_7:
> + dp->link.rate = DP_LINK_BW_1_62;
> + break;
> + case DP_LINK_BW_5_4:
> + dp->link.rate = DP_LINK_BW_2_7;
> + break;
> + default:
> + dp->link.rate = DP_LINK_BW_5_4;
> + break;
> + }
> +
> + return 0;
> +}
> +
> +int cdn_dp_software_train_link(struct cdn_dp_device *dp)
> +{
> + int ret, stop_err;
> + u8 link_config[2];
> + u32 rate, sink_max, source_max;
> +
> + ret = drm_dp_dpcd_read(&dp->aux, DP_DPCD_REV, dp->dpcd,
> + sizeof(dp->dpcd));
> + if (ret < 0) {
> + DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret);
> + return ret;
> + }
> +
> + source_max = dp->lanes;
> + sink_max = drm_dp_max_lane_count(dp->dpcd);
> + dp->link.num_lanes = min(source_max, sink_max);
> +
> + source_max = drm_dp_bw_code_to_link_rate(CDN_DP_MAX_LINK_RATE);
> + sink_max = drm_dp_max_link_rate(dp->dpcd);
> + rate = min(source_max, sink_max);
> + dp->link.rate = drm_dp_link_rate_to_bw_code(rate);
> +
> + link_config[0] = 0;
> + link_config[1] = 0;
> + if (dp->dpcd[DP_MAIN_LINK_CHANNEL_CODING] & 0x01)
> + link_config[1] = DP_SET_ANSI_8B10B;
> + drm_dp_dpcd_write(&dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
> +
> + while (true) {
> +
> + /* Write the link configuration data */
> + link_config[0] = dp->link.rate;
> + link_config[1] = dp->link.num_lanes;
> + if (drm_dp_enhanced_frame_cap(dp->dpcd))
> + link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
> + drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, link_config, 2);
> +
> + ret = cdn_dp_link_training_clock_recovery(dp);
> + if (ret) {
> + if (!cdn_dp_get_lower_link_rate(dp))
> + continue;
> +
> + DRM_ERROR("training clock recovery failed: %d\n", ret);
> + break;
> + }
> +
> + ret = cdn_dp_link_training_channel_equalization(dp);
> + if (ret) {
> + if (!cdn_dp_get_lower_link_rate(dp))
> + continue;
> +
> + DRM_ERROR("training channel eq failed: %d\n", ret);
> + break;
> + }
> +
> + break;
> + }
> +
> + stop_err = cdn_dp_stop_link_train(dp);
> + if (stop_err) {
> + DRM_ERROR("stop training fail, error: %d\n", stop_err);
> + return stop_err;
> + }
> +
> + return ret;
> +}
> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c
> index 979355d..e1273e6 100644
> --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c
> +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c
> @@ -17,7 +17,9 @@
> #include <linux/delay.h>
> #include <linux/io.h>
> #include <linux/iopoll.h>
> +#include <linux/phy/phy.h>
> #include <linux/reset.h>
> +#include <soc/rockchip/rockchip_phy_typec.h>
>
> #include "cdn-dp-core.h"
> #include "cdn-dp-reg.h"
> @@ -189,7 +191,7 @@ static int cdn_dp_mailbox_send(struct cdn_dp_device *dp, u8 module_id,
> return 0;
> }
>
> -static int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val)
> +int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val)
> {
> u8 msg[6];
>
> @@ -609,6 +611,31 @@ int cdn_dp_train_link(struct cdn_dp_device *dp)
> {
> int ret;
>
> + /*
> + * DP firmware uses fixed phy config values to do training, but some
> + * boards need to adjust these values to fit for their unique hardware
> + * design. So if the phy is using custom config values, do software
> + * link training instead of relying on firmware, if software training
> + * fail, keep firmware training as a fallback if sw training fails.
> + */
> + ret = cdn_dp_software_train_link(dp);
> + if (ret) {
> + DRM_DEV_ERROR(dp->dev,
> + "Failed to do software training %d\n", ret);
> + goto do_fw_training;
> + }
> + ret = cdn_dp_reg_write(dp, SOURCE_HDTX_CAR, 0xf);
> + if (ret) {
> + DRM_DEV_ERROR(dp->dev,
> + "Failed to write SOURCE_HDTX_CAR register %d\n", ret);
> + goto do_fw_training;
> + }
> + dp->use_fw_training = false;
> + return 0;
> +
> +do_fw_training:
> + dp->use_fw_training = true;
> + DRM_DEV_DEBUG_KMS(dp->dev, "use fw training\n");
> ret = cdn_dp_training_start(dp);
> if (ret) {
> DRM_DEV_ERROR(dp->dev, "Failed to start training %d\n", ret);
> @@ -623,7 +650,7 @@ int cdn_dp_train_link(struct cdn_dp_device *dp)
>
> DRM_DEV_DEBUG_KMS(dp->dev, "rate:0x%x, lanes:%d\n", dp->link.rate,
> dp->link.num_lanes);
> - return ret;
> + return 0;
> }
>
> int cdn_dp_set_video_status(struct cdn_dp_device *dp, int active)
> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.h b/drivers/gpu/drm/rockchip/cdn-dp-reg.h
> index 6580b11..3420771 100644
> --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.h
> +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.h
> @@ -137,7 +137,7 @@
> #define HPD_EVENT_MASK 0x211c
> #define HPD_EVENT_DET 0x2120
>
> -/* dpyx framer addr */
> +/* dptx framer addr */
> #define DP_FRAMER_GLOBAL_CONFIG 0x2200
> #define DP_SW_RESET 0x2204
> #define DP_FRAMER_TU 0x2208
> @@ -431,6 +431,40 @@
> /* Reference cycles when using lane clock as reference */
> #define LANE_REF_CYC 0x8000
>
> +/* register CM_VID_CTRL */
> +#define LANE_VID_REF_CYC(x) (((x) & (BIT(24) - 1)) << 0)
> +#define NMVID_MEAS_TOLERANCE(x) (((x) & 0xf) << 24)
> +
> +/* register DP_TX_PHY_CONFIG_REG */
> +#define DP_TX_PHY_TRAINING_ENABLE(x) ((x) & 1)
> +#define DP_TX_PHY_TRAINING_TYPE_PRBS7 (0 << 1)
> +#define DP_TX_PHY_TRAINING_TYPE_TPS1 (1 << 1)
> +#define DP_TX_PHY_TRAINING_TYPE_TPS2 (2 << 1)
> +#define DP_TX_PHY_TRAINING_TYPE_TPS3 (3 << 1)
> +#define DP_TX_PHY_TRAINING_TYPE_TPS4 (4 << 1)
> +#define DP_TX_PHY_TRAINING_TYPE_PLTPAT (5 << 1)
> +#define DP_TX_PHY_TRAINING_TYPE_D10_2 (6 << 1)
> +#define DP_TX_PHY_TRAINING_TYPE_HBR2CPAT (8 << 1)
> +#define DP_TX_PHY_TRAINING_PATTERN(x) ((x) << 1)
> +#define DP_TX_PHY_SCRAMBLER_BYPASS(x) (((x) & 1) << 5)
> +#define DP_TX_PHY_ENCODER_BYPASS(x) (((x) & 1) << 6)
> +#define DP_TX_PHY_SKEW_BYPASS(x) (((x) & 1) << 7)
> +#define DP_TX_PHY_DISPARITY_RST(x) (((x) & 1) << 8)
> +#define DP_TX_PHY_LANE0_SKEW(x) (((x) & 7) << 9)
> +#define DP_TX_PHY_LANE1_SKEW(x) (((x) & 7) << 12)
> +#define DP_TX_PHY_LANE2_SKEW(x) (((x) & 7) << 15)
> +#define DP_TX_PHY_LANE3_SKEW(x) (((x) & 7) << 18)
> +#define DP_TX_PHY_10BIT_ENABLE(x) (((x) & 1) << 21)
> +
> +/* register DP_FRAMER_GLOBAL_CONFIG */
> +#define NUM_LANES(x) ((x) & 3)
> +#define SST_MODE (0 << 2)
> +#define RG_EN (0 << 4)
> +#define GLOBAL_EN BIT(3)
> +#define NO_VIDEO BIT(5)
> +#define ENC_RST_DIS BIT(6)
> +#define WR_VHSYNC_FALL BIT(7)
> +
> enum voltage_swing_level {
> VOLTAGE_LEVEL_0,
> VOLTAGE_LEVEL_1,
> @@ -476,6 +510,7 @@ int cdn_dp_set_host_cap(struct cdn_dp_device *dp, u8 lanes, bool flip);
> int cdn_dp_event_config(struct cdn_dp_device *dp);
> u32 cdn_dp_get_event(struct cdn_dp_device *dp);
> int cdn_dp_get_hpd_status(struct cdn_dp_device *dp);
> +int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val);
> ssize_t cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr,
> u8 *data, u16 len);
> ssize_t cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr,
> @@ -489,4 +524,5 @@ int cdn_dp_config_video(struct cdn_dp_device *dp);
> int cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio);
> int cdn_dp_audio_mute(struct cdn_dp_device *dp, bool enable);
> int cdn_dp_audio_config(struct cdn_dp_device *dp, struct audio_info *audio);
> +int cdn_dp_software_train_link(struct cdn_dp_device *dp);
> #endif /* _CDN_DP_REG_H */
> --
> 2.7.4
>
--
Sean Paul, Software Engineer, Google / Chromium OS
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: [PATCH 3/3] arm64: dts: renesas: r8a7795: add ccree binding
From: Geert Uytterhoeven @ 2018-05-17 13:49 UTC (permalink / raw)
To: Gilad Ben-Yossef
Cc: Simon Horman, Magnus Damm, Rob Herring, Mark Rutland,
Catalin Marinas, Will Deacon, Geert Uytterhoeven,
Michael Turquette, Stephen Boyd, Herbert Xu, David S. Miller,
Ofir Drang, Linux-Renesas,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Linux ARM, Linux Kernel Mailing List, linux-clk
In-Reply-To: <CAOtvUMee+cn+=bEuB5iBiU9yeSsCiDPDwej8Uw-_3wVP4fagpA@mail.gmail.com>
Hi Gilad,
On Thu, May 17, 2018 at 3:41 PM, Gilad Ben-Yossef <gilad@benyossef.com> wrote:
> On Thu, May 17, 2018 at 4:35 PM, Geert Uytterhoeven
> <geert@linux-m68k.org> wrote:
>> On Thu, May 17, 2018 at 3:09 PM, Gilad Ben-Yossef <gilad@benyossef.com> wrote:
>>> On Thu, May 17, 2018 at 1:16 PM, Geert Uytterhoeven
>>> <geert@linux-m68k.org> wrote:
>>>> However, even with your clock patch, the signature checking fails for me,
>>>> on both R-Car H3 ES1.0 and ES2.0.
>>>> Does this need changes to the ARM Trusted Firmware, to allow Linux to
>>>> access the public SCEG module?
>>>
>>> Well, this is actually something different. If you look you will
>>> notice that my patch was part of a 3 part patch series,
>>> the first of which disabled this test.
>>
>> Sorry, I had completely forgotten about the first patch from the series.
>> With that applied, it continues:
>>
>> ccree e6601000.crypto: ARM CryptoCell 630P Driver: HW version
>> 0x00000000, Driver version 4.0
>> ccree e6601000.crypto: Cache params previous: 0x00000777
>> ccree e6601000.crypto: Cache params current: 0x00000000
>> (expect: 0x00000000)
>> alg: No test for cts1(cbc(aes)) (cts1-cbc-aes-ccree)
>> alg: No test for authenc(xcbc(aes),cbc(aes))
>> (authenc-xcbc-aes-cbc-aes-ccree)
>> alg: No test for authenc(xcbc(aes),rfc3686(ctr(aes)))
>> (authenc-xcbc-aes-rfc3686-ctr-aes-ccree)
>> ccree e6601000.crypto: ARM ccree device initialized
>>
>> Is HW version 0x00000000 expected?
>
> It's related to the problem with reading the wrong register I've
> mentioned before.
OK.
>>> If you take all the 3 patches, it will work.
>>
>> is there an easy way to test proper operation?
>
> The lines of the form " alg: No test for cts1(cbc(aes))
> (cts1-cbc-aes-ccree)" indicates
> you have the Crypto API testmgr enable (or rather not disabled would
> be more accurate) so every
> cryptographic algorithm except those specified in these messages was
> tested with test
> vectors from crypto/testmgr.c upon registration. If you don't seen
> failure warnings, it works.
OK.
> You can also check /proc/crypto for all the algorithm with ccree
> listed as their driver and check
> that their test passed.
OK, in that case everything works as expected, on both R-Car H3 ES1.0 and
ES2.0.
Thanks!
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH 3/3] arm64: dts: renesas: r8a7795: add ccree binding
From: Gilad Ben-Yossef @ 2018-05-17 13:41 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Simon Horman, Magnus Damm, Rob Herring, Mark Rutland,
Catalin Marinas, Will Deacon, Geert Uytterhoeven,
Michael Turquette, Stephen Boyd, Herbert Xu, David S. Miller,
Ofir Drang, Linux-Renesas,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Linux ARM, Linux Kernel Mailing List, linux-clk
In-Reply-To: <CAMuHMdX5quhZzaPkcrtB4CuHWeaKsyF1SustjB9V0SWw_SzXVg@mail.gmail.com>
On Thu, May 17, 2018 at 4:35 PM, Geert Uytterhoeven
<geert@linux-m68k.org> wrote:
> Hi Gilad,
>
> On Thu, May 17, 2018 at 3:09 PM, Gilad Ben-Yossef <gilad@benyossef.com> wrote:
>> On Thu, May 17, 2018 at 1:16 PM, Geert Uytterhoeven
>> <geert@linux-m68k.org> wrote:
>>> However, even with your clock patch, the signature checking fails for me,
>>> on both R-Car H3 ES1.0 and ES2.0.
>>> Does this need changes to the ARM Trusted Firmware, to allow Linux to
>>> access the public SCEG module?
>>
>> Well, this is actually something different. If you look you will
>> notice that my patch was part of a 3 part patch series,
>> the first of which disabled this test.
>
> Sorry, I had completely forgotten about the first patch from the series.
> With that applied, it continues:
>
> ccree e6601000.crypto: ARM CryptoCell 630P Driver: HW version
> 0x00000000, Driver version 4.0
> ccree e6601000.crypto: Cache params previous: 0x00000777
> ccree e6601000.crypto: Cache params current: 0x00000000
> (expect: 0x00000000)
> alg: No test for cts1(cbc(aes)) (cts1-cbc-aes-ccree)
> alg: No test for authenc(xcbc(aes),cbc(aes))
> (authenc-xcbc-aes-cbc-aes-ccree)
> alg: No test for authenc(xcbc(aes),rfc3686(ctr(aes)))
> (authenc-xcbc-aes-rfc3686-ctr-aes-ccree)
> ccree e6601000.crypto: ARM ccree device initialized
>
> Is HW version 0x00000000 expected?
It's related to the problem with reading the wrong register I've
mentioned before.
>
>> If you take all the 3 patches, it will work.
>
> is there an easy way to test proper operation?
The lines of the form " alg: No test for cts1(cbc(aes))
(cts1-cbc-aes-ccree)" indicates
you have the Crypto API testmgr enable (or rather not disabled would
be more accurate) so every
cryptographic algorithm except those specified in these messages was
tested with test
vectors from crypto/testmgr.c upon registration. If you don't seen
failure warnings, it works.
You can also check /proc/crypto for all the algorithm with ccree
listed as their driver and check
that their test passed.
> I enabled CONFIG_CRYPT_TEST, and did insmod tcrypt.ko, but I mostly see
> "Failed to load transform" messages.
>
tcrypt.ko is a rather crude developer tool. It has hard coded lists of
test for different algorithms that does
not take into account if some crypto algs are enagled in the build or
not. It's more of a stress test.
Gilad
--
Gilad Ben-Yossef
Chief Coffee Drinker
"If you take a class in large-scale robotics, can you end up in a
situation where the homework eats your dog?"
-- Jean-Baptiste Queru
^ permalink raw reply
* Re: [PATCH v2] ASoC: ssm2305: Add amplifier driver
From: Marco Felsch @ 2018-05-17 13:38 UTC (permalink / raw)
To: Lars-Peter Clausen
Cc: mark.rutland, devicetree, alsa-devel, lgirdwood, robh+dt, broonie,
kernel
In-Reply-To: <6c7a72fc-f086-78e5-c920-809aeb738528@metafoo.de>
On 18-05-17 15:11, Lars-Peter Clausen wrote:
> On 05/17/2018 03:00 PM, Marco Felsch wrote:
> [...]
> > + if (IS_ERR(priv->gpiod_shutdown)) {
> > + err = PTR_ERR(priv->gpiod_shutdown);
> > + if (err != -EPROBE_DEFER) {
> > + dev_err(dev, "Failed to get 'shutdown' gpio: %d\n",
> > + err);
> > + return err;
>
> You also want to return the error in the EPROBE_DEFER case, so the driver
> tries to probe again later.
>
Yes, you're right.
> > + }
> > + }
> > +
> > + return devm_snd_soc_register_component(dev, &ssm2305_component_driver,
> > + NULL, 0);
> > +}
> [...]
>
^ permalink raw reply
* Re: [PATCH 3/3] arm64: dts: renesas: r8a7795: add ccree binding
From: Geert Uytterhoeven @ 2018-05-17 13:35 UTC (permalink / raw)
To: Gilad Ben-Yossef
Cc: Simon Horman, Magnus Damm, Rob Herring, Mark Rutland,
Catalin Marinas, Will Deacon, Geert Uytterhoeven,
Michael Turquette, Stephen Boyd, Herbert Xu, David S. Miller,
Ofir Drang, Linux-Renesas,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Linux ARM, Linux Kernel Mailing List, linux-clk
In-Reply-To: <CAOtvUMdVNX_vBRofpc5rNiVL-a1NvWMDyWSOaXKYPkm57wkR_A@mail.gmail.com>
Hi Gilad,
On Thu, May 17, 2018 at 3:09 PM, Gilad Ben-Yossef <gilad@benyossef.com> wrote:
> On Thu, May 17, 2018 at 1:16 PM, Geert Uytterhoeven
> <geert@linux-m68k.org> wrote:
>> However, even with your clock patch, the signature checking fails for me,
>> on both R-Car H3 ES1.0 and ES2.0.
>> Does this need changes to the ARM Trusted Firmware, to allow Linux to
>> access the public SCEG module?
>
> Well, this is actually something different. If you look you will
> notice that my patch was part of a 3 part patch series,
> the first of which disabled this test.
Sorry, I had completely forgotten about the first patch from the series.
With that applied, it continues:
ccree e6601000.crypto: ARM CryptoCell 630P Driver: HW version
0x00000000, Driver version 4.0
ccree e6601000.crypto: Cache params previous: 0x00000777
ccree e6601000.crypto: Cache params current: 0x00000000
(expect: 0x00000000)
alg: No test for cts1(cbc(aes)) (cts1-cbc-aes-ccree)
alg: No test for authenc(xcbc(aes),cbc(aes))
(authenc-xcbc-aes-cbc-aes-ccree)
alg: No test for authenc(xcbc(aes),rfc3686(ctr(aes)))
(authenc-xcbc-aes-rfc3686-ctr-aes-ccree)
ccree e6601000.crypto: ARM ccree device initialized
Is HW version 0x00000000 expected?
> If you take all the 3 patches, it will work.
is there an easy way to test proper operation?
I enabled CONFIG_CRYPT_TEST, and did insmod tcrypt.ko, but I mostly see
"Failed to load transform" messages.
Thanks!
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH V6 10/12] ARM: dts: ipq8074: Add peripheral nodes
From: kbuild test robot @ 2018-05-17 13:31 UTC (permalink / raw)
Cc: kbuild-all, robh+dt, robh, mark.rutland, linux, andy.gross,
david.brown, catalin.marinas, will.deacon, sboyd, bjorn.andersson,
devicetree, linux-kernel, linux-arm-kernel, linux-arm-msm,
linux-soc, absahu, marc.zyngier, richardcochran, sricharan
In-Reply-To: <1526475004-10341-11-git-send-email-sricharan@codeaurora.org>
[-- Attachment #1: Type: text/plain, Size: 1471 bytes --]
Hi Sricharan,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on robh/for-next]
[also build test ERROR on v4.17-rc5]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Sricharan-R/ARM-dts-ipq-updates-to-enable-a-few-peripherals/20180517-155124
base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: arm64-defconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=arm64
Note: the linux-review/Sricharan-R/ARM-dts-ipq-updates-to-enable-a-few-peripherals/20180517-155124 HEAD 1e054800261138fd8f0f8f93340f5781ff622233 builds fine.
It only hurts bisectibility.
All errors (new ones prefixed by >>):
arch/arm64/boot/dts/qcom/ipq8074-hk01.dtb: ERROR (duplicate_label): /soc/pinctrl@1000000/serial4_pinmux: Duplicate label 'serial_4_pins' on /soc/pinctrl@1000000/serial4_pinmux and /soc/pinctrl@1000000/serial4-pinmux
>> ERROR: Input tree has errors, aborting (use -f to force output)
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 38151 bytes --]
^ permalink raw reply
* [PATCH] ASoC: ssm2602: Fix ADC powerup sequencing
From: Marco Felsch @ 2018-05-17 13:30 UTC (permalink / raw)
To: lars, lgirdwood, broonie, robh+dt, mark.rutland
Cc: devicetree, alsa-devel, Sascha Hauer, Philipp Zabel, kernel
From: Philipp Zabel <p.zabel@pengutronix.de>
According to the ssm2603 data sheet (control register sequencing), the
digital core should be activated only after all necessary bits in the
power register are enabled, and a delay determined by the decoupling
capacitor on the VMID pin has passed. If the digital core is activated
too early, or even before the ADC is powered up, audible artifacts
appear at the beginning of the recorded signal.
The digital core is also needed for playback, so when recording starts
it may already be enabled. This means we cannot get the power sequence
correct when we want to be able to start recording after playback.
As a workaround put the MIC mute switch into the DAPM routes. This
way we can keep the recording disabled until the MIC Bias has settled
and thus get rid of audible artifacts.
The delay we have to wait depends on a board specific capacitor
connected to the VMID pins, so make the delay configurable in the device
tree.
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
.../devicetree/bindings/sound/adi,ssm2602.txt | 7 +++++
sound/soc/codecs/ssm2602.c | 30 +++++++++++++++++--
2 files changed, 35 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/sound/adi,ssm2602.txt b/Documentation/devicetree/bindings/sound/adi,ssm2602.txt
index 3b3302fe399b..9334d48c0462 100644
--- a/Documentation/devicetree/bindings/sound/adi,ssm2602.txt
+++ b/Documentation/devicetree/bindings/sound/adi,ssm2602.txt
@@ -11,9 +11,16 @@ Required properties:
- reg : the I2C address of the device for I2C, the chip select
number for SPI.
+Optional properties:
+
+ - startup-delay-us : delay between powering on and activating the digital
+ core, determined by the decoupling capacitor C on the
+ VMID pin: delay [µs] = C [µF] * 25000 / 3.5
+
Example:
ssm2602: ssm2602@1a {
compatible = "adi,ssm2602";
reg = <0x1a>;
+ startup-delay-us = <34000>; /* 4.7 µF * 25000 / 3.5 -> ~34 ms */
};
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index 501a4e73b185..1b99f5d44f8d 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -26,9 +26,11 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <linux/delay.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/slab.h>
+#include <linux/of.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -46,6 +48,7 @@ struct ssm2602_priv {
enum ssm2602_type type;
unsigned int clk_out_pwr;
+ u32 startup_delay_us;
};
/*
@@ -111,7 +114,6 @@ SOC_SINGLE_TLV("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1,
SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0),
SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 8, 1, 0),
-SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1),
};
/* Output Mixer */
@@ -121,10 +123,26 @@ SOC_DAPM_SINGLE("HiFi Playback Switch", SSM2602_APANA, 4, 1, 0),
SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0),
};
+static const struct snd_kcontrol_new mic_ctl =
+ SOC_DAPM_SINGLE("Switch", SSM2602_APANA, 1, 1, 1);
+
/* Input mux */
static const struct snd_kcontrol_new ssm2602_input_mux_controls =
SOC_DAPM_ENUM("Input Select", ssm2602_enum[0]);
+static int ssm2602_mic_switch_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
+
+ if (ssm2602->startup_delay_us)
+ usleep_range(ssm2602->startup_delay_us,
+ ssm2602->startup_delay_us * 2);
+
+ return 0;
+}
+
static const struct snd_soc_dapm_widget ssm260x_dapm_widgets[] = {
SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2602_PWR, 3, 1),
SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1),
@@ -146,6 +164,9 @@ SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1,
SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &ssm2602_input_mux_controls),
SND_SOC_DAPM_MICBIAS("Mic Bias", SSM2602_PWR, 1, 1),
+SND_SOC_DAPM_SWITCH_E("Mic Switch", SSM2602_APANA, 1, 1, &mic_ctl,
+ ssm2602_mic_switch_event, SND_SOC_DAPM_PRE_PMU),
+
SND_SOC_DAPM_OUTPUT("LHPOUT"),
SND_SOC_DAPM_OUTPUT("RHPOUT"),
SND_SOC_DAPM_INPUT("MICIN"),
@@ -178,9 +199,11 @@ static const struct snd_soc_dapm_route ssm2602_routes[] = {
{"LHPOUT", NULL, "Output Mixer"},
{"Input Mux", "Line", "Line Input"},
- {"Input Mux", "Mic", "Mic Bias"},
+ {"Input Mux", "Mic", "Mic Switch"},
{"ADC", NULL, "Input Mux"},
+ {"Mic Switch", NULL, "Mic Bias"},
+
{"Mic Bias", NULL, "MICIN"},
};
@@ -645,6 +668,9 @@ int ssm2602_probe(struct device *dev, enum ssm2602_type type,
if (ssm2602 == NULL)
return -ENOMEM;
+ of_property_read_u32(dev->of_node, "startup-delay-us",
+ &ssm2602->startup_delay_us);
+
dev_set_drvdata(dev, ssm2602);
ssm2602->type = type;
ssm2602->regmap = regmap;
--
2.17.0
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
^ permalink raw reply related
* RE: [PATCH v5 05/14] usb: typec: add API to get typec basic port power and data config
From: Jun Li @ 2018-05-17 13:26 UTC (permalink / raw)
To: Heikki Krogerus, Mats Karrman
Cc: robh+dt@kernel.org, gregkh@linuxfoundation.org,
linux@roeck-us.net, a.hajda@samsung.com, cw00.choi@samsung.com,
shufan_lee@richtek.com, Peter Chen, gsomlo@gmail.com,
devicetree@vger.kernel.org, linux-usb@vger.kernel.org,
dl-linux-imx
In-Reply-To: <20180516122527.GC11469@kuha.fi.intel.com>
Hi
> -----Original Message-----
> From: Heikki Krogerus [mailto:heikki.krogerus@linux.intel.com]
> Sent: 2018年5月16日 20:25
> To: Jun Li <jun.li@nxp.com>; Mats Karrman <mats.dev.list@gmail.com>
> Cc: robh+dt@kernel.org; gregkh@linuxfoundation.org; linux@roeck-us.net;
> a.hajda@samsung.com; cw00.choi@samsung.com; shufan_lee@richtek.com;
> Peter Chen <peter.chen@nxp.com>; gsomlo@gmail.com;
> devicetree@vger.kernel.org; linux-usb@vger.kernel.org; dl-linux-imx
> <linux-imx@nxp.com>
> Subject: Re: [PATCH v5 05/14] usb: typec: add API to get typec basic port power
> and data config
>
> Hi guys,
>
> On Tue, May 15, 2018 at 10:52:57PM +0200, Mats Karrman wrote:
> > Hi,
> >
> > On 05/14/2018 11:36 AM, Jun Li wrote:
> >
> > > Hi
> > >> -----Original Message-----
> > >> From: Mats Karrman [mailto:mats.dev.list@gmail.com]
> > >> Sent: 2018???5???12??? 3:56
> > >> To: Jun Li <jun.li@nxp.com>; robh+dt@kernel.org;
> > >> gregkh@linuxfoundation.org; heikki.krogerus@linux.intel.com;
> > >> linux@roeck-us.net
> > >> Cc: a.hajda@samsung.com; cw00.choi@samsung.com;
> > >> shufan_lee@richtek.com; Peter Chen <peter.chen@nxp.com>;
> > >> gsomlo@gmail.com; devicetree@vger.kernel.org;
> > >> linux-usb@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> > >> Subject: Re: [PATCH v5 05/14] usb: typec: add API to get typec
> > >> basic port power and data config
> > >>
> > >> Hi Li Jun,
> > >>
> > >> On 2018-05-03 02:24, Li Jun wrote:
> > >>
> > >>> This patch adds 3 APIs to get the typec port power and data type,
> > >>> and preferred power role by its name string.
> > >>>
> > >>> Signed-off-by: Li Jun <jun.li@nxp.com>
> > >>> ---
> > >>> drivers/usb/typec/class.c | 52
> > >> +++++++++++++++++++++++++++++++++++++++++++++++
> > >>> include/linux/usb/typec.h | 3 +++
> > >>> 2 files changed, 55 insertions(+)
> > >>>
> > >>> diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
> > >>> index 53df10d..5981e18 100644
> > >>> --- a/drivers/usb/typec/class.c
> > >>> +++ b/drivers/usb/typec/class.c
> > >>> @@ -9,6 +9,7 @@
> > >>> #include <linux/device.h>
> > >>> #include <linux/module.h>
> > >>> #include <linux/mutex.h>
> > >>> +#include <linux/property.h>
>
> I don't think you need that anymore.
I will remove it.
>
> > >>> #include <linux/slab.h>
> > >>> #include <linux/usb/typec.h>
> > >>> #include <linux/usb/typec_mux.h> @@ -802,6 +803,12 @@ static
> > >>> const char * const typec_port_types[] = {
> > >>> [TYPEC_PORT_DRP] = "dual",
> > >>> };
> > >>>
> > >>> +static const char * const typec_data_types[] = {
> > >>> + [TYPEC_PORT_DFP] = "host",
> > >>> + [TYPEC_PORT_UFP] = "device",
> > >>> + [TYPEC_PORT_DRD] = "dual",
> > >>> +};
> > >>> +
> > >>> static const char * const typec_port_types_drp[] = {
> > >>> [TYPEC_PORT_SRC] = "dual [source] sink",
> > >>> [TYPEC_PORT_SNK] = "dual source [sink]", @@ -1252,6 +1259,51
> > >> @@
> > >>> void typec_set_pwr_opmode(struct typec_port *port,
> > >>> }
> > >>> EXPORT_SYMBOL_GPL(typec_set_pwr_opmode);
> > >>>
> > >>> +/**
> > >>> + * typec_find_power_type - Get the typec port power type
> > >> Why is this function called typec_find_power_type() and not
> > >> typec_find_port_type()?
> > >> It's called port_type in sysfs, having different names just adds confusion.
> > >> (Otherwise I agree power_type is a better name but...)
> > > We have "port type" before the power and data role separation, this
> > > API name's intention is to reflect the power cap, anyway I leave
> > > this to be decided by Heikki then.
>
> I really hate the "*_type" naming. It was understandable when there was no
> separate power and data roles defined in the specification, but now that there
> are, it's just confusing. IMO we should not use it anywhere.
OK, know your preference now.
>
> So to me typec_find_type() is just as bad as typec_find_power_type() because it
> has the "type" in it. I wonder if this function is necessary at all? If it is, then
> perhaps we can think of some better name for it, name that gives a better hint
> what it is used for.
We need a way to match a string to a value which has to be done via typec
class.
>
> > >>> + * @name: port type string
> > >>> + *
> > >>> + * This routine is used to find the typec_port_type by its string name.
> > >>> + *
> > >>> + * Returns typec_port_type if success, otherwise negative error code.
> > >>> + */
> > >>> +int typec_find_power_type(const char *name) {
> > >>> + return match_string(typec_port_types,
> ARRAY_SIZE(typec_port_types),
> > >>> + name);
> > >>> +}
> > >>> +EXPORT_SYMBOL_GPL(typec_find_power_type);
> > >>> +
> > >>> +/**
> > >>> + * typec_find_preferred_role - Find the typec drp port preferred
> > >>> +power role
> > >> Why typec_find_preferred_role()? Could be used for any power_role
> > >> so why not typec_find_power_role()?
> > > I am not sure if I catch your point of this comment.
> > > For preferred role(if support try.sink or try.src) the only allowed
> > > power roles are "sink"
> > > "source"
> > > But for power role, the allowed type are "sink"
> > > "source"
> > > "dual"
> >
> > Uhm, typing too fast again, I am. A better name would be just
> typec_find_role().
> > What I mean is that the function could be used for any situation when
> > someone wants to map a string to a TYPEC_{SOURCE,SINK} constant so it
> > is unnecessary to limit its usage to just preferred role.
>
> That sounds reasonable to me.
Agreed
thanks
Li Jun
>
>
> Thanks,
>
> --
> heikki
^ permalink raw reply
* Re: [PATCH 3/3] arm64: dts: renesas: r8a7795: add ccree binding
From: Geert Uytterhoeven @ 2018-05-17 13:17 UTC (permalink / raw)
To: Gilad Ben-Yossef
Cc: Simon Horman, Magnus Damm, Rob Herring, Mark Rutland,
Catalin Marinas, Will Deacon, Geert Uytterhoeven,
Michael Turquette, Stephen Boyd, Herbert Xu, David S. Miller,
Ofir Drang, Linux-Renesas,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Linux ARM, Linux Kernel Mailing List, linux-clk
In-Reply-To: <CAMuHMdVM55S7+PdnKusX-qkTxioc=0kQ6EGSbwv+kbLk5RCUYw@mail.gmail.com>
On Thu, May 17, 2018 at 12:16 PM, Geert Uytterhoeven
<geert@linux-m68k.org> wrote:
> On Thu, May 17, 2018 at 10:01 AM, Gilad Ben-Yossef <gilad@benyossef.com> wrote:
>> On Wed, May 16, 2018 at 10:43 AM, Simon Horman <horms@verge.net.au> wrote:
>>> On Tue, May 15, 2018 at 04:50:44PM +0200, Geert Uytterhoeven wrote:
>>>> On Tue, May 15, 2018 at 2:29 PM, Gilad Ben-Yossef <gilad@benyossef.com> wrote:
>>>> > Add bindings for CryptoCell instance in the SoC.
>>>> >
>>>> > Signed-off-by: Gilad Ben-Yossef <gilad@benyossef.com>
>>>>
>>>> Thanks for your patch!
>>>>
>>>> > --- a/arch/arm64/boot/dts/renesas/r8a7795.dtsi
>>>> > +++ b/arch/arm64/boot/dts/renesas/r8a7795.dtsi
>>>> > @@ -528,6 +528,14 @@
>>>> > status = "disabled";
>>>> > };
>>>> >
>>>> > + arm_cc630p: crypto@e6601000 {
>>>> > + compatible = "arm,cryptocell-630p-ree";
>>>> > + interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
>>>> > + #interrupt-cells = <2>;
>>>>
>>>> I believe the #interrupt-cells property is not needed.
>>>>
>>>> > + reg = <0x0 0xe6601000 0 0x1000>;
>>>> > + clocks = <&cpg CPG_MOD 229>;
>
> Missing "power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;", as
> the Secure Engine is part of the CPG/MSSR clock domain (see below [*]).
And missing "resets = <&cpg 229>;", as the module is tied to the CPG/MSSR
reset controller.
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* RE: [PATCH v5 12/14] staging: typec: tcpci: keep the not connecting cc line open
From: Jun Li @ 2018-05-17 13:17 UTC (permalink / raw)
To: Peter Chen, robh+dt@kernel.org, gregkh@linuxfoundation.org,
heikki.krogerus@linux.intel.com, linux@roeck-us.net
Cc: a.hajda@samsung.com, cw00.choi@samsung.com,
shufan_lee@richtek.com, gsomlo@gmail.com,
devicetree@vger.kernel.org, linux-usb@vger.kernel.org,
dl-linux-imx
In-Reply-To: <HE1PR04MB1450507C65FD86DA4BE46F7B8B920@HE1PR04MB1450.eurprd04.prod.outlook.com>
> -----Original Message-----
> From: Peter Chen
> Sent: 2018年5月16日 16:36
> To: Jun Li <jun.li@nxp.com>; robh+dt@kernel.org; gregkh@linuxfoundation.org;
> heikki.krogerus@linux.intel.com; linux@roeck-us.net
> Cc: a.hajda@samsung.com; cw00.choi@samsung.com;
> shufan_lee@richtek.com; gsomlo@gmail.com; devicetree@vger.kernel.org;
> linux-usb@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> Subject: RE: [PATCH v5 12/14] staging: typec: tcpci: keep the not connecting cc
> line open
>
>
> >
> > While set polarity, we should keep the not connecting cc line to be open.
> >
>
> keep the disconnected cc line open?
Okay, I will change.
Thanks
Li Jun
>
> Peter
>
> > Signed-off-by: Li Jun <jun.li@nxp.com>
> > ---
> > drivers/staging/typec/tcpci.c | 18 ++++++++++++++----
> > 1 file changed, 14 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c index
> > 5c48810..5c0c5e3 100644
> > --- a/drivers/staging/typec/tcpci.c
> > +++ b/drivers/staging/typec/tcpci.c
> > @@ -185,15 +185,25 @@ static int tcpci_set_polarity(struct tcpc_dev *tcpc,
> > enum typec_cc_polarity polarity) {
> > struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
> > + unsigned int reg;
> > int ret;
> >
> > - ret = regmap_write(tcpci->regmap, TCPC_TCPC_CTRL,
> > - (polarity == TYPEC_POLARITY_CC2) ?
> > - TCPC_TCPC_CTRL_ORIENTATION : 0);
> > + /* Keep the disconnect cc line open */
> > + ret = regmap_read(tcpci->regmap, TCPC_ROLE_CTRL, ®);
> > if (ret < 0)
> > return ret;
> >
> > - return 0;
> > + if (polarity == TYPEC_POLARITY_CC2)
> > + reg |= TCPC_ROLE_CTRL_CC_OPEN <<
> > TCPC_ROLE_CTRL_CC1_SHIFT;
> > + else
> > + reg |= TCPC_ROLE_CTRL_CC_OPEN <<
> > TCPC_ROLE_CTRL_CC2_SHIFT;
> > + ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> > + if (ret < 0)
> > + return ret;
> > +
> > + return regmap_write(tcpci->regmap, TCPC_TCPC_CTRL,
> > + (polarity == TYPEC_POLARITY_CC2) ?
> > + TCPC_TCPC_CTRL_ORIENTATION : 0);
> > }
> >
> > static int tcpci_set_vconn(struct tcpc_dev *tcpc, bool enable)
> > --
> > 2.7.4
^ 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