* Re: [PULL 2/5] Renesas ARM SoC updates for v5.4
From: Geert Uytterhoeven @ 2019-09-04 7:15 UTC (permalink / raw)
To: Arnd Bergmann
Cc: arm-soc, Geert Uytterhoeven, Magnus Damm, Linux-Renesas, arm-soc,
Simon Horman, Linux ARM
In-Reply-To: <CAK8P3a11EfOXfwZ5Xx3vYJwfBGPh=yX73f_=3u7Zmm+hJF6HVg@mail.gmail.com>
Hi Arnd,
On Tue, Sep 3, 2019 at 11:15 PM Arnd Bergmann <arnd@arndb.de> wrote:
> On Fri, Aug 23, 2019 at 2:36 PM Geert Uytterhoeven
> <geert+renesas@glider.be> wrote:
> > Renesas ARM SoC updates for v5.4
> >
> > - Low-level debugging support for RZ/A2M.
> >
>
> Pulled into arm/soc, thanks!
>
> This should be the last of your pull requests for the moment. Can you check that
> everything is there once it hits linux-next (probably Wednesday, I may have just
> missed today).
$ for i in $(git tag | grep renesas-.*-for-v5.4); do echo --- $i ---;
git cherry -v arm-soc/for-next $i; done
--- renesas-arm-dt-for-v5.4-tag1 ---
--- renesas-arm-soc-for-v5.4-tag1 ---
--- renesas-arm64-dt-for-v5.4-tag1 ---
--- renesas-arm64-dt-for-v5.4-tag2 ---
--- renesas-drivers-for-v5.4-tag1 ---
--- renesas-drivers-for-v5.4-tag2 ---
--- renesas-dt-bindings-for-v5.4-tag1 ---
--- renesas-dt-bindings-for-v5.4-tag2 ---
Yep, all included.
Thanks a lot!
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
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH] soc: imx: imx-scu: Getting UID from SCU should have response
From: Anson Huang @ 2019-09-04 19:13 UTC (permalink / raw)
To: shawnguo, s.hauer, kernel, festevam, daniel.baluta, aisheng.dong,
abel.vesa, linux-arm-kernel, linux-kernel
Cc: Linux-imx
The SCU firmware API for getting UID should have response,
otherwise, the message stored in function stack could be
released and then the response data received from SCU will be
stored into that released stack and cause kernel NULL pointer
dump.
Fixes: 73feb4d0f8f1 ("soc: imx-scu: Add SoC UID(unique identifier) support")
Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
---
drivers/soc/imx/soc-imx-scu.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/soc/imx/soc-imx-scu.c b/drivers/soc/imx/soc-imx-scu.c
index 50831eb..c68882e 100644
--- a/drivers/soc/imx/soc-imx-scu.c
+++ b/drivers/soc/imx/soc-imx-scu.c
@@ -46,7 +46,7 @@ static ssize_t soc_uid_show(struct device *dev,
hdr->func = IMX_SC_MISC_FUNC_UNIQUE_ID;
hdr->size = 1;
- ret = imx_scu_call_rpc(soc_ipc_handle, &msg, false);
+ ret = imx_scu_call_rpc(soc_ipc_handle, &msg, true);
if (ret) {
pr_err("%s: get soc uid failed, ret %d\n", __func__, ret);
return ret;
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH v3 0/7] add support USB for MT8183
From: Greg Kroah-Hartman @ 2019-09-04 7:06 UTC (permalink / raw)
To: Chunfeng Yun
Cc: Mark Rutland, devicetree, Mathias Nyman, linux-usb, linux-kernel,
Rob Herring, linux-mediatek, Matthias Brugger, linux-arm-kernel
In-Reply-To: <1567562067.7317.52.camel@mhfsdcap03>
On Wed, Sep 04, 2019 at 09:54:27AM +0800, Chunfeng Yun wrote:
> Hi Greg,
>
>
> Please don't try to pick up this series, the dependent ones are still
> under public review, I'll fix build warning and send out new version
> after the dependent ones are applied
> Sorry for inconvenience
No problem, now dropped from my review queue.
greg k-h
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 4/4] gpio: Update documentation with ast2600 controllers
From: Bartosz Golaszewski @ 2019-09-04 7:02 UTC (permalink / raw)
To: Rashmica Gupta
Cc: linux-aspeed, Andrew Jeffery, Linus Walleij, LKML, linux-gpio,
Joel Stanley, arm-soc
In-Reply-To: <20190904061245.30770-4-rashmica.g@gmail.com>
śr., 4 wrz 2019 o 08:13 Rashmica Gupta <rashmica.g@gmail.com> napisał(a):
>
Again, this needs a proper commit description and the subject should
start with "dt-bindings: ...".
You also need to Cc the device-tree maintainers. Use
scripts/get_maintainer.pl to list all people that should get this
patch.
Bart
> Signed-off-by: Rashmica Gupta <rashmica.g@gmail.com>
> ---
> Documentation/devicetree/bindings/gpio/gpio-aspeed.txt | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/gpio/gpio-aspeed.txt b/Documentation/devicetree/bindings/gpio/gpio-aspeed.txt
> index 7e9b586770b0..cd388797e07c 100644
> --- a/Documentation/devicetree/bindings/gpio/gpio-aspeed.txt
> +++ b/Documentation/devicetree/bindings/gpio/gpio-aspeed.txt
> @@ -2,7 +2,8 @@ Aspeed GPIO controller Device Tree Bindings
> -------------------------------------------
>
> Required properties:
> -- compatible : Either "aspeed,ast2400-gpio" or "aspeed,ast2500-gpio"
> +- compatible : Either "aspeed,ast2400-gpio", "aspeed,ast2500-gpio",
> + "aspeed,ast2600-gpio", or "aspeed,ast2600-1-8v-gpio"
>
> - #gpio-cells : Should be two
> - First cell is the GPIO line number
> --
> 2.20.1
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 08/13] swiotlb-xen: always use dma-direct helpers to alloc coherent pages
From: Christoph Hellwig @ 2019-09-04 7:00 UTC (permalink / raw)
To: Boris Ostrovsky
Cc: Juergen Gross, Stefano Stabellini, Konrad Rzeszutek Wilk, x86,
linux-kernel, iommu, xen-devel, Christoph Hellwig,
linux-arm-kernel
In-Reply-To: <8a7f9e23-ef26-e83b-8d1e-dcd7d233642a@oracle.com>
On Tue, Sep 03, 2019 at 06:25:54PM -0400, Boris Ostrovsky wrote:
> > If I am reading __dma_direct_alloc_pages() correctly there is a path
> > that will force us to use GFP_DMA32 and as Juergen pointed out in
> > another message that may not be desirable.
Yes, it will add GFP_DMA32. So I guess for now we'll just keep the
direct page allocator calls and resend. I don't think this is the
right thing to do long term, but I'd really like to get this series
finished.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 1/4] gpio/aspeed: Fix incorrect number of banks
From: Bartosz Golaszewski @ 2019-09-04 6:57 UTC (permalink / raw)
To: Rashmica Gupta
Cc: linux-aspeed, Andrew Jeffery, Linus Walleij, LKML, linux-gpio,
Joel Stanley, arm-soc
In-Reply-To: <20190904061245.30770-1-rashmica.g@gmail.com>
śr., 4 wrz 2019 o 08:13 Rashmica Gupta <rashmica.g@gmail.com> napisał(a):
>
> Fixes: 361b79119a4b7 ('gpio: Add Aspeed driver')
>
Please, add a proper commit description. Checkpatch should have warned
you about it.
Bart
> Signed-off-by: Rashmica Gupta <rashmica.g@gmail.com>
> ---
> drivers/gpio/gpio-aspeed.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c
> index 9defe25d4721..77752b2624e8 100644
> --- a/drivers/gpio/gpio-aspeed.c
> +++ b/drivers/gpio/gpio-aspeed.c
> @@ -1165,7 +1165,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
> gpio->chip.base = -1;
>
> /* Allocate a cache of the output registers */
> - banks = gpio->config->nr_gpios >> 5;
> + banks = (gpio->config->nr_gpios >> 5) + 1;
> gpio->dcache = devm_kcalloc(&pdev->dev,
> banks, sizeof(u32), GFP_KERNEL);
> if (!gpio->dcache)
> --
> 2.20.1
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 2/2] mm/page_owner: determine the last stack state of page with CONFIG_KASAN_DUMP_PAGE=y
From: Walter Wu @ 2019-09-04 6:57 UTC (permalink / raw)
To: Andrey Ryabinin, Alexander Potapenko, Dmitry Vyukov,
Matthias Brugger, Andrew Morton, Thomas Gleixner, Michal Hocko,
Josh Poimboeuf, Greg Kroah-Hartman
Cc: Walter Wu, wsd_upstream, linux-kernel, kasan-dev, linux-mm,
linux-mediatek, linux-arm-kernel
When enable CONFIG_KASAN_DUMP_PAGE, then page_owner will record last stack,
So we need to know the last stack is allocation or free state.
Signed-off-by: Walter Wu <walter-zh.wu@mediatek.com>
---
mm/page_owner.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/mm/page_owner.c b/mm/page_owner.c
index addcbb2ae4e4..2756adca250e 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -418,6 +418,12 @@ void __dump_page_owner(struct page *page)
nr_entries = stack_depot_fetch(handle, &entries);
pr_alert("page allocated via order %u, migratetype %s, gfp_mask %#x(%pGg)\n",
page_owner->order, migratetype_names[mt], gfp_mask, &gfp_mask);
+#ifdef CONFIG_KASAN_DUMP_PAGE
+ if ((unsigned long)page->flags & PAGE_FLAGS_CHECK_AT_PREP)
+ pr_info("Allocation stack of page:\n");
+ else
+ pr_info("Free stack of page:\n");
+#endif
stack_trace_print(entries, nr_entries, 0);
if (page_owner->last_migrate_reason != -1)
--
2.18.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH v3] input: keyboard: snvs_pwrkey: Send key events for i.MX6 S, DL and Q
From: Marco Felsch @ 2019-09-04 6:52 UTC (permalink / raw)
To: Robin van der Gracht
Cc: Adam Ford, Dmitry Torokhov, linux-kernel @ vger . kernel . org,
Pengutronix Kernel Team, linux-input @ vger . kernel . org,
RobinGong, Shawn Guo, linux-arm-kernel @ lists . infradead . org
In-Reply-To: <20190904062329.97520-1-robin@protonic.nl>
Hi Robin,
thanks for the patch it looks quite good, just two minor nitpicks.
On 19-09-04 06:23, Robin van der Gracht wrote:
> The first generation i.MX6 processors does not send an interrupt when the
> power key is pressed. It sends a power down request interrupt if the key is
> released before a hard shutdown (5 second press). This should allow
> software to bring down the SoC safely.
>
> For this driver to work as a regular power key with the older SoCs, we need
> to send a keypress AND release when we get the power down request irq.
>
> Signed-off-by: Robin van der Gracht <robin@protonic.nl>
> ---
>
> Changes v2 -> v3:
> - Drop alt compatible string for identifying first revision snvs hardware,
> read minor revision from register instead.
> - Drop imx6qdl.dtsi modification and device-tree binding documentation.
> - Add an additional input_sync() to create 2 seperate input reports for press
> and release.
>
> drivers/input/keyboard/Kconfig | 2 +-
> drivers/input/keyboard/snvs_pwrkey.c | 28 ++++++++++++++++++++++++++--
> 2 files changed, 27 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
> index 7c4f19dab34f..937e58da5ce1 100644
> --- a/drivers/input/keyboard/Kconfig
> +++ b/drivers/input/keyboard/Kconfig
> @@ -436,7 +436,7 @@ config KEYBOARD_SNVS_PWRKEY
> depends on OF
> help
> This is the snvs powerkey driver for the Freescale i.MX application
> - processors that are newer than i.MX6 SX.
> + processors.
>
> To compile this driver as a module, choose M here; the
> module will be called snvs_pwrkey.
> diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c
> index 5342d8d45f81..828580eee0d2 100644
> --- a/drivers/input/keyboard/snvs_pwrkey.c
> +++ b/drivers/input/keyboard/snvs_pwrkey.c
> @@ -19,6 +19,7 @@
> #include <linux/mfd/syscon.h>
> #include <linux/regmap.h>
>
> +#define SNVS_HPVIDR1_REG 0xF8
> #define SNVS_LPSR_REG 0x4C /* LP Status Register */
> #define SNVS_LPCR_REG 0x38 /* LP Control Register */
> #define SNVS_HPSR_REG 0x14
> @@ -37,6 +38,7 @@ struct pwrkey_drv_data {
> int wakeup;
> struct timer_list check_timer;
> struct input_dev *input;
> + u8 minor_rev;
> };
>
> static void imx_imx_snvs_check_for_events(struct timer_list *t)
> @@ -45,6 +47,20 @@ static void imx_imx_snvs_check_for_events(struct timer_list *t)
> struct input_dev *input = pdata->input;
> u32 state;
>
> + if (pdata->minor_rev == 0) {
Should we use a define here and ..
> + /*
> + * The first generation i.MX6 SoCs only sends an interrupt on
> + * button release. To mimic power-key usage, we'll prepend a
> + * press event.
> + */
> + input_report_key(input, pdata->keycode, 1);
> + input_sync(input);
> + input_report_key(input, pdata->keycode, 0);
> + input_sync(input);
> + pm_relax(input->dev.parent);
> + return;
> + }
> +
> regmap_read(pdata->snvs, SNVS_HPSR_REG, &state);
> state = state & SNVS_HPSR_BTN ? 1 : 0;
>
> @@ -67,13 +83,17 @@ static irqreturn_t imx_snvs_pwrkey_interrupt(int irq, void *dev_id)
> {
> struct platform_device *pdev = dev_id;
> struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev);
> + unsigned long expire = jiffies;
> u32 lp_status;
>
> pm_wakeup_event(pdata->input->dev.parent, 0);
>
> regmap_read(pdata->snvs, SNVS_LPSR_REG, &lp_status);
> - if (lp_status & SNVS_LPSR_SPO)
> - mod_timer(&pdata->check_timer, jiffies + msecs_to_jiffies(DEBOUNCE_TIME));
> + if (lp_status & SNVS_LPSR_SPO) {
> + if (pdata->minor_rev > 0)
here? Just a nitpick, feel free to add/drop it.
> + expire = jiffies + msecs_to_jiffies(DEBOUNCE_TIME);
> + mod_timer(&pdata->check_timer, expire);
> + }
>
> /* clear SPO status */
> regmap_write(pdata->snvs, SNVS_LPSR_REG, SNVS_LPSR_SPO);
> @@ -94,6 +114,7 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
> struct input_dev *input = NULL;
> struct device_node *np;
> int error;
> + u32 vid;
>
> /* Get SNVS register Page */
> np = pdev->dev.of_node;
> @@ -123,6 +144,9 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
> return -EINVAL;
> }
>
> + regmap_read(pdata->snvs, SNVS_HPVIDR1_REG, &vid);
Should we check the return val here?
Regards,
Marco
> + pdata->minor_rev = vid & 0xff;
> +
> regmap_update_bits(pdata->snvs, SNVS_LPCR_REG, SNVS_LPCR_DEP_EN, SNVS_LPCR_DEP_EN);
>
> /* clear the unexpected interrupt before driver ready */
> --
> 2.20.1
>
>
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 1/2] mm/kasan: dump alloc/free stack for page allocator
From: Walter Wu @ 2019-09-04 6:51 UTC (permalink / raw)
To: Andrey Ryabinin, Alexander Potapenko, Dmitry Vyukov,
Matthias Brugger, Andrew Morton, Martin Schwidefsky,
Arnd Bergmann
Cc: Walter Wu, wsd_upstream, linux-kernel, kasan-dev, linux-mm,
linux-mediatek, linux-arm-kernel
This patch is KASAN report adds the alloc/free stacks for page allocator
in order to help programmer to see memory corruption caused by page.
By default, KASAN doesn't record alloc/free stack for page allocator.
It is difficult to fix up page use-after-free issue.
This feature depends on page owner to record the last stack of pages.
It is very helpful for solving the page use-after-free or out-of-bound.
KASAN report will show the last stack of page, it may be:
a) If page is in-use state, then it prints alloc stack.
It is useful to fix up page out-of-bound issue.
BUG: KASAN: slab-out-of-bounds in kmalloc_pagealloc_oob_right+0x88/0x90
Write of size 1 at addr ffffffc0d64ea00a by task cat/115
...
Allocation stack of page:
prep_new_page+0x1a0/0x1d8
get_page_from_freelist+0xd78/0x2748
__alloc_pages_nodemask+0x1d4/0x1978
kmalloc_order+0x28/0x58
kmalloc_order_trace+0x28/0xe0
kmalloc_pagealloc_oob_right+0x2c/0x90
b) If page is freed state, then it prints free stack.
It is useful to fix up page use-after-free issue.
BUG: KASAN: use-after-free in kmalloc_pagealloc_uaf+0x70/0x80
Write of size 1 at addr ffffffc0d651c000 by task cat/115
...
Free stack of page:
kasan_free_pages+0x68/0x70
__free_pages_ok+0x3c0/0x1328
__free_pages+0x50/0x78
kfree+0x1c4/0x250
kmalloc_pagealloc_uaf+0x38/0x80
This has been discussed, please refer below link.
https://bugzilla.kernel.org/show_bug.cgi?id=203967
Signed-off-by: Walter Wu <walter-zh.wu@mediatek.com>
---
lib/Kconfig.kasan | 9 +++++++++
mm/kasan/common.c | 6 ++++++
2 files changed, 15 insertions(+)
diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan
index 4fafba1a923b..ba17f706b5f8 100644
--- a/lib/Kconfig.kasan
+++ b/lib/Kconfig.kasan
@@ -135,6 +135,15 @@ config KASAN_S390_4_LEVEL_PAGING
to 3TB of RAM with KASan enabled). This options allows to force
4-level paging instead.
+config KASAN_DUMP_PAGE
+ bool "Dump the page last stack information"
+ depends on KASAN && PAGE_OWNER
+ help
+ By default, KASAN doesn't record alloc/free stack for page allocator.
+ It is difficult to fix up page use-after-free issue.
+ This feature depends on page owner to record the last stack of page.
+ It is very helpful for solving the page use-after-free or out-of-bound.
+
config TEST_KASAN
tristate "Module for testing KASAN for bug detection"
depends on m && KASAN
diff --git a/mm/kasan/common.c b/mm/kasan/common.c
index 2277b82902d8..2a32474efa74 100644
--- a/mm/kasan/common.c
+++ b/mm/kasan/common.c
@@ -35,6 +35,7 @@
#include <linux/vmalloc.h>
#include <linux/bug.h>
#include <linux/uaccess.h>
+#include <linux/page_owner.h>
#include "kasan.h"
#include "../slab.h"
@@ -227,6 +228,11 @@ void kasan_alloc_pages(struct page *page, unsigned int order)
void kasan_free_pages(struct page *page, unsigned int order)
{
+#ifdef CONFIG_KASAN_DUMP_PAGE
+ gfp_t gfp_flags = GFP_KERNEL;
+
+ set_page_owner(page, order, gfp_flags);
+#endif
if (likely(!PageHighMem(page)))
kasan_poison_shadow(page_address(page),
PAGE_SIZE << order,
--
2.18.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [RFC PATCH V2 4/4] platform: mtk-isp: Add Mediatek FD driver
From: Tomasz Figa @ 2019-09-04 6:34 UTC (permalink / raw)
To: Jerry-ch Chen
Cc: devicetree@vger.kernel.org, Sean Cheng (鄭昇弘),
laurent.pinchart+renesas@ideasonboard.com,
Rynn Wu (吳育恩), srv_heupstream,
Po-Yang Huang (黃柏陽), mchehab@kernel.org,
suleiman@chromium.org, shik@chromium.org,
Jungo Lin (林明俊),
Sj Huang (黃信璋), yuzhao@chromium.org,
linux-mediatek@lists.infradead.org, zwisler@chromium.org,
matthias.bgg@gmail.com, Christie Yu (游雅惠),
Frederic Chen (陳俊元), hans.verkuil@cisco.com,
linux-arm-kernel@lists.infradead.org, linux-media@vger.kernel.org
In-Reply-To: <1567577389.18318.100.camel@mtksdccf07>
On Wed, Sep 4, 2019 at 3:09 PM Jerry-ch Chen <Jerry-ch.Chen@mediatek.com> wrote:
>
> Hi Tomasz,
>
> On Wed, 2019-09-04 at 12:15 +0800, Tomasz Figa wrote:
> > On Wed, Sep 4, 2019 at 12:38 PM Jerry-ch Chen
> > <Jerry-ch.Chen@mediatek.com> wrote:
> > >
> > > Hi Tomasz,
> > >
> > > On Tue, 2019-09-03 at 20:05 +0800, Tomasz Figa wrote:
> > > > On Tue, Sep 3, 2019 at 8:46 PM Jerry-ch Chen <Jerry-ch.Chen@mediatek.com> wrote:
> > > > >
> > > > > Hi Tomasz,
> > > > >
> > > > > On Tue, 2019-09-03 at 15:04 +0800, Tomasz Figa wrote:
> > > > > > On Tue, Sep 3, 2019 at 3:44 PM Jerry-ch Chen <Jerry-ch.Chen@mediatek.com> wrote:
> > > > > > >
> > > > > > > On Tue, 2019-09-03 at 13:19 +0800, Tomasz Figa wrote:
> > > > > > > > On Mon, Sep 2, 2019 at 8:47 PM Jerry-ch Chen <Jerry-ch.Chen@mediatek.com> wrote:
> > > > > > > > >
> > > > > > > > > Hi Tomasz,
> > > > > > > > >
> > > > > > > > > On Fri, 2019-08-30 at 16:33 +0800, Tomasz Figa wrote:
> > > > > > > > > > On Wed, Aug 28, 2019 at 11:00 AM Jerry-ch Chen
> > > > > > > > > > <Jerry-ch.Chen@mediatek.com> wrote:
> > > > > > > > > > >
> > > > > > > > > > > Hi Tomasz,
> > > > > > > > > > >
> > > > > > > > > > > On Mon, 2019-08-26 at 14:36 +0800, Tomasz Figa wrote:
> > > > > > > > > > > > Hi Jerry,
> > > > > > > > > > > >
> > > > > > > > > > > > On Sun, Aug 25, 2019 at 6:18 PM Jerry-ch Chen
> > > > > > > > > > > > <Jerry-ch.Chen@mediatek.com> wrote:
> > > > > > > > > > > > >
> > > > > > > > > > > > > Hi Tomasz,
> > > > > > > > > > > > >
> > > > > > > > > > > > > On Fri, 2019-08-02 at 16:28 +0800, Tomasz Figa wrote:
> > > > > > > > > > > > > > Hi Jerry,
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > On Tue, Jul 09, 2019 at 04:41:12PM +0800, Jerry-ch Chen wrote:
> > > [snip]
> > > > > > > > > > > > [snip]
> > > > > > > > > > > >
> > > > > > > > > > > > > > > +static void mtk_fd_vb2_stop_streaming(struct vb2_queue *vq)
> > > > > > > > > > > > > > > +{
> > > > > > > > > > > > > > > + struct mtk_fd_ctx *ctx = vb2_get_drv_priv(vq);
> > > > > > > > > > > > > > > + struct vb2_buffer *vb;
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > How do we guarantee here that the hardware isn't still accessing the buffers
> > > > > > > > > > > > > > removed below?
> > > > > > > > > > > > > >
> > > > > > > > > > > > > Maybe we can check the driver state flag and aborting the unfinished
> > > > > > > > > > > > > jobs?
> > > > > > > > > > > > > (fd_hw->state == FD_ENQ)
> > > > > > > > > > > > >
> > > > > > > > > > > >
> > > > > > > > > > > > Yes, we need to either cancel or wait for the currently processing
> > > > > > > > > > > > job. It depends on hardware capabilities, but cancelling is generally
> > > > > > > > > > > > preferred for the lower latency.
> > > > > > > > > > > >
> > > > > > > > > > > Ok, it the state is ENQ, then we can disable the FD hw by controlling
> > > > > > > > > > > the registers.
> > > > > > > > > > >
> > > > > > > > > > > for example:
> > > > > > > > > > > writel(0x0, fd->fd_base + FD_HW_ENABLE);
> > > > > > > > > > > writel(0x0, fd->fd_base + FD_INT_EN);
> > > > > > > > > > >
> > > > > > > > > >
> > > > > > > > > > What's exactly the effect of writing 0 to FD_HW_ENABLE?
> > > > > > > > > >
> > > > > > > > > Sorry, my last reply didn't solve the question,
> > > > > > > > > we should implement a mtk_fd_job_abort() for v4l2_m2m_ops().
> > > > > > > > >
> > > > > > > > > which is able to readl_poll_timeout_atomic()
> > > > > > > > > and check the HW busy bits in the register FD_INT_EN;
> > > > > > > > >
> > > > > > > > > if they are not cleared until timeout, we could handle the last
> > > > > > > > > processing job.
> > > > > > > > > Otherwise, the FD irq handler should have handled the last processing
> > > > > > > > > job and we could continue the stop_streaming().
> > > > > > > > >
> > > > > > > > > For job_abort():
> > > > > > > > > static void mtk_fd_job_abort(void *priv)
> > > > > > > > > {
> > > > > > > > > struct mtk_fd_ctx *ctx = priv;
> > > > > > > > > struct mtk_fd_dev *fd = ctx->fd_dev;
> > > > > > > > > u32 val;
> > > > > > > > > u32 ret;
> > > > > > > > >
> > > > > > > > > ret = readl_poll_timeout_atomic(fd->fd_base + MTK_FD_REG_OFFSET_INT_EN,
> > > > > > > > > val,
> > > > > > > > > (val & MTK_FD_HW_BUSY_MASK) ==
> > > > > > > > > MTK_FD_HW_STATE_IS_BUSY,
> > > > > > > > > USEC_PER_MSEC, MTK_FD_STOP_HW_TIMEOUT);
> > > > > > > >
> > > > > > > > Hmm, would it be possible to avoid the busy wait by having a
> > > > > > > > completion that could be signalled from the interrupt handler?
> > > > > > > >
> > > > > > > > Best regards,
> > > > > > > > Tomasz
> > > > > > >
> > > > > > > I suppose that would be wakeup a wait queue in the interrupt handler,
> > > > > > > the the wait_event_interrupt_timeout() will be used in here and system
> > > > > > > suspend e.g. mtk_fd_suspend().
> > > > > >
> > > > > > Yes, that should work.
> > > > > >
> > > > > > > Or do you suggest to wait_event_interrupt_timeout() every frame in the
> > > > > > > mtk_fd_ipi_handler()?
> > > > > >
> > > > > > Nope, we shouldn't need that.
> > > > > >
> > > > > > > I think maybe the readl_poll_timeout_atomic would be good enough.
> > > > > > >
> > > > > >
> > > > > > Not really. Busy waiting should be avoided as much as possible. What's
> > > > > > the point of entering suspend if you end up burning the power by
> > > > > > spinning the CPU for some milliseconds?
> > > > > >
> > > > > Ok, I see, busy waiting is not a good idea, I will use the wait queue
> > > > > instead. the job abort will refine as following:
> > > > >
> > > > > static void mtk_fd_job_abort(void *priv)
> > > > > {
> > > > > struct mtk_fd_ctx *ctx = priv;
> > > > > struct mtk_fd_dev *fd = ctx->fd_dev;
> > > > > u32 ret;
> > > > >
> > > > > ret = wait_event_interruptible_timeout
> > > > > (fd->wq, (fd->fd_irq_result & MTK_FD_HW_IRQ_MASK),
> > > > > usecs_to_jiffies(50000));
> > > > > if (ret)
> > > > > mtk_fd_hw_job_finish(fd, VB2_BUF_STATE_ERROR);
> > > > > dev_dbg(fd->dev, "%s, ret:%d\n", __func__, ret);
> > > > >
> > > > > fd->fd_irq_result = 0;
> > > > > }
> > > > >
> > > > > static struct v4l2_m2m_ops fd_m2m_ops = {
> > > > > .device_run = mtk_fd_device_run,
> > > > > .job_abort = mtk_fd_job_abort,
> > > >
> > > > I'm not sure we should be using the functon above as the .job_abort
> > > > callback. It's expected to abort the job, but we're just waiting for
> > > > it to finish. I think we should just call mtk_fd_job_abort() manually
> > > > from .stop_streaming.
> > > >
> > >
> > > Ok, I will fix it.
> > >
> > > > > };
> > > > >
> > > > > and we could use it in suspend.
> > > > > static int mtk_fd_suspend(struct device *dev)
> > > > > {
> > > > > struct mtk_fd_dev *fd = dev_get_drvdata(dev);
> > > > >
> > > > > if (pm_runtime_suspended(dev))
> > > > > return 0;
> > > > >
> > > > > if (fd->fd_stream_count)
> > > > > mtk_fd_job_abort(fd->ctx);
> > > > >
> > > > > /* suspend FD HW */
> > > > > writel(0x0, fd->fd_base + MTK_FD_REG_OFFSET_INT_EN);
> > > > > writel(0x0, fd->fd_base + MTK_FD_REG_OFFSET_HW_ENABLE);
> > > > > clk_disable_unprepare(fd->fd_clk);
> > > > > dev_dbg(dev, "%s:disable clock\n", __func__);
> > > > >
> > > > > return 0;
> > > > > }
> > > > >
> > > > > static irqreturn_t mtk_fd_irq(int irq, void *data)
> > > > > {
> > > > > struct mtk_fd_dev *fd = (struct mtk_fd_dev *)data;
> > > > >
> > > > > fd->fd_irq_result = readl(fd->fd_base + MTK_FD_REG_OFFSET_INT_VAL);
> > > > > wake_up_interruptible(&fd->wq);
> > > >
> > > > The wake up should be done at the very end of this function. Otherwise
> > > > we end up with m2m framework racing with the mtk_fd_hw_job_finish()
> > > > below.
> > > >
> > > > Also, I'd use a completion here rather than an open coded wait and
> > > > wake-up. The driver could reinit_completion() before queuing a job to
> > > > the hardware and the IRQ handler would complete(). There would be no
> > > > need to store the IRQ flags in driver data anymore.
> > > Ok, It will be refined as following:
> > >
> > > suspend and stop streaming will call mtk_fd_job_abort()
> > >
> > > static void mtk_fd_job_abort(struct mtk_fd_dev *fd)
> > > {
> > > u32 ret;
> > >
> > > ret = wait_for_completion_timeout(&fd->fd_irq_done,
> > > msecs_to_jiffies(MTK_FD_HW_TIMEOUT));
> > > if (ret)
> >
> > For the _timeout variants, !ret means the timeout and ret > 0 means
> > that the wait ended successfully before.
> >
> Thanks, fixed.
>
> > Also please make sure that the timeout is big enough not to happen
> > normally on a heavily loaded system. Something like 1 second should be
> > good.
> >
> Ok, I will make it 1 second
> #define MTK_FD_HW_TIMEOUT 1000
>
> Also, I will add a condition in mtk_fd_vb2_stop_streaming(), since it
> would be called twice, now it works fine whether I reuse the condition
> with mtk_fd_hw_disconnect or not, however, I think do it before buffer
> remove looks more reasonable.
>
> static void mtk_fd_vb2_stop_streaming(struct vb2_queue *vq)
> {
> struct mtk_fd_ctx *ctx = vb2_get_drv_priv(vq);
> struct mtk_fd_dev *fd = ctx->fd_dev;
> struct vb2_v4l2_buffer *vb;
> struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
> struct v4l2_m2m_queue_ctx *queue_ctx;
>
> if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
> mtk_fd_job_abort(fd);
We need to do it regardless of the queue type, otherwise we could
still free CAPTURE buffers before the hardware releases them.
Best regards,
Tomasz
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v3] mmc: sdhci-of-aspeed: Depend on CONFIG_OF_ADDRESS
From: Ulf Hansson @ 2019-09-04 6:32 UTC (permalink / raw)
To: Andrew Jeffery
Cc: kbuild test robot, linux-aspeed, OpenBMC Maillist,
linux-mmc@vger.kernel.org, Adrian Hunter,
Linux Kernel Mailing List, Joel Stanley, Linux ARM
In-Reply-To: <20190904022120.4174-1-andrew@aj.id.au>
On Wed, 4 Sep 2019 at 04:20, Andrew Jeffery <andrew@aj.id.au> wrote:
>
> Resolves the following build error reported by the 0-day bot:
>
> ERROR: "of_platform_device_create" [drivers/mmc/host/sdhci-of-aspeed.ko] undefined!
>
> SPARC does not set CONFIG_OF_ADDRESS so the symbol is missing. Depend on
> CONFIG_OF_ADDRESS to ensure the driver is only built for supported
> configurations.
>
> Fixes: 2d28dbe042f4 ("mmc: sdhci-of-aspeed: Add support for the ASPEED SD controller")
> Reported-by: kbuild test robot <lkp@intel.com>
> Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Applied for next, thanks!
Kind regards
Uffe
> ---
> v2 was a series of 4 patches, three of which were applied leaving this build
> fix to be reworked. The v2 series can be found here:
>
> https://patchwork.ozlabs.org/cover/1156457/
>
> drivers/mmc/host/Kconfig | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> index 0f8a230de2f3..3a52f5703286 100644
> --- a/drivers/mmc/host/Kconfig
> +++ b/drivers/mmc/host/Kconfig
> @@ -157,7 +157,7 @@ config MMC_SDHCI_OF_ARASAN
> config MMC_SDHCI_OF_ASPEED
> tristate "SDHCI OF support for the ASPEED SDHCI controller"
> depends on MMC_SDHCI_PLTFM
> - depends on OF
> + depends on OF && OF_ADDRESS
> help
> This selects the ASPEED Secure Digital Host Controller Interface.
>
> --
> 2.20.1
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v3] input: keyboard: snvs_pwrkey: Send key events for i.MX6 S, DL and Q
From: Robin van der Gracht @ 2019-09-04 6:23 UTC (permalink / raw)
To: robin
Cc: Adam Ford, Dmitry Torokhov, Marco Felsch,
linux-kernel @ vger . kernel . org, Pengutronix Kernel Team,
linux-input @ vger . kernel . org, RobinGong, Shawn Guo,
linux-arm-kernel @ lists . infradead . org
The first generation i.MX6 processors does not send an interrupt when the
power key is pressed. It sends a power down request interrupt if the key is
released before a hard shutdown (5 second press). This should allow
software to bring down the SoC safely.
For this driver to work as a regular power key with the older SoCs, we need
to send a keypress AND release when we get the power down request irq.
Signed-off-by: Robin van der Gracht <robin@protonic.nl>
---
Changes v2 -> v3:
- Drop alt compatible string for identifying first revision snvs hardware,
read minor revision from register instead.
- Drop imx6qdl.dtsi modification and device-tree binding documentation.
- Add an additional input_sync() to create 2 seperate input reports for press
and release.
drivers/input/keyboard/Kconfig | 2 +-
drivers/input/keyboard/snvs_pwrkey.c | 28 ++++++++++++++++++++++++++--
2 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 7c4f19dab34f..937e58da5ce1 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -436,7 +436,7 @@ config KEYBOARD_SNVS_PWRKEY
depends on OF
help
This is the snvs powerkey driver for the Freescale i.MX application
- processors that are newer than i.MX6 SX.
+ processors.
To compile this driver as a module, choose M here; the
module will be called snvs_pwrkey.
diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c
index 5342d8d45f81..828580eee0d2 100644
--- a/drivers/input/keyboard/snvs_pwrkey.c
+++ b/drivers/input/keyboard/snvs_pwrkey.c
@@ -19,6 +19,7 @@
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
+#define SNVS_HPVIDR1_REG 0xF8
#define SNVS_LPSR_REG 0x4C /* LP Status Register */
#define SNVS_LPCR_REG 0x38 /* LP Control Register */
#define SNVS_HPSR_REG 0x14
@@ -37,6 +38,7 @@ struct pwrkey_drv_data {
int wakeup;
struct timer_list check_timer;
struct input_dev *input;
+ u8 minor_rev;
};
static void imx_imx_snvs_check_for_events(struct timer_list *t)
@@ -45,6 +47,20 @@ static void imx_imx_snvs_check_for_events(struct timer_list *t)
struct input_dev *input = pdata->input;
u32 state;
+ if (pdata->minor_rev == 0) {
+ /*
+ * The first generation i.MX6 SoCs only sends an interrupt on
+ * button release. To mimic power-key usage, we'll prepend a
+ * press event.
+ */
+ input_report_key(input, pdata->keycode, 1);
+ input_sync(input);
+ input_report_key(input, pdata->keycode, 0);
+ input_sync(input);
+ pm_relax(input->dev.parent);
+ return;
+ }
+
regmap_read(pdata->snvs, SNVS_HPSR_REG, &state);
state = state & SNVS_HPSR_BTN ? 1 : 0;
@@ -67,13 +83,17 @@ static irqreturn_t imx_snvs_pwrkey_interrupt(int irq, void *dev_id)
{
struct platform_device *pdev = dev_id;
struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev);
+ unsigned long expire = jiffies;
u32 lp_status;
pm_wakeup_event(pdata->input->dev.parent, 0);
regmap_read(pdata->snvs, SNVS_LPSR_REG, &lp_status);
- if (lp_status & SNVS_LPSR_SPO)
- mod_timer(&pdata->check_timer, jiffies + msecs_to_jiffies(DEBOUNCE_TIME));
+ if (lp_status & SNVS_LPSR_SPO) {
+ if (pdata->minor_rev > 0)
+ expire = jiffies + msecs_to_jiffies(DEBOUNCE_TIME);
+ mod_timer(&pdata->check_timer, expire);
+ }
/* clear SPO status */
regmap_write(pdata->snvs, SNVS_LPSR_REG, SNVS_LPSR_SPO);
@@ -94,6 +114,7 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
struct input_dev *input = NULL;
struct device_node *np;
int error;
+ u32 vid;
/* Get SNVS register Page */
np = pdev->dev.of_node;
@@ -123,6 +144,9 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
return -EINVAL;
}
+ regmap_read(pdata->snvs, SNVS_HPVIDR1_REG, &vid);
+ pdata->minor_rev = vid & 0xff;
+
regmap_update_bits(pdata->snvs, SNVS_LPCR_REG, SNVS_LPCR_DEP_EN, SNVS_LPCR_DEP_EN);
/* clear the unexpected interrupt before driver ready */
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v17 5/5] arm64: dts: mt8183: add scp node
From: Pi-Hsun Shih @ 2019-09-04 6:16 UTC (permalink / raw)
Cc: Mark Rutland,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Erin Lo, open list, Rob Herring,
moderated list:ARM/Mediatek SoC support, Pi-Hsun Shih,
Matthias Brugger, Eddie Huang,
moderated list:ARM/Mediatek SoC support
In-Reply-To: <20190904061649.69099-1-pihsun@chromium.org>
From: Eddie Huang <eddie.huang@mediatek.com>
Add scp node to mt8183 and mt8183-evb
Signed-off-by: Erin Lo <erin.lo@mediatek.com>
Signed-off-by: Pi-Hsun Shih <pihsun@chromium.org>
Signed-off-by: Eddie Huang <eddie.huang@mediatek.com>
---
Changes from v16, v15, v14:
- No change.
Changes from v13:
- Change the size of the cfg register region.
Changes from v12, v11, v10:
- No change.
Changes from v9:
- Remove extra reserve-memory-vpu_share node.
Changes from v8:
- New patch.
---
arch/arm64/boot/dts/mediatek/mt8183-evb.dts | 11 +++++++++++
arch/arm64/boot/dts/mediatek/mt8183.dtsi | 12 ++++++++++++
2 files changed, 23 insertions(+)
diff --git a/arch/arm64/boot/dts/mediatek/mt8183-evb.dts b/arch/arm64/boot/dts/mediatek/mt8183-evb.dts
index 1fb195c683c3..ddb7a7ac9655 100644
--- a/arch/arm64/boot/dts/mediatek/mt8183-evb.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8183-evb.dts
@@ -24,6 +24,17 @@
chosen {
stdout-path = "serial0:921600n8";
};
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ scp_mem_reserved: scp_mem_region {
+ compatible = "shared-dma-pool";
+ reg = <0 0x50000000 0 0x2900000>;
+ no-map;
+ };
+ };
};
&auxadc {
diff --git a/arch/arm64/boot/dts/mediatek/mt8183.dtsi b/arch/arm64/boot/dts/mediatek/mt8183.dtsi
index 97f84aa9fc6e..3dd1b76bbaf5 100644
--- a/arch/arm64/boot/dts/mediatek/mt8183.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8183.dtsi
@@ -269,6 +269,18 @@
clock-names = "spi", "wrap";
};
+ scp: scp@10500000 {
+ compatible = "mediatek,mt8183-scp";
+ reg = <0 0x10500000 0 0x80000>,
+ <0 0x105c0000 0 0x19080>;
+ reg-names = "sram", "cfg";
+ interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&infracfg CLK_INFRA_SCPSYS>;
+ clock-names = "main";
+ memory-region = <&scp_mem_reserved>;
+ status = "disabled";
+ };
+
auxadc: auxadc@11001000 {
compatible = "mediatek,mt8183-auxadc",
"mediatek,mt8173-auxadc";
--
2.23.0.187.g17f5b7556c-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v17 4/5] rpmsg: add rpmsg support for mt8183 SCP.
From: Pi-Hsun Shih @ 2019-09-04 6:16 UTC (permalink / raw)
Cc: Ohad Ben-Cohen, open list:REMOTE PROCESSOR REMOTEPROC SUBSYSTEM,
open list, Bjorn Andersson,
moderated list:ARM/Mediatek SoC support, Pi-Hsun Shih,
Matthias Brugger, moderated list:ARM/Mediatek SoC support
In-Reply-To: <20190904061649.69099-1-pihsun@chromium.org>
Add a simple rpmsg support for mt8183 SCP, that use IPI / IPC directly.
Signed-off-by: Pi-Hsun Shih <pihsun@chromium.org>
---
Changes from v16:
- Change year on another Copyright header to 2019.
Changes from v15:
- No change.
Changes from v14:
- Change year on Copyright header to 2019.
Changes from v13:
- No change.
Changes from v12:
- Use strscpy instead of strncpy.
Changes from v11:
- Fix a bug that when rproc_boot fails, the ns_ept won't be properly
destroyed, causing memory leak.
- Add documentation for mtk_rpmsg_info.
Changes from v10, v9, v8, v7:
- No change.
Changes from v6:
- Decouple mtk_rpmsg from mtk_scp by putting all necessary informations
(name service IPI id, register/unregister/send functions) into a
struct, and pass it to the mtk_rpmsg_create_rproc_subdev function.
Changes from v5:
- CONFIG_MTK_SCP now selects CONFIG_RPMSG_MTK_SCP, and the dummy
implementation for mtk_rpmsg_{create,destroy}_rproc_subdev when
CONFIG_RPMSG_MTK_SCP is not defined is removed.
Changes from v4:
- Match and fill the device tree node to the created rpmsg subdevice,
so the rpmsg subdevice can utilize the properties and subnodes on
device tree (This is similar to what drivers/rpmsg/qcom_smd.c does).
Changes from v3:
- Change from unprepare to stop, to stop the rpmsg driver before the
rproc is stopped, avoiding problem that some rpmsg would fail after
rproc is stopped.
- Add missing spin_lock_init, and use destroy_ept instead of kref_put.
Changes from v2:
- Unregiser IPI handler on unprepare.
- Lock the channel list on operations.
- Move SCP_IPI_NS_SERVICE to 0xFF.
Changes from v1:
- Do cleanup properly in mtk_rpmsg.c, which also removes the problem of
short-lived work items.
- Fix several issues checkpatch found.
---
drivers/remoteproc/Kconfig | 1 +
drivers/remoteproc/mtk_common.h | 2 +
drivers/remoteproc/mtk_scp.c | 38 ++-
drivers/remoteproc/mtk_scp_ipi.c | 1 +
drivers/rpmsg/Kconfig | 9 +
drivers/rpmsg/Makefile | 1 +
drivers/rpmsg/mtk_rpmsg.c | 414 +++++++++++++++++++++++++++++
include/linux/remoteproc/mtk_scp.h | 4 +-
include/linux/rpmsg/mtk_rpmsg.h | 38 +++
9 files changed, 503 insertions(+), 5 deletions(-)
create mode 100644 drivers/rpmsg/mtk_rpmsg.c
create mode 100644 include/linux/rpmsg/mtk_rpmsg.h
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index ea71cad399f7..cff3a9fa817b 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -26,6 +26,7 @@ config IMX_REMOTEPROC
config MTK_SCP
tristate "Mediatek SCP support"
depends on ARCH_MEDIATEK
+ select RPMSG_MTK_SCP
help
Say y here to support Mediatek's System Companion Processor (SCP) via
the remote processor framework.
diff --git a/drivers/remoteproc/mtk_common.h b/drivers/remoteproc/mtk_common.h
index 622e9aebe9ab..40fa890e6d60 100644
--- a/drivers/remoteproc/mtk_common.h
+++ b/drivers/remoteproc/mtk_common.h
@@ -69,6 +69,8 @@ struct mtk_scp {
void __iomem *cpu_addr;
phys_addr_t phys_addr;
size_t dram_size;
+
+ struct rproc_subdev *rpmsg_subdev;
};
/**
diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c
index ce4acffbb115..92657acc5e70 100644
--- a/drivers/remoteproc/mtk_scp.c
+++ b/drivers/remoteproc/mtk_scp.c
@@ -13,6 +13,7 @@
#include <linux/platform_device.h>
#include <linux/remoteproc.h>
#include <linux/remoteproc/mtk_scp.h>
+#include <linux/rpmsg/mtk_rpmsg.h>
#include "mtk_common.h"
#include "remoteproc_internal.h"
@@ -549,6 +550,31 @@ static int scp_map_memory_region(struct mtk_scp *scp)
return 0;
}
+static struct mtk_rpmsg_info mtk_scp_rpmsg_info = {
+ .send_ipi = scp_ipi_send,
+ .register_ipi = scp_ipi_register,
+ .unregister_ipi = scp_ipi_unregister,
+ .ns_ipi_id = SCP_IPI_NS_SERVICE,
+};
+
+static void scp_add_rpmsg_subdev(struct mtk_scp *scp)
+{
+ scp->rpmsg_subdev =
+ mtk_rpmsg_create_rproc_subdev(to_platform_device(scp->dev),
+ &mtk_scp_rpmsg_info);
+ if (scp->rpmsg_subdev)
+ rproc_add_subdev(scp->rproc, scp->rpmsg_subdev);
+}
+
+static void scp_remove_rpmsg_subdev(struct mtk_scp *scp)
+{
+ if (scp->rpmsg_subdev) {
+ rproc_remove_subdev(scp->rproc, scp->rpmsg_subdev);
+ mtk_rpmsg_destroy_rproc_subdev(scp->rpmsg_subdev);
+ scp->rpmsg_subdev = NULL;
+ }
+}
+
static int scp_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -632,22 +658,25 @@ static int scp_probe(struct platform_device *pdev)
init_waitqueue_head(&scp->run.wq);
init_waitqueue_head(&scp->ack_wq);
+ scp_add_rpmsg_subdev(scp);
+
ret = devm_request_threaded_irq(dev, platform_get_irq(pdev, 0), NULL,
scp_irq_handler, IRQF_ONESHOT,
pdev->name, scp);
if (ret) {
dev_err(dev, "failed to request irq\n");
- goto destroy_mutex;
+ goto remove_subdev;
}
ret = rproc_add(rproc);
if (ret)
- goto destroy_mutex;
+ goto remove_subdev;
- return ret;
+ return 0;
-destroy_mutex:
+remove_subdev:
+ scp_remove_rpmsg_subdev(scp);
for (i = 0; i < SCP_IPI_MAX; i++)
mutex_destroy(&scp->ipi_desc[i].lock);
mutex_destroy(&scp->send_lock);
@@ -662,6 +691,7 @@ static int scp_remove(struct platform_device *pdev)
struct mtk_scp *scp = platform_get_drvdata(pdev);
int i;
+ scp_remove_rpmsg_subdev(scp);
for (i = 0; i < SCP_IPI_MAX; i++)
mutex_destroy(&scp->ipi_desc[i].lock);
mutex_destroy(&scp->send_lock);
diff --git a/drivers/remoteproc/mtk_scp_ipi.c b/drivers/remoteproc/mtk_scp_ipi.c
index f26fad007bd6..2c8cbf3c7eae 100644
--- a/drivers/remoteproc/mtk_scp_ipi.c
+++ b/drivers/remoteproc/mtk_scp_ipi.c
@@ -115,6 +115,7 @@ int scp_ipi_send(struct platform_device *pdev,
int ret;
if (WARN_ON(id <= SCP_IPI_INIT) || WARN_ON(id >= SCP_IPI_MAX) ||
+ WARN_ON(id == SCP_IPI_NS_SERVICE) ||
WARN_ON(len > sizeof(send_obj->share_buf)) || WARN_ON(!buf))
return -EINVAL;
diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
index d0322b41eca5..85e3cc075cb4 100644
--- a/drivers/rpmsg/Kconfig
+++ b/drivers/rpmsg/Kconfig
@@ -15,6 +15,15 @@ config RPMSG_CHAR
in /dev. They make it possible for user-space programs to send and
receive rpmsg packets.
+config RPMSG_MTK_SCP
+ tristate "MediaTek SCP"
+ depends on MTK_SCP
+ select RPMSG
+ help
+ Say y here to enable support providing communication channels to
+ remote processors in MediaTek platforms.
+ This use IPI and IPC to communicate with remote processors.
+
config RPMSG_QCOM_GLINK_NATIVE
tristate
select RPMSG
diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile
index 9aa859502d27..ae92a7fb08f6 100644
--- a/drivers/rpmsg/Makefile
+++ b/drivers/rpmsg/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_RPMSG) += rpmsg_core.o
obj-$(CONFIG_RPMSG_CHAR) += rpmsg_char.o
+obj-$(CONFIG_RPMSG_MTK_SCP) += mtk_rpmsg.o
obj-$(CONFIG_RPMSG_QCOM_GLINK_RPM) += qcom_glink_rpm.o
obj-$(CONFIG_RPMSG_QCOM_GLINK_NATIVE) += qcom_glink_native.o
obj-$(CONFIG_RPMSG_QCOM_GLINK_SMEM) += qcom_glink_smem.o
diff --git a/drivers/rpmsg/mtk_rpmsg.c b/drivers/rpmsg/mtk_rpmsg.c
new file mode 100644
index 000000000000..ebe52c302734
--- /dev/null
+++ b/drivers/rpmsg/mtk_rpmsg.c
@@ -0,0 +1,414 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright 2019 Google LLC.
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/remoteproc.h>
+#include <linux/rpmsg/mtk_rpmsg.h>
+#include <linux/workqueue.h>
+
+#include "rpmsg_internal.h"
+
+struct mtk_rpmsg_rproc_subdev {
+ struct platform_device *pdev;
+ struct mtk_rpmsg_info *info;
+ struct rpmsg_endpoint *ns_ept;
+ struct rproc_subdev subdev;
+
+ struct work_struct register_work;
+ struct list_head channels;
+ struct mutex channels_lock;
+};
+
+#define to_mtk_subdev(d) container_of(d, struct mtk_rpmsg_rproc_subdev, subdev)
+
+struct mtk_rpmsg_channel_info {
+ struct rpmsg_channel_info info;
+ bool registered;
+ struct list_head list;
+};
+
+/**
+ * struct rpmsg_ns_msg - dynamic name service announcement message
+ * @name: name of remote service that is published
+ * @addr: address of remote service that is published
+ *
+ * This message is sent across to publish a new service. When we receive these
+ * messages, an appropriate rpmsg channel (i.e device) is created. In turn, the
+ * ->probe() handler of the appropriate rpmsg driver will be invoked
+ * (if/as-soon-as one is registered).
+ */
+struct rpmsg_ns_msg {
+ char name[RPMSG_NAME_SIZE];
+ u32 addr;
+} __packed;
+
+struct mtk_rpmsg_device {
+ struct rpmsg_device rpdev;
+ struct mtk_rpmsg_rproc_subdev *mtk_subdev;
+};
+
+struct mtk_rpmsg_endpoint {
+ struct rpmsg_endpoint ept;
+ struct mtk_rpmsg_rproc_subdev *mtk_subdev;
+};
+
+#define to_mtk_rpmsg_device(r) container_of(r, struct mtk_rpmsg_device, rpdev)
+#define to_mtk_rpmsg_endpoint(r) container_of(r, struct mtk_rpmsg_endpoint, ept)
+
+static const struct rpmsg_endpoint_ops mtk_rpmsg_endpoint_ops;
+
+static void __ept_release(struct kref *kref)
+{
+ struct rpmsg_endpoint *ept = container_of(kref, struct rpmsg_endpoint,
+ refcount);
+ kfree(to_mtk_rpmsg_endpoint(ept));
+}
+
+static void mtk_rpmsg_ipi_handler(void *data, unsigned int len, void *priv)
+{
+ struct mtk_rpmsg_endpoint *mept = priv;
+ struct rpmsg_endpoint *ept = &mept->ept;
+ int ret;
+
+ ret = (*ept->cb)(ept->rpdev, data, len, ept->priv, ept->addr);
+ if (ret)
+ dev_warn(&ept->rpdev->dev, "rpmsg handler return error = %d",
+ ret);
+}
+
+static struct rpmsg_endpoint *
+__rpmsg_create_ept(struct mtk_rpmsg_rproc_subdev *mtk_subdev,
+ struct rpmsg_device *rpdev, rpmsg_rx_cb_t cb, void *priv,
+ u32 id)
+{
+ struct mtk_rpmsg_endpoint *mept;
+ struct rpmsg_endpoint *ept;
+ struct platform_device *pdev = mtk_subdev->pdev;
+ int ret;
+
+ mept = kzalloc(sizeof(*mept), GFP_KERNEL);
+ if (!mept)
+ return NULL;
+ mept->mtk_subdev = mtk_subdev;
+
+ ept = &mept->ept;
+ kref_init(&ept->refcount);
+
+ ept->rpdev = rpdev;
+ ept->cb = cb;
+ ept->priv = priv;
+ ept->ops = &mtk_rpmsg_endpoint_ops;
+ ept->addr = id;
+
+ ret = mtk_subdev->info->register_ipi(pdev, id, mtk_rpmsg_ipi_handler,
+ mept);
+ if (ret) {
+ dev_err(&pdev->dev, "IPI register failed, id = %d", id);
+ kref_put(&ept->refcount, __ept_release);
+ return NULL;
+ }
+
+ return ept;
+}
+
+static struct rpmsg_endpoint *
+mtk_rpmsg_create_ept(struct rpmsg_device *rpdev, rpmsg_rx_cb_t cb, void *priv,
+ struct rpmsg_channel_info chinfo)
+{
+ struct mtk_rpmsg_rproc_subdev *mtk_subdev =
+ to_mtk_rpmsg_device(rpdev)->mtk_subdev;
+
+ return __rpmsg_create_ept(mtk_subdev, rpdev, cb, priv, chinfo.src);
+}
+
+static void mtk_rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
+{
+ struct mtk_rpmsg_rproc_subdev *mtk_subdev =
+ to_mtk_rpmsg_endpoint(ept)->mtk_subdev;
+
+ mtk_subdev->info->unregister_ipi(mtk_subdev->pdev, ept->addr);
+ kref_put(&ept->refcount, __ept_release);
+}
+
+static int mtk_rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)
+{
+ struct mtk_rpmsg_rproc_subdev *mtk_subdev =
+ to_mtk_rpmsg_endpoint(ept)->mtk_subdev;
+
+ return mtk_subdev->info->send_ipi(mtk_subdev->pdev, ept->addr, data,
+ len, 0);
+}
+
+static int mtk_rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len)
+{
+ struct mtk_rpmsg_rproc_subdev *mtk_subdev =
+ to_mtk_rpmsg_endpoint(ept)->mtk_subdev;
+
+ /*
+ * TODO: This currently is same as mtk_rpmsg_send, and wait until SCP
+ * received the last command.
+ */
+ return mtk_subdev->info->send_ipi(mtk_subdev->pdev, ept->addr, data,
+ len, 0);
+}
+
+static const struct rpmsg_endpoint_ops mtk_rpmsg_endpoint_ops = {
+ .destroy_ept = mtk_rpmsg_destroy_ept,
+ .send = mtk_rpmsg_send,
+ .trysend = mtk_rpmsg_trysend,
+};
+
+static void mtk_rpmsg_release_device(struct device *dev)
+{
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
+ struct mtk_rpmsg_device *mdev = to_mtk_rpmsg_device(rpdev);
+
+ kfree(mdev);
+}
+
+static const struct rpmsg_device_ops mtk_rpmsg_device_ops = {
+ .create_ept = mtk_rpmsg_create_ept,
+};
+
+static struct device_node *
+mtk_rpmsg_match_device_subnode(struct device_node *node, const char *channel)
+{
+ struct device_node *child;
+ const char *name;
+ int ret;
+
+ for_each_available_child_of_node(node, child) {
+ ret = of_property_read_string(child, "mtk,rpmsg-name", &name);
+ if (ret)
+ continue;
+
+ if (strcmp(name, channel) == 0)
+ return child;
+ }
+
+ return NULL;
+}
+
+static int mtk_rpmsg_register_device(struct mtk_rpmsg_rproc_subdev *mtk_subdev,
+ struct rpmsg_channel_info *info)
+{
+ struct rpmsg_device *rpdev;
+ struct mtk_rpmsg_device *mdev;
+ struct platform_device *pdev = mtk_subdev->pdev;
+ int ret;
+
+ mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
+ if (!mdev)
+ return -ENOMEM;
+
+ mdev->mtk_subdev = mtk_subdev;
+
+ rpdev = &mdev->rpdev;
+ rpdev->ops = &mtk_rpmsg_device_ops;
+ rpdev->src = info->src;
+ rpdev->dst = info->dst;
+ strscpy(rpdev->id.name, info->name, RPMSG_NAME_SIZE);
+
+ rpdev->dev.of_node =
+ mtk_rpmsg_match_device_subnode(pdev->dev.of_node, info->name);
+ rpdev->dev.parent = &pdev->dev;
+ rpdev->dev.release = mtk_rpmsg_release_device;
+
+ ret = rpmsg_register_device(rpdev);
+ if (ret) {
+ kfree(mdev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void mtk_register_device_work_function(struct work_struct *register_work)
+{
+ struct mtk_rpmsg_rproc_subdev *subdev = container_of(
+ register_work, struct mtk_rpmsg_rproc_subdev, register_work);
+ struct platform_device *pdev = subdev->pdev;
+ struct mtk_rpmsg_channel_info *info;
+ int ret;
+
+ mutex_lock(&subdev->channels_lock);
+ list_for_each_entry(info, &subdev->channels, list) {
+ if (info->registered)
+ continue;
+
+ ret = mtk_rpmsg_register_device(subdev, &info->info);
+ if (ret) {
+ dev_err(&pdev->dev, "Can't create rpmsg_device\n");
+ continue;
+ }
+
+ info->registered = true;
+ }
+ mutex_unlock(&subdev->channels_lock);
+}
+
+static int mtk_rpmsg_create_device(struct mtk_rpmsg_rproc_subdev *mtk_subdev,
+ char *name, u32 addr)
+{
+ struct mtk_rpmsg_channel_info *info;
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ strscpy(info->info.name, name, RPMSG_NAME_SIZE);
+ info->info.src = addr;
+ info->info.dst = RPMSG_ADDR_ANY;
+ mutex_lock(&mtk_subdev->channels_lock);
+ list_add(&info->list, &mtk_subdev->channels);
+ mutex_unlock(&mtk_subdev->channels_lock);
+
+ schedule_work(&mtk_subdev->register_work);
+ return 0;
+}
+
+static int mtk_rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len,
+ void *priv, u32 src)
+{
+ struct rpmsg_ns_msg *msg = data;
+ struct mtk_rpmsg_rproc_subdev *mtk_subdev = priv;
+ struct device *dev = &mtk_subdev->pdev->dev;
+
+ int ret;
+
+ if (len != sizeof(*msg)) {
+ dev_err(dev, "malformed ns msg (%d)\n", len);
+ return -EINVAL;
+ }
+
+ /*
+ * the name service ept does _not_ belong to a real rpmsg channel,
+ * and is handled by the rpmsg bus itself.
+ * for sanity reasons, make sure a valid rpdev has _not_ sneaked
+ * in somehow.
+ */
+ if (rpdev) {
+ dev_err(dev, "anomaly: ns ept has an rpdev handle\n");
+ return -EINVAL;
+ }
+
+ /* don't trust the remote processor for null terminating the name */
+ msg->name[RPMSG_NAME_SIZE - 1] = '\0';
+
+ dev_info(dev, "creating channel %s addr 0x%x\n", msg->name, msg->addr);
+
+ ret = mtk_rpmsg_create_device(mtk_subdev, msg->name, msg->addr);
+ if (ret) {
+ dev_err(dev, "create rpmsg device failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+int mtk_rpmsg_prepare(struct rproc_subdev *subdev)
+{
+ struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev);
+
+ /* a dedicated endpoint handles the name service msgs */
+ if (mtk_subdev->info->ns_ipi_id >= 0) {
+ mtk_subdev->ns_ept =
+ __rpmsg_create_ept(mtk_subdev, NULL, mtk_rpmsg_ns_cb,
+ mtk_subdev,
+ mtk_subdev->info->ns_ipi_id);
+ if (!mtk_subdev->ns_ept) {
+ dev_err(&mtk_subdev->pdev->dev,
+ "failed to create name service endpoint\n");
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
+void mtk_rpmsg_unprepare(struct rproc_subdev *subdev)
+{
+ struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev);
+
+ if (mtk_subdev->ns_ept) {
+ mtk_rpmsg_destroy_ept(mtk_subdev->ns_ept);
+ mtk_subdev->ns_ept = NULL;
+ }
+}
+
+void mtk_rpmsg_stop(struct rproc_subdev *subdev, bool crashed)
+{
+ struct mtk_rpmsg_channel_info *info, *next;
+ struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev);
+ struct device *dev = &mtk_subdev->pdev->dev;
+
+ /*
+ * Destroy the name service endpoint here, to avoid new channel being
+ * created after the rpmsg_unregister_device loop below.
+ */
+ if (mtk_subdev->ns_ept) {
+ mtk_rpmsg_destroy_ept(mtk_subdev->ns_ept);
+ mtk_subdev->ns_ept = NULL;
+ }
+
+ cancel_work_sync(&mtk_subdev->register_work);
+
+ mutex_lock(&mtk_subdev->channels_lock);
+ list_for_each_entry(info, &mtk_subdev->channels, list) {
+ if (!info->registered)
+ continue;
+ if (rpmsg_unregister_device(dev, &info->info)) {
+ dev_warn(
+ dev,
+ "rpmsg_unregister_device failed for %s.%d.%d\n",
+ info->info.name, info->info.src,
+ info->info.dst);
+ }
+ }
+
+ list_for_each_entry_safe(info, next,
+ &mtk_subdev->channels, list) {
+ list_del(&info->list);
+ kfree(info);
+ }
+ mutex_unlock(&mtk_subdev->channels_lock);
+}
+
+struct rproc_subdev *
+mtk_rpmsg_create_rproc_subdev(struct platform_device *pdev,
+ struct mtk_rpmsg_info *info)
+{
+ struct mtk_rpmsg_rproc_subdev *mtk_subdev;
+
+ mtk_subdev = kzalloc(sizeof(*mtk_subdev), GFP_KERNEL);
+ if (!mtk_subdev)
+ return NULL;
+
+ mtk_subdev->pdev = pdev;
+ mtk_subdev->subdev.prepare = mtk_rpmsg_prepare;
+ mtk_subdev->subdev.stop = mtk_rpmsg_stop;
+ mtk_subdev->subdev.unprepare = mtk_rpmsg_unprepare;
+ mtk_subdev->info = info;
+ INIT_LIST_HEAD(&mtk_subdev->channels);
+ INIT_WORK(&mtk_subdev->register_work,
+ mtk_register_device_work_function);
+ mutex_init(&mtk_subdev->channels_lock);
+
+ return &mtk_subdev->subdev;
+}
+EXPORT_SYMBOL_GPL(mtk_rpmsg_create_rproc_subdev);
+
+void mtk_rpmsg_destroy_rproc_subdev(struct rproc_subdev *subdev)
+{
+ struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev);
+
+ kfree(mtk_subdev);
+}
+EXPORT_SYMBOL_GPL(mtk_rpmsg_destroy_rproc_subdev);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MediaTek scp rpmsg driver");
diff --git a/include/linux/remoteproc/mtk_scp.h b/include/linux/remoteproc/mtk_scp.h
index 707556f6b899..67ae6674397b 100644
--- a/include/linux/remoteproc/mtk_scp.h
+++ b/include/linux/remoteproc/mtk_scp.h
@@ -40,9 +40,11 @@ enum scp_ipi_id {
SCP_IPI_ISP_FRAME,
SCP_IPI_FD_CMD,
SCP_IPI_CROS_HOST_CMD,
- SCP_IPI_MAX,
+ SCP_IPI_NS_SERVICE = 0xFF,
+ SCP_IPI_MAX = 0x100,
};
+
/**
* scp_ipi_register - register an ipi function
*
diff --git a/include/linux/rpmsg/mtk_rpmsg.h b/include/linux/rpmsg/mtk_rpmsg.h
new file mode 100644
index 000000000000..5aa2d84ac0e2
--- /dev/null
+++ b/include/linux/rpmsg/mtk_rpmsg.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2019 Google LLC.
+ */
+
+#ifndef __LINUX_RPMSG_MTK_RPMSG_H
+#define __LINUX_RPMSG_MTK_RPMSG_H
+
+#include <linux/device.h>
+#include <linux/remoteproc.h>
+
+typedef void (*ipi_handler_t)(void *data, unsigned int len, void *priv);
+
+/*
+ * struct mtk_rpmsg_info - IPI functions tied to the rpmsg device.
+ * @register_ipi: register IPI handler for an IPI id.
+ * @unregister_ipi: unregister IPI handler for a registered IPI id.
+ * @send_ipi: send IPI to an IPI id. wait is the timeout (in msecs) to wait
+ * until response, or 0 if there's no timeout.
+ * @ns_ipi_id: the IPI id used for name service, or -1 if name service isn't
+ * supported.
+ */
+struct mtk_rpmsg_info {
+ int (*register_ipi)(struct platform_device *pdev, u32 id,
+ ipi_handler_t handler, void *priv);
+ void (*unregister_ipi)(struct platform_device *pdev, u32 id);
+ int (*send_ipi)(struct platform_device *pdev, u32 id,
+ void *buf, unsigned int len, unsigned int wait);
+ int ns_ipi_id;
+};
+
+struct rproc_subdev *
+mtk_rpmsg_create_rproc_subdev(struct platform_device *pdev,
+ struct mtk_rpmsg_info *info);
+
+void mtk_rpmsg_destroy_rproc_subdev(struct rproc_subdev *subdev);
+
+#endif
--
2.23.0.187.g17f5b7556c-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v17 3/5] remoteproc: mt8183: add reserved memory manager API
From: Pi-Hsun Shih @ 2019-09-04 6:16 UTC (permalink / raw)
Cc: Ohad Ben-Cohen, Erin Lo,
open list:REMOTE PROCESSOR REMOTEPROC SUBSYSTEM, open list,
Bjorn Andersson, moderated list:ARM/Mediatek SoC support,
Pi-Hsun Shih, Matthias Brugger,
moderated list:ARM/Mediatek SoC support
In-Reply-To: <20190904061649.69099-1-pihsun@chromium.org>
From: Erin Lo <erin.lo@mediatek.com>
Add memory table mapping API for other driver to lookup
reserved physical and virtual memory
Signed-off-by: Erin Lo <erin.lo@mediatek.com>
Signed-off-by: Pi-Hsun Shih <pihsun@chromium.org>
---
Changes from v16, v15:
- No change.
Changes from v14:
- Fix a typo in variable name in DEBUG section.
Changes from v13:
- Add one more reserved region.
- Rename scp_get_reserve_* to scp_get_reserved_*.
- Minor fixes addressing comment.
Changes from v12:
- Reformat a line to fit 80 character width.
Changes from v11:
- No change.
Changes from v10:
- Fix some type mismatch warnings when printing debug messages.
Changes from v9:
- No change.
Changes from v8:
- Add more reserved regions for camera ISP.
Changes from v7, v6, v5:
- No change.
Changes from v4:
- New patch.
---
drivers/remoteproc/mtk_scp.c | 145 +++++++++++++++++++++++++++++
include/linux/remoteproc/mtk_scp.h | 25 +++++
2 files changed, 170 insertions(+)
diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c
index 99e226f38ca4..ce4acffbb115 100644
--- a/drivers/remoteproc/mtk_scp.c
+++ b/drivers/remoteproc/mtk_scp.c
@@ -374,11 +374,142 @@ void *scp_mapping_dm_addr(struct platform_device *pdev, u32 mem_addr)
}
EXPORT_SYMBOL_GPL(scp_mapping_dm_addr);
+#if SCP_RESERVED_MEM
+static phys_addr_t scp_mem_base_phys;
+static phys_addr_t scp_mem_base_virt;
+static size_t scp_mem_size;
+
+static struct scp_reserve_mblock scp_reserve_mblock[] = {
+ {
+ .num = SCP_ISP_MEM_ID,
+ .start_phys = 0x0,
+ .start_virt = 0x0,
+ .size = 0x200000, /*2MB*/
+ },
+ {
+ .num = SCP_ISP_MEM2_ID,
+ .start_phys = 0x0,
+ .start_virt = 0x0,
+ .size = 0x800000, /*8MB*/
+ },
+ {
+ .num = SCP_MDP_MEM_ID,
+ .start_phys = 0x0,
+ .start_virt = 0x0,
+ .size = 0x600000, /*6MB*/
+ },
+ {
+ .num = SCP_DIP_MEM_ID,
+ .start_phys = 0x0,
+ .start_virt = 0x0,
+ .size = 0x900000, /*9MB*/
+ },
+ {
+ .num = SCP_FD_MEM_ID,
+ .start_phys = 0x0,
+ .start_virt = 0x0,
+ .size = 0x100000, /*1MB*/
+ },
+ {
+ .num = SCP_FD_MEM2_ID,
+ .start_phys = 0x0,
+ .start_virt = 0x0,
+ .size = 0x100000, /*1MB*/
+ },
+};
+
+static int scp_reserve_mem_init(struct mtk_scp *scp)
+{
+ enum scp_reserve_mem_id_t id;
+ phys_addr_t accumlate_memory_size = 0;
+
+ scp_mem_base_phys = (phys_addr_t) (scp->phys_addr + MAX_CODE_SIZE);
+ scp_mem_size = scp->dram_size - MAX_CODE_SIZE;
+
+ dev_info(scp->dev,
+ "phys:0x%llx - 0x%llx (0x%llx)\n",
+ (unsigned long long)scp_mem_base_phys,
+ (unsigned long long)(scp_mem_base_phys + scp_mem_size),
+ (unsigned long long)scp_mem_size);
+ accumlate_memory_size = 0;
+ for (id = 0; id < SCP_NUMS_MEM_ID; id++) {
+ scp_reserve_mblock[id].start_phys =
+ scp_mem_base_phys + accumlate_memory_size;
+ accumlate_memory_size += scp_reserve_mblock[id].size;
+ dev_info(
+ scp->dev,
+ "[reserve_mem:%d]: phys:0x%llx - 0x%llx (0x%llx)\n", id,
+ (unsigned long long)scp_reserve_mblock[id].start_phys,
+ (unsigned long long)(scp_reserve_mblock[id].start_phys +
+ scp_reserve_mblock[id].size),
+ (unsigned long long)scp_reserve_mblock[id].size);
+ }
+ return 0;
+}
+
+static int scp_reserve_memory_ioremap(struct mtk_scp *scp)
+{
+ enum scp_reserve_mem_id_t id;
+ phys_addr_t accumlate_memory_size = 0;
+
+ scp_mem_base_virt = (phys_addr_t)(size_t)ioremap_wc(scp_mem_base_phys,
+ scp_mem_size);
+
+ dev_info(scp->dev,
+ "virt:0x%llx - 0x%llx (0x%llx)\n",
+ (unsigned long long)scp_mem_base_virt,
+ (unsigned long long)(scp_mem_base_virt + scp_mem_size),
+ (unsigned long long)scp_mem_size);
+ for (id = 0; id < SCP_NUMS_MEM_ID; id++) {
+ scp_reserve_mblock[id].start_virt =
+ scp_mem_base_virt + accumlate_memory_size;
+ accumlate_memory_size += scp_reserve_mblock[id].size;
+ }
+ /* the reserved memory should be larger then expected memory
+ * or scp_reserve_mblock does not match dts
+ */
+ WARN_ON(accumlate_memory_size > scp_mem_size);
+ return 0;
+}
+phys_addr_t scp_get_reserved_mem_phys(enum scp_reserve_mem_id_t id)
+{
+ if (id >= SCP_NUMS_MEM_ID) {
+ pr_err("[SCP] no reserve memory for %d", id);
+ return 0;
+ }
+ return scp_reserve_mblock[id].start_phys;
+}
+EXPORT_SYMBOL_GPL(scp_get_reserved_mem_phys);
+
+phys_addr_t scp_get_reserved_mem_virt(enum scp_reserve_mem_id_t id)
+{
+ if (id >= SCP_NUMS_MEM_ID) {
+ pr_err("[SCP] no reserve memory for %d", id);
+ return 0;
+ }
+ return scp_reserve_mblock[id].start_virt;
+}
+EXPORT_SYMBOL_GPL(scp_get_reserved_mem_virt);
+
+size_t scp_get_reserved_mem_size(enum scp_reserve_mem_id_t id)
+{
+ if (id >= SCP_NUMS_MEM_ID) {
+ pr_err("[SCP] no reserve memory for %d", id);
+ return 0;
+ }
+ return scp_reserve_mblock[id].size;
+}
+EXPORT_SYMBOL_GPL(scp_get_reserved_mem_size);
+#endif
+
static int scp_map_memory_region(struct mtk_scp *scp)
{
struct device_node *node;
struct resource r;
int ret;
+#ifdef DEBUG
+ enum scp_reserve_mem_id_t id;
+#endif
node = of_parse_phandle(scp->dev->of_node, "memory-region", 0);
if (!node) {
@@ -401,6 +532,20 @@ static int scp_map_memory_region(struct mtk_scp *scp)
return -EBUSY;
}
+#if SCP_RESERVED_MEM
+ scp_reserve_mem_init(scp);
+ scp_reserve_memory_ioremap(scp);
+#ifdef DEBUG
+ for (id = 0; id < SCP_NUMS_MEM_ID; id++) {
+ dev_info(scp->dev,
+ "[mem_reserve-%d] phys:0x%llx,virt:0x%llx,size:0x%llx\n",
+ id,
+ scp_get_reserved_mem_phys(id),
+ scp_get_reserved_mem_virt(id),
+ scp_get_reserved_mem_size(id));
+ }
+#endif
+#endif
return 0;
}
diff --git a/include/linux/remoteproc/mtk_scp.h b/include/linux/remoteproc/mtk_scp.h
index b80d8e3f7959..707556f6b899 100644
--- a/include/linux/remoteproc/mtk_scp.h
+++ b/include/linux/remoteproc/mtk_scp.h
@@ -138,4 +138,29 @@ unsigned int scp_get_venc_hw_capa(struct platform_device *pdev);
void *scp_mapping_dm_addr(struct platform_device *pdev,
u32 mem_addr);
+#define SCP_RESERVED_MEM (1)
+#if SCP_RESERVED_MEM
+/* scp reserve memory ID definition*/
+enum scp_reserve_mem_id_t {
+ SCP_ISP_MEM_ID,
+ SCP_ISP_MEM2_ID,
+ SCP_MDP_MEM_ID,
+ SCP_DIP_MEM_ID,
+ SCP_FD_MEM_ID,
+ SCP_FD_MEM2_ID,
+ SCP_NUMS_MEM_ID,
+};
+
+struct scp_reserve_mblock {
+ enum scp_reserve_mem_id_t num;
+ u64 start_phys;
+ u64 start_virt;
+ u64 size;
+};
+
+extern phys_addr_t scp_get_reserved_mem_phys(enum scp_reserve_mem_id_t id);
+extern phys_addr_t scp_get_reserved_mem_virt(enum scp_reserve_mem_id_t id);
+extern size_t scp_get_reserved_mem_size(enum scp_reserve_mem_id_t id);
+#endif
+
#endif /* _MTK_SCP_H */
--
2.23.0.187.g17f5b7556c-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v17 2/5] remoteproc/mediatek: add SCP support for mt8183
From: Pi-Hsun Shih @ 2019-09-04 6:16 UTC (permalink / raw)
Cc: Ohad Ben-Cohen, Nicolas Boichat, Erin Lo,
open list:REMOTE PROCESSOR REMOTEPROC SUBSYSTEM, open list,
Bjorn Andersson, moderated list:ARM/Mediatek SoC support,
Pi-Hsun Shih, Matthias Brugger,
moderated list:ARM/Mediatek SoC support
In-Reply-To: <20190904061649.69099-1-pihsun@chromium.org>
From: Erin Lo <erin.lo@mediatek.com>
Provide a basic driver to control Cortex M4 co-processor
Signed-off-by: Erin Lo <erin.lo@mediatek.com>
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Signed-off-by: Pi-Hsun Shih <pihsun@chromium.org>
---
Changes from v16:
- Change the desc_lock mutex to be a per-id lock.
- Put the execution of handler inside the per-id lock, to prevent race
between scp_ipi_unregister and handler being run.
- Move the initialization of mutex to before scp_ipi_register.
Changes from v15:
- Fix a bug on incorrect usage of wait_event_timeout return value.
Changes from v14:
- No change.
Changes from v13:
- Move include/linux/platform_data/mtk_scp.h to
include/linux/remoteproc/mtk_scp.h.
- Add lock for access of scp->ipi_desc.
- Lock the whole ipi_send function.
- Move more setting of cache size from SCP firmware to kernel driver,
to prevent problem while loading firmware onto DRAM.
- Cleanup and remove unused branch in scp_da_to_va.
- Minor fixes addressing comment.
Changes from v12:
- Initialize cache before firmware load, to avoid problem while loading
large firmware.
- Disable watchdog before stopping SCP, to avoid extra warning message.
- Use strscpy instead of strncpy.
Changes from v11:
- No change.
Changes from v10:
- Add a clock reset before loading firmware.
Changes from v9:
- No change.
Changes from v8:
- Add a missing space.
Changes from v7:
- Moved the location of shared SCP buffer.
- Fix clock enable/disable sequence.
- Add more IPI ID that would be used.
Changes from v6:
- No change.
Changes from v5:
- Changed some space to tab.
Changes from v4:
- Rename most function from mtk_scp_* to scp_*.
- Change the irq to threaded handler.
- Load ELF file instead of plain binary file as firmware by default
(Squashed patch 6 in v4 into this patch).
Changes from v3:
- Fix some issue found by checkpatch.
- Make writes aligned in scp_ipi_send.
Changes from v2:
- Squash patch 3 from v2 (separate the ipi interface) into this patch.
- Remove unused name argument from scp_ipi_register.
- Add scp_ipi_unregister for proper cleanup.
- Move IPI ids in sync with firmware.
- Add mb() in proper place, and correctly clear the run->signaled.
Changes from v1:
- Extract functions and rename variables in mtk_scp.c.
---
drivers/remoteproc/Kconfig | 9 +
drivers/remoteproc/Makefile | 1 +
drivers/remoteproc/mtk_common.h | 92 +++++
drivers/remoteproc/mtk_scp.c | 547 +++++++++++++++++++++++++++++
drivers/remoteproc/mtk_scp_ipi.c | 176 ++++++++++
include/linux/remoteproc/mtk_scp.h | 141 ++++++++
6 files changed, 966 insertions(+)
create mode 100644 drivers/remoteproc/mtk_common.h
create mode 100644 drivers/remoteproc/mtk_scp.c
create mode 100644 drivers/remoteproc/mtk_scp_ipi.c
create mode 100644 include/linux/remoteproc/mtk_scp.h
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 28ed306982f7..ea71cad399f7 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -23,6 +23,15 @@ config IMX_REMOTEPROC
It's safe to say N here.
+config MTK_SCP
+ tristate "Mediatek SCP support"
+ depends on ARCH_MEDIATEK
+ help
+ Say y here to support Mediatek's System Companion Processor (SCP) via
+ the remote processor framework.
+
+ It's safe to say N here.
+
config OMAP_REMOTEPROC
tristate "OMAP remoteproc support"
depends on ARCH_OMAP4 || SOC_OMAP5
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 00f09e658cb3..e30a1b15fbac 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -10,6 +10,7 @@ remoteproc-y += remoteproc_sysfs.o
remoteproc-y += remoteproc_virtio.o
remoteproc-y += remoteproc_elf_loader.o
obj-$(CONFIG_IMX_REMOTEPROC) += imx_rproc.o
+obj-$(CONFIG_MTK_SCP) += mtk_scp.o mtk_scp_ipi.o
obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o
obj-$(CONFIG_WKUP_M3_RPROC) += wkup_m3_rproc.o
obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o
diff --git a/drivers/remoteproc/mtk_common.h b/drivers/remoteproc/mtk_common.h
new file mode 100644
index 000000000000..622e9aebe9ab
--- /dev/null
+++ b/drivers/remoteproc/mtk_common.h
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ */
+
+#ifndef __RPROC_MTK_COMMON_H
+#define __RPROC_MTK_COMMON_H
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/remoteproc.h>
+
+#define MT8183_SW_RSTN 0x0
+#define MT8183_SW_RSTN_BIT BIT(0)
+#define MT8183_SCP_TO_HOST 0x1C
+#define MT8183_SCP_IPC_INT_BIT BIT(0)
+#define MT8183_SCP_WDT_INT_BIT BIT(8)
+#define MT8183_HOST_TO_SCP 0x28
+#define MT8183_HOST_IPC_INT_BIT BIT(0)
+#define MT8183_WDT_CFG 0x84
+#define MT8183_SCP_CLK_SW_SEL 0x4000
+#define MT8183_SCP_CLK_DIV_SEL 0x4024
+#define MT8183_SCP_SRAM_PDN 0x402C
+#define MT8183_SCP_L1_SRAM_PD 0x4080
+#define MT8183_SCP_TCM_TAIL_SRAM_PD 0x4094
+
+#define MT8183_SCP_CACHE_SEL(x) (0x14000 + (x) * 0x3000)
+#define MT8183_SCP_CACHE_CON MT8183_SCP_CACHE_SEL(0)
+#define MT8183_SCP_DCACHE_CON MT8183_SCP_CACHE_SEL(1)
+#define MT8183_SCP_CACHESIZE_8KB BIT(8)
+#define MT8183_SCP_CACHE_CON_WAYEN BIT(10)
+
+#define SCP_FW_VER_LEN 32
+#define SCP_SHARE_BUFFER_SIZE 288
+
+struct scp_run {
+ u32 signaled;
+ s8 fw_ver[SCP_FW_VER_LEN];
+ u32 dec_capability;
+ u32 enc_capability;
+ wait_queue_head_t wq;
+};
+
+struct scp_ipi_desc {
+ /* For protecting handler. */
+ struct mutex lock;
+ scp_ipi_handler_t handler;
+ void *priv;
+};
+
+struct mtk_scp {
+ struct device *dev;
+ struct rproc *rproc;
+ struct clk *clk;
+ void __iomem *reg_base;
+ void __iomem *sram_base;
+ size_t sram_size;
+
+ struct share_obj *recv_buf;
+ struct share_obj *send_buf;
+ struct scp_run run;
+ /* To prevent multiple ipi_send run concurrently. */
+ struct mutex send_lock;
+ struct scp_ipi_desc ipi_desc[SCP_IPI_MAX];
+ bool ipi_id_ack[SCP_IPI_MAX];
+ wait_queue_head_t ack_wq;
+
+ void __iomem *cpu_addr;
+ phys_addr_t phys_addr;
+ size_t dram_size;
+};
+
+/**
+ * struct share_obj - SRAM buffer shared with
+ * AP and SCP
+ *
+ * @id: IPI id
+ * @len: share buffer length
+ * @share_buf: share buffer data
+ */
+struct share_obj {
+ u32 id;
+ u32 len;
+ u8 share_buf[SCP_SHARE_BUFFER_SIZE];
+};
+
+void scp_memcpy_aligned(void *dst, const void *src, unsigned int len);
+void scp_ipi_lock(struct mtk_scp *scp, u32 id);
+void scp_ipi_unlock(struct mtk_scp *scp, u32 id);
+
+#endif
diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c
new file mode 100644
index 000000000000..99e226f38ca4
--- /dev/null
+++ b/drivers/remoteproc/mtk_scp.c
@@ -0,0 +1,547 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2019 MediaTek Inc.
+
+#include <asm/barrier.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/remoteproc.h>
+#include <linux/remoteproc/mtk_scp.h>
+
+#include "mtk_common.h"
+#include "remoteproc_internal.h"
+
+#define MAX_CODE_SIZE 0x500000
+#define SCP_FW_END 0x7C000
+
+struct platform_device *scp_get_pdev(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *scp_node;
+ struct platform_device *scp_pdev;
+
+ scp_node = of_parse_phandle(dev->of_node, "mediatek,scp", 0);
+ if (!scp_node) {
+ dev_err(dev, "can't get SCP node\n");
+ return NULL;
+ }
+
+ scp_pdev = of_find_device_by_node(scp_node);
+ if (WARN_ON(!scp_pdev)) {
+ dev_err(dev, "SCP pdev failed\n");
+ of_node_put(scp_node);
+ return NULL;
+ }
+
+ return scp_pdev;
+}
+EXPORT_SYMBOL_GPL(scp_get_pdev);
+
+static void scp_wdt_handler(struct mtk_scp *scp, u32 scp_to_host)
+{
+ dev_err(scp->dev, "SCP watchdog timeout! 0x%x", scp_to_host);
+ rproc_report_crash(scp->rproc, RPROC_WATCHDOG);
+}
+
+static void scp_init_ipi_handler(void *data, unsigned int len, void *priv)
+{
+ struct mtk_scp *scp = (struct mtk_scp *)priv;
+ struct scp_run *run = (struct scp_run *)data;
+
+ scp->run.signaled = run->signaled;
+ strscpy(scp->run.fw_ver, run->fw_ver, SCP_FW_VER_LEN);
+ scp->run.dec_capability = run->dec_capability;
+ scp->run.enc_capability = run->enc_capability;
+ wake_up_interruptible(&scp->run.wq);
+}
+
+static void scp_ipi_handler(struct mtk_scp *scp)
+{
+ struct share_obj *rcv_obj = scp->recv_buf;
+ struct scp_ipi_desc *ipi_desc = scp->ipi_desc;
+ u8 tmp_data[SCP_SHARE_BUFFER_SIZE];
+ scp_ipi_handler_t handler;
+ u32 id = rcv_obj->id;
+
+ if (rcv_obj->len > SCP_SHARE_BUFFER_SIZE) {
+ dev_err(scp->dev, "ipi message too long (len %d, max %d)",
+ rcv_obj->len, SCP_SHARE_BUFFER_SIZE);
+ return;
+ }
+ if (id >= SCP_IPI_MAX) {
+ dev_err(scp->dev, "No such ipi id = %d\n", id);
+ return;
+ }
+
+ scp_ipi_lock(scp, id);
+ handler = ipi_desc[id].handler;
+ if (!handler) {
+ dev_err(scp->dev, "No such ipi id = %d\n", id);
+ scp_ipi_unlock(scp, id);
+ return;
+ }
+
+ memcpy_fromio(tmp_data, &rcv_obj->share_buf, rcv_obj->len);
+ handler(tmp_data, rcv_obj->len, ipi_desc[id].priv);
+ scp_ipi_unlock(scp, id);
+
+ scp->ipi_id_ack[id] = true;
+ wake_up(&scp->ack_wq);
+}
+
+static int scp_ipi_init(struct mtk_scp *scp)
+{
+ size_t send_offset = SCP_FW_END - sizeof(struct share_obj);
+ size_t recv_offset = send_offset - sizeof(struct share_obj);
+
+ /* Disable SCP to host interrupt */
+ writel(MT8183_SCP_IPC_INT_BIT, scp->reg_base + MT8183_SCP_TO_HOST);
+
+ /* shared buffer initialization */
+ scp->recv_buf = (__force struct share_obj *)(scp->sram_base +
+ recv_offset);
+ scp->send_buf = (__force struct share_obj *)(scp->sram_base +
+ send_offset);
+ memset_io(scp->recv_buf, 0, sizeof(scp->recv_buf));
+ memset_io(scp->send_buf, 0, sizeof(scp->send_buf));
+
+ return 0;
+}
+
+static void scp_reset_assert(const struct mtk_scp *scp)
+{
+ u32 val;
+
+ val = readl(scp->reg_base + MT8183_SW_RSTN);
+ val &= ~MT8183_SW_RSTN_BIT;
+ writel(val, scp->reg_base + MT8183_SW_RSTN);
+}
+
+static void scp_reset_deassert(const struct mtk_scp *scp)
+{
+ u32 val;
+
+ val = readl(scp->reg_base + MT8183_SW_RSTN);
+ val |= MT8183_SW_RSTN_BIT;
+ writel(val, scp->reg_base + MT8183_SW_RSTN);
+}
+
+static irqreturn_t scp_irq_handler(int irq, void *priv)
+{
+ struct mtk_scp *scp = priv;
+ u32 scp_to_host;
+ int ret;
+
+ ret = clk_prepare_enable(scp->clk);
+ if (ret) {
+ dev_err(scp->dev, "failed to enable clocks\n");
+ return IRQ_NONE;
+ }
+
+ scp_to_host = readl(scp->reg_base + MT8183_SCP_TO_HOST);
+ if (scp_to_host & MT8183_SCP_IPC_INT_BIT)
+ scp_ipi_handler(scp);
+ else
+ scp_wdt_handler(scp, scp_to_host);
+
+ /*
+ * Ensure that all writes to SRAM are committed before another
+ * interrupt.
+ */
+ mb();
+ /* SCP won't send another interrupt until we set SCP_TO_HOST to 0. */
+ writel(MT8183_SCP_IPC_INT_BIT | MT8183_SCP_WDT_INT_BIT,
+ scp->reg_base + MT8183_SCP_TO_HOST);
+ clk_disable_unprepare(scp->clk);
+
+ return IRQ_HANDLED;
+}
+
+static int scp_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
+{
+ struct device *dev = &rproc->dev;
+ struct elf32_hdr *ehdr;
+ struct elf32_phdr *phdr;
+ int i, ret = 0;
+ const u8 *elf_data = fw->data;
+
+ ehdr = (struct elf32_hdr *)elf_data;
+ phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
+
+ /* go through the available ELF segments */
+ for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
+ u32 da = phdr->p_paddr;
+ u32 memsz = phdr->p_memsz;
+ u32 filesz = phdr->p_filesz;
+ u32 offset = phdr->p_offset;
+ void __iomem *ptr;
+
+ if (phdr->p_type != PT_LOAD)
+ continue;
+
+ dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
+ phdr->p_type, da, memsz, filesz);
+
+ if (filesz > memsz) {
+ dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
+ filesz, memsz);
+ ret = -EINVAL;
+ break;
+ }
+
+ if (offset + filesz > fw->size) {
+ dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
+ offset + filesz, fw->size);
+ ret = -EINVAL;
+ break;
+ }
+
+ /* grab the kernel address for this device address */
+ ptr = rproc_da_to_va(rproc, da, memsz);
+ if (!ptr) {
+ dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
+ ret = -EINVAL;
+ break;
+ }
+
+ /* put the segment where the remote processor expects it */
+ if (phdr->p_filesz)
+ scp_memcpy_aligned(ptr, elf_data + phdr->p_offset,
+ filesz);
+ }
+
+ return ret;
+}
+
+static int scp_load(struct rproc *rproc, const struct firmware *fw)
+{
+ const struct mtk_scp *scp = rproc->priv;
+ struct device *dev = scp->dev;
+ int ret;
+
+ ret = clk_prepare_enable(scp->clk);
+ if (ret) {
+ dev_err(dev, "failed to enable clocks\n");
+ return ret;
+ }
+
+ /* Hold SCP in reset while loading FW. */
+ scp_reset_assert(scp);
+
+ /* Reset clocks before loading FW */
+ writel(0x0, scp->reg_base + MT8183_SCP_CLK_SW_SEL);
+ writel(0x0, scp->reg_base + MT8183_SCP_CLK_DIV_SEL);
+
+ /* Initialize TCM before loading FW. */
+ writel(0x0, scp->reg_base + MT8183_SCP_L1_SRAM_PD);
+ writel(0x0, scp->reg_base + MT8183_SCP_TCM_TAIL_SRAM_PD);
+
+ /* Turn on the power of SCP's SRAM before using it. */
+ writel(0x0, scp->reg_base + MT8183_SCP_SRAM_PDN);
+
+ /*
+ * Set I-cache and D-cache size before loading SCP FW.
+ * SCP SRAM logical address may change when cache size setting differs.
+ */
+ writel(MT8183_SCP_CACHE_CON_WAYEN | MT8183_SCP_CACHESIZE_8KB,
+ scp->reg_base + MT8183_SCP_CACHE_CON);
+ writel(MT8183_SCP_CACHESIZE_8KB, scp->reg_base + MT8183_SCP_DCACHE_CON);
+
+ ret = scp_elf_load_segments(rproc, fw);
+ clk_disable_unprepare(scp->clk);
+
+ return ret;
+}
+
+static int scp_start(struct rproc *rproc)
+{
+ struct mtk_scp *scp = (struct mtk_scp *)rproc->priv;
+ struct device *dev = scp->dev;
+ struct scp_run *run = &scp->run;
+ int ret;
+
+ ret = clk_prepare_enable(scp->clk);
+ if (ret) {
+ dev_err(dev, "failed to enable clocks\n");
+ return ret;
+ }
+
+ run->signaled = false;
+
+ scp_reset_deassert(scp);
+
+ ret = wait_event_interruptible_timeout(
+ run->wq,
+ run->signaled,
+ msecs_to_jiffies(2000));
+
+ if (ret == 0) {
+ dev_err(dev, "wait SCP initialization timeout!\n");
+ ret = -ETIME;
+ goto stop;
+ }
+ if (ret == -ERESTARTSYS) {
+ dev_err(dev, "wait SCP interrupted by a signal!\n");
+ goto stop;
+ }
+ clk_disable_unprepare(scp->clk);
+ dev_info(dev, "SCP is ready. FW version %s\n", run->fw_ver);
+
+ return 0;
+
+stop:
+ scp_reset_assert(scp);
+ clk_disable_unprepare(scp->clk);
+ return ret;
+}
+
+static void *scp_da_to_va(struct rproc *rproc, u64 da, int len)
+{
+ struct mtk_scp *scp = (struct mtk_scp *)rproc->priv;
+ int offset;
+
+ if (da < scp->sram_size) {
+ offset = da;
+ if (offset >= 0 && (offset + len) < scp->sram_size)
+ return scp->sram_base + offset;
+ } else {
+ offset = da - scp->phys_addr;
+ if (offset >= 0 && (offset + len) < scp->dram_size)
+ return scp->cpu_addr + offset;
+ }
+
+ return NULL;
+}
+
+static int scp_stop(struct rproc *rproc)
+{
+ struct mtk_scp *scp = (struct mtk_scp *)rproc->priv;
+ int ret;
+
+ ret = clk_prepare_enable(scp->clk);
+ if (ret) {
+ dev_err(scp->dev, "failed to enable clocks\n");
+ return ret;
+ }
+
+ scp_reset_assert(scp);
+ /* Disable SCP watchdog */
+ writel(0, scp->reg_base + MT8183_WDT_CFG);
+ clk_disable_unprepare(scp->clk);
+
+ return 0;
+}
+
+static const struct rproc_ops scp_ops = {
+ .start = scp_start,
+ .stop = scp_stop,
+ .load = scp_load,
+ .da_to_va = scp_da_to_va,
+};
+
+unsigned int scp_get_vdec_hw_capa(struct platform_device *pdev)
+{
+ struct mtk_scp *scp = platform_get_drvdata(pdev);
+
+ return scp->run.dec_capability;
+}
+EXPORT_SYMBOL_GPL(scp_get_vdec_hw_capa);
+
+unsigned int scp_get_venc_hw_capa(struct platform_device *pdev)
+{
+ struct mtk_scp *scp = platform_get_drvdata(pdev);
+
+ return scp->run.enc_capability;
+}
+EXPORT_SYMBOL_GPL(scp_get_venc_hw_capa);
+
+void *scp_mapping_dm_addr(struct platform_device *pdev, u32 mem_addr)
+{
+ struct mtk_scp *scp = platform_get_drvdata(pdev);
+ void *ptr;
+
+ ptr = scp_da_to_va(scp->rproc, mem_addr, 0);
+ if (!ptr)
+ return ERR_PTR(-EINVAL);
+
+ return ptr;
+}
+EXPORT_SYMBOL_GPL(scp_mapping_dm_addr);
+
+static int scp_map_memory_region(struct mtk_scp *scp)
+{
+ struct device_node *node;
+ struct resource r;
+ int ret;
+
+ node = of_parse_phandle(scp->dev->of_node, "memory-region", 0);
+ if (!node) {
+ dev_err(scp->dev, "no memory-region specified\n");
+ return -EINVAL;
+ }
+
+ ret = of_address_to_resource(node, 0, &r);
+ if (ret)
+ return ret;
+
+ scp->phys_addr = r.start;
+ scp->dram_size = resource_size(&r);
+ scp->cpu_addr =
+ devm_ioremap_wc(scp->dev, scp->phys_addr, scp->dram_size);
+
+ if (!scp->cpu_addr) {
+ dev_err(scp->dev, "unable to map memory region: %pa+%zx\n",
+ &r.start, scp->dram_size);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int scp_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct mtk_scp *scp;
+ struct rproc *rproc;
+ struct resource *res;
+ char *fw_name = "scp.img";
+ int ret, i;
+
+ rproc = rproc_alloc(dev,
+ np->name,
+ &scp_ops,
+ fw_name,
+ sizeof(*scp));
+ if (!rproc) {
+ dev_err(dev, "unable to allocate remoteproc\n");
+ return -ENOMEM;
+ }
+
+ scp = (struct mtk_scp *)rproc->priv;
+ scp->rproc = rproc;
+ scp->dev = dev;
+ platform_set_drvdata(pdev, scp);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram");
+ scp->sram_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR((__force void *)scp->sram_base)) {
+ dev_err(dev, "Failed to parse and map sram memory\n");
+ ret = PTR_ERR((__force void *)scp->sram_base);
+ goto free_rproc;
+ }
+ scp->sram_size = resource_size(res);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
+ scp->reg_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR((__force void *)scp->reg_base)) {
+ dev_err(dev, "Failed to parse and map cfg memory\n");
+ ret = PTR_ERR((__force void *)scp->reg_base);
+ goto free_rproc;
+ }
+
+ ret = scp_map_memory_region(scp);
+ if (ret)
+ goto free_rproc;
+
+ scp->clk = devm_clk_get(dev, "main");
+ if (IS_ERR(scp->clk)) {
+ dev_err(dev, "Failed to get clock\n");
+ ret = PTR_ERR(scp->clk);
+ goto free_rproc;
+ }
+
+ ret = clk_prepare_enable(scp->clk);
+ if (ret) {
+ dev_err(dev, "failed to enable clocks\n");
+ goto free_rproc;
+ }
+
+ mutex_init(&scp->send_lock);
+ for (i = 0; i < SCP_IPI_MAX; i++)
+ mutex_init(&scp->ipi_desc[i].lock);
+
+ ret = scp_ipi_init(scp);
+ clk_disable_unprepare(scp->clk);
+ if (ret) {
+ dev_err(dev, "Failed to init ipi\n");
+ goto free_rproc;
+ }
+
+ /* register SCP initialization IPI */
+ ret = scp_ipi_register(pdev,
+ SCP_IPI_INIT,
+ scp_init_ipi_handler,
+ scp);
+ if (ret) {
+ dev_err(dev, "Failed to register IPI_SCP_INIT\n");
+ goto free_rproc;
+ }
+
+ init_waitqueue_head(&scp->run.wq);
+ init_waitqueue_head(&scp->ack_wq);
+
+ ret = devm_request_threaded_irq(dev, platform_get_irq(pdev, 0), NULL,
+ scp_irq_handler, IRQF_ONESHOT,
+ pdev->name, scp);
+
+ if (ret) {
+ dev_err(dev, "failed to request irq\n");
+ goto destroy_mutex;
+ }
+
+ ret = rproc_add(rproc);
+ if (ret)
+ goto destroy_mutex;
+
+ return ret;
+
+destroy_mutex:
+ for (i = 0; i < SCP_IPI_MAX; i++)
+ mutex_destroy(&scp->ipi_desc[i].lock);
+ mutex_destroy(&scp->send_lock);
+free_rproc:
+ rproc_free(rproc);
+
+ return ret;
+}
+
+static int scp_remove(struct platform_device *pdev)
+{
+ struct mtk_scp *scp = platform_get_drvdata(pdev);
+ int i;
+
+ for (i = 0; i < SCP_IPI_MAX; i++)
+ mutex_destroy(&scp->ipi_desc[i].lock);
+ mutex_destroy(&scp->send_lock);
+ rproc_del(scp->rproc);
+ rproc_free(scp->rproc);
+
+ return 0;
+}
+
+static const struct of_device_id mtk_scp_of_match[] = {
+ { .compatible = "mediatek,mt8183-scp"},
+ {},
+};
+MODULE_DEVICE_TABLE(of, mtk_scp_of_match);
+
+static struct platform_driver mtk_scp_driver = {
+ .probe = scp_probe,
+ .remove = scp_remove,
+ .driver = {
+ .name = "mtk-scp",
+ .of_match_table = of_match_ptr(mtk_scp_of_match),
+ },
+};
+
+module_platform_driver(mtk_scp_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MediaTek SCP control driver");
diff --git a/drivers/remoteproc/mtk_scp_ipi.c b/drivers/remoteproc/mtk_scp_ipi.c
new file mode 100644
index 000000000000..f26fad007bd6
--- /dev/null
+++ b/drivers/remoteproc/mtk_scp_ipi.c
@@ -0,0 +1,176 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2019 MediaTek Inc.
+
+#include <asm/barrier.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/remoteproc/mtk_scp.h>
+
+#include "mtk_common.h"
+
+int scp_ipi_register(struct platform_device *pdev,
+ enum scp_ipi_id id,
+ scp_ipi_handler_t handler,
+ void *priv)
+{
+ struct mtk_scp *scp = platform_get_drvdata(pdev);
+
+ if (!scp) {
+ dev_err(&pdev->dev, "scp device is not ready\n");
+ return -EPROBE_DEFER;
+ }
+
+ if (WARN_ON(id < 0) || WARN_ON(id >= SCP_IPI_MAX) ||
+ WARN_ON(handler == NULL))
+ return -EINVAL;
+
+ scp_ipi_lock(scp, id);
+ scp->ipi_desc[id].handler = handler;
+ scp->ipi_desc[id].priv = priv;
+ scp_ipi_unlock(scp, id);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(scp_ipi_register);
+
+void scp_ipi_unregister(struct platform_device *pdev, enum scp_ipi_id id)
+{
+ struct mtk_scp *scp = platform_get_drvdata(pdev);
+
+ if (!scp)
+ return;
+
+ if (WARN_ON(id < 0) || WARN_ON(id >= SCP_IPI_MAX))
+ return;
+
+ scp_ipi_lock(scp, id);
+ scp->ipi_desc[id].handler = NULL;
+ scp->ipi_desc[id].priv = NULL;
+ scp_ipi_unlock(scp, id);
+}
+EXPORT_SYMBOL_GPL(scp_ipi_unregister);
+
+/*
+ * Copy src to dst, where dst is in SCP SRAM region.
+ * Since AP access of SCP SRAM don't support byte write, this always write a
+ * full word at a time, and may cause some extra bytes to be written at the
+ * beginning & ending of dst.
+ */
+void scp_memcpy_aligned(void *dst, const void *src, unsigned int len)
+{
+ void *ptr;
+ u32 val;
+ unsigned int i = 0;
+
+ if (!IS_ALIGNED((unsigned long)dst, 4)) {
+ ptr = (void *)ALIGN_DOWN((unsigned long)dst, 4);
+ i = 4 - (dst - ptr);
+ val = readl_relaxed(ptr);
+ memcpy((u8 *)&val + (4 - i), src, i);
+ writel_relaxed(val, ptr);
+ }
+
+ while (i + 4 <= len) {
+ val = *((u32 *)(src + i));
+ writel_relaxed(val, dst + i);
+ i += 4;
+ }
+ if (i < len) {
+ val = readl_relaxed(dst + i);
+ memcpy(&val, src + i, len - i);
+ writel_relaxed(val, dst + i);
+ }
+}
+EXPORT_SYMBOL_GPL(scp_memcpy_aligned);
+
+void scp_ipi_lock(struct mtk_scp *scp, u32 id)
+{
+ if (WARN_ON(id >= SCP_IPI_MAX))
+ return;
+ mutex_lock(&scp->ipi_desc[id].lock);
+}
+EXPORT_SYMBOL_GPL(scp_ipi_lock);
+
+void scp_ipi_unlock(struct mtk_scp *scp, u32 id)
+{
+ if (WARN_ON(id >= SCP_IPI_MAX))
+ return;
+ mutex_unlock(&scp->ipi_desc[id].lock);
+}
+EXPORT_SYMBOL_GPL(scp_ipi_unlock);
+
+int scp_ipi_send(struct platform_device *pdev,
+ enum scp_ipi_id id,
+ void *buf,
+ unsigned int len,
+ unsigned int wait)
+{
+ struct mtk_scp *scp = platform_get_drvdata(pdev);
+ struct share_obj *send_obj = scp->send_buf;
+ unsigned long timeout;
+ int ret;
+
+ if (WARN_ON(id <= SCP_IPI_INIT) || WARN_ON(id >= SCP_IPI_MAX) ||
+ WARN_ON(len > sizeof(send_obj->share_buf)) || WARN_ON(!buf))
+ return -EINVAL;
+
+ mutex_lock(&scp->send_lock);
+
+ ret = clk_prepare_enable(scp->clk);
+ if (ret) {
+ dev_err(scp->dev, "failed to enable clock\n");
+ goto unlock_mutex;
+ }
+
+ /* Wait until SCP receives the last command */
+ timeout = jiffies + msecs_to_jiffies(2000);
+ do {
+ if (time_after(jiffies, timeout)) {
+ dev_err(scp->dev, "%s: IPI timeout!\n", __func__);
+ ret = -ETIMEDOUT;
+ goto clock_disable;
+ }
+ } while (readl(scp->reg_base + MT8183_HOST_TO_SCP));
+
+ scp_memcpy_aligned(send_obj->share_buf, buf, len);
+
+ send_obj->len = len;
+ send_obj->id = id;
+
+ scp->ipi_id_ack[id] = false;
+ /*
+ * Ensure that all writes to SRAM are committed before sending the
+ * interrupt to SCP.
+ */
+ mb();
+ /* send the command to SCP */
+ writel(MT8183_HOST_IPC_INT_BIT, scp->reg_base + MT8183_HOST_TO_SCP);
+
+ if (wait) {
+ /* wait for SCP's ACK */
+ timeout = msecs_to_jiffies(wait);
+ ret = wait_event_timeout(scp->ack_wq,
+ scp->ipi_id_ack[id],
+ timeout);
+ scp->ipi_id_ack[id] = false;
+ if (WARN(!ret, "scp ipi %d ack time out !", id))
+ ret = -EIO;
+ else
+ ret = 0;
+ }
+
+clock_disable:
+ clk_disable_unprepare(scp->clk);
+unlock_mutex:
+ mutex_unlock(&scp->send_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(scp_ipi_send);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MediaTek scp IPI interface");
diff --git a/include/linux/remoteproc/mtk_scp.h b/include/linux/remoteproc/mtk_scp.h
new file mode 100644
index 000000000000..b80d8e3f7959
--- /dev/null
+++ b/include/linux/remoteproc/mtk_scp.h
@@ -0,0 +1,141 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ */
+
+#ifndef _MTK_SCP_H
+#define _MTK_SCP_H
+
+#include <linux/platform_device.h>
+
+typedef void (*scp_ipi_handler_t) (void *data,
+ unsigned int len,
+ void *priv);
+
+/**
+ * enum ipi_id - the id of inter-processor interrupt
+ *
+ * @SCP_IPI_INIT: The interrupt from scp is to notfiy kernel
+ * SCP initialization completed.
+ * IPI_SCP_INIT is sent from SCP when firmware is
+ * loaded. AP doesn't need to send IPI_SCP_INIT
+ * command to SCP.
+ * For other IPI below, AP should send the request
+ * to SCP to trigger the interrupt.
+ * @SCP_IPI_MAX: The maximum IPI number
+ */
+
+enum scp_ipi_id {
+ SCP_IPI_INIT = 0,
+ SCP_IPI_VDEC_H264,
+ SCP_IPI_VDEC_VP8,
+ SCP_IPI_VDEC_VP9,
+ SCP_IPI_VENC_H264,
+ SCP_IPI_VENC_VP8,
+ SCP_IPI_MDP_INIT,
+ SCP_IPI_MDP_DEINIT,
+ SCP_IPI_MDP_FRAME,
+ SCP_IPI_DIP,
+ SCP_IPI_ISP_CMD,
+ SCP_IPI_ISP_FRAME,
+ SCP_IPI_FD_CMD,
+ SCP_IPI_CROS_HOST_CMD,
+ SCP_IPI_MAX,
+};
+
+/**
+ * scp_ipi_register - register an ipi function
+ *
+ * @pdev: SCP platform device
+ * @id: IPI ID
+ * @handler: IPI handler
+ * @priv: private data for IPI handler
+ *
+ * Register an ipi function to receive ipi interrupt from SCP.
+ *
+ * Return: Return 0 if ipi registers successfully, otherwise it is failed.
+ */
+int scp_ipi_register(struct platform_device *pdev,
+ enum scp_ipi_id id,
+ scp_ipi_handler_t handler,
+ void *priv);
+
+/**
+ * scp_ipi_unregister - unregister an ipi function
+ *
+ * @pdev: SCP platform device
+ * @id: IPI ID
+ *
+ * Unregister an ipi function to receive ipi interrupt from SCP.
+ */
+void scp_ipi_unregister(struct platform_device *pdev, enum scp_ipi_id id);
+
+/**
+ * scp_ipi_send - send data from AP to scp.
+ *
+ * @pdev: SCP platform device
+ * @id: IPI ID
+ * @buf: the data buffer
+ * @len: the data buffer length
+ * @wait: 1: need ack
+ *
+ * This function is thread-safe. When this function returns,
+ * SCP has received the data and starts the processing.
+ * When the processing completes, IPI handler registered
+ * by scp_ipi_register will be called in interrupt context.
+ *
+ * Return: Return 0 if sending data successfully, otherwise it is failed.
+ **/
+int scp_ipi_send(struct platform_device *pdev,
+ enum scp_ipi_id id,
+ void *buf,
+ unsigned int len,
+ unsigned int wait);
+
+/**
+ * scp_get_pdev - get SCP's platform device
+ *
+ * @pdev: the platform device of the module requesting SCP platform
+ * device for using SCP API.
+ *
+ * Return: Return NULL if it is failed.
+ * otherwise it is SCP's platform device
+ **/
+struct platform_device *scp_get_pdev(struct platform_device *pdev);
+
+/**
+ * scp_get_vdec_hw_capa - get video decoder hardware capability
+ *
+ * @pdev: SCP platform device
+ *
+ * Return: video decoder hardware capability
+ **/
+unsigned int scp_get_vdec_hw_capa(struct platform_device *pdev);
+
+/**
+ * scp_get_venc_hw_capa - get video encoder hardware capability
+ *
+ * @pdev: SCP platform device
+ *
+ * Return: video encoder hardware capability
+ **/
+unsigned int scp_get_venc_hw_capa(struct platform_device *pdev);
+
+/**
+ * scp_mapping_dm_addr - Mapping SRAM/DRAM to kernel virtual address
+ *
+ * @pdev: SCP platform device
+ * @mem_addr: SCP views memory address
+ *
+ * Mapping the SCP's SRAM address /
+ * DMEM (Data Extended Memory) memory address /
+ * Working buffer memory address to
+ * kernel virtual address.
+ *
+ * Return: Return ERR_PTR(-EINVAL) if mapping failed,
+ * otherwise the mapped kernel virtual address
+ **/
+void *scp_mapping_dm_addr(struct platform_device *pdev,
+ u32 mem_addr);
+
+#endif /* _MTK_SCP_H */
--
2.23.0.187.g17f5b7556c-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v17 1/5] dt-bindings: Add a binding for Mediatek SCP
From: Pi-Hsun Shih @ 2019-09-04 6:16 UTC (permalink / raw)
Cc: Ohad Ben-Cohen, Rob Herring,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Erin Lo, open list:REMOTE PROCESSOR REMOTEPROC SUBSYSTEM,
open list, Bjorn Andersson, Rob Herring,
moderated list:ARM/Mediatek SoC support, Pi-Hsun Shih,
Matthias Brugger, Mark Rutland,
moderated list:ARM/Mediatek SoC support
In-Reply-To: <20190904061649.69099-1-pihsun@chromium.org>
From: Erin Lo <erin.lo@mediatek.com>
Add a DT binding documentation of SCP for the
MT8183 SoC from Mediatek.
Signed-off-by: Erin Lo <erin.lo@mediatek.com>
Signed-off-by: Pi-Hsun Shih <pihsun@chromium.org>
Reviewed-by: Rob Herring <robh@kernel.org>
---
Changes from v16, v15, v14, v13, v12, v11, v10, v9, v8, v7, v6:
- No change.
Changes from v5:
- Remove dependency on CONFIG_RPMSG_MTK_SCP.
Changes from v4:
- Add detail of more properties.
- Document the usage of mtk,rpmsg-name in subnode from the new design.
Changes from v3:
- No change.
Changes from v2:
- No change. I realized that for this patch series, there's no need to
add anything under the mt8183-scp node (neither the mt8183-rpmsg or
the cros-ec-rpmsg) for them to work, since mt8183-rpmsg is added
directly as a rproc_subdev by code, and cros-ec-rpmsg is dynamically
created by SCP name service.
Changes from v1:
- No change.
---
.../bindings/remoteproc/mtk,scp.txt | 36 +++++++++++++++++++
1 file changed, 36 insertions(+)
create mode 100644 Documentation/devicetree/bindings/remoteproc/mtk,scp.txt
diff --git a/Documentation/devicetree/bindings/remoteproc/mtk,scp.txt b/Documentation/devicetree/bindings/remoteproc/mtk,scp.txt
new file mode 100644
index 000000000000..3ba668bab14b
--- /dev/null
+++ b/Documentation/devicetree/bindings/remoteproc/mtk,scp.txt
@@ -0,0 +1,36 @@
+Mediatek SCP Bindings
+----------------------------------------
+
+This binding provides support for ARM Cortex M4 Co-processor found on some
+Mediatek SoCs.
+
+Required properties:
+- compatible Should be "mediatek,mt8183-scp"
+- reg Should contain the address ranges for the two memory
+ regions, SRAM and CFG.
+- reg-names Contains the corresponding names for the two memory
+ regions. These should be named "sram" & "cfg".
+- clocks Clock for co-processor (See: ../clock/clock-bindings.txt)
+- clock-names Contains the corresponding name for the clock. This
+ should be named "main".
+
+Subnodes
+--------
+
+Subnodes of the SCP represent rpmsg devices. The names of the devices are not
+important. The properties of these nodes are defined by the individual bindings
+for the rpmsg devices - but must contain the following property:
+
+- mtk,rpmsg-name Contains the name for the rpmsg device. Used to match
+ the subnode to rpmsg device announced by SCP.
+
+Example:
+
+ scp: scp@10500000 {
+ compatible = "mediatek,mt8183-scp";
+ reg = <0 0x10500000 0 0x80000>,
+ <0 0x105c0000 0 0x5000>;
+ reg-names = "sram", "cfg";
+ clocks = <&infracfg CLK_INFRA_SCPSYS>;
+ clock-names = "main";
+ };
--
2.23.0.187.g17f5b7556c-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v17 0/5] Add support for mt8183 SCP.
From: Pi-Hsun Shih @ 2019-09-04 6:16 UTC (permalink / raw)
Cc: open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
open list:REMOTE PROCESSOR REMOTEPROC SUBSYSTEM, open list,
moderated list:ARM/Mediatek SoC support, Pi-Hsun Shih,
moderated list:ARM/Mediatek SoC support
Add support for controlling and communicating with mt8183's system
control processor (SCP), using the remoteproc & rpmsg framework.
And also add a cros_ec driver for CrOS EC host command over rpmsg.
The overall structure of the series is:
* remoteproc/mtk_scp.c: Control the start / stop of SCP (Patch 2, 3).
* remoteproc/mtk_scp_ipi.c: Communicates to SCP using inter-processor
interrupt (IPI) and shared memory (Patch 2, 3).
* rpmsg/mtk_rpmsg.c: Wrapper to wrap the IPI communication into a rpmsg
device. Supports name service for SCP firmware to
announce channels (Patch 4).
* add scp dts node to mt8183 platform (Patch 5).
Changes from v16:
- Change the desc_lock mutex to be a per-id lock.
- Put the execution of handler inside the per-id lock, to prevent race
between scp_ipi_unregister and handler being run.
- Move the initialization of mutex to before scp_ipi_register.
Changes from v15:
- Fix a bug on incorrect usage of wait_event_timeout return value.
Changes from v14:
- Fix a typo on variable in DEBUG section.
Changes from v13:
- Move include/linux/platform_data/mtk_scp.h to
include/linux/remoteproc/mtk_scp.h.
- Rename scp_get_reserve_* to scp_get_reserved_*.
- Add lock for access of scp->ipi_desc.
- Lock the whole ipi_send function.
- Move more setting of cache size from SCP firmware to kernel driver,
to prevent problem while loading firmware onto DRAM.
- Minor fixes addressing comment.
Changes from v12:
- Initialize cache before firmware load, to avoid problem while loading
large firmware.
- Disable watchdog before stopping SCP, to avoid extra warning message.
- Fix new warnings by checkpatch.
Changes from v11:
- Fixed a bug that mtk_rpmsg_endpoint is not properly cleaned up if
rproc_boot fails.
- Add missing documentation in comment.
Changes from v10:
- Drop applied cros_ec_rpmsg patches.
- Add clock reset before loading SCP firmware.
- Fix some type mismatch warnings when printing debug messages.
Changes from v9:
- Remove reserve-memory-vpu_share node.
- Remove change to cros_ec_commands.h (That is already in
https://lore.kernel.org/lkml/20190518063949.GY4319@dell/T/)
Changes from v8:
- Rebased onto https://patchwork.kernel.org/cover/10962385/.
- Drop merged cros_ec_rpmsg patch, and add scp dts node patch.
- Add more reserved memory region.
Changes from v7:
- Rebase onto https://lore.kernel.org/patchwork/patch/1059196/.
- Fix clock enable/disable timing for SCP driver.
- Add more SCP IPI ID.
Changes from v6:
- Decouple mtk_rpmsg from mtk_scp.
- Change data of EC response to be aligned to 4 bytes.
Changes from v5:
- Add device tree binding document for cros_ec_rpmsg.
- Better document in comments for cros_ec_rpmsg.
- Remove dependency on CONFIG_ in binding tree document.
Changes from v4:
- Merge patch 6 (Load ELF firmware) into patch 2, so the driver loads
ELF firmware by default, and no longer accept plain binary.
- rpmsg_device listed in device tree (as a child of the SCP node) would
have it's device tree node mapped to the rpmsg_device, so the rpmsg
driver can use the properties on device tree.
Changes from v3:
- Make writing to SCP SRAM aligned.
- Add a new patch (Patch 6) to load ELF instead of bin firmware.
- Add host event support for EC driver.
- Fix some bugs found in testing (missing spin_lock_init,
rproc_subdev_unprepare to rproc_subdev_stop).
- Fix some coding style issue found by checkpatch.pl.
Changes from v2:
- Fold patch 3 into patch 2 in v2.
- Move IPI id around to support cross-testing for old and new firmware.
- Finish more TODO items.
Changes from v1:
- Extract functions and rename variables in mtk_scp.c.
- Do cleanup properly in mtk_rpmsg.c, which also removes the problem of
short-lived work items.
- Code format fix based on feedback for cros_ec_rpmsg.c.
- Extract feature detection for SCP into separate patch (Patch 6).
Eddie Huang (1):
arm64: dts: mt8183: add scp node
Erin Lo (3):
dt-bindings: Add a binding for Mediatek SCP
remoteproc/mediatek: add SCP support for mt8183
remoteproc: mt8183: add reserved memory manager API
Pi-Hsun Shih (1):
rpmsg: add rpmsg support for mt8183 SCP.
.../bindings/remoteproc/mtk,scp.txt | 36 +
arch/arm64/boot/dts/mediatek/mt8183-evb.dts | 11 +
arch/arm64/boot/dts/mediatek/mt8183.dtsi | 12 +
drivers/remoteproc/Kconfig | 10 +
drivers/remoteproc/Makefile | 1 +
drivers/remoteproc/mtk_common.h | 94 +++
drivers/remoteproc/mtk_scp.c | 722 ++++++++++++++++++
drivers/remoteproc/mtk_scp_ipi.c | 177 +++++
drivers/rpmsg/Kconfig | 9 +
drivers/rpmsg/Makefile | 1 +
drivers/rpmsg/mtk_rpmsg.c | 414 ++++++++++
include/linux/remoteproc/mtk_scp.h | 168 ++++
include/linux/rpmsg/mtk_rpmsg.h | 38 +
13 files changed, 1693 insertions(+)
create mode 100644 Documentation/devicetree/bindings/remoteproc/mtk,scp.txt
create mode 100644 drivers/remoteproc/mtk_common.h
create mode 100644 drivers/remoteproc/mtk_scp.c
create mode 100644 drivers/remoteproc/mtk_scp_ipi.c
create mode 100644 drivers/rpmsg/mtk_rpmsg.c
create mode 100644 include/linux/remoteproc/mtk_scp.h
create mode 100644 include/linux/rpmsg/mtk_rpmsg.h
--
2.23.0.187.g17f5b7556c-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 1/1] mm/pgtable/debug: Add test validating architecture page table helpers
From: Anshuman Khandual @ 2019-09-04 6:14 UTC (permalink / raw)
To: kbuild test robot
Cc: Mark Rutland, linux-ia64, linux-sh, Tetsuo Handa, James Hogan,
Heiko Carstens, Michal Hocko, linux-mm, Paul Mackerras,
sparclinux, Dan Williams, linux-s390, Michael Ellerman, x86,
Russell King - ARM Linux, Matthew Wilcox, Steven Price,
Jason Gunthorpe, Vlastimil Babka, linux-snps-arc, kbuild-all,
Kees Cook, Mark Brown, Thomas Gleixner, linux-arm-kernel,
Sri Krishna chowdary, Masahiro Yamada, Greg Kroah-Hartman,
Ard Biesheuvel, Dave Hansen, linux-mips, Ralf Baechle,
linux-kernel, Peter Zijlstra, Mike Rapoport, Paul Burton,
Vineet Gupta, Martin Schwidefsky, Andrew Morton, linuxppc-dev,
David S. Miller
In-Reply-To: <201909031912.htvWy2Bu%lkp@intel.com>
On 09/03/2019 04:43 PM, kbuild test robot wrote:
> Hi Anshuman,
>
> Thank you for the patch! Yet something to improve:
>
> [auto build test ERROR on linus/master]
> [cannot apply to v5.3-rc7 next-20190902]
> [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/Anshuman-Khandual/mm-debug-Add-tests-for-architecture-exported-page-table-helpers/20190903-162959
> config: m68k-allmodconfig (attached as .config)
> compiler: m68k-linux-gcc (GCC) 7.4.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
> GCC_VERSION=7.4.0 make.cross ARCH=m68k
>
> If you fix the issue, kindly add following tag
> Reported-by: kbuild test robot <lkp@intel.com>
>
> All error/warnings (new ones prefixed by >>):
>
> In file included from arch/m68k/include/asm/bug.h:32:0,
> from include/linux/bug.h:5,
> from include/linux/thread_info.h:12,
> from include/asm-generic/preempt.h:5,
> from ./arch/m68k/include/generated/asm/preempt.h:1,
> from include/linux/preempt.h:78,
> from arch/m68k/include/asm/irqflags.h:6,
> from include/linux/irqflags.h:16,
> from arch/m68k/include/asm/atomic.h:6,
> from include/linux/atomic.h:7,
> from include/linux/mm_types_task.h:13,
> from include/linux/mm_types.h:5,
> from include/linux/hugetlb.h:5,
> from mm/arch_pgtable_test.c:14:
> mm/arch_pgtable_test.c: In function 'pmd_clear_tests':
>>> arch/m68k/include/asm/page.h:31:22: error: lvalue required as unary '&' operand
> #define pmd_val(x) ((&x)->pmd[0])
> ^
> include/asm-generic/bug.h:124:25: note: in definition of macro 'WARN_ON'
> int __ret_warn_on = !!(condition); \
> ^~~~~~~~~
>>> arch/m68k/include/asm/motorola_pgtable.h:138:26: note: in expansion of macro 'pmd_val'
> #define pmd_none(pmd) (!pmd_val(pmd))
> ^~~~~~~
>>> mm/arch_pgtable_test.c:233:11: note: in expansion of macro 'pmd_none'
> WARN_ON(!pmd_none(READ_ONCE(*pmdp)));
> ^~~~~~~~
> mm/arch_pgtable_test.c: In function 'pmd_populate_tests':
>>> arch/m68k/include/asm/page.h:31:22: error: lvalue required as unary '&' operand
> #define pmd_val(x) ((&x)->pmd[0])
Storing READ_ONCE(*pmdp) in a local pmd_t variable first solves the problem.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 4/4] gpio: Update documentation with ast2600 controllers
From: Rashmica Gupta @ 2019-09-04 6:12 UTC (permalink / raw)
To: linus.walleij, linux-gpio, bgolaszewski
Cc: linux-aspeed, andrew, linux-kernel, joel, Rashmica Gupta,
linux-arm-kernel
In-Reply-To: <20190904061245.30770-1-rashmica.g@gmail.com>
Signed-off-by: Rashmica Gupta <rashmica.g@gmail.com>
---
Documentation/devicetree/bindings/gpio/gpio-aspeed.txt | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/gpio/gpio-aspeed.txt b/Documentation/devicetree/bindings/gpio/gpio-aspeed.txt
index 7e9b586770b0..cd388797e07c 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-aspeed.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio-aspeed.txt
@@ -2,7 +2,8 @@ Aspeed GPIO controller Device Tree Bindings
-------------------------------------------
Required properties:
-- compatible : Either "aspeed,ast2400-gpio" or "aspeed,ast2500-gpio"
+- compatible : Either "aspeed,ast2400-gpio", "aspeed,ast2500-gpio",
+ "aspeed,ast2600-gpio", or "aspeed,ast2600-1-8v-gpio"
- #gpio-cells : Should be two
- First cell is the GPIO line number
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 3/4] gpio: Add in ast2600 details to Aspeed driver
From: Rashmica Gupta @ 2019-09-04 6:12 UTC (permalink / raw)
To: linus.walleij, linux-gpio, bgolaszewski
Cc: linux-aspeed, andrew, linux-kernel, joel, Rashmica Gupta,
linux-arm-kernel
In-Reply-To: <20190904061245.30770-1-rashmica.g@gmail.com>
The ast2600 has two gpio controllers, one for 3.6V GPIOS and one for 1.8V GPIOS.
Signed-off-by: Rashmica Gupta <rashmica.g@gmail.com>
---
drivers/gpio/gpio-aspeed.c | 29 +++++++++++++++++++++++++++--
1 file changed, 27 insertions(+), 2 deletions(-)
diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c
index 60ab042c9129..98881c99d0b9 100644
--- a/drivers/gpio/gpio-aspeed.c
+++ b/drivers/gpio/gpio-aspeed.c
@@ -662,12 +662,14 @@ static void aspeed_gpio_irq_handler(struct irq_desc *desc)
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
struct irq_chip *ic = irq_desc_get_chip(desc);
struct aspeed_gpio *data = gpiochip_get_data(gc);
- unsigned int i, p, girq;
+ unsigned int i, p, girq, banks;
unsigned long reg;
+ struct aspeed_gpio *gpio = gpiochip_get_data(gc);
chained_irq_enter(ic, desc);
- for (i = 0; i < ARRAY_SIZE(aspeed_gpio_banks); i++) {
+ banks = (gpio->config->nr_gpios >> 5) + 1;
+ for (i = 0; i < banks; i++) {
const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i];
reg = ioread32(bank_reg(data, bank, reg_irq_status));
@@ -1108,9 +1110,32 @@ static const struct aspeed_gpio_config ast2500_config =
/* 232 for simplicity, actual number is 228 (4-GPIO hole in GPIOAB) */
{ .nr_gpios = 232, .props = ast2500_bank_props, };
+static const struct aspeed_bank_props ast2600_bank_props[] = {
+ /* input output */
+ {5, 0xffffffff, 0x0000ffff}, /* U/V/W/X */
+ {6, 0xffff0000, 0x0fff0000}, /* Y/Z */
+ { },
+};
+
+static const struct aspeed_gpio_config ast2600_config =
+ /* 208 3.6V GPIOs */
+ { .nr_gpios = 208, .props = ast2600_bank_props, };
+
+static const struct aspeed_bank_props ast2600_1_8v_bank_props[] = {
+ /* input output */
+ {1, 0x0000000f, 0x0000000f}, /* E */
+ { },
+};
+
+static const struct aspeed_gpio_config ast2600_1_8v_config =
+ /* 36 1.8V GPIOs */
+ { .nr_gpios = 36, .props = ast2600_1_8v_bank_props, };
+
static const struct of_device_id aspeed_gpio_of_table[] = {
{ .compatible = "aspeed,ast2400-gpio", .data = &ast2400_config, },
{ .compatible = "aspeed,ast2500-gpio", .data = &ast2500_config, },
+ { .compatible = "aspeed,ast2600-gpio", .data = &ast2600_config, },
+ { .compatible = "aspeed,ast2600-1-8v-gpio", .data = &ast2600_1_8v_config,},
{}
};
MODULE_DEVICE_TABLE(of, aspeed_gpio_of_table);
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 2/4] gpio/aspeed: Setup irqchip dynamically
From: Rashmica Gupta @ 2019-09-04 6:12 UTC (permalink / raw)
To: linus.walleij, linux-gpio, bgolaszewski
Cc: linux-aspeed, andrew, linux-kernel, joel, Rashmica Gupta,
linux-arm-kernel
In-Reply-To: <20190904061245.30770-1-rashmica.g@gmail.com>
This is in preparation for ast2600 as we will have two gpio drivers
which need their own irqchip.
Signed-off-by: Rashmica Gupta <rashmica.g@gmail.com>
---
drivers/gpio/gpio-aspeed.c | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c
index 77752b2624e8..60ab042c9129 100644
--- a/drivers/gpio/gpio-aspeed.c
+++ b/drivers/gpio/gpio-aspeed.c
@@ -52,6 +52,7 @@ struct aspeed_gpio_config {
*/
struct aspeed_gpio {
struct gpio_chip chip;
+ struct irq_chip irqc;
spinlock_t lock;
void __iomem *base;
int irq;
@@ -681,14 +682,6 @@ static void aspeed_gpio_irq_handler(struct irq_desc *desc)
chained_irq_exit(ic, desc);
}
-static struct irq_chip aspeed_gpio_irqchip = {
- .name = "aspeed-gpio",
- .irq_ack = aspeed_gpio_irq_ack,
- .irq_mask = aspeed_gpio_irq_mask,
- .irq_unmask = aspeed_gpio_irq_unmask,
- .irq_set_type = aspeed_gpio_set_type,
-};
-
static void set_irq_valid_mask(struct aspeed_gpio *gpio)
{
const struct aspeed_bank_props *props = gpio->config->props;
@@ -1192,7 +1185,12 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
gpio->irq = rc;
girq = &gpio->chip.irq;
- girq->chip = &aspeed_gpio_irqchip;
+ girq->chip = &gpio->irqc;
+ girq->chip->name = dev_name(&pdev->dev);
+ girq->chip->irq_ack = aspeed_gpio_irq_ack;
+ girq->chip->irq_mask = aspeed_gpio_irq_mask;
+ girq->chip->irq_unmask = aspeed_gpio_irq_unmask;
+ girq->chip->irq_set_type = aspeed_gpio_set_type;
girq->parent_handler = aspeed_gpio_irq_handler;
girq->num_parents = 1;
girq->parents = devm_kcalloc(&pdev->dev, 1,
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 1/4] gpio/aspeed: Fix incorrect number of banks
From: Rashmica Gupta @ 2019-09-04 6:12 UTC (permalink / raw)
To: linus.walleij, linux-gpio, bgolaszewski
Cc: linux-aspeed, andrew, linux-kernel, joel, Rashmica Gupta,
linux-arm-kernel
Fixes: 361b79119a4b7 ('gpio: Add Aspeed driver')
Signed-off-by: Rashmica Gupta <rashmica.g@gmail.com>
---
drivers/gpio/gpio-aspeed.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c
index 9defe25d4721..77752b2624e8 100644
--- a/drivers/gpio/gpio-aspeed.c
+++ b/drivers/gpio/gpio-aspeed.c
@@ -1165,7 +1165,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
gpio->chip.base = -1;
/* Allocate a cache of the output registers */
- banks = gpio->config->nr_gpios >> 5;
+ banks = (gpio->config->nr_gpios >> 5) + 1;
gpio->dcache = devm_kcalloc(&pdev->dev,
banks, sizeof(u32), GFP_KERNEL);
if (!gpio->dcache)
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [RFC PATCH V2 4/4] platform: mtk-isp: Add Mediatek FD driver
From: Jerry-ch Chen @ 2019-09-04 6:09 UTC (permalink / raw)
To: Tomasz Figa
Cc: devicetree@vger.kernel.org, Sean Cheng (鄭昇弘),
laurent.pinchart+renesas@ideasonboard.com,
Rynn Wu (吳育恩), srv_heupstream,
Po-Yang Huang (黃柏陽), mchehab@kernel.org,
suleiman@chromium.org, shik@chromium.org,
Jungo Lin (林明俊),
Sj Huang (黃信璋), yuzhao@chromium.org,
linux-mediatek@lists.infradead.org, zwisler@chromium.org,
matthias.bgg@gmail.com, Christie Yu (游雅惠),
Frederic Chen (陳俊元), hans.verkuil@cisco.com,
linux-arm-kernel@lists.infradead.org, linux-media@vger.kernel.org
In-Reply-To: <CAAFQd5CRC2cyV30B4Qv59HdrJ7Cpe_yK5aY-BecQQ3J3i0PtCQ@mail.gmail.com>
Hi Tomasz,
On Wed, 2019-09-04 at 12:15 +0800, Tomasz Figa wrote:
> On Wed, Sep 4, 2019 at 12:38 PM Jerry-ch Chen
> <Jerry-ch.Chen@mediatek.com> wrote:
> >
> > Hi Tomasz,
> >
> > On Tue, 2019-09-03 at 20:05 +0800, Tomasz Figa wrote:
> > > On Tue, Sep 3, 2019 at 8:46 PM Jerry-ch Chen <Jerry-ch.Chen@mediatek.com> wrote:
> > > >
> > > > Hi Tomasz,
> > > >
> > > > On Tue, 2019-09-03 at 15:04 +0800, Tomasz Figa wrote:
> > > > > On Tue, Sep 3, 2019 at 3:44 PM Jerry-ch Chen <Jerry-ch.Chen@mediatek.com> wrote:
> > > > > >
> > > > > > On Tue, 2019-09-03 at 13:19 +0800, Tomasz Figa wrote:
> > > > > > > On Mon, Sep 2, 2019 at 8:47 PM Jerry-ch Chen <Jerry-ch.Chen@mediatek.com> wrote:
> > > > > > > >
> > > > > > > > Hi Tomasz,
> > > > > > > >
> > > > > > > > On Fri, 2019-08-30 at 16:33 +0800, Tomasz Figa wrote:
> > > > > > > > > On Wed, Aug 28, 2019 at 11:00 AM Jerry-ch Chen
> > > > > > > > > <Jerry-ch.Chen@mediatek.com> wrote:
> > > > > > > > > >
> > > > > > > > > > Hi Tomasz,
> > > > > > > > > >
> > > > > > > > > > On Mon, 2019-08-26 at 14:36 +0800, Tomasz Figa wrote:
> > > > > > > > > > > Hi Jerry,
> > > > > > > > > > >
> > > > > > > > > > > On Sun, Aug 25, 2019 at 6:18 PM Jerry-ch Chen
> > > > > > > > > > > <Jerry-ch.Chen@mediatek.com> wrote:
> > > > > > > > > > > >
> > > > > > > > > > > > Hi Tomasz,
> > > > > > > > > > > >
> > > > > > > > > > > > On Fri, 2019-08-02 at 16:28 +0800, Tomasz Figa wrote:
> > > > > > > > > > > > > Hi Jerry,
> > > > > > > > > > > > >
> > > > > > > > > > > > > On Tue, Jul 09, 2019 at 04:41:12PM +0800, Jerry-ch Chen wrote:
> > [snip]
> > > > > > > > > > > [snip]
> > > > > > > > > > >
> > > > > > > > > > > > > > +static void mtk_fd_vb2_stop_streaming(struct vb2_queue *vq)
> > > > > > > > > > > > > > +{
> > > > > > > > > > > > > > + struct mtk_fd_ctx *ctx = vb2_get_drv_priv(vq);
> > > > > > > > > > > > > > + struct vb2_buffer *vb;
> > > > > > > > > > > > >
> > > > > > > > > > > > > How do we guarantee here that the hardware isn't still accessing the buffers
> > > > > > > > > > > > > removed below?
> > > > > > > > > > > > >
> > > > > > > > > > > > Maybe we can check the driver state flag and aborting the unfinished
> > > > > > > > > > > > jobs?
> > > > > > > > > > > > (fd_hw->state == FD_ENQ)
> > > > > > > > > > > >
> > > > > > > > > > >
> > > > > > > > > > > Yes, we need to either cancel or wait for the currently processing
> > > > > > > > > > > job. It depends on hardware capabilities, but cancelling is generally
> > > > > > > > > > > preferred for the lower latency.
> > > > > > > > > > >
> > > > > > > > > > Ok, it the state is ENQ, then we can disable the FD hw by controlling
> > > > > > > > > > the registers.
> > > > > > > > > >
> > > > > > > > > > for example:
> > > > > > > > > > writel(0x0, fd->fd_base + FD_HW_ENABLE);
> > > > > > > > > > writel(0x0, fd->fd_base + FD_INT_EN);
> > > > > > > > > >
> > > > > > > > >
> > > > > > > > > What's exactly the effect of writing 0 to FD_HW_ENABLE?
> > > > > > > > >
> > > > > > > > Sorry, my last reply didn't solve the question,
> > > > > > > > we should implement a mtk_fd_job_abort() for v4l2_m2m_ops().
> > > > > > > >
> > > > > > > > which is able to readl_poll_timeout_atomic()
> > > > > > > > and check the HW busy bits in the register FD_INT_EN;
> > > > > > > >
> > > > > > > > if they are not cleared until timeout, we could handle the last
> > > > > > > > processing job.
> > > > > > > > Otherwise, the FD irq handler should have handled the last processing
> > > > > > > > job and we could continue the stop_streaming().
> > > > > > > >
> > > > > > > > For job_abort():
> > > > > > > > static void mtk_fd_job_abort(void *priv)
> > > > > > > > {
> > > > > > > > struct mtk_fd_ctx *ctx = priv;
> > > > > > > > struct mtk_fd_dev *fd = ctx->fd_dev;
> > > > > > > > u32 val;
> > > > > > > > u32 ret;
> > > > > > > >
> > > > > > > > ret = readl_poll_timeout_atomic(fd->fd_base + MTK_FD_REG_OFFSET_INT_EN,
> > > > > > > > val,
> > > > > > > > (val & MTK_FD_HW_BUSY_MASK) ==
> > > > > > > > MTK_FD_HW_STATE_IS_BUSY,
> > > > > > > > USEC_PER_MSEC, MTK_FD_STOP_HW_TIMEOUT);
> > > > > > >
> > > > > > > Hmm, would it be possible to avoid the busy wait by having a
> > > > > > > completion that could be signalled from the interrupt handler?
> > > > > > >
> > > > > > > Best regards,
> > > > > > > Tomasz
> > > > > >
> > > > > > I suppose that would be wakeup a wait queue in the interrupt handler,
> > > > > > the the wait_event_interrupt_timeout() will be used in here and system
> > > > > > suspend e.g. mtk_fd_suspend().
> > > > >
> > > > > Yes, that should work.
> > > > >
> > > > > > Or do you suggest to wait_event_interrupt_timeout() every frame in the
> > > > > > mtk_fd_ipi_handler()?
> > > > >
> > > > > Nope, we shouldn't need that.
> > > > >
> > > > > > I think maybe the readl_poll_timeout_atomic would be good enough.
> > > > > >
> > > > >
> > > > > Not really. Busy waiting should be avoided as much as possible. What's
> > > > > the point of entering suspend if you end up burning the power by
> > > > > spinning the CPU for some milliseconds?
> > > > >
> > > > Ok, I see, busy waiting is not a good idea, I will use the wait queue
> > > > instead. the job abort will refine as following:
> > > >
> > > > static void mtk_fd_job_abort(void *priv)
> > > > {
> > > > struct mtk_fd_ctx *ctx = priv;
> > > > struct mtk_fd_dev *fd = ctx->fd_dev;
> > > > u32 ret;
> > > >
> > > > ret = wait_event_interruptible_timeout
> > > > (fd->wq, (fd->fd_irq_result & MTK_FD_HW_IRQ_MASK),
> > > > usecs_to_jiffies(50000));
> > > > if (ret)
> > > > mtk_fd_hw_job_finish(fd, VB2_BUF_STATE_ERROR);
> > > > dev_dbg(fd->dev, "%s, ret:%d\n", __func__, ret);
> > > >
> > > > fd->fd_irq_result = 0;
> > > > }
> > > >
> > > > static struct v4l2_m2m_ops fd_m2m_ops = {
> > > > .device_run = mtk_fd_device_run,
> > > > .job_abort = mtk_fd_job_abort,
> > >
> > > I'm not sure we should be using the functon above as the .job_abort
> > > callback. It's expected to abort the job, but we're just waiting for
> > > it to finish. I think we should just call mtk_fd_job_abort() manually
> > > from .stop_streaming.
> > >
> >
> > Ok, I will fix it.
> >
> > > > };
> > > >
> > > > and we could use it in suspend.
> > > > static int mtk_fd_suspend(struct device *dev)
> > > > {
> > > > struct mtk_fd_dev *fd = dev_get_drvdata(dev);
> > > >
> > > > if (pm_runtime_suspended(dev))
> > > > return 0;
> > > >
> > > > if (fd->fd_stream_count)
> > > > mtk_fd_job_abort(fd->ctx);
> > > >
> > > > /* suspend FD HW */
> > > > writel(0x0, fd->fd_base + MTK_FD_REG_OFFSET_INT_EN);
> > > > writel(0x0, fd->fd_base + MTK_FD_REG_OFFSET_HW_ENABLE);
> > > > clk_disable_unprepare(fd->fd_clk);
> > > > dev_dbg(dev, "%s:disable clock\n", __func__);
> > > >
> > > > return 0;
> > > > }
> > > >
> > > > static irqreturn_t mtk_fd_irq(int irq, void *data)
> > > > {
> > > > struct mtk_fd_dev *fd = (struct mtk_fd_dev *)data;
> > > >
> > > > fd->fd_irq_result = readl(fd->fd_base + MTK_FD_REG_OFFSET_INT_VAL);
> > > > wake_up_interruptible(&fd->wq);
> > >
> > > The wake up should be done at the very end of this function. Otherwise
> > > we end up with m2m framework racing with the mtk_fd_hw_job_finish()
> > > below.
> > >
> > > Also, I'd use a completion here rather than an open coded wait and
> > > wake-up. The driver could reinit_completion() before queuing a job to
> > > the hardware and the IRQ handler would complete(). There would be no
> > > need to store the IRQ flags in driver data anymore.
> > Ok, It will be refined as following:
> >
> > suspend and stop streaming will call mtk_fd_job_abort()
> >
> > static void mtk_fd_job_abort(struct mtk_fd_dev *fd)
> > {
> > u32 ret;
> >
> > ret = wait_for_completion_timeout(&fd->fd_irq_done,
> > msecs_to_jiffies(MTK_FD_HW_TIMEOUT));
> > if (ret)
>
> For the _timeout variants, !ret means the timeout and ret > 0 means
> that the wait ended successfully before.
>
Thanks, fixed.
> Also please make sure that the timeout is big enough not to happen
> normally on a heavily loaded system. Something like 1 second should be
> good.
>
Ok, I will make it 1 second
#define MTK_FD_HW_TIMEOUT 1000
Also, I will add a condition in mtk_fd_vb2_stop_streaming(), since it
would be called twice, now it works fine whether I reuse the condition
with mtk_fd_hw_disconnect or not, however, I think do it before buffer
remove looks more reasonable.
static void mtk_fd_vb2_stop_streaming(struct vb2_queue *vq)
{
struct mtk_fd_ctx *ctx = vb2_get_drv_priv(vq);
struct mtk_fd_dev *fd = ctx->fd_dev;
struct vb2_v4l2_buffer *vb;
struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
struct v4l2_m2m_queue_ctx *queue_ctx;
if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
mtk_fd_job_abort(fd);
queue_ctx = V4L2_TYPE_IS_OUTPUT(vq->type) ?
&m2m_ctx->out_q_ctx :
&m2m_ctx->cap_q_ctx;
while ((vb = v4l2_m2m_buf_remove(queue_ctx)))
v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR);
if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
mtk_fd_hw_disconnect(fd);
}
> > mtk_fd_hw_job_finish(fd, VB2_BUF_STATE_ERROR);
> > }
> >
> > complete at irq handler
> >
> > static irqreturn_t mtk_fd_irq(int irq, void *data)
> > {
> > struct mtk_fd_dev *fd = (struct mtk_fd_dev *)data;
> >
> > /* must read this register otherwise HW will keep sending irq */
> > readl(fd->fd_base + MTK_FD_REG_OFFSET_INT_VAL);
> > fd->output->number = readl(fd->fd_base + MTK_FD_REG_OFFSET_RESULT);
> > dev_dbg(fd->dev, "mtk_fd_face_num:%d\n", fd->output->number);
> >
> > pm_runtime_put((fd->dev));
> > mtk_fd_hw_job_finish(fd, VB2_BUF_STATE_DONE);
> > complete(&fd->fd_irq_done);
> > return IRQ_HANDLED;
> > }
> >
> > and reinit_completion before time before sending a job to HW
> >
> > static int mtk_fd_hw_job_exec(struct mtk_fd_dev *fd,
> > struct fd_enq_param *fd_param)
> > {
> > struct ipi_message fd_ipi_msg;
> > int ret;
> >
> > pm_runtime_get_sync((fd->dev));
> >
> > reinit_completion(&fd->fd_irq_done);
> > fd_ipi_msg.cmd_id = MTK_FD_IPI_CMD_ENQUEUE;
> > memcpy(&fd_ipi_msg.fd_enq_param, fd_param, sizeof(struct
> > fd_enq_param));
> > ret = scp_ipi_send(fd->scp_pdev, SCP_IPI_FD_CMD, &fd_ipi_msg,
> > sizeof(fd_ipi_msg), MTK_FD_IPI_SEND_TIMEOUT);
> > if (ret) {
> > pm_runtime_put((fd->dev));
> > mtk_fd_hw_job_finish(fd, VB2_BUF_STATE_ERROR);
> > return ret;
> > }
> > return 0;
> > }
>
> Looks good, thanks. Please also don't forget about init_completion()
> in driver probe.
>
Yes, thanks for remind.
Best regards,
Jerry
> Best regards,
> Tomasz
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v2 09/11] coresight: etm4x: docs: Update ABI doc for sysfs features added.
From: Greg KH @ 2019-09-04 5:48 UTC (permalink / raw)
To: Mathieu Poirier
Cc: Jon Corbet, Coresight ML, open list:DOCUMENTATION,
linux-arm-kernel, Suzuki K. Poulose, Mike Leach
In-Reply-To: <CANLsYkwvasYKaepXuWdkTKDj7RquATaum-dmTZZQL237wesryQ@mail.gmail.com>
On Tue, Sep 03, 2019 at 04:51:40PM -0600, Mathieu Poirier wrote:
> On Tue, 3 Sep 2019 at 13:59, Greg KH <gregkh@linuxfoundation.org> wrote:
> >
> > On Thu, Aug 29, 2019 at 10:33:19PM +0100, Mike Leach wrote:
> > > Update document to include the new sysfs features added during this
> > > patchset.
> > >
> > > Updated to reflect the new sysfs component nameing schema.
> > >
> > > Signed-off-by: Mike Leach <mike.leach@linaro.org>
> > > ---
> > > .../testing/sysfs-bus-coresight-devices-etm4x | 183 +++++++++++-------
> > > 1 file changed, 115 insertions(+), 68 deletions(-)
> > >
> > > diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
> > > index 36258bc1b473..112c50ae9986 100644
> > > --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
> > > +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
> > > @@ -1,4 +1,4 @@
> > > -What: /sys/bus/coresight/devices/<memory_map>.etm/enable_source
> > > +What: /sys/bus/coresight/devices/etm<N>/enable_source
> >
> > You are renaming sysfs directories that have been around since:
> >
> > > Date: April 2015
> >
> > ???
> >
> > Really?
> >
> > That's brave.
>
>
> When I worked on the coresight sysfs ABI a while back I specifically
> added it at the "testing" level as I was well aware that things could
> change in the future. According to the guidelines in the
> documentation userspace can rely on it which was accurate since the
> interface didn't change for 4 years. But the guidelines also mention
> that changes can occur before the interfaces are move to stables, and
> that programs are encouraged to manifest their interest by adding
> their name to the "users" field.
>
> The interface was changed in 5.2 to support coresight from ACPI and
> make things easier to understand for users. It is a lot more
> intuitive to associate an ETM tracer with the CPU it belongs to by
> referring to the CPU number than the memory mapped address. Given the
> "testing" status of the interface and the absence of registered users
> I decided to move forward with the change. If "testing" is too strict
> for that I suggest to add an "experimental" category where it would be
> more acceptable to change things as subsystems mature.
"testing" is not really "testing" if you have userspace tools/programs
assuming the location and contents of specific files in sysfs.
You can change things in sysfs by creating new files, but to do
wholesale renaming like you did here can be very dangerous as you might
be breaking things. Usually new files are created, not existing ones
moved.
What tools use these today? What is going to break?
thanks,
greg k-h
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ 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